Here are reference versions of the documentation for each subsystem, these go very deep into details.
process()
functionrouter()
functioncrossbar()
functionserver()
function:"
(doublecolon).", "include"[", "test"attributesbasenamebreakbuiltincarcatcdcdrchannelcontinuedaemondbechoelementsenvarserraddronevalexitexportfileprivfirstgensymgetgetoptsgrindgroupmembershashhomedirectoryhosthostnameifssplitlappendlastlengthlistlistaddresseslistexpandlogin2uidlreplacemalcontentsprintaliasesprocessreadrecaserecipientrelationrestreturnreturnsrfc822rfc822daterfc822syntaxrunassendersetshiftsleepsquirrelstabilitytest", "["timestracetraptypeuid2loginumaskunsetuntraceuserwaitThe ZMailer distribution contains an smtpserver program for the BSD socket implementation of TCP/IP. It is an asynchronous implementation, in that while address syntax is checked in real time, semantics are not, nor are other (optional in the SMTP standard) functions that require router functionality.
The server will run an RFC-821 syntax scanner for addresses, plus possible policy analysis phase, and if things are ok, it says “Yes yes, sure!” to everything. The program may also be used in non-daemon mode to unpack BSMTP format messages on the standard input stream.
This program implements the server side of the SMTP protocol as described in RFC821, and knows about the common extensions to the protocol expected by sendmail and BSMTP clients. By default the program will kill the previous smtpserver daemon, if any, then detach and listen for SMTP connections. Incoming messages will be submitted for processing using the zmailer(3) interface to ZMailer. Some non-trivial address checking is doable in optional policy analysis functions within the smtpserver, or can be acomplished with synchronous (or asynchronous) running of router. This behaviour can be changed by a command line option (or HELO/EHLO style patterns) if you cannot afford to transfer data just to bounce it back.
All router assisted checking is done by executing the router(8) program in interactive mode, and executing well-known shell function with well-known parameters for each request.
The server implements also most of the ESMTP facilities invented up to date (Feb, 2000). The ones that are active are visible at greeting response to “EHLO” command, as can be seen in figure Figure 17-1.
Figure 17-1. Sample “EHLO” greeting with smtpserver
$ telnet 127.1 smtp Connected to 127.1. Escape character is '^]'. 220 localhost ZMailer .... EHLO foo 250-localhost expected "EHLO localhost" 250-SIZE 1234567 250-8BITMIME 250-PIPELINING 250-CHUNKING 250-ENHANCEDSTATUSCODES 250-EXPN 250-VRFY 250-DSN 250-X-RCPTLIMIT 10000 250-ETRN 250 HELP ... |
smtpserver [-46aginvBV] [-p port] [-l logfile] [-s ] [-s
[ftveRS]] [-L maxloadaver] [-M SMTPmaxsize] [-P postoffice] [-R router] [-C cfgfile]'strict'
-4Explicitly use IPv4 type of socket even on machines that are capable to do IPv6 type of sockets.
-6Explicitely (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.
-8This option is part of optional inbound translate processing; see “-X” option below.
-aTurn on RFC931/RFC1413 identification protocol, and log the information acquired with it into the submitted file. Reliability, validity, worthwhileness, ... all such are suspect at this.
-BFlags the email to arrive via BSMTP channel (via BITNET, for example).
-B cfgfileSpecifies nonstandard configuration file location; the default is $MAILSHARE/smtpserver.conf.
-d nnnnThis option sets numeric debug value. Any non-zero will work. This numeric argument is provision for possible bit-flag or level oriented debugging mode….)
-gThe “gullible” option will make the program believe any information it is told (such as origin of a connection) without checking.
-hCheck “HELO” parameter very closely (syntax), and if it is bad, complain with “501”. Such behaviour is against interoperability minded “Be lenient on what you accept” policy, and apparently will break a lot of common clients….
-iRuns the server interactively, which makes it usable for processing a batched SMTP stream (BSMTP) on
stdin. With “-v” option this echoes incoming BSMTP to create more accurate faximile of
BITNET BSMTP mailers.
-L maxloadaverThe maximum load-average the system is under when we still accept email.
Not all systems are supported for load-aver extraction; and as that information happens to be very poorly extractable without major magics, it is our considered opinnion that it is better to spend time to figure other methods for limiting incoming email induced load impact, than trying to see any load-average — anyway the ZMailer smtpserverused without interactive routing is very low load inpact system.
-l 'SYSLOG'Specifies that incoming SMTP conversations are
logged via syslog(3) to system syslogd(8) server by
using facility LOG_MAIL and level LOG_DEBUG messages.
-l LOGFILESpecifies a logfile and enables recording of incoming SMTP conversations to go there.
This can be used in parallel with -l
'SYSLOG' version!
-M SMTPmaxsizeDefines the absolute maximum size we accept from incoming email. (Default: infinite) (This is a local policy issue.)
-nIndicates the program is being run from {\em inetd(8)}.
-P postofficedirSpecifies an alternate $POSTOFFICE/
directory.
-P portSpecifies the TCP port to listen on instead of the default SMTP port: 25.
-R routerpathSpecifies an alternate router(8) program to use for address verification.
-s 'strict'This turns server protocol processing into extremely strict mode, any misplaced character is rejected. Not very practical in real file, but nice for protocol interoperability bakeout testing.
-s 'strict'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:
fRun “MAIL FROM” address through online router for analysis.
tRun “RCPT TO” address through online router for analysis.
vEnable “VRFY” command for this
style selector (if configuration “PARAM
vrfycmd” is in effect)
eEnable “EXPN” command for this
style selector (if configuration “PARAM
expncmd” is in effect)
RRequire incoming addresses to be of fully-qualified domained form.
Don't use this if you want to allow non-domained addresses accepted into your server through SMTP.
SAllow “Sloppy” behaviour from the sending smtp clients; namely allow “MAIL FROM:foo@bar”, that is, an addresses without mandatory (RFC-821) angle braces.
-s” option. The default is “ve”.-S suffixstyleThis defines log suffix which can alter the default logfile name to one which splits incoming traffic into separate files.
Possible values are:
'remote'Append remote hostname to the logfile name (after a dot) so that from host “foo.bar.edu” the logfile would be: “smtpserver.foo.bar.edu”.
'local'Append local end reversed hostname to the logfile name (after a dot) so that in multihomed hosts all different “hosts” have different logfiles. Such does, of course, assume that different IP addresses in the host reverse to different names.
-vThis is a “verbose” option to be used with “-i” option. This is especially for “BSMTP” processing.
-Vprints a version message and exits.
-XThis is “Xlate” option. For more info, see source file:
|
“It may be necessary in some cases (e.g. in Cyrillic-language countries) to translate charset on the messages coming from the clients with, e.g. old Eudora or other MUAs that do not correctly support koi8-r charset. …” |
||
| --README.translation | ||
If the $MAILSHARE/smtpserver.conf file exists it is read to
configure two kinds of things. Specifically the following:
Allow server start-time parametrization of several things, including:
system parameters
help texts
acceptance/rejection database definitions
-s) optionsBehaviour is based on glob patterns matching the HELO/EHLO name given by a remote client. Lines beginning with a “#” 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 “!” 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.
Maximum size in the number of bytes of the entire spool message containing both the transport envelope, and the actual message. That is, if the max-size is too low, and there are a lot of addresses, the message may entirely become undeliverable..
This sets system default value, and overrides commandline “-M” option.
In case the message envelope is an error envelope (MAIL FROM:<>), the don't accept more than this many separate recipient addresses for it. The default value is 3, which should be enough for most cases. (Some SPAMs claim to be error messages, and then provide a huge number of recipient addresses… Of course as spam-spewers learn, they begin just sending single recipients per message — less efficient, but working still…)
(Effective only on daemon-mode server — not on “-i”, nor “-n”
modes.) Sometimes some systems set up multiple parallel connections to same host (qmail ones especially, not
that ZMailer has entirely clean papers on this either — at least up to 2.99.X series), we won't accept
more than this many connections from the same IP source address open in parallel.
The default value for this limit is 10.
The principal reason for this has been authors experience at nic.funet.fi, where some MS-Windows users have caused huge numbers of parallel connections to some services. So huge, that the system did in fact run out of swap due to that, and caused all manner of other nasty things to occur too… All this simply because some windows client had opened 800+ parallel sessions, and each server process consumed separate blocks of swap space… To avoid the system to succumb under such an accidental denial-of-service attack at the overall system, this parallel limit was created.
This sets setsockopt(SO_RCVBUF) value, in case the system default is not
suitable for some reason.
This sets setsockopt(SO_SNDBUF) value, in case the system default is not
suitable for some reason.
This relates to newer systems where the listen(2) system call can define
higher limits, than the traditional/original 5. This limit tells how many nascent TCP streams we can have in
SYN_RCVD state before the socket stops answering to incoming SYN packets requesting opening of a connection.
Such sockets have not opened sufficiently to reach a
state where bi-directional communication has been established, thus they won't appear to accept(2) yet for the server to pick them up!
There are entirely deliberate denial-of-service attacks based on flooding to some server many SYNS on which it can't send replies back (because the target machines don't have network connectivity, for example), and thus filling the back-queue of nascent sockets.
This can also happen accidentally, as the connectivity in between the client host, and the server host may have a black hole into which the SYN-ACK packets disappear, and the client thus will not be able to get the TCP startup three-way handshake completed.
Most modern systems can have this value upped to thousands to improve systems resiliency against malicious attacks, and most likely to provide complete immunity against the accidental “attack” by the failing network routing.
Do consult your system specific information on how much memory each nascent (and matured) socket will require before you commence upping this very much. You might commit heaps of unswappable memory to useless waste.
This one adds yet another string (no quotes are used) into those that are presented to the client when it asks for “HELP” in the SMTP session.
Enables “DEBUG” command in the server. This command turns on various trace functions which ruin the protocol from standards compliant client, but may help interactive debuggers.
Enables “EXPN” command in the server.
Enables “VRFY” command in the server.
This defines the database type, and file path prefix to the binary database containing policy processing information. Actual binary database file names are formed by appending type specific suffixes to the path prefix. For example NDBM database appends “.pag” and “.dir”, while BSD-Btree appends only “.db”. (And the latter has only one file, while the first has two.)
More information below, and at newdb at Section 24.3
When present, this parameter will not convert input of form <@aa,@bb:cc@dd> into source-route-less form of <cc@dd> Instead it carries the original source-route into the system as is.
A possible smtpserver configuration file is shown in figure Figure 17-2.
Figure 17-2. Full-featured smtpserver.conf file example
#
# {\rm{}smtpserver.conf - autogenerated edition}
#
#PARAM maxsize 10000000 # {\rm{}Same as -M -option}
#PARAM max-error-recipients 3 # {\rm{}More than this is propably SPAM!}
#PARAM MaxSameIpSource 10 # {\rm{}Max simultaneous connections from}
# # {\rm{}any IP source address}
#PARAM TcpRcvBufferSize 32000 # {\rm{}Should not need to set!}
#PARAM TcpXmitBufferSize 32000 # {\rm{}Should not need to set!}
#PARAM ListenQueueSize 10 # {\rm{}listen(2) parameter}
# {\rm{}Enables of some commands:}
PARAM debugcmd
PARAM expncmd
PARAM vrfycmd
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 =============================================================
# {\rm{}Uncomment following for not to strip incoming addresses of format:}
# <@aa,@bb:cc@dd> into non-source-routed base form: <cc@dd>
#PARAM allowsourceroute
PARAM accept-percent-kludge # "localpart" can contain '%' and '!'
#PARAM reject-percent-kludge # "localpart" can't contain --"--
# {\rm{}The policy database: (NOTE: See 'makedb' for its default suffixes!)}
PARAM policydb btree /opt/mail/db/smtp-policy
#
# HELO/EHLO-pattern style-flags
# [max loadavg]
localhost 999 ftveR
some.host.domain 999 !NO EMAIL ACCEPTED FROM YOUR MACHINE
# {\rm{}If the host presents itself as: HELO [1.2.3.4], be lenient to it..}
# {\rm{}The syntax below is due to these patterns being SH-GLOB patterns,}
# {\rm{}where brackets are special characters.}
\[*\] 999 ve
# {\rm{}Per default demant strict syntactic adherence, including fully}
# {\rm{}qualified addresses for MAIL FROM, and RCPT TO. To be lenient}
# {\rm{}on that detail, remove the "R" from "veR" string below:}
* 999 veR
|
The policy database that {\em smtpserver} uses is built with {\tt policy-builder.sh} script, which bundles together a set of policy source files:
DB/smtp-policy.src The boilerplate
DB/localnames ('= _localnames')
DB/smtp-policy.relay ('= _full_rights')
DB/smtp-policy.mx ('relaytargets +')
DB/smtp-policy.spam ('= _bulk_mail')
|
At the moment, {\tt smtp-policy.spam} source is retrieved with LYNX from
the URL:
\begin{alltt}\medskip\scriptsize\medskip
http://www.webeasy.com:8080/spam/spam_download_table
\medskip\end{alltt}\medskip
however it seems there are sites out there that are spam havens, and
that serve valid spam source/responce domains, which are not registered
at that database.
{\em If you want, you can modify your {\tt smtp-policy.src} boilerplate
file as well as your installed {\tt\small policy-builder.sh} script.}
{\bf In fact you SHOULD modify both to match your environment!}
Doing {\tt make install} will overwrite {\tt\small policy-builder.sh},
but not {\tt smtp-policy.src}.
Basically these various source files (if they exist) are used to
combine knowledge of valid users around us:
\begin{description}
\item[\tt localnames] \mbox{}
Who we are -- ok domains for receiving.
\item[\tt smtp-policy.relay] \mbox{}
Who can use us as outbound relay.
Use {\em\verb/[/ip.number\verb/]//maskwidth} here for
listing those senders (networks) we absolutely trust.
You may also use domains, or domain suffixes so that the IP-reversed
hostnames are accepted (but that is a it risky thing due to ease of
fakeing the reversed domain names):
\begin{alltt}\medskip\hrule\medskip
[11.22.33.00]/24
ip-reversed.host.name
.domain.suffix
\medskip\hrule\end{alltt}\medskip
Server sets its internal “always_accept” flag at the source IP tests
before it decides on what to tell to the contacting client.
The flag is not modified afterwards during the session.
Usage of domain names here is discouraged as there is no way to tell
that domain “foo.bar” here has different meaning than same domain
elsewere -- at “{\tt smtp-policy.mx}”, for example.
\item[\tt smtp-policy.mx] \mbox{}
Who really are our MX clients.
Use this when you really know them, and don't want just to trust
that if recipient has MX to you, it would be ok…
You can substitute this knowledge with a fuzzy feeling by using
“acceptifmx -” attribute at the generic boilerplate.
List here domain names.
\begin{alltt}\medskip\hrule\medskip
mx-target.dom
.mx-target.dom
\medskip\hrule\end{alltt}\medskip
You CAN also list here all POSTMASTER addresses you accept email routed to:
\begin{alltt}\medskip\hrule\medskip
postmaster@local.domain
postmaster@client.domain
\medskip\hrule\end{alltt}\medskip
these are magic addresses that email is accepted to, even when everything
else is blocked.
\item[\tt smtp-policy.spam] \mbox{}
Those users, and domains that are absolutely no-no for senders,
or recipients no matter what earlier analysis has shown.
(Except for those senders that we absolutely trust..)
\begin{alltt}\medskip\hrule\medskip
user@domain
user@
domain
\medskip\hrule\end{alltt}\medskip
The “{\tt policy-builder.sh}” builds this file from external sources.
\end{description}
|
Policy based filter database boilerplate for smtp-server.
File: {\tt \$MAILVAR/db/smtp-policy.src}
This file is compiled into an actual database using the command:
\begin{alltt}\medskip\hrule\medskip
\$MAILBIN/policy-builder.sh
\medskip\hrule
\end{alltt}\par
The basic syntax of non-comment lines in the policy source is:
\begin{alltt}\medskip\hrule\medskip
key [attribute value]* [= _tag]
\medskip\hrule
\end{alltt}\par
There are any number of attribute-value pairs associated with the key.
There can be only one key of any kind currently active, unless “{\em makedb}”
is called with “-A” option (Append mode) in which case latter appearances
of some keys will yield catenation of of latter data into previous datasets.
(This may or may not be a good idea…)
The key can be any of following forms:
\begin{description}
\item[\rm domain, or .domain.suffix] \mbox{} \\
a domain name optionally preceded by a dot (.)
\item[\rm“user@”, or “user@domain”] \mbox{} \\
Usernames -- domainless (“user@”) or domainfull.
\item[\rm An IP address in {[}nn.nn.nn.nn{]}/prefix form] \mbox{} \\
Unspecified bits must be 0.
(Network IPv6 addresses containing IPv4-mapped addresses are translated
into plain IPv4.)
\item[\rm A tag -- word begining with underscore] \mbox{} \\
An “alias” dataset entry for “=” “attribute” uses.
\end{description}
{\em attribute} and {\em value} are tokens.
They are used by {\tt policytest()} to make decisions.
The attribute scanners operate in a manner, where the first
instance of interesting attribute is the one that is used.
Thus you can construct setups which set some attribute, and
then {\em ignore} all latter instances of that same attribute
which have been pulled in via “{\em = _alias_tag}” mechanism,
for example.
In following, “understood” value is one or both of literals: “+”, “-”,
if they are listed at the definition entry.
In case only one is understood, the other one can be considered as
placeholder which stops the scanner for that attribute.
Attribute names, and understood value tokens are:
\begin{description}
\item[\tt = _any_tag] \mbox{} \\
The analysis function will descend to look up “_any_tag” from
the database, and expand its content in this place.
\item[\tt rejectnet +] \mbox{} \\
Existence of this attribute pair sets persistent session flag:
“always-reject”, which causes all “MAIL FROM” and “RCPT TO”
commands to fail until end of the session.
This is tested for at the connection start against connecting
IP address, and against IP-reversed domain name.
This is also tested against the “HELO/EHLO” supplied parameter
string.
Use of this should be limited only to addresses against which you
really have grudges.
\item[\tt freezenet +] \mbox{} \\
Existence of this attribute pair sets persistent session flag:
“always-freeze”, which will accept messages in, but all of them
are moved into “freezer” spool directory.
This is tested for at the same time as “rejectnet”.
\item[\tt rejectsource +] \mbox{} \\
Existence of this attribute pair rejects “MAIL FROM” address,
and thus all subsequent “RCPT TO” and “DATA” transactions
until new “MAIL FROM” is supplied.
\item[\tt freezesource +] \mbox{} \\
Existence of this attribute pair causes subsequently following
“DATA” phase message to be placed into “freezer” spool directory.
This is tested for only at “MAIL FROM”, and subsequent “MAIL FROM”
may supply another value.
\item[\tt relaycustomer +/-] \mbox{} \\
Existence of this attribute pair is tested for at “MAIL FROM”,
and it affects subsequent “RCPT TO” address testing.
Pair “relaycustomer -” is a placeholder no-op, while
“relaycustomer +” tells to the system that it should not
test the “RCPT TO” address very deeply.
{\em Usage of this attribute is not encouraged!
Anybody could get email relayed through just by claiming
a “MAIL FROM” domain which has this attribute.}
\item[\tt relaycustnet +] \mbox{} \\
Existence of this attribute pair is tested for at the connection
start against connecting IP address, and against IP-reversed domain name.
If this pair exists, session sets persistent “always-accept” flag,
and will not do further policy analysing for the “MAIL FROM”, nor
“RCPT TO” addresses. (Except looking for valid A/MX data from the
DNS for the sender/recipient domains.)
\item[\tt fulltrustnet +] \mbox{} \\
Because the DNS lookups still done with “relaycustnet +” setting on,
a massive feed for fanout servers might become slowed down/effectively
killed, unless we use “fulltrustnet +” specification for the feeder
host. Then everything is taken in happily from that source address.
\item[\tt trustrecipients +] \mbox{} \\
This is a variant of “relaycustnet,” where “RCPT TO” addresses are
not checked at all, but “MAIL FROM” addresses are looked up from
the DNS. (Unless some other test with the “MAIL FROM” domain name
has matched before that.)
\item[\tt trust-whoson +] \mbox{} \\
If the system has been compiled with support to “{\em whoson}” services,
see file “{\em whoson-*.tar.gz}” in the “contrib/” subdirectory.
This facilitates indirectly authenticated (via POP/IMAP) SMTP message
submission for dialup-type users.
\item[\tt relaytarget +] \mbox{} \\
With this attribute pair the current “RCPT TO” address is accepted in
without further trouble. (Theory being, that keys where this attribute
pair exist are fully qualified, and valid, thus no need for DNS analysis.)
See “RCPT TO” processing algorithm for further details.
\item[\tt relaytarget -] \mbox{} \\
This attribute pair causes instant rejection of the current “RCPT TO”
address.
See “RCPT TO” processing algorithm for further details.
\item[\tt freeze +] \mbox{} \\
When “RCPT TO” address test meets this attribute pair, the entire
message will be placed into “freezer” directory.
\item[\tt acceptifmx +/-] \mbox{} \\
This attribute pair is used to give fuzzy feeling in anti-relay setups
so that we don't need to list {\bf all} those target domains that we
are allowing to use ourselves as relays.
This will basically check that “RCPT TO” address has our server
as one of its MX entries.
The value (“+” or “-”) determines how “severe” the nonexistence
of MX data is. With “+” the server will yield “400” series temporary
error with implied invitation to try again, and with “-” the server will
yield “500” series permanent error.
\item[\tt acceptifdns +/-] \mbox{} \\
This attribute pair is complementary for the “acceptifmx” in sense
that it accept the recipient address in case the DNS system has any
A or MX information for it.
This attribute pair should not be used.
\item[\tt senderokwithdns +/-] \mbox{} \\
This attribute pair will do DNS analysis for “MAIL FROM” domain, and
accept it only if there exists A or MX data for the said domain.
The value (“+” or “-”) determines how “severe” the nonexistence
of DNS data is. With “+” the server will yield “400” series temporary
error with implied invitation to try again, and with “-” the server will
yield “500” series permanent error.
\item[\tt sendernorelay +] \mbox{} \\
Tested at “MAIL FROM” address domain, and affects “RCPT TO”
address domain analysis.
{\em At the moment this attribute does not make sense, don't use!}
\item[\tt test-dns-rbl +] \mbox{} \\
This attribute pair will use Paul Vixie's RBL
( HTTP://maps.vix.com/rbl/ )
system to block undesired connection sources.
\item[\tt rply-dns-rbl +] \mbox{} \\
\item[\tt test-rply-dns-rbl +] \mbox{} \\
This is a “recipient selective” version of the RBL.
The first one is to be placed into the default address case
(the “[0.0.0.0]/0”), and then the latter can be used in given
destination domain(s) to test for the result of the lookup.
This allows selective usage of 'RBL' blocking via this server.
For example if you have {\tt smtp-policy.mx} file listing special
cases (opposite of your default domain address “.” values)
\begin{alltt}\medskip\hrule\medskip
fobar.com test-rply-dns-rbl + relaytarget +
barfo.dom test-rply-dns-rbl + relaytarget +
\medskip\hrule\end{alltt}\medskip
The selectivity can be either by means of listing those where the test
happens, or those where it doesn't happen -- the latter means that
the default domain address (“.”) must have “test-rply-dns-rbl +” entry.
\item[\tt maxinsize nnn] \mbox{} \\
This attribute pair yields numeric limit for incoming message
size. With this you can define source specific message size
limits so that if your intranetwork has a system with lower
inbound message size, than you do, you can report this limit
at the “EHLO” responses.
Partly this is placeholder for further code with for example
source/target domain specific runtime enforced size limits.
\item[\tt maxoutsize nnn] \mbox{} \\
Placeholder for further code
\item[\tt localdomain *] \mbox{} \\
Placeholder for further code
\item[\tt message "text string in quotes"] \mbox{} \\
Placeholder for further code
\end{description}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\end{multicols}
|
The {\tt policytest()} function is called by smtp-server to check the client
host, the sender's and recipients' addresses.
|
The ZMailer smtpserver can do also message content analysis with an external program at the end of DATA-dot-phase, and BDAT LAST-phase (that is, when the input message is complete, and final acknowledgement is expected by the email sender.)
The program becomes active if PARAM entry “contentfilter” is set:
# External program for received message content analysis: #PARAM contentfilter $MAILBIN/smtp-contentfilter |
The interface to the program is simple synchronous half-duplex one, smtpserver writes relative filepath of the message into programs stdin, ending it with a newline. The filter programs reply must begin with a signed integer, then whatever text is desired to give to the user.
The contentfilter program is started without parameters
running userid of daemon in directory $POSTOFFICE/.
The program must silently wait for input, which is full path to the message spool file, analyze it, and reply with exactly one line matching rule of: “%i ” — begin with signed integer, then have one or more whitespace, then whatever filter writer liked to tell.
General rule:
-1 negatives are condemned into rejection 0 zero is ok! gladly accepted 1 positives are sent into the freezer |
The program may produce also the numeric SMTP reply codes in its response text:
-1 -1 250 2.7.1 Glad to see some spam, immediately destroyed :) 0 0 250 2.6.0 Message OK! 1 1 550 5.7.1 That is spam, rejected! |
If the message has no text, some defaults are supplied. If the message text starts with numbers, it is presumed that it contains both the SMTP reply code, and ENHANCEDSTATUSCODE before the text. (If no ENHANCEDSTATUSCODE part is present, then some possibly senseless default is supplied.)
Interface message text lines beginning with anything except signed integer are logged, and the communication channel from the smtpserver to the contentfilter program is closed. Interface continues to scan things reported by the contentfilter program, and if no properly formatted line appears, default is to send the message into the freezer ("-1"); FIXME! FIXME! "-1" == Kill ??? (Copy&paste from man-page, which may have a bug in it..)
This “sendmail” program is an emulation of the original
sendmail interface. It provides all the original options that make sense to support in
the context of ZMailer. This is not intended to be the normal user interface to mail, rather it is
used by the old User Agent programs, e.g., mail(1), to submit mail. This mechanism has
been superseded by the zmailer(3) library routines as the native submission interface
(Application Program Interface) for ZMailer.
The default action is to submit the RFC822 format mail message expected on STDIN to the mailer, with the addresses listed on the command line as recipients. If there are no recipient addresses specified on the command line, the mailer will infer them from the message header. The sender is the account of the current userid, except for root where the preferred sender is the account of the current login session. The message terminates when a period is seen by itself on a line, or at end of file on the input stream. (modulo used options.)
If the message submission fails immediately on the mail_open(3), the data on STDIN will be appended to a ~/dead.letter file in the submitters home
directory.
/usr/sbin/sendmail: unknown option -?
Usage: sendmail [sendmail options] [recipient addresses]
ZMailer's sendmail recognizes and implements following options:
-B bodytype - Valid values: 8BITMIME, 7BIT
-C conffile - specifies config file (meaningfull for -bt)
-E - flag 'external' source
-F 'full name' sender's full name string
-N notifyopt - Notify option(s): NEVER or a set of:
SUCCESS,DELAY,FAILURE
-P priority# - numeric priority for ZMailer router queue
pre-selection
-R returnopt - Error report return option, either of: FULL, HDRS
-U - Flag as 'user submission'
-V envidstring - XTEXT encoded ENVID string
-b? - operational mode flags
-bd - starts smtpserver in daemon mode
-bi - runs 'newaliases' command
-bm - deliver mail; always :-)
-bp - runs 'mailq' command
-bs - speak smtp; runs server in interactive mode
-bt - starts router in interactive test mode
-e* - (ignored)
-f fromaddr - sets envelope from address for the message
-i - on inputs from tty this will ignore SMTP-like
dot-EOF
-m - send a copy of the message to the sender too
(ignored)
-o* - multiple options; those not listed cause error
-oQ queuedir - defines POSTOFFICE directory for message
submission
-ob* - (ignored)
-od* - (ignored)
-oe* - (ignored)
-oi - alias of '-i' option
-or* - (ignored)
-p submitprotocol - value for 'with' label at 'Received:' header
-q* - queue processing commands (ignored)
-r fromaddr - (alternate for -f)
-t - scan message rfc822 headers for recipients
-v - verbose trace of processing
|
-bmasks sendmail to deliver mail, which it does anyway. This option has no effect.
-bswill start a SMTP server reading from STDIN. This causes the smtpserver(8) program to be executed.
-bdstarts the router(8) and scheduler(8) programs to emulate sendmail's daemon mode. This is not a recommended method to start these programs, instead use zmailer(1) script.
-btruns the router(8) in interactive mode for testing.
-buruns newaliases(8) to rebuild the alias file database.
-bpruns mailq(1) to print the mail transport queue status.
-C configfilespecifies the router(8) configuration file.
-Eindicates the origin of this message is an insecure channel. This should be used when sendmail is used to submit messages coming in from outside the local machine, to avoid security problems during message processing. This flag ensures the message will have no privileges even if the current userid is “trusted”.
-f addressspecifies the sender address. This is the default originator address if there is no “From:” headerin the message. It becomes the “Sender:” address otherwise. In either case if the current userid is not “trusted” by the mailer, it is free to ignore both this option and any header information to ensure properly authenticated originator information.
-F fullnamespecifies the full name of the (local) sender.
-itells sendmail to not use a period (“.”) on a line by itself as a message terminator, only the end of file will terminate the message.
-masks the mailer not to ignore the originator in the addressee list. This is default behaviour, so this option has no effect.
-N notifysets Delivery-Status-Notification notify parameter to be: NEVER, or any
combination of: SUCCESS, FAILURE, DELAY.
-oiis like -i.
-oQ postofficespecifies an alternate $POSTOFFICE/ directory.
-qasks for queue processing. This option has no effect.
-Q retmodesets Delivery-Status-Notification parameter to be either of: FULL, HDRS.
-r addressis like -f.
-tscans header for recipient addresses if none are specified on the command line. This is also the default behaviour, so this option has no effect.
-vwill report the progress of the message after it has been submitted. The sendmail process will write verbose log information to the STDERR stream until the scheduler deletes the message.
-V envidsets Delivery-Status-Notification parameter ENVID to be any arbitrary [xtext] string.
The rmail is a program to process incoming UUCP mail. rmail is usually invoked by a remote UUCP neighbour host's mailer using a command line like:
uux - -r -asender -gC thishost!rmail (recipient1) (recipient2) ... |
The end result is that the remote neighbour's uuxqt(8) runs rmail on thishost with this command line:
rmail recipient1 recipient2 ... |
In both cases, a UUCP format mail message is on the standard input.
The task of rmail is to transform the trace information in the UUCP format message to the equivalent RFC822 trace information, and to submit the message to the zmailer(1) router with the appropriate envelope information.
The expected input format looks like:
From address3 date3 remote from host3 >From address2 date2 remote from host2 >From address1 date1 remote from host1 |
From host3!host2!host1!address1 date Received: by host3 ... ; date3 Received: by host2 ... ; date2 Received: by host1 ... ; date1 |
In order for the mailer to process the incoming message properly, rmail must be run by a “userid” which the router(1) will accept forged mail from. his is normally the UUCP account id.
rmail [-d] [-h somewhere] recipient...
-dturns on debugging output.
-h somewherewill use the argument as the default remote UUCP host name to use if there is no remote from host tag in the first From-space line in the message. The default value for this is usually somewhere or uunet (since uunet was a frequent purveyor of this protocol violation).
#include <stdio.h> #include <zmailer.h> FILE *mail_open(char *); int mail_priority; int mail_abort(FILE *); int mail_close(FILE *); int mail_close_alternate(FILE *mfp, char *where, char *suffix); char *mail_alloc(unsigned int); int mail_free(char *); char *mail_host(); |
At linkage time use -lzmailer.
mail_open() will return a FILE * to a message file
that should be written to by the application. This message file contains three parts:
the message envelope
the message header
the message body
mail_open(). The choices are predetermined by the capabilities of the mailer, and are
defined in the header file. The known possibilities are:
this is the only format supported by default by the mailer. The message headers and body in this format are defined by the IETF Request For Comments 822 and 1123. The message envelope syntax is similar to the message header syntax.
intended for fax transmissions. (never used)
intended for old style UUCP format message headers (never used)
intended for X.400(88) messages.
The mail_open() routine will look for $FULLNAME and
$PRETTYLOGIN environment variables and translate them into message envelope data for
use by the mailer if it generates a sender address header for the message.
Note that the return value from the mail_open() routine corresponds to the return
value of an fopen(3), and similarly the return values from mail_abort() and mail_close() correspond to the return value of
fclose(3).
The mail_priority variable has a default value of 0, and is used on scanning
Zmailer configuration variable $ROUTERDIRS, which tells alternate router directories
under the $POSTOFFICE/ directory. At value 0, $ROUTERDIRS variable is not used. At higher values, successive directory from $ROUTERDIRS is taken. See below about Z-Environment.
The mail_close_alternate(3) can be used to send currently open message file to
some alternate destination, and is used at smtpserver(8) to
send some quick-action requests directly to the scheduler(8).
The mail_alloc() and mail_free() routines are used
to provide memory space for internal data structures. The versions of these routines in the library simply call
malloc(3) and free(3) but an application may override
them if desired.
Similarly the mail_host() routine is intended to return a unique string for each
host, by default the hostname, and this too is intended to be overridden by an application that may already have
this information available in some form.
The message envelope headers are used to carry meta-information about the message. The goal is to carry transport-envelope information separate from message (RFC-822) headers, and body. At first the message starts with a set of envelope headers (*-prefix denotes optional):
*external \n *rcvdfrom %s@%s (%s) \n *bodytype %s \n *with %s \n *identinfo %s \n Either: from <%s> \n Or: channel error \n *envid %s \n *notaryret %s \n Then for each recipient pairs of: *todsn [NOTIFY=...] [ORCPT=...] \n to <%s> \n Just before the data starts, a magic entry: env-end \n |
Then starts the message RFC-822 headers, and below it, the body.
... set up signal handlers ...
FILE *mfp = mail_open(MSG_RFC822,0);
if (mfp != NULL) {
... output the mail message to mfp ...
} else
... error handling for not being able to open the file ...
if (some application processing went wrong
|| we took an interrupt)
(void) mail_abort(mfp);
else if (mail_close(mfp) == EOF)
... error handling if something went wrong ...
|
FULLNAMEvariable defines textual fullname, for example: “Sample User”
PRETTYLOGINvariable defines user@node format of what user wants to claim as his/her own address (it must match those of mail router accepts.)
POSTOFFICEdefines the directory where all $POSTOFFICE/
functions are. Example:
POSTOFFICE=/var/spool/postoffice/ |
ROUTERDIRSdefines a “:” separated list of alternate router directories. If these are defined at all, they must exist, if alternate queueing priority mechanism is desired to be used. Example:
ROUTERDIRS=router1:router2:router3:router4 |
process()
functionrouter()
functioncrossbar()
functionserver()
function:"
(doublecolon).", "include"[", "test"attributesbasenamebreakbuiltincarcatcdcdrchannelcontinuedaemondbechoelementsenvarserraddronevalexitexportfileprivfirstgensymgetgetoptsgrindgroupmembershashhomedirectoryhosthostnameifssplitlappendlastlengthlistlistaddresseslistexpandlogin2uidlreplacemalcontentsprintaliasesprocessreadrecaserecipientrelationrestreturnreturnsrfc822rfc822daterfc822syntaxrunassendersetshiftsleepsquirrelstabilitytest", "["timestracetraptypeuid2loginumaskunsetuntraceuserwaitThe router daemon makes all decisions affecting the processing of messages in ZMailer.
A mail message is submitted by placing it in a file in the $POSTOFFICE/router/ directory. The router frequently scans this directory for
new files and will lock and process them as it finds them. The result is a message control file that gets linked into the
$POSTOFFICE/scheduler/ and $POSTOFFICE/transport/ directories for use by the scheduler in the next step
of message processing. The original message file is then moved to the $POSTOFFICE/queue/ directory.
The router's behaviour is controlled by a configuration file read at startup. It is really a zmsh(1) script that uses facilities provided builtin to the router.
Invoking router without any arguments will do nothing (except make it read its configuration file and promptly exit). The normal startup method is to run the zmailer(1) script, as in "zmailer router". This will start the router as a daemon and kill the previous incarnation of the router.
router [-diksSV] [-f configfile] [-n #routers] [-o zmsh-options] [-t traceflag] [-L logfile] [-P postoffice]
-dDetach and run as a daemon.
-f configfileOverrides the default configuration file $MAILSHARE/router.cf.
-iRun interactively, presenting a zmsh session with the configuration file preloaded.
-kKill the currently running router by sending it a SIGTERM signal.
-L logfileOverrides the default log file location $LOGDIR/router.
-n #routersStarts the specified number of parallel router processes. The default is a single router process.
-o zmsh-optionsSets the option string passed on the internal zmsh invocation. The default is -O. Note that the leading "-" is mandatory. See zmsh(1) (at Section 21.1.2) for the available options.
-P postofficeSpecifies an alternate $POSTOFFICE/ directory.
-SCan be used to turn off non-serious syslogging.
-sTurns stability-flag off and on. Without this flag, the search of new jobs will be done with (sometimes) timeconsuming care of organizing the job files into time order.
-t traceflagSets trace options, one per -t switch, even before the configuration file is
loaded. This is otherwise equivalent to the builtin trace command. The currently known
options are: assign, bind, compare, db, final, functions, matched, memory, on, regexp,
resolv, rewrite, router, and sequencer.
-VPrint version message and run interactively.
To restart a router daemon:
router -dk |
To test an address, start up an interactive session:
router -i |
sendmail -bt |
Then just use the pre-defined functions.
zmsh is an implementation of the Bourne shell suitable for use with the ZMailer router(8) as its configuration file language interpreter. It contains extensions that allow structured data (in the form of lists) to be manipulated.
The shell supports three basic kinds of functions: Unix commands, user-defined functions, and builtin commands. The latter comes in two variations: normal functions which take string arguments and return a status code (much as an embedded Unix command would work), and list-manipulation functions which understand list arguments and can return list arguments. The defined functions can take any form of argument and return any form of value (a status code, a string, or a list).
Shell operations (pipes, backquote evaluation and substitution) will work between combinations of builtin functions, defined functions, and Unix commands.
The shell precompiles its input to a (possibly optimized) byte-code form, which is then interpreted as required. This means that the original form of the input is not kept around in-core for future reference. If the input is an included file, the shell will try to save the byte-code form in a .fc file associated with the input file. For example, if input is from file.cf, the shell will try to create fc/file.fc and then file.fc. These files will in turn be searched for and loaded (after a consistency check) whenever a .cf file is included.
The effects of input and output redirections are predicted prior to the execution of a command and its I/O setup.
-c commandRun the given argument as a shell command script.
-aAutomatically export new or changed shell variables.
-eExit on non-zero status return of any command.
-fDisables filename generation.
-hHash and cache the location of Unix commands. The option is set by default.
-iThis shell is interactive, meaning prompts are printed when ready for more input, SIGTERM signal is ignored, and the shell does not exit easily. This flag is automatically set if stdin and stderr are both attached to a /dev/tty.
-nRead commands but do not execute them.
-sRead commands from stdin. If there are non-option arguments to the shell, the first of these will be interpreted as a shell script to open on stdin, and the rest as arguments to the script.
-tExit after running one command.
-uUnset variables produce an error on substitution.
-vPrint shell input as it is read.
-xPrint commands as they are executed.
-CPrint code generation output onto stdout. If this option is doubled, the non-optimized code is printed out instead.
-IPrint runtime interpreter activity onto /dev/tty.
-LPrint lexer output onto stdout.
-OOptimize the compiled script. If this option is doubled, the optimized code is also printed out.
-PPrint parser output (S/SL trace output) onto stdout.
-RPrint I/O actions onto /dev/tty.
-SPrint scanner output (token assembly) onto stdout.
-YOpen /dev/tty for internal debugging use.
Text to be inserted here. |
Text to be inserted here. |
This section describes the router internal functions used as entrypoints by various uses inside and outside the router program.
process() functionFIXME! WRITEME!
router() functionFIXME! WRITEME!