NAME¶
FBB::Milter - Interface to the sendmail mail filter facilities
SYNOPSIS¶
#include <bobcat/milter>
Linking option:
-lmilter -lbobcat
DESCRIPTION¶
Milter defines an abtract base class interfacing to the sendmail mail
filter (milter) facilities. It defines a
C++ interface, based on the
assumption that a single mail filter program does not implement multiple mail
filters. The traditional sendmail
C-based Milter API uses a
(
SMFICTX) pointer representing a mail connection, and a pointer to
connection-specific `private’ data, requiring the Milter constructor to
perform quite a few administrative tasks. While acceptable in a
C
environment these administratve tasks distract from the main task: the
Milter’s mail filtering functionality. The
FBB::Milter class
hides these administrative tasks from the programmer, who is then able to
concentrate on filtering mail. The main benefits of
Milter are
therefore
- o
- Basic administration is performed by the Milter
class
- o
- The class’ interface is more C++ like than the
raw C interface offered by the milter API.
- o
- Administration, allocation and communicating of connection
specific data is no longer required
- o
- It is not normally necessary to use connection-specific
data, like a pointer identifying the connection, anymore when implementing
the Milter.
- o
- Milter uses current-day design patterns enforcing
principles of reuable software, thus simplifying the construction of the
actual Milter. To activate a milter from the sendmail.mc
configuration file, use, e.g., INPUT_MAIL_FILTER(`name’,
`S=socket’), where name is the milter’s name, and
socket is the name of the socket. See also the
setConnection() member below.
NAMESPACE¶
FBB
All constructors, members, operators and manipulators, mentioned in this
man-page, are defined in the namespace
FBB.
INHERITS FROM¶
-
ENUMERATIONS¶
The class defines four enumerations. One enumeration is used to indicate the
callback-functions that need to be called, the second one renames the flags
that can be passed to sendmail to indicate which actions the milter is allowed
to perform. The third one defines status values that may be used to inform
sendmail how to further process a message. The fourth one defines return
values. The enumerations are:
enum CallBack
This enumeration holds the following values:
- o
- CONNECT:
Indicates that the milter defines (overrides) the connection-functionality.
This is the first callback function that can be called by sendmail.
- o
- HELO:
Indicates that the milter defines (overrides) the helo-functionality. This
indicates that the helo() function should be called by sendmail,
providing the milter with information about the connecting client.
- o
- SENDER:
Indicates that the milter defines (overrides) the sender-functionality. This
indicates that the sender() function should be called by sendmail,
providing the milter with the sender’s envelope information.
- o
- RECIPIENT:
Indicates that the milter defines (overrides) the recipient-functionality.
This indicates that the recipient() function should be called by
sendmail, providing the milter with the recipient’s envelope
information.
- o
- HEADER:
Indicates that the milter defines (overrides) the header-functionality. This
indicates that the header() function should be called by sendmail
for each mail header that is used in the current mail message.
- o
- EOH:
Indicates that the milter defines (overrides) the
end-of-header-functionality. This indicates that the eoh() function
should be called by sendmail once all header lines have been
processed.
- o
- BODY:
Indicates that the milter defines (overrides) the body-functionality. This
indicates that the body() function should be called by sendmail,
offering the mail-body to the milter.
- o
- EOM:
Indicates that the milter defines (overrides) the
end-of-message-functionality. This indicates that the eom()
function should be called by sendmail, once all elements of the e-mail
message have been processed.
- o
- ABORT:
Indicates that the milter defines (overrides) the abort-functionality. The
abort() function may be called by sendmail before eom() is
called. It should reclaim all resources used by the message, but not
delete any memory allocated by the milter, as this is
close()’s job.
- o
- CLOSE:
Indicates that the milter defines (overrides) the close-functionality. The
close() function should delete all (connection specific) memory
allocated by the milter. It may be called `out-of-order’, i.e. even
before connect() is called and developers should anticipate this
possibility when crafting their close() code. In particular, it is
incorrect to assume the private context pointer will be something other
than 0 in this callback.
- o
- UNKNOWN:
Currently not used. Reserved for versions exceeding version 2 of the
sendmail milter API
- o
- DATA:
Currently not used. Reserved for versions exceeding version 3 of the
sendmail milter API
- o
- ALL_CALLBACKS:
Shortcut to indicate all callback facilities. The CallBack values are
bit-flags. The bit_or operator may be used to combine them, and the
bit_not operator may be used to remove a flag from
ALL_CALLBACKS (e.g., ALL_CALLBACKS && ~ABORT).
enum Flags
This enumeration holds the following values:
- o
- NO_FLAGS:
No flags are defined.
- o
- ADD_HEADERS:
This flag indicates that the milter is allowed to add headers to the current
e-mail message.
- o
- ADD_RECIPIENTS:
This flag indicates that the milter is allowed to add recipients to the
current e-mail message.
- o
- CHANGE_BODY:
This flag indicates that the milter is allowed to modify the message’s
body contents.
- o
- CHANGE_HEADERS:
This flag indicates that the milter is allowed to change headers of the
current e-mail message.
- o
- DELETE_RECIPIENTS:
This flag indicates that the milter is allowed to remove recipients from the
current e-mail message.
- o
- QUARANTINE:
This flag indicates that the milter is allowed to request sendmail to
quarantine the current e-mail message.
- o
- ALL_FLAGS:
Shortcut to indicate all callback facilities. The Flags values are
bit-flags. The bit_or operator may be used to combine them, and the
bit_not operator may be used to remove a flag from ALL_FLAGS
(e.g., ALL_FLAGS && ~QUARANTINE).
Status
This enumeration simplifies the extended
SMFIS_ values used by the
C API. These values may be used to return
sfsistat values:
- o
- ACCEPT:
This value is equal to SMFIS_ACCEPT, indicating that Sendmail should
accept the message. For a connection-oriented callback (see below at
PROTECTED VIRTUAL MEMBER FUNCTIONS), accept this connection without
further filter processing, call close() (see below). For other
callbacks: accept this message without further filtering.
- o
- CONTINUE:
This value is equal to SMFIS_CONTINUE, indicating that Sendmail
should continue processing. This is the default for all callback functions
which are not overridden by the class derived from Milter.
- o
- DISCARD:
This value is equal to SMFIS_DISCARD, indicating that Sendmail should
discard the mail message. It should not be returned by a
connection-oriented callback. For other callbacks: the message is
accepted, but silently discarded.
- o
- REJECT:
This value is equal to SMFIS_REJECT, indicating that Sendmail should
reject the mail message. For a connection-oriented callback, reject this
connection; call close(). For a message-oriented callback (except
for eom() or abort(), see below), reject this message. For a
recipient-oriented callback, reject the current recipient (but continue
processing the current message).
- o
- TEMPFAIL:
This value is equal to SMFIS_TEMPFAIL, indicating that Sendmail
should return a `temporary unavailable’ message to the sender of the
mail message. For a message-oriented callback (except sender(), see
below), fail for this message. For a connection-oriented callback, fail
for this connection and call close(). For a recipient-oriented
callback, only fail for the current recipient and continue message
processing.
Return
This enumeration simplifies the extended
MI_ values used by the
C
API. Most return values used by the
Milter class, however, are
bool values. The
Return values are:
- o
- FAILURE:
This value is equal to MI_FAILURE, indicating that a C-api
function failed to perform its task.
- o
- SUCCESS:
This value is equal to MI_SUCCESS, indicating that a C-api
function succeeded in performing its task.
CONSTRUCTORS¶
The default- and copy constructors are available for derived classes. They
perform no actions.
PUBLIC STATIC MEMBER FUNCTIONS¶
These functions form the heart of the
Milter base-class. They can be
called to initialize, start and stop the Milter.
- o
- void initialize(std::string const &name,
Milter &milter, callback_set callbacks = CONNECT,
flag_set flags = NO_FLAGS):
This function initializes the Milter’s administration. It expects the
name of the mailfilter as its first argument. Its second argument is a
reference to a Milter object. Since Milter is an abstract
base class the actual object is always an object of a class derived from
Milter. Its third argument specifies the callbacks to call for this
milter. By default the connect() callback will be called. Note that
the close() callback is not called by default. This is ok, since
the Milter object doesn’t have to cleanup `private’
data, as is normal with the C API. The last argument defines flags,
specifying the Milter’s capabilities.
- o
- std::string const &name():
This function returns the milter’s name.
- o
- bool start():
This member function calls smfi_main(), controlling the
milter’s event loop. It returns true if the event-loop is
successfully terminated.
- o
- void stop():
This member function terminates the milter’s event loop, after
finishing all threads. Following this call start() may be called
again to continue the milter.
PROTECTED VIRTUAL MEMBER FUNCTIONS¶
The remaining functionality of the class
Milter is useful only for
Milter-implementations in classes derived from
Milter. The following
members can be overridden by derived classes. Note that
clone()
must be overridden. Except for
clone(), all the members in this
sections are
callback functions. I.e., the MTA will call them to
process parts of the mail message. Recipient-, message-, and
connection-oriented callbacks are distinguished.
The recipient-oriented callback (
recipient(), see below) may affect the
processing of a single message to a single recipient. Connection-oriented
callbacks (
connect(), helo() and
close()) affect the processing
of the entire connection (during which multiple messages may be delivered to
multiple sets of recipients). The remaining callbacks are message-oriented,
affecting the processing of a single message to all its recipients.
- o
- virtual sfsistat abort():
This message-oriented member may be called at any time during message
processing (i.e. between some message-oriented routine and eom()).
abort() reclaim any resources allocated on a per-message basis
(which are not the connection specific data, which should be
handled by the derived class’ destructor), and must be tolerant of
being called between any two message-oriented callbacks. abort() is
only called if the message is aborted outside the filter’s control
and the filter has not completed its message-oriented processing. For
example, if a filter has already returned ACCEPT, REJECT, or
DISCARD from a message-oriented routine, abort() will not be
called even if the message is later aborted outside its control.
- o
- virtual sfsistat body(unsigned char *text, size_t
length):
This message-oriented member is called zero or more times between
eoh() and eom(). text points to a sequence of bytes.
It is not necessarily a 0-terminated. Moreover, the sequence may contain
0-characters. Since message bodies can be very large, defining
body() can significantly impact filter performance. End-of-lines
are represented as received from SMTP (normally CR/LF). Later filters will
see body changes made by earlier ones, and message bodies may be sent in
multiple chunks, with one call to body() per chunk.
- o
- virtual Milter *clone() const = 0:
This pure virtual function must be implemented by derived classes to return
a newly allocated copy of the derived object passed to the
initialize() static member. It is used by the standard `virtual
constructor’ design pattern. The destruction of the allocated object
is the responsibility of clone()’s caller.
- o
- virtual sfsistat close():
This connection-oriented member is always called once at the end of each
connection. It may be called "out-of-order", i.e. before even
the connect() is called. After a connection is established by the
MTA to the filter, if the MTA decides this connection’s traffic will
be discarded (e.g. via an access_db result), no data will be passed to the
filter from the MTA until the client closes down. At that time,
close() is called. It can therefore be the only callback ever used
for a given connection, and developers should anticipate this possibility
when crafting their close() code. The member close() is
called on close even if the previous mail transaction was aborted.
- o
- virtual sfsistat connect(char *hostname, _SOCK_ADDR
*hostaddr):
This connection-oriented member may be called once, at the start of each
SMTP connection. The parameter hostname is he host name of the
message sender, as determined by a reverse lookup on the host address. If
the reverse lookup fails, hostname will contain the message sender’s
IP address enclosed in square brackets (e.g. [a.b.c.d]). The
parameter hostaddr is the host address, as determined by a
getpeername(2) call on the SMTP socket. It is 0 if the type is not
supported in the current version or if the SMTP connection is made via
stdin.
- o
- virtual sfsistat data():
Not yet supported. Will be available with libmilter versions beyond 3.
- o
- virtual sfsistat eoh():
This message-oriented member is called once after all headers have been
processed.
- o
- virtual sfsistat eom():
This message-oriented member is called once after all calls to body()
for a given message have been completed. Note that only in this
function modifications to the message headers, body, and envelope can be
made (see the add-, change- and delete- members listed
below).
- o
- virtual sfsistat header(char *headerf, char
*headerv):
This message-oriented member is called zero or more times between
recipient() and eoh(), once per message header. The
headerf parameter will contain the text of the header, the
headerv parameter will contain its value. E.g., if an e-mail
message contains the following headers:
From: sender <f@example.com>
Subject:no
then header() will be called twice with the following values for,
respectively headerf and headerv:
First header: "From", " sender <f@example.com>"
Second header: "Subject", "no"
Further details about header information is given in RFC 882.
- o
- virtual sfsistat helo(char *helohost):
This connection-oriented member is called whenever the client sends a
HELO/EHLO command. It may therefore be called between zero and three
times. The helohost parameter should be the domain name of the
sending host (but is, in practice, anything the sending host wants to
send).
- o
- virtual sfsistat recipient(char **argv):
This recipient-oriented member is called once per recipient, hence one or
more times per message, immediately after sender. The parameter
argv is a 0-terminated array of pointers to SMTP command arguments;
argv[0] is guaranteed to be the recipient address. Later arguments are the
ESMTP arguments. TEMPFAIL may be returned indicate that sendmail should
return a temporary failure for this particular recipient; further
recipients may still be sent, abort() is not called. REJECT will
reject this particular recipient; further recipients may still be sent,
abort() is not called. DISCARD will accept (but discard) the
message, abort() will be called. ACCEPT will accept recipient,
abort() will not be called. More details on ESTMP responses, are
described in RFC 1869.
- o
- virtual sfsistat sender(char **argv):
This message-oriented member is called once at the beginning of each
message, before recipient(). TEMPFAIL may be returned indicate that
sendmail should return a temporary failure for this particular message,
abort() is not called. REJECT will reject this message,
abort() is not called. DISCARD will accept (but discard) the
message, abort() will be called. ACCEPT will accept recipient,
abort() will not be called. More details on ESTMP responses, are
described in RFC 1869.
- o
- virtual sfsistat unknown(char *ptr):
Not yet supported. Will be available with libmilter versions beyond 2.
PROTECTED MEMBER FUNCTIONS¶
The following members are non-virtual. They can be called by members of classes
derived from
Milter:
- o
- bool addHeader(std::string const &hdrName,
std::string const &hdrValue):
This member may only be called from eom(), and the flag
ADD_HEADERS must have been specified or it will fail. The
hdrName and hdrValue must be non-empty strings. Each line of
the header must be under 2048 characters and should be under 998
characters. If longer headers are needed, make them multi-line. To make a
multi-line header, insert a line feed ( \n) followed by at least
one whitespace character such as a space or tab ( \t). The line
feed should not be preceded by a carriage return. It is the filter
writer’s responsibility to ensure that no standards are
violated.
- o
- bool addRecipient(std::string const &rcptName):
This member may only be called from eom(), and the flag
ADD_RECIPIENTS must have been specified or it will fail.
- o
- bool changeHeader(std::string const &hdrName,
size_t headerNr, std::string const &hdrValue):
This member may only be called from eom(), and the flag
CHANGE_HEADERS must have been specified or it will fail. See
addHeader() for the header-requirements. The headerNr
parameter is a 1-based header index value. A headerNr value of 1
will modify the first occurrence of a header named hdrValue. If
headerNr is greater than the number of times hdrName
appears, a new hdrName-header will be added. If hdrValue is
empty, the header is deleted.
- o
- bool deleteRecipient(std::string const
&rcptName):
This member may only be called from eom(), and the flag
DELETE_RECIPIENTS must have been specified or it will fail. This
member removes the named recipient from the current message’s
envelope.
- o
- SMFICTX *id() const:
This member may be called by the Milter object to obtain a pointer
identifying its sendmail-connection. Normally it should not be necessary
to call this member.
- o
- bool insertHeader(size_t hdrIdx, std::string const
&hdrName, std::string const &hdrValue):
This member may only be called from eom(), and the flag
ADD_HEADERS must have been specified or it will fail. See
addHeader() for the header-requirements. The headerNr
parameter is a header index value. A headerNr value of 0 will
insert this header as the first of the hdrName headers. If
headerNr is greater than the number of times hdrName
appears, a new hdrName-header will be added.
- o
- bool openSocket(bool removeIfTrue = true):
This member should be called before start() is called. This member
attempts to create the socket specified by setConnection() (see
below). This allows the calling application to ensure that the socket can
be created, possibly changing its protection (access rights) before the
milter starts its work. If this member is not called, it will be called
implicitly when run() is started. It returns true if the
socket could be created.
- o
- bool quarantine(std::string const &reason):
This member may only be called from eom() and causes the MTA to
quarantines the message using the given reason.
- o
- bool replaceBody(std::string const &body):
This member may only be called from eom(), and the flag
CHANGE_BODY must have been specified or it will fail. It may be
called multiple times in which case the various body contents are
concatenated in the final message. Newlines should be coded as CRLF.
- o
- bool setBacklog(size_t backlog = 5):
This member should be called before start() is called. Sets the
incoming socket backlog used by listen(2). If setBacklog()
is not called, the operating system default is used. The function returns
false if the backlog could not be set as requested. It is the
responsibility of the programmer not to call this function with a 0
argument.
- o
- bool setConnection(std::string const &name):
This member should be called before start() is called. Sets the
socket through which the filter communicates with sendmail. The socket may
be specified using one of the following variants:
{unix|local}:/path/to/file - A named pipe;
net:port@{hostname|ip-address} - An IPV4 socket;
inet6:port@{hostname|ip-address} - An IPV6 socket.
- If possible, filters should not run as root when
communicating over unix/local domain sockets.
- Unix/local sockets should have their permissions set to
0600 (read/write permission only for the socket’s owner) or 0660
(read/write permission for the socket’s owner and group) which is
useful if the sendmail RunAsUser option is used. The permissions for a
unix/local domain socket are determined as usual by umask, which should be
set to 007 or 077.
- Possible failure of this function cannot be determined from
its return value. Rather, run() will fail.
- o
- setReply(std::string const &rcode, std::string const
&xcode = "", std::string const &msg =
""):
This member sets the default SMTP error reply code. It may be called from
any callback member, except connect(). The parameter rcode
should be a he three-digit (RFC 821/2821) SMTP reply code and it must be a
valid 4XX or 5XX reply code. The parameter xcode, when specified,
must be a extended (RFC 1893/2034) reply code. The parameter msg
may be an additional textual message. The Milter class has no
member comparable to the libmilter API function smfi_setmlreply().
the Milter class.
- o
- void setTimeout(size_t seconds = 7210):
This member should be called before start() is called. Sets the
number of seconds libmilter will wait for an MTA connection before timing
out a socket. If setTimeout() is not called, a default timeout of
7210 seconds is used. It is the responsibility of the programmer not to
call this function with an argument equal to 0.
- o
- char const *symval(std::string const &name)
const:
This member returns the value of a specific sendmail macro. The name
parameter should be set to he name of a sendmail macro . Single letter
macros can optionally be enclosed in braces ( { and }),
longer macro names must be enclosed in braces, just as in a sendmail.cf
file.0 is returned if the macro is not defined. By default, the following
macros are valid in the given contexts:
for connect(): daemon_name, if_name, if_addr, j, _;
for helo(): tls_version, cipher, cipher_bits, cert_subject,
cert_issuer;
for sender(): i, auth_type, auth_authen, auth_ssf,
auth_author, mail_mailer, mail_host, mail_addr;
for recipient(): rcpt_mailer, rcpt_host, rcpt_addr.
All macros stay in effect from the point they are received until the end of
the connection for the first two sets, the end of the message for the
third ( sender()), and just for each recipient for the final set (
recipient()).
The following macros may be specified in the sendmail.mc configuration file:
define(`confMILTER_MACROS_CONNECT’, `m1’, ...),
define(`confMILTER_MACROS_HELO’, ...),
define(`confMILTER_MACROS_ENVFROM’, ...),
define(`confMILTER_MACROS_ENVRCPT’, ...), where
`m1’, ... represents a comma separated list of returnable
macros. Single letter macros can optionally be enclosed in braces (
{ and }), longer macro names must be enclosed in
braces.
- o
- bool wait():
This member may only be called from eom() and tells the MTA that the
filter is still working on a message, causing the MTA to re-start its
timeouts.
EXAMPLE¶
To do
FILES¶
bobcat/milter - defines the class interface
SEE ALSO¶
bobcat(7),
getpeername(2),
listen(2),
http://www.milter.org (e.g.,
http://www.milter.org/developers/api)
http://sendmail.org/m4/readme.html
http://rfc.net/rfc821.html
http://rfc.net/rfc822.html
http://rfc.net/rfc1869.html
http://rfc.net/rfc1893.html
http://rfc.net/rfc2034.html
http://rfc.net/rfc2821.html
BUGS¶
Note that
-lmilter must be specified before
-lbobcat.
DISTRIBUTION FILES¶
- o
- bobcat_3.01.00-x.dsc: detached signature;
- o
- bobcat_3.01.00-x.tar.gz: source archive;
- o
- bobcat_3.01.00-x_i386.changes: change log;
- o
- libbobcat1_3.01.00-x_*.deb: debian package holding
the libraries;
- o
- libbobcat1-dev_3.01.00-x_*.deb: debian package
holding the libraries, headers and manual pages;
- o
- http://sourceforge.net/projects/bobcat: public
archive location;
BOBCAT¶
Bobcat is an acronym of `Brokken’s Own Base Classes And Templates’.
COPYRIGHT¶
This is free software, distributed under the terms of the GNU General Public
License (GPL).
AUTHOR¶
Frank B. Brokken (
f.b.brokken@rug.nl).