<sect>Reference
<p>

This reference section tries to tell all the details of how each
subsystem parameter affects things, though perhaps without wide
explanations in every place. The usage examples and elaborations
are left (mostly) for the Administration part.

<sect1>SMTP-server
<p>

The ZMailer distribution contains an <em>SMTP</em> server program for the BSD socket
implementation of TCP/IP.  It is an asynchronous implementation, in that
address semantics are not checked in real time, nor are other (optional in
the <em>SMTP</em> standard) functions that require <em>router</em> functionality. The server
will run an RFC-821 syntax scanner for addresses and if things are ok, it 
says ``Yes yes, sure!'' to everything, and passes the information to
the <em>router</em> for verification.  The program may also be used in non-daemon
mode to unpack BSMTP format messages on the standard input stream.  For
compatibility with the <em>sendmail</em> variation on the <em>SMTP</em> protocol, it accepts
the <bf>VERB</bf> and <bf>ONEX</bf> commands as No-Ops. The <bf>VRFY</bf>, 
<bf>EXPN</bf>, <bf>HELP</bf>, and
<bf>TURN</bf> commands are presently unimplemented, as is the case for the
interactive <bf>SEND</bf>, <bf>SAML</bf>, and <bf>SOML</bf> commands.

This program implements the server side of the <em>SMTP</em> protocol as described in 
RFC821, and knows about the common extensions to the protocol expected by
<em>sendmail</em> and BSMTP clients. By default the program will kill the previous 
smtp-server daemon, if any, then detach and listen for <em>SMTP</em> connections. 
Incoming messages will be submitted for processing using the 
<tt>zmailer(3)</tt> interface to ZMailer. Nontrivial address checking is 
done asynchronously, although this behaviour can be changed by a command 
line option if you cannot afford to transfer data just to bounce it back. 
All checking is done by executing the <em>router(8)</em> program in 
interactive mode, and executing a well-known shell function with well-known 
parameters for each request.

<sect2>SMTP-server Runtime Parameters
<p>

<bf>Usage</bf>

<tt>smtpserver &lsqb; -46aginvBV &rsqb; &lsqb; -p port &rsqb; &lsqb; -l logfile &rsqb; &lsqb; -s &lsqb;ftveR&rsqb; &rsqb; &lsqb; -L maxloadaver &rsqb; &lsqb; 
-M SMTPmaxsize &rsqb; &lsqb; -P postoffice &rsqb; &lsqb; -R router &rsqb; 
&lsqb; -C cfgfile &rsqb;</tt>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-4</tt>/ Explicitly use IPv4 type of socket even on machines that are capable to do IPv6 type of sockets.
<tag/<tt>-6</tt>/ Explicitly (try to) use IPv6 type of socket even if the machine does not support it. 
By default the server will try to use IPv6, if it has been compiled in an environment where it is present, 
but will fall back to IPv4 if the runtime system does not have IPv6.
<tag/<tt>-a</tt>/ Turn on RFC931/RFC1413 identification protocol, and log the information acquired with it to the 
submitted file.
<tag/<tt>-B</tt>/ Flags the email to arrive via BSMTP channel (via BITNET, for example).
<tag/<tt>-C cfgfile</tt>/ Specifies nonstandard configuration file location; the default is 
<tt>&dollar;MAILSHARE/smtpserver.conf</tt>.
<tag/<tt>-g</tt>/ The gullible option will make the program believe any information it is told 
(such as origin of a connection) without checking.
<tag/<tt>-i</tt>/ Runs the server interactively, which makes it usable for processing a batched 
<em>SMTP</em> stream (BSMTP) on <tt>stdin</tt>. With <tt>-v</tt> option this echoes incoming BSMTP to create more 
accurate faximile of BITNET BSMTP mailers.
<tag/<tt>-L maxloadaver</tt>/ The maximum load-average the system is under when we still accept email.
<tag/<tt>-l logfile</tt>/ Specifies a logfile and enables recording of incoming <em>SMTP</em> conversations.
<tag/<tt>-M SMTPmaxsize</tt>/ Defines the absolute maximum size we accept from incoming email. 
(Default: infinite) (This is a local policy issue.)
<tag/<tt>-n</tt>/ Indicates the program is being run from <em>inetd(8)</em>.
<tag/<tt>-P postoffice</tt>/ Specifies an alternate <tt>&dollar;POSTOFFICE</tt> directory.
<tag/<tt>-p port</tt>/ Specifies the TCP port to listen on instead of the default <em>SMTP</em> port, 25.
<tag/<tt>-R <em>router</em></tt>/ Specifies an alternate <em>router(8)</em> program to use for address verification.
<tag/<tt>-s</tt>/ Specifies the style of address verification to be performed. There are four independent commands 
that can invoke some kind of address verification, and four independent flags to control whether this should be done. 
They are:
<tt>f</tt> check <bf>MAIL FROM</bf> addresses
<tt>t</tt> check <bf>RCPT TO</bf> addresses
<tt>v</tt> check <bf>VRFY</bf> command argument
<tt>e</tt> check <bf>EXPN</bf> command argument
<tt>R</tt> require addresses to be of syntax: <tt>local@remote (strict 821)</tt>
The flags are concatenated to form the argument to the <tt>-s</tt> option. 
The default is <tt>ve</tt>.
<tag/<tt>-V</tt>/ prints a version message and exits.
</descrip>

<sect2>Configuration
<p>

If the <tt>&dollar;MAILSHARE/smtpserver.conf</tt> file exists it is read 
to configure two kinds of things. Specifically the following:

<itemize>
<item>The style (<tt>-s</tt>) options

Behaviour is based on glob patterns matching the <bf>HELO/EHLO</bf> name given by 
a remote client. Lines beginning with a &num; or whitespace are ignored in the file, 
and all other lines must consist of two tokens: a shell-style (glob) pattern starting 
at the beginning of the line, whitespace, and a sequence of style flags. The first 
matching line is used. As a special case, the flags section may start with a <tt>!</tt> 
character in which case the remainder of the line is a failure comment message to 
print at the client. This configuration capability is intended as a way to control 
misbehaving client software or mailers.
</itemize>

<itemize>
<item>PARAM -entries
</itemize>

Allow server start-time parametrization of several things, including:

<itemize>
<item> system parameters
<item> help texts
<item> acceptance/rejection database definitions
</itemize>

<descrip>
<tag/<tt>PARAM maxsize</tt>/ This is synonym to the start-time <tt>-M</tt> option.
<tag/<tt>PARAM max-error-recipients</tt>/ This defines how many recipients can be on a 
message whose source address is <bf>MAIL FROM:&lt;&gt</bf>. That is, is an error message.
<tag/<tt>PARAM TcpRcvBufferSize</tt>/ This sets <tt>setsockopt(SO_RCVBUF)</tt> value, 
in case the system default is not suitable.
<tag/<tt>PARAM policydb</tt>/ This defines <em>SMTP</em> input policy filtering/analysis 
database location. See the comments in the sample <tt>proto/db/smtp-policy.src</tt> file.
</descrip>

Here is a possible configuration file:

<tscreen><verb>
#PARAM maxsize          10000000  # Same as -M -option
#PARAM max-error-recipients   10  # More than this is propably SPAM! 
#PARAM TcpRcvBufferSize    32000  # Should not need to set!

# Our company contact info:
PARAM help ---------------------------------------------------
PARAM help  This mail-server is at Yoyodyne Propulsion Inc. 
PARAM help  Our telephone number is: +1-234-567-8900, and 
PARAM help  telefax number is: +1-234-567-8999
PARAM help  Our business-hours are Mon-Fri: 0800-1700 (Timezone: -0700) 
PARAM help
PARAM help  Questions regarding our email service should be sent via 
PARAM help  email to address  <postmaster@OURDOMAIN>
PARAM help  Reports about abuse are to be sent to: <abuse@OURDOMAIN> 
PARAM help ----------------------------------------------------
#
PARAM  accept-percent-kludge # "localpart" can contain '%' and '!' 
#PARAM reject-percent-kludge # "localpart" can't contain  --"-
#
# The policy database:
#     (NOTE: See 'makedb' for its default suffixes!)
#
PARAM  policydb btree /opt/mail/db/smtp-policy
#
# HELO pattern	style flags
#
*.mgmt.utoronto.ca	ftve
*.mgmt.toronto.edu	ftve
badguy.org		!Sorry, try later.
localhost		ve
*			-
</verb></tscreen>

<sect2>Policy Filtering Language
<p>

Policy based filter database boilerplate for smtp-server.

File:  <tt>&dollar;MAILVAR/db/smtp-policy.src</tt>

This file is compiled into an actual database using the command:

<tt>&dollar;MAILBIN/policy-builder.sh</tt>

<bf>Usage</bf>

<tt> key &lsqb;attribute value&rsqb;... &lsqb;= _tag&rsqb;</tt>
 
Where:

<tt>key</tt> is: 

<itemize>
<item>a domain name optionally preceded by a dot (.)
<item>``user@'' / ``user@domain'' names.
<item>an IP address expression in canonical &lsqb;nn.nn.nn.nn&rsqb;/prefix form. 
Unspecified bits must be 0. (Network IPv6 addresses containing IPv4-mapped 
addresses are translated into plain IPv4.)
<item>any arbitrary word referred as <tt>_tag</tt> at the right side
</itemize>
     <tt>_tag</tt> may be any key of this database

<tt>attribute</tt> and <tt>value</tt> are tokens. They are used by 
<tt>policytest()</tt> to make decisions.  Attribute names, and understood 
value tokens are:

<tscreen><verb>
	'='		'_any_token_with_starting_underscore' (aliasing)

	'rejectnet'	  { '+', '-' }
	'freezenet'	  { '+', '-' }
	'rejectsource'	  { '+', '-' }
	'freezesource'	  { '+', '-' }
	'relaycustomer'	  { '+', '-' }
	'relaycustnet'	  { '+', '-' }
	'relaytarget'	  { '+', '-' }
	'freeze'	  { '+', '-' }
	'senderokwithdns' { '+', '-' }
	'acceptifmx'	  { '+', '-' }
	'acceptifdns'	  { '+', '-' }
</verb></tscreen>

<sect3>Semantics
<p>

The <tt>policytest()</tt> function is called by smtp-server to check the client 
host, the sender's and recipients' addresses.  <tt>policytest()</tt> looks for 
the name and address of the client host as well as full and partial user address 
and domain part of sender and recipient addresses in this database.  The 
retrieved attributes are used to make decissions on accepting or rejecting 
the incoming mail.

If looking for `foo.bar.edu' and an exact match failed, the database looks for 
keys in sequence:  `.foo.bar.edu', `.bar.edu', `.edu', and `.'.

The order of entries in this file is not important.

When searching for an IP address the entry with the most common (leftside) bits
is returned. So you can have a &lsqb;0.0.0.0&rsqb;/0 entry what specifies the 
default addributes for all unlisted IP addresses. (Both IPv4 and IPv6)

 `=' is a special attribute.

The notation `= _tag' means ``See also at `_tag'". If <tt>server()</tt> doesn't 
find the requested attribute of the object, it will replace object name 
with `_tag' and restart the search.
 
Here is an example configuration, assuming the following decision 
chains of <tt>smtpserver/policytest.c</tt> routines:

Connection establishment:  (IP address tested)

<tscreen><verb>
  if (IP address of SMTP client has 'REJECTNET +' attribute) then
  any further conversation refused
   &lsqb;state->always_reject = 1; return REJECT;&rsqb;
  if (IP address of SMTP client has 'FREEZENET +' attribute) then
  we present happy face, but always put the messages into a freezer...
   &lsqb;state->always_freeze = 1; return FREEZE;&rsqb;
  if (IP address of SMTP client has 'RELAYCUSTNET +' attribute) then
   sender accepted, recipients not checked
   &lsqb;state->always_accept = 1; return ACCEPT;&rsqb;
  default: return ACCEPT
</verb></tscreen>

<bf>HELO/EHLO</bf> parameter string:

<tscreen><verb>
  if (state->always_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (HELO-name of SMTP client has 'REJECTNET +' attribute) then
   any further conversation refused
   &lsqb;state->always_reject = 1; return REJECT;&rsqb;
  if (HELO-name of SMTP client has 'FREEZENET +' attribute) then
   we present happy face, but always put the messages into a freezer..
   [state->always_freeze = 1; return FREEZE;]
  default: return ACCEPT
</verb></tscreen>

<bf>MAIL FROM</bf> address:

<tscreen><verb>
  set state->rcpt_nocheck  = 0;
  set state->sender_reject = 0;
  set state->sender_freeze = 0;
  if (state->always_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (sender's address has 'REJECTSOURCE +' attribute) then
   sender rejected, any further conversation refused
   [state->always_reject = 1; return REJECT;]
  if (sender's address has 'FREEZESOURCE +' attribute) then
   we accept with the happy face, but place it into a freezer
   [state->always_freeze = 1; return FREEZE;]
  when (sender's address is not in policy-db, continue with sender's domain)
  if (sender's domain is not in policy-db) then
    return ACCEPT
  if (sender's domain has 'REJECTSOURCE +' attribute) then
   sender rejected, any further conversation refused
   [state->sender_reject = 1; return REJECT;]
  if (sender's domain has 'FREEZESOURCE +' attribute) then
   we accept with the happy face, but place it into a freezer
   [state->sender_freeze = 1; return FREEZE;]
  if (sender's domain gas 'RELAYCUSTOMER +' attribute) then
   DANGER ! DANGER !
   We will accept all destination addresses for this MAIL FROM,
   except those that are explicitely blocked, of course..
   [state->rcpt_nocheck = 1; return ACCEPT;]
  if (sender's domain has 'SENDEROKWITHDNS +' attribute) then
    verify that is DNS data for the target domain.  If yes, return ACCEPT;
    if not, return "-100" (soft reject)
  if (sender's domain has 'SENDEROKWITHDNS -' attribute) then
    verify that is DNS data for the target domain.  If yes, return ACCEPT;
    if not, return REJECT
  else
    return ACCEPT
</verb></tscreen>

<bf>RCPT TO</bf> address:

<tscreen><verb>
  if (state->always_reject == 1) return REJECT;
  if (state->sender_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->sender_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (recipient address has 'RELAYTARGET +' attribute) then
    return ACCEPT
  if (recipient address has 'RELAYTARGET -' attribute) then
    return REJECT
  if (recipient address has 'FREEZE +' attribute) then
    we accept with the happy face, but place it into a freezer
    [status->sender_freeze = 1; return FREEZE;]
  if (recipient's domain has 'RELAYTARGET +' attribute) then
    return ACCEPT
  if (recipient's domain has 'RELAYTARGET -' attribute) then
    return REJECT
  if (recipient's domain has 'FREEZE +' attribute) then
    we accept with the happy face, but place it into a freezer
    [status->sender_freeze = 1; return FREEZE;]
  If (state->rcpt_nocheck  == 1) return ACCEPT;
  If (recipient's domain has 'ACCEPTIFMX +' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return "-100" (soft reject)
  If (recipient's domain has 'ACCEPTIFMX -' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return REJECT
  If (recipient's domain has 'ACCEPTIFDNS +' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return "-100" (soft reject)
  If (recipient's domain has 'ACCEPTIFDNS -' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return REJECT
  Else
    return ACCEPT
</verb></tscreen>

Default handling boilerplate. We are not relaying between off-site hosts, 
except when:

<tscreen><verb>
# -- 1st alternate: No MX target usage, no DNS existence verify
.			relaycustomer - relaytarget -
[0.0.0.0]/0		relaycustomer - relaytarget -
# -- 2nd alternate: No MX target usage, DNS existence verify
.			relaycustomer - relaytarget - senderokwithdns +
[0.0.0.0]/0		relaycustomer - relaytarget - senderokwithdns +
# -- 3rd alternate: MX relay trust, DNS existence verify
.			relaycustomer - acceptifmx + senderokwithdns +
[0.0.0.0]/0		relaycustomer - acceptifmx + senderokwithdns +
# -- 4th alternate: Sender & recipient DNS existence verify
.			senderokwithdns + acceptifdns +
[0.0.0.0]/0		senderokwithdns + acceptifdns +
</verb></tscreen>

These rules mean that locally accepted hostnames MUST be listed in
the database with the '<tt>relaytarget +</tt>' attribute.

Generally we refuse <em>SMTP</em> connections from host in private address space
and refuse mails to or from <tt>user@[nn.nn.nn.nn]</tt> if nn.nn.nn.nn is a
private IP address...

<tscreen><verb>
_private_address    rejectnet + rejectsource + relaycustomer - relaytarget -
[172.16.0.0]/12		= _private_address
[192.168.0.0]/16	= _private_address
[10.0.0.0]/8		= _private_address
</verb></tscreen>

...but hosts in the address range 192.168.16.0-192.168.17.255 may be
our <em>SMTP</em> clients.

<tscreen><verb>
[192.168.16.0]/23	rejectnet - = _private_address
</verb></tscreen>

Hosts of our organization can do anything...

<tscreen><verb>
_our_network		= _full_rights
_full_rights	rejectnet - relaycustnet + relaycustomer + relaytarget +

sztaki.hu		= _full_rights
.sztaki.hu		= _full_rights
192.84.225.0/24	= _our_network
192.84.226.0/23	= _our_network
192.84.228.0/23	= _our_network
</verb></tscreen>

...except that no use to relaying for dial-up hosts

<tscreen><verb>
.dial.sztaki.hu		relaytarget - = _full_rights
</verb></tscreen>

...and we have a misconfigured <em>SMTP</em> client somewhere

<tscreen><verb>
[192.84.225.1]/32		rejectnet + = _our_network
</verb></tscreen>

We are MX for some UUCP nodes;  The actual list of domains should
be retrieved from some listing, and inserted here, or generated from
a file into compatible format, and appended into the database.

<tscreen><verb>
.uucp.iif.hu		relaytarget +
</verb></tscreen>

Thanks, no bulk mails! Drop them when used as sources, also reject
when asked to send for them.

<tscreen><verb>
_bulk_mail		rejectsource + relaytarget -
</verb></tscreen>

The actual list of domains, and perhaps user addresses should
be retrieved from some active Anti-SPAM database

<tscreen><verb>
nobody.com		= _bulk_mail
.nobody.com		= _bulk_mail
nodomain.com		= _bulk_mail
.nodomain.com		= _bulk_mail
</verb></tscreen>

Some source users we reject always: (frequent spammers...)
(see comment above about Anti-SPAM databases)

<tscreen><verb>
friend@			= _bulk_mail
friends@		= _bulk_mail
</verb></tscreen>

