diff options
Diffstat (limited to 'contrib/sendmail/libmilter')
66 files changed, 12505 insertions, 0 deletions
diff --git a/contrib/sendmail/libmilter/Makefile b/contrib/sendmail/libmilter/Makefile new file mode 100644 index 0000000..b5bfba4 --- /dev/null +++ b/contrib/sendmail/libmilter/Makefile @@ -0,0 +1,19 @@ +# $Id: Makefile,v 8.2 2006/05/23 21:55:55 ca Exp $ + +SHELL= /bin/sh +BUILD= ./Build +OPTIONS= $(CONFIG) $(FLAGS) + +all: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ +check: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ +clean: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ +install: FRC + $(SHELL) $(BUILD) $(OPTIONS) $@ + +fresh: FRC + $(SHELL) $(BUILD) $(OPTIONS) -c + +FRC: diff --git a/contrib/sendmail/libmilter/Makefile.m4 b/contrib/sendmail/libmilter/Makefile.m4 new file mode 100644 index 0000000..bc9bc66 --- /dev/null +++ b/contrib/sendmail/libmilter/Makefile.m4 @@ -0,0 +1,40 @@ +dnl $Id: Makefile.m4,v 8.85 2009/11/24 21:59:33 ca Exp $ +include(confBUILDTOOLSDIR`/M4/switch.m4') + +dnl only required for compilation of EXTRAS +define(`confREQUIRE_SM_OS_H', `true') +define(`confMT', `true') + +# sendmail dir +SMSRCDIR=ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail') +PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ') + +bldPRODUCT_START(`library', `libmilter') +define(`bldINSTALLABLE', `true') +define(`LIBMILTER_EXTRAS', `errstring.c strl.c') +APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL -Dsm_snprintf=snprintf') +define(`bldSOURCES', `main.c engine.c listener.c worker.c handler.c comm.c smfi.c signal.c sm_gethost.c monitor.c LIBMILTER_EXTRAS ') +define(`confBEFORE', `LIBMILTER_EXTRAS') +bldPUSH_INSTALL_TARGET(`install-mfapi') +bldPRODUCT_END + +PUSHDIVERT(3) +errstring.c: + ${LN} ${LNOPTS} ${SRCDIR}/libsm/errstring.c . + +strl.c: + ${LN} ${LNOPTS} ${SRCDIR}/libsm/strl.c . +POPDIVERT + + +divert(bldTARGETS_SECTION) +# Install the API header files +MFAPI= ${SRCDIR}/inc`'lude/libmilter/mfapi.h +MFDEF= ${SRCDIR}/inc`'lude/libmilter/mfdef.h +install-mfapi: ${MFAPI} + if [ ! -d ${DESTDIR}${INCLUDEDIR}/libmilter ]; then mkdir -p ${DESTDIR}${INCLUDEDIR}/libmilter; else :; fi + ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFAPI} ${DESTDIR}${INCLUDEDIR}/libmilter/mfapi.h + ${INSTALL} -c -o ${INCOWN} -g ${INCGRP} -m ${INCMODE} ${MFDEF} ${DESTDIR}${INCLUDEDIR}/libmilter/mfdef.h +divert(0) + +bldFINISH diff --git a/contrib/sendmail/libmilter/README b/contrib/sendmail/libmilter/README new file mode 100644 index 0000000..e9c2cb1 --- /dev/null +++ b/contrib/sendmail/libmilter/README @@ -0,0 +1,234 @@ +This directory contains the source files for libmilter. + +The sendmail Mail Filter API (Milter) is designed to allow third-party +programs access to mail messages as they are being processed in order to +filter meta-information and content. + +This README file describes the steps needed to compile and run a filter, +through reference to a sample filter which is attached at the end of this +file. It is necessary to first build libmilter.a, which can be done by +issuing the './Build' command in SRCDIR/libmilter . + +Starting with 8.13 sendmail is compiled by default with support for +the milter API. + +Note: if you want to write a milter in Java, then see +http://sendmail-jilter.sourceforge.net/ + ++----------------+ +| SECURITY HINTS | ++----------------+ + +Note: we strongly recommend not to run any milter as root. Libmilter +does not need root access to communicate with sendmail. It is a +good security practice to run a program only with root privileges +if really necessary. A milter should probably check first whether +it runs as root and refuse to start in that case. libmilter will +not unlink a socket when running as root. + ++----------------------+ +| CONFIGURATION MACROS | ++----------------------+ + +Libmilter uses a set of C preprocessor macros to specify platform specific +features of the C compiler and standard C libraries. + +SM_CONF_POLL + Set to 1 if poll(2) should be used instead of select(2). + ++-------------------+ +| BUILDING A FILTER | ++-------------------+ + +The following command presumes that the sample code from the end of this +README is saved to a file named 'sample.c' and built in the local platform- +specific build subdirectory (SRCDIR/obj.*/libmilter). + + cc -I../../include -o sample sample.c libmilter.a ../libsm/libsm.a -pthread + +It is recommended that you build your filters in a location outside of +the sendmail source tree. Modify the compiler include references (-I) +and the library locations accordingly. Also, some operating systems may +require additional libraries. For example, SunOS 5.X requires '-lresolv +-lsocket -lnsl'. Depending on your operating system you may need a library +instead of the option -pthread, e.g., -lpthread. + +Filters must be thread-safe! Many operating systems now provide support for +POSIX threads in the standard C libraries. The compiler flag to link with +threading support differs according to the compiler and linker used. Check +the Makefile in your appropriate obj.*/libmilter build subdirectory if you +are unsure of the local flag used. + +Note that since filters use threads, it may be necessary to alter per +process limits in your filter. For example, you might look at using +setrlimit() to increase the number of open file descriptors if your filter +is going to be busy. + + ++----------------------------------------+ +| SPECIFYING FILTERS IN SENDMAIL CONFIGS | ++----------------------------------------+ + +Filters are specified with a key letter ``X'' (for ``eXternal''). + +For example: + + Xfilter1, S=local:/var/run/f1.sock, F=R + Xfilter2, S=inet6:999@localhost, F=T, T=C:10m;S:1s;R:1s;E:5m + Xfilter3, S=inet:3333@localhost + +specifies three filters. Filters can be specified in your .mc file using +the following: + + INPUT_MAIL_FILTER(`filter1', `S=local:/var/run/f1.sock, F=R') + INPUT_MAIL_FILTER(`filter2', `S=inet6:999@localhost, F=T, T=C:10m;S:1s;R:1s;E:5m') + INPUT_MAIL_FILTER(`filter3', `S=inet:3333@localhost') + +The first attaches to a Unix-domain socket in the /var/run directory; the +second uses an IPv6 socket on port 999 of localhost, and the third uses an +IPv4 socket on port 3333 of localhost. The current flags (F=) are: + + R Reject connection if filter unavailable + T Temporary fail connection if filter unavailable + 4 Shut down connection if filter unavailable + (with a 421 temporary error). + +If none of these is specified, the message is passed through sendmail +in case of filter errors as if the failing filters were not present. + +Finally, you can override the default timeouts used by sendmail when +talking to the filters using the T= equate. There are four fields inside +of the T= equate: + +Letter Meaning + C Timeout for connecting to a filter (if 0, use system timeout) + S Timeout for sending information from the MTA to a filter + R Timeout for reading reply from the filter + E Overall timeout between sending end-of-message to filter + and waiting for the final acknowledgment + +Note the separator between each is a ';' as a ',' already separates equates +and therefore can't separate timeouts. The default values (if not set in +the config) are: + +T=C:5m;S:10s;R:10s;E:5m + +where 's' is seconds and 'm' is minutes. + +Which filters are invoked and their sequencing is handled by the +InputMailFilters option. Note: if InputMailFilters is not defined no filters +will be used. + + O InputMailFilters=filter1, filter2, filter3 + +This is is set automatically according to the order of the +INPUT_MAIL_FILTER commands in your .mc file. Alternatively, you can +reset its value by setting confINPUT_MAIL_FILTERS in your .mc file. +This options causes the three filters to be called in the same order +they were specified. It allows for possible future filtering on output +(although this is not intended for this release). + +Also note that a filter can be defined without adding it to the input +filter list by using MAIL_FILTER() instead of INPUT_MAIL_FILTER() in your +.mc file. + +To test sendmail with the sample filter, the following might be added (in +the appropriate locations) to your .mc file: + + INPUT_MAIL_FILTER(`sample', `S=local:/var/run/f1.sock') + + ++------------------+ +| TESTING A FILTER | ++------------------+ + +Once you have compiled a filter, modified your .mc file and restarted +the sendmail process, you will want to test that the filter performs as +intended. + +The sample filter takes one argument -p, which indicates the local port +on which to create a listening socket for the filter. Maintaining +consistency with the suggested options for sendmail.cf, this would be the +UNIX domain socket located in /var/run/f1.sock. + + % ./sample -p local:/var/run/f1.sock + +If the sample filter returns immediately to a command line, there was either +an error with your command or a problem creating the specified socket. +Further logging can be captured through the syslogd daemon. Using the +'netstat -a' command can ensure that your filter process is listening on +the appropriate local socket. + +Email messages must be injected via SMTP to be filtered. There are two +simple means of doing this; either using the 'sendmail -bs' command, or +by telnetting to port 25 of the machine configured for milter. Once +connected via one of these options, the session can be continued through +the use of standard SMTP commands. + +% sendmail -bs +220 test.sendmail.com ESMTP Sendmail 8.14.0/8.14.0; Thu, 22 Jun 2006 13:05:23 -0500 (EST) +HELO localhost +250 test.sendmail.com Hello testy@localhost, pleased to meet you +MAIL From:<testy> +250 2.1.0 <testy>... Sender ok +RCPT To:<root> +250 2.1.5 <root>... Recipient ok +DATA +354 Enter mail, end with "." on a line by itself +From: testy@test.sendmail.com +To: root@test.sendmail.com +Subject: testing sample filter + +Sample body +. +250 2.0.0 dB73Zxi25236 Message accepted for delivery +QUIT +221 2.0.0 test.sendmail.com closing connection + +In the above example, the lines beginning with numbers are output by the +mail server, and those without are your input. If everything is working +properly, you will find a file in /tmp by the name of msg.XXXXXXXX (where +the Xs represent any combination of letters and numbers). This file should +contain the message body and headers from the test email entered above. + +If the sample filter did not log your test email, there are a number of +methods to narrow down the source of the problem. Check your system +logs written by syslogd and see if there are any pertinent lines. You +may need to reconfigure syslogd to capture all relevant data. Additionally, +the logging level of sendmail can be raised with the LogLevel option. +See the sendmail(8) manual page for more information. + + ++--------------+ +| REQUIREMENTS | ++--------------+ + +libmilter requires pthread support in the operating system. Moreover, it +requires that the library functions it uses are thread safe; which is true +for the operating systems libmilter has been developed and tested on. On +some operating systems this requires special compile time options (e.g., +not just -pthread). libmilter is currently known to work on (modulo problems +in the pthread support of some specific versions): + +FreeBSD 3.x, 4.x +SunOS 5.x (x >= 5) +AIX 4.3.x +HP UX 11.x +Linux (recent versions/distributions) + +libmilter is currently not supported on: + +IRIX 6.x +Ultrix + +Feedback about problems (and possible fixes) is welcome. + ++--------------------------+ +| SOURCE FOR SAMPLE FILTER | ++--------------------------+ + +Note that the filter example.c may not be thread safe on some operating +systems. You should check your system man pages for the functions used +below to verify the functions are thread safe. + +$Revision: 8.42 $, Last updated $Date: 2006/06/29 17:10:16 $ diff --git a/contrib/sendmail/libmilter/comm.c b/contrib/sendmail/libmilter/comm.c new file mode 100644 index 0000000..e04681c --- /dev/null +++ b/contrib/sendmail/libmilter/comm.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1999-2004, 2009 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: comm.c,v 8.70 2009/12/16 16:33:48 ca Exp $") + +#include "libmilter.h" +#include <sm/errstring.h> +#include <sys/uio.h> + +static ssize_t retry_writev __P((socket_t, struct iovec *, int, struct timeval *)); +static size_t Maxdatasize = MILTER_MAX_DATA_SIZE; + +/* +** SMFI_SETMAXDATASIZE -- set limit for milter data read/write. +** +** Parameters: +** sz -- new limit. +** +** Returns: +** old limit +*/ + +size_t +smfi_setmaxdatasize(sz) + size_t sz; +{ + size_t old; + + old = Maxdatasize; + Maxdatasize = sz; + return old; +} + +/* +** MI_RD_CMD -- read a command +** +** Parameters: +** sd -- socket descriptor +** timeout -- maximum time to wait +** cmd -- single character command read from sd +** rlen -- pointer to length of result +** name -- name of milter +** +** Returns: +** buffer with rest of command +** (malloc()ed here, should be free()d) +** hack: encode error in cmd +*/ + +char * +mi_rd_cmd(sd, timeout, cmd, rlen, name) + socket_t sd; + struct timeval *timeout; + char *cmd; + size_t *rlen; + char *name; +{ + ssize_t len; + mi_int32 expl; + ssize_t i; + FD_RD_VAR(rds, excs); + int ret; + int save_errno; + char *buf; + char data[MILTER_LEN_BYTES + 1]; + + *cmd = '\0'; + *rlen = 0; + + i = 0; + for (;;) + { + FD_RD_INIT(sd, rds, excs); + ret = FD_RD_READY(sd, rds, excs, timeout); + if (ret == 0) + break; + else if (ret < 0) + { + if (errno == EINTR) + continue; + break; + } + if (FD_IS_RD_EXC(sd, rds, excs)) + { + *cmd = SMFIC_SELECT; + return NULL; + } + + len = MI_SOCK_READ(sd, data + i, sizeof data - i); + if (MI_SOCK_READ_FAIL(len)) + { + smi_log(SMI_LOG_ERR, + "%s, mi_rd_cmd: read returned %d: %s", + name, (int) len, sm_errstring(errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + if (len == 0) + { + *cmd = SMFIC_EOF; + return NULL; + } + if (len >= (ssize_t) sizeof data - i) + break; + i += len; + } + if (ret == 0) + { + *cmd = SMFIC_TIMEOUT; + return NULL; + } + else if (ret < 0) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: %s() returned %d: %s", + name, MI_POLLSELECT, ret, sm_errstring(errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + + *cmd = data[MILTER_LEN_BYTES]; + data[MILTER_LEN_BYTES] = '\0'; + (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES); + expl = ntohl(expl) - 1; + if (expl <= 0) + return NULL; + if (expl > Maxdatasize) + { + *cmd = SMFIC_TOOBIG; + return NULL; + } +#if _FFR_ADD_NULL + buf = malloc(expl + 1); +#else /* _FFR_ADD_NULL */ + buf = malloc(expl); +#endif /* _FFR_ADD_NULL */ + if (buf == NULL) + { + *cmd = SMFIC_MALLOC; + return NULL; + } + + i = 0; + for (;;) + { + FD_RD_INIT(sd, rds, excs); + ret = FD_RD_READY(sd, rds, excs, timeout); + if (ret == 0) + break; + else if (ret < 0) + { + if (errno == EINTR) + continue; + break; + } + if (FD_IS_RD_EXC(sd, rds, excs)) + { + *cmd = SMFIC_SELECT; + free(buf); + return NULL; + } + len = MI_SOCK_READ(sd, buf + i, expl - i); + if (MI_SOCK_READ_FAIL(len)) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: read returned %d: %s", + name, (int) len, sm_errstring(errno)); + ret = -1; + break; + } + if (len == 0) + { + *cmd = SMFIC_EOF; + free(buf); + return NULL; + } + if (len > expl - i) + { + *cmd = SMFIC_RECVERR; + free(buf); + return NULL; + } + if (len >= expl - i) + { + *rlen = expl; +#if _FFR_ADD_NULL + /* makes life simpler for common string routines */ + buf[expl] = '\0'; +#endif /* _FFR_ADD_NULL */ + return buf; + } + i += len; + } + + save_errno = errno; + free(buf); + + /* select returned 0 (timeout) or < 0 (error) */ + if (ret == 0) + { + *cmd = SMFIC_TIMEOUT; + return NULL; + } + if (ret < 0) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: %s() returned %d: %s", + name, MI_POLLSELECT, ret, sm_errstring(save_errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + *cmd = SMFIC_UNKNERR; + return NULL; +} + +/* +** RETRY_WRITEV -- Keep calling the writev() system call +** until all the data is written out or an error occurs. +** +** Parameters: +** fd -- socket descriptor +** iov -- io vector +** iovcnt -- number of elements in io vector +** must NOT exceed UIO_MAXIOV. +** timeout -- maximum time to wait +** +** Returns: +** success: number of bytes written +** otherwise: MI_FAILURE +*/ + +static ssize_t +retry_writev(fd, iov, iovcnt, timeout) + socket_t fd; + struct iovec *iov; + int iovcnt; + struct timeval *timeout; +{ + int i; + ssize_t n, written; + FD_WR_VAR(wrs); + + written = 0; + for (;;) + { + while (iovcnt > 0 && iov[0].iov_len == 0) + { + iov++; + iovcnt--; + } + if (iovcnt <= 0) + return written; + + /* + ** We don't care much about the timeout here, + ** it's very long anyway; correct solution would be + ** to take the time before the loop and reduce the + ** timeout after each invocation. + ** FD_SETSIZE is checked when socket is created. + */ + + FD_WR_INIT(fd, wrs); + i = FD_WR_READY(fd, wrs, timeout); + if (i == 0) + return MI_FAILURE; + if (i < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + return MI_FAILURE; + } + n = writev(fd, iov, iovcnt); + if (n == -1) + { + if (errno == EINTR || errno == EAGAIN) + continue; + return MI_FAILURE; + } + + written += n; + for (i = 0; i < iovcnt; i++) + { + if (iov[i].iov_len > (unsigned int) n) + { + iov[i].iov_base = (char *)iov[i].iov_base + n; + iov[i].iov_len -= (unsigned int) n; + break; + } + n -= (int) iov[i].iov_len; + iov[i].iov_len = 0; + } + if (i == iovcnt) + return written; + } +} + +/* +** MI_WR_CMD -- write a cmd to sd +** +** Parameters: +** sd -- socket descriptor +** timeout -- maximum time to wait +** cmd -- single character command to write +** buf -- buffer with further data +** len -- length of buffer (without cmd!) +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_wr_cmd(sd, timeout, cmd, buf, len) + socket_t sd; + struct timeval *timeout; + int cmd; + char *buf; + size_t len; +{ + size_t sl; + ssize_t l; + mi_int32 nl; + int iovcnt; + struct iovec iov[2]; + char data[MILTER_LEN_BYTES + 1]; + + if (len > Maxdatasize || (len > 0 && buf == NULL)) + return MI_FAILURE; + + nl = htonl(len + 1); /* add 1 for the cmd char */ + (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES); + data[MILTER_LEN_BYTES] = (char) cmd; + sl = MILTER_LEN_BYTES + 1; + + /* set up the vector for the size / command */ + iov[0].iov_base = (void *) data; + iov[0].iov_len = sl; + iovcnt = 1; + if (len >= 0 && buf != NULL) + { + iov[1].iov_base = (void *) buf; + iov[1].iov_len = len; + iovcnt = 2; + } + + l = retry_writev(sd, iov, iovcnt, timeout); + if (l == MI_FAILURE) + return MI_FAILURE; + return MI_SUCCESS; +} diff --git a/contrib/sendmail/libmilter/docs/api.html b/contrib/sendmail/libmilter/docs/api.html new file mode 100644 index 0000000..578e0ca --- /dev/null +++ b/contrib/sendmail/libmilter/docs/api.html @@ -0,0 +1,322 @@ +<HTML> +<HEAD><TITLE>Milter API</TITLE></HEAD> +<BODY> +<!-- +$Id: api.html,v 1.37 2009/05/19 00:40:52 ca Exp $ +--> +<H1>Milter API</H1> + +<H2>Contents</H2> +<UL> + <LI><A HREF="#LibraryControlFunctions">Library Control Functions</A> + <LI><A HREF="#DataAccessFunctions">Data Access Functions</A> + <LI><A HREF="#MessageModificationFunctions">Message Modification Functions</A> + <LI><A HREF="#Callbacks">Callbacks</A> + <LI><A HREF="#Miscellaneous">Miscellaneous</A> +</UL> + +<H2><A NAME="LibraryControlFunctions">Library Control Functions</A></H2> + +Before handing control to libmilter (by calling +<A HREF="smfi_main.html">smfi_main</A>), a filter may call the following +functions to set libmilter parameters. +In particular, the filter must call +<A HREF="smfi_register.html">smfi_register</A> to register its callbacks. +Each function will return either MI_SUCCESS or MI_FAILURE to +indicate the status of the operation. + +<P> +None of these functions communicate with the MTA. All alter the +library's state, some of which is communicated to the MTA inside +<A HREF="smfi_main.html">smfi_main</A>. + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Function</TH><TH>Description</TH></TR> + +<TR><TD><A HREF="smfi_opensocket.html">smfi_opensocket</A></TD><TD>Try to create the interface socket.</TD></TR> + +<TR><TD><A HREF="smfi_register.html">smfi_register</A></TD><TD>Register a filter.</TD></TR> + +<TR><TD><A HREF="smfi_setconn.html">smfi_setconn</A></TD><TD>Specify socket to use.</TD></TR> + +<TR><TD><A HREF="smfi_settimeout.html">smfi_settimeout</A></TD><TD>Set timeout.</TD></TR> + +<TR><TD><A HREF="smfi_setbacklog.html">smfi_setbacklog</A></TD><TD>Define the incoming <CODE>listen(2)</CODE> queue size.</TD></TR> + +<TR><TD><A HREF="smfi_setdbg.html">smfi_setdbg</A></TD><TD>Set the milter library debugging (tracing) level.</TD></TR> + +<TR><TD><A HREF="smfi_stop.html">smfi_stop</A></TD><TD>Cause an orderly shutdown.</TD></TR> + +<TR><TD><A HREF="smfi_main.html">smfi_main</A></TD><TD>Hand control to libmilter.</TD></TR> + +</TABLE> + +<H2><A NAME="DataAccessFunctions">Data Access Functions</A></H2> + +The following functions may be called from within the filter-defined callbacks +to access information about the current connection or message. +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR bgcolor="#dddddd"><TH>Function</TH><TH>Description</TH></TR> +<TR><TD><A HREF="smfi_getsymval.html">smfi_getsymval</A></TD><TD>Return the value +of a symbol.</TD></TR> + +<TR><TD><A HREF="smfi_getpriv.html">smfi_getpriv</A></TD><TD>Get the private data +pointer.</TD></TR> + +<TR><TD><A HREF="smfi_setpriv.html">smfi_setpriv</A></TD><TD>Set the private data +pointer.</TD></TR> + +<TR><TD><A HREF="smfi_setreply.html">smfi_setreply</A></TD><TD>Set the specific +reply code to be used.</TD></TR> + +<TR><TD><A HREF="smfi_setmlreply.html">smfi_setmlreply</A></TD><TD>Set the +specific multi-line reply to be used.</TD></TR> + +</TABLE> + +<H2><A NAME="MessageModificationFunctions">Message Modification Functions</A></H2> + +The following functions change a message's contents and attributes. +<EM>They may only be called in <A HREF="xxfi_eom.html">xxfi_eom</A></EM>. +All of these functions may invoke additional communication with the MTA. +They will return either MI_SUCCESS or MI_FAILURE to indicate the status of +the operation. Message data (senders, recipients, headers, body chunks) +passed to these functions via parameters is copied and does not need to be +preserved (i.e., allocated memory can be freed). + +<P> +A filter must have set the appropriate flag (listed below) in the +description passed to <A HREF="smfi_register.html">smfi_register</A> +to call any message modification function. Failure to do so will +cause the MTA to treat a call to the function as a failure of the +filter, terminating its connection. + +<P> +Note that the status returned indicates only whether or not the +filter's message was successfully sent to the MTA, not whether or not +the MTA performed the requested operation. For example, +<A HREF="smfi_addheader.html">smfi_addheader</A>, when called with an +illegal header name, will return MI_SUCCESS even though the MTA may +later refuse to add the illegal header. +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Function</TH><TH>Description</TH><TH>SMFIF_* flag</TR> +<TR><TD><A HREF="smfi_addheader.html">smfi_addheader</A></TD><TD>Add a header to +the message.</TD><TD>SMFIF_ADDHDRS</TD></TR> + +<TR><TD><A HREF="smfi_chgheader.html">smfi_chgheader</A></TD><TD>Change or delete a header.</TD><TD>SMFIF_CHGHDRS</TD></TR> + +<TR><TD><A HREF="smfi_insheader.html">smfi_insheader</A></TD><TD>Insert a +header into the message.</TD><TD>SMFIF_ADDHDRS</TD></TR> + +<TR><TD><A HREF="smfi_chgfrom.html">smfi_chgfrom</A></TD><TD>Change the +envelope sender address.</TD><TD>SMFIF_CHGFROM</TD></TR> + +<TR><TD><A HREF="smfi_addrcpt.html">smfi_addrcpt</A></TD><TD>Add a recipient to +the envelope.</TD><TD>SMFIF_ADDRCPT</TD></TR> + +<TR><TD><A HREF="smfi_addrcpt_par.html">smfi_addrcpt_par</A></TD><TD>Add +a recipient including ESMTP parameter to the envelope. +</TD><TD>SMFIF_ADDRCPT_PAR</TD></TR> + +<TR><TD><A HREF="smfi_delrcpt.html">smfi_delrcpt</A></TD><TD>Delete a recipient +from the envelope.</TD><TD>SMFIF_DELRCPT</TD></TR> + +<TR><TD><A HREF="smfi_replacebody.html">smfi_replacebody</A></TD><TD>Replace the +body of the message.</TD><TD>SMFIF_CHGBODY</TD></TR> + +</TABLE> + +<H2>Other Message Handling Functions</H2> + +The following functions provide special case handling instructions for +milter or the MTA, without altering the content or status of the message. +<EM>They too may only be called in <A HREF="xxfi_eom.html">xxfi_eom</A></EM>. +All of these functions may invoke additional communication with the MTA. +They will return either MI_SUCCESS or MI_FAILURE to indicate the status of +the operation. + +<P> +Note that the status returned indicates only whether or not the +filter's message was successfully sent to the MTA, not whether or not +the MTA performed the requested operation. + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Function</TH><TH>Description</TH></TR> +<TR><TD><A HREF="smfi_progress.html">smfi_progress</A></TD><TD>Report operation in progress.</TD></TR> + +<TR><TD><A HREF="smfi_quarantine.html">smfi_quarantine</A></TD><TD>Quarantine a message.</TD></TR> + +</TABLE> + +<H2><A NAME="Callbacks">Callbacks</A></H2> + +The filter should implement one or more of the following callbacks, +which are registered via <A HREF="smfi_register.html">smfi_register</A>: + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Function</TH><TH>Description</TH></TR> + +<TR><TD><A HREF="xxfi_connect.html">xxfi_connect</A></TD><TD>connection info</TD></TR> + +<TR><TD><A HREF="xxfi_helo.html">xxfi_helo</A></TD><TD>SMTP HELO/EHLO command</TD></TR> + +<TR><TD><A HREF="xxfi_envfrom.html">xxfi_envfrom</A></TD><TD>envelope sender</TD></TR> + +<TR><TD><A HREF="xxfi_envrcpt.html">xxfi_envrcpt</A></TD><TD>envelope recipient</TD></TR> + +<TR><TD><A HREF="xxfi_data.html">xxfi_data</A></TD><TD>DATA command</TD></TR> + +<TR><TD><A HREF="xxfi_unknown.html">xxfi_unknown</A></TD><TD>Unknown SMTP command</TD></TR> + +<TR><TD><A HREF="xxfi_header.html">xxfi_header</A></TD><TD>header</TD></TR> + +<TR><TD><A HREF="xxfi_eoh.html">xxfi_eoh</A></TD><TD>end of header</TD></TR> + +<TR><TD><A HREF="xxfi_body.html">xxfi_body</A></TD><TD>body block</TD></TR> + +<TR><TD><A HREF="xxfi_eom.html">xxfi_eom</A></TD><TD>end of message</TD></TR> + +<TR><TD><A HREF="xxfi_abort.html">xxfi_abort</A></TD><TD>message aborted</TD></TR> + +<TR><TD><A HREF="xxfi_close.html">xxfi_close</A></TD><TD>connection cleanup</TD></TR> + +<TR><TD><A HREF="xxfi_negotiate.html">xxfi_negotiate</A></TD><TD>option negotiattion</TD></TR> + +</TABLE> + +<P> +The above callbacks should all return one of the following return values, +having the indicated meanings. Any return other than one of the below +values constitutes an error, and will cause sendmail to terminate its +connection to the offending filter. + +<P><A NAME="conn-spec">Milter</A> distinguishes between recipient-, +message-, and connection-oriented routines. Recipient-oriented +callbacks may affect the processing of a single message recipient; +message-oriented callbacks, a single message; connection-oriented +callbacks, an entire connection (during which multiple messages may be +delivered to multiple sets of recipients). +<A HREF="xxfi_envrcpt.html">xxfi_envrcpt</A> is recipient-oriented. +<A HREF="xxfi_connect.html">xxfi_connect</A>, +<A HREF="xxfi_helo.html">xxfi_helo</A> and +<A HREF="xxfi_close.html">xxfi_close</A> are connection-oriented. All +other callbacks are message-oriented. + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2> + <TR BGCOLOR="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR VALIGN="TOP"> + <TD>SMFIS_CONTINUE</TD> + <TD>Continue processing the current connection, message, or recipient. + </TD> + </TR> + <TR VALIGN="TOP"> + <TD>SMFIS_REJECT</TD> + <TD>For a connection-oriented routine, reject this connection; call <A HREF="xxfi_close.html">xxfi_close</A>.<BR> + For a message-oriented routine (except + <A HREF="xxfi_eom.html">xxfi_eom</A> or + <A HREF="xxfi_abort.html">xxfi_abort</A>), reject this message.<BR> + For a recipient-oriented routine, reject the current recipient (but continue processing the current message). + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_DISCARD</TD> + <TD>For a message- or recipient-oriented routine, accept this message, but silently discard it.<BR> + SMFIS_DISCARD should not be returned by a connection-oriented routine. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_ACCEPT</TD> + <TD>For a connection-oriented routine, accept this connection without further filter processing; call <A HREF="xxfi_close.html">xxfi_close</A>.<BR> + For a message- or recipient-oriented routine, accept this message without further filtering.<BR> + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Return a temporary failure, i.e., the corresponding SMTP command will return an appropriate 4xx status code. + For a message-oriented routine (except <A HREF="xxfi_envfrom.html">xxfi_envfrom</A>), fail for this message. <BR> + For a connection-oriented routine, fail for this connection; call <A HREF="xxfi_close.html">xxfi_close</A>. <BR> + For a recipient-oriented routine, only fail for the current recipient; continue message processing. + </TD> + </TR> + + <TR valign="top"> + <TD><A NAME="SMFIS_SKIP">SMFIS_SKIP</A></TD> + <TD>Skip further callbacks of the same type in this transaction. + Currently this return value is only allowed in + <A HREF="xxfi_body.html">xxfi_body()</A>. + It can be used if a milter has received sufficiently many + body chunks to make a decision, but still wants to invoke + message modification functions that are only allowed to be called from + <A HREF="xxfi_eom.html">xxfi_eom()</A>. + Note: the milter <EM>must</EM> + <A HREF="xxfi_negotiate.html">negotiate</A> + this behavior with the MTA, i.e., it must check whether + the protocol action + <A HREF="xxfi_negotiate.html#SMFIP_SKIP"><CODE>SMFIP_SKIP</CODE></A> + is available and if so, the milter must request it. + </TD> + </TR> + + <TR valign="top"> + <TD><A NAME="SMFIS_NOREPLY">SMFIS_NOREPLY</A></TD> + <TD>Do not send a reply back to the MTA. + The milter <EM>must</EM> + <A HREF="xxfi_negotiate.html">negotiate</A> + this behavior with the MTA, i.e., it must check whether + the appropriate protocol action + <A HREF="xxfi_negotiate.html#SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A> + is available and if so, the milter must request it. + If you set the + <A HREF="xxfi_negotiate.html#SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A> + protocol action for a callback, that callback <EM>must</EM> + always reply with + SMFIS_NOREPLY. + Using any other reply code is a violation of the API. + If in some cases your callback may return another value + (e.g., due to some resource shortages), then you + <EM>must not</EM> set + <A HREF="xxfi_negotiate.html#SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A> + and you must use + SMFIS_CONTINUE as the default return code. + (Alternatively you can try to delay reporting the problem to + a later callback for which + <A HREF="xxfi_negotiate.html#SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A> + is not set.) + </TD> + </TR> + +</TABLE> + +<H2><A NAME="Miscellaneous">Miscellaneous</A></H2> + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Function</TH><TH>Description</TH></TR> + +<TR><TD><A HREF="smfi_version.html">smfi_version</A></TD><TD>libmilter (runtime) version info</TD></TR> + +<TR><TD><A HREF="smfi_setsymlist.html">smfi_setsymlist</A></TD><TD> +Set the list of macros that the milter wants to receive from the MTA +for a protocol stage. +</TD></TR> + +</TABLE> + +<P> +<TABLE BORDER="1" CELLSPACING=0 CELLPADDING=2><TR BGCOLOR="#dddddd"><TH>Constant</TH><TH>Description</TH></TR> + +<TR><TD><A HREF="smfi_version.html">SMFI_VERSION</A></TD><TD>libmilter (compile time) version info</TD></TR> + +</TABLE> + + +<HR SIZE="1"> +<FONT SIZE="-1"> +Copyright (c) 2000, 2003, 2006, 2009 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/design.html b/contrib/sendmail/libmilter/docs/design.html new file mode 100644 index 0000000..f2e5f11 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/design.html @@ -0,0 +1,147 @@ +<HTML> +<HEAD> +<TITLE>Architecture</TITLE> +</HEAD> +<BODY> +<!-- +$Id: design.html,v 1.12 2006/08/08 20:55:57 ca Exp $ +--> + +<H1>Architecture</H1> + +<H2>Contents</H2> + +<UL> + <LI>Design Goals + <LI>Implementing Filtering Policies + <LI>MTA - Filter Communication +</UL> + +<H2>Goals</H2> + +The Sendmail Content Management API (Milter) provides an interface for +third-party software to validate and modify messages as they pass +through the mail transport system. Filters can process messages' +connection (IP) information, envelope protocol elements, message +headers, and/or message body contents, and modify a message's +recipients, headers, and body. The MTA configuration file specifies +which filters are to be applied, and in what order, allowing an +administrator to combine multiple independently-developed filters. + +<P> +We expect to see both vendor-supplied, configurable mail filtering +applications and a multiplicity of script-like filters designed by and +for MTA administrators. A certain degree of coding sophistication and +domain knowledge on the part of the filter provider is assumed. This +allows filters to exercise fine-grained control at the SMTP level. +However, as will be seen in the example, many filtering applications +can be written with relatively little protocol knowledge. + +<P> +Given these expectations, the API is designed to achieve the following +goals: + +<OL> + <LI>Safety/security. + Filter processes should not need to run as root + (of course, they can if required, but that is a local issue); + this will simplify coding + and limit the impact of security flaws in the filter program. +<P> + <LI>Reliability. + Coding failures in a Milter process that cause that process + to hang or core-dump + should not stop mail delivery. + Faced with such a failure, + sendmail should use a default mechanism, + either behaving as if the filter were not present + or as if a required resource were unavailable. + The latter failure mode will generally have sendmail return + a 4xx SMTP code (although in later phases of the SMTP protocol + it may cause the mail to be queued for later processing). +<P> + <LI>Simplicity. + The API should make implementation of a new filter + no more difficult than absolutely necessary. + Subgoals include: + <UL> + <LI>Encourage good thread practice + by defining thread-clean interfaces including local data hooks. + <LI>Provide all interfaces required + while avoiding unnecessary pedanticism. + </UL> +<P> + <LI>Performance. + Simple filters should not seriously impact overall MTA performance. +</OL> + +<H2>Implementing Filtering Policies</H2> + +Milter is designed to allow a server administrator to combine +third-party filters to implement a desired mail filtering policy. For +example, if a site wished to scan incoming mail for viruses on several +platforms, eliminate unsolicited commercial email, and append a mandated +footer to selected incoming messages, the administrator could configure +the MTA to filter messages first through a server based anti-virus +engine, then via a large-scale spam-catching service, and finally +append the desired footer if the message still met requisite criteria. +Any of these filters could be added or changed independently. + +<P> +Thus the site administrator, not the filter writer, controls the +overall mail filtering environment. In particular, he/she must decide +which filters are run, in what order they are run, and how they +communicate with the MTA. These parameters, as well as the +actions to be taken if a filter becomes unavailable, are selectable +during MTA configuration. <A href="installation.html">Further +details</A> are available later in this document. + +<H2>MTA - Filter communication</H2> + +Filters run as separate processes, outside of the sendmail address +space. The benefits of this are threefold: + +<OL> + <LI>The filter need not run with "root" permissions, thereby + avoiding a large family of potential security problems.</LI> + + <LI>Failures in a particular filter will not affect the MTA or + other filters.</LI> + + <LI>The filter can potentially have higher performance because of + the parallelism inherent in multiple processes.</LI> +</OL> + +<P> +Each filter may communicate with multiple MTAs at the same time over +local or remote connections, using multiple threads of execution. +<A HREF="#figure-1">Figure 1</A> illustrates a possible network of +communication channels between a site's filters, its MTAs, and other +MTAs on the network: +</P> +<DIV align="center"> +<A name="figure-1"><IMG src="figure1.jpg" ALT=""></A><BR> +<B>Figure 1: A set of MTA's interacting with a set of filters.</B> +</DIV> +<P> +The Milter library (libmilter) implements the communication protocol. +It accepts connections from various MTAs, passes the relevant data to +the filter through callbacks, then makes appropriate responses based +on return codes. A filter may also send data to the MTA as a result +of library calls. <A href="#figure-2">Figure 2</A> shows a single +filter process processing messages from two MTAs: +</P> +<DIV align="center"> +<IMG src="figure2.jpg" ALT=""><BR> +<B>Figure 2: A filter handling simultaneous requests from two MTA's.</B> +</DIV> +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/figure1.fig b/contrib/sendmail/libmilter/docs/figure1.fig new file mode 100644 index 0000000..e0cbdc8 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure1.fig @@ -0,0 +1,56 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +6 975 225 5025 3375 +6 1500 1275 2700 2025 +2 2 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 5 + 1650 1425 2550 1425 2550 1875 1650 1875 1650 1425 +4 0 1 50 0 0 20 0.0000 4 195 645 1800 1725 MTA\001 +-6 +6 1950 2625 3150 3375 +2 2 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 5 + 2100 2775 3000 2775 3000 3225 2100 3225 2100 2775 +4 0 4 50 0 0 20 0.0000 4 195 645 2250 3075 MTA\001 +-6 +6 1050 225 2250 975 +2 2 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 5 + 1200 375 2100 375 2100 825 1200 825 1200 375 +4 0 14 50 0 0 20 0.0000 4 195 645 1350 675 MTA\001 +-6 +2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2 + 2550 1575 3750 2625 +2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2 + 2550 1575 3750 1575 +2 1 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 2 + 2550 1575 3750 825 +2 1 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 2 + 3000 2925 3750 2625 +2 1 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 2 + 2100 525 3750 825 +2 1 0 2 14 7 50 0 -1 0.000 0 0 7 0 0 2 + 2100 525 3750 2625 +2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2 + 1050 3075 2100 3075 +2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2 + 1050 1725 1650 1725 +2 1 0 4 0 7 50 0 -1 0.000 0 0 7 0 0 2 + 1050 675 1200 675 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3750 2475 4950 2475 4950 2925 3750 2925 3750 2475 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3750 1425 4950 1425 4950 1875 3750 1875 3750 1425 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3750 525 4950 525 4950 975 3750 975 3750 525 +4 0 0 50 0 1 20 0.0000 4 210 795 3900 2775 Filter 3\001 +4 0 0 50 0 1 20 0.0000 4 210 795 3900 1725 Filter 2\001 +4 0 0 50 0 1 20 0.0000 4 210 795 3900 825 Filter 1\001 +-6 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 300 525 1050 525 1050 3225 300 3225 300 525 +4 0 0 50 0 2 24 1.5708 4 255 1950 825 2850 INTERNET\001 diff --git a/contrib/sendmail/libmilter/docs/figure1.jpg b/contrib/sendmail/libmilter/docs/figure1.jpg Binary files differnew file mode 100644 index 0000000..1a5f1de --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure1.jpg diff --git a/contrib/sendmail/libmilter/docs/figure1.ps b/contrib/sendmail/libmilter/docs/figure1.ps new file mode 100644 index 0000000..ae31760 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure1.ps @@ -0,0 +1,173 @@ +%!PS-Adobe-2.0 +%%Title: figure1.fig +%%Creator: fig2dev Version 3.2.3 Patchlevel +%%CreationDate: Tue Jun 6 14:00:04 2000 +%%For: sean@host232.Sendmail.COM (Sean O'rourke,5400) +%%Orientation: Landscape +%%Pages: 1 +%%BoundingBox: 0 0 612 792 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath +198.0 238.0 translate + 90 rotate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +%%Page: 1 1 +10 setmiterlimit + 0.06000 0.06000 sc +%%Page: 1 1 +/Times-Bold ff 360.00 scf sf +825 2850 m +gs 1 -1 sc 90.0 rot (INTERNET) col0 sh gr +/Times-Roman ff 300.00 scf sf +1800 1725 m +gs 1 -1 sc (MTA) col1 sh gr +% Polyline +15.000 slw +n 2100 2775 m 3000 2775 l 3000 3225 l 2100 3225 l + cp gs col4 s gr +/Times-Roman ff 300.00 scf sf +2250 3075 m +gs 1 -1 sc (MTA) col4 sh gr +% Polyline +n 1200 375 m 2100 375 l 2100 825 l 1200 825 l + cp gs col14 s gr +/Times-Roman ff 300.00 scf sf +1350 675 m +gs 1 -1 sc (MTA) col14 sh gr +% Polyline +n 2550 1575 m + 3750 2625 l gs col1 s gr +% Polyline +n 2550 1575 m + 3750 1575 l gs col1 s gr +% Polyline +n 2550 1575 m + 3750 825 l gs col1 s gr +% Polyline +n 3000 2925 m + 3750 2625 l gs col4 s gr +% Polyline +n 2100 525 m + 3750 825 l gs col14 s gr +% Polyline +n 2100 525 m + 3750 2625 l gs col14 s gr +% Polyline +45.000 slw +n 1050 3075 m + 2100 3075 l gs col0 s gr +% Polyline +n 1050 1725 m + 1650 1725 l gs col0 s gr +% Polyline +n 1050 675 m + 1200 675 l gs col0 s gr +% Polyline +15.000 slw +n 3750 2475 m 4950 2475 l 4950 2925 l 3750 2925 l + cp gs col0 s gr +% Polyline +n 3750 1425 m 4950 1425 l 4950 1875 l 3750 1875 l + cp gs col0 s gr +% Polyline +n 3750 525 m 4950 525 l 4950 975 l 3750 975 l + cp gs col0 s gr +/Times-Italic ff 300.00 scf sf +3900 2775 m +gs 1 -1 sc (Filter 3) col0 sh gr +/Times-Italic ff 300.00 scf sf +3900 1725 m +gs 1 -1 sc (Filter 2) col0 sh gr +/Times-Italic ff 300.00 scf sf +3900 825 m +gs 1 -1 sc (Filter 1) col0 sh gr +% Polyline +7.500 slw +n 300 525 m 1050 525 l 1050 3225 l 300 3225 l + cp gs col0 s gr +% Polyline +15.000 slw +n 1650 1425 m 2550 1425 l 2550 1875 l 1650 1875 l + cp gs col1 s gr +$F2psEnd +rs +showpage diff --git a/contrib/sendmail/libmilter/docs/figure2.fig b/contrib/sendmail/libmilter/docs/figure2.fig new file mode 100644 index 0000000..c93bfe3 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure2.fig @@ -0,0 +1,67 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +5 1 0 1 0 7 50 0 -1 0.000 0 0 1 0 2981.250 1200.000 2700 1050 3300 1200 2700 1350 + 1 1 1.00 60.00 120.00 +6 4200 900 6450 1350 +2 2 0 1 1 7 50 0 -1 0.000 0 0 7 0 0 5 + 4200 900 6450 900 6450 1350 4200 1350 4200 900 +4 0 1 50 0 0 16 0.0000 4 195 2040 4350 1200 xxfi_header callback\001 +-6 +6 4200 2250 6450 2700 +2 2 0 1 4 7 50 0 -1 0.000 0 0 7 0 0 5 + 4200 2250 6450 2250 6450 2700 4200 2700 4200 2250 +4 0 4 50 0 0 16 0.0000 4 195 2040 4350 2550 xxfi_header callback\001 +-6 +6 600 2100 1800 2850 +2 2 0 2 4 7 50 0 -1 0.000 0 0 7 0 0 5 + 750 2250 1650 2250 1650 2700 750 2700 750 2250 +4 0 4 50 0 0 20 0.0000 4 195 645 900 2550 MTA\001 +-6 +6 600 750 1800 1500 +2 2 0 2 1 7 50 0 -1 0.000 0 0 7 0 0 5 + 750 900 1650 900 1650 1350 750 1350 750 900 +4 0 1 50 0 0 20 0.0000 4 195 645 900 1200 MTA\001 +-6 +2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 4200 1200 3600 1200 +2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 3450 900 4050 900 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 2400 300 6600 300 6600 3300 2400 3300 2400 300 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 2550 750 3450 750 3450 2700 2550 2700 2550 750 +2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 3450 2700 4050 2700 +2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 4200 2400 3600 2400 +2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 1650 2700 2250 2700 +2 1 0 2 4 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 2400 2400 1800 2400 +2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 1650 900 2250 900 +2 1 0 2 1 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 2400 1200 1800 1200 +4 0 0 50 0 0 20 0.0000 4 195 630 3900 600 Filter\001 +4 0 4 50 0 0 12 0.0000 4 180 1620 3450 3000 callback (arguments)\001 +4 0 4 50 0 0 12 0.0000 4 180 1575 3900 1950 optional library calls,\001 +4 0 4 50 0 0 12 0.0000 4 135 855 3900 2175 return code\001 +4 0 4 50 0 0 12 0.0000 4 135 780 1500 2100 responses\001 +4 0 0 50 0 0 16 0.0000 4 165 645 2700 2085 Milter\001 +4 0 0 50 0 0 16 0.0000 4 225 675 2700 2400 library\001 +4 0 4 50 0 0 12 0.0000 4 135 510 1500 3000 header\001 diff --git a/contrib/sendmail/libmilter/docs/figure2.jpg b/contrib/sendmail/libmilter/docs/figure2.jpg Binary files differnew file mode 100644 index 0000000..8b11485 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure2.jpg diff --git a/contrib/sendmail/libmilter/docs/figure2.ps b/contrib/sendmail/libmilter/docs/figure2.ps new file mode 100644 index 0000000..861a193 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/figure2.ps @@ -0,0 +1,242 @@ +%!PS-Adobe-2.0 +%%Title: figure2.fig +%%Creator: fig2dev Version 3.2.3 Patchlevel +%%CreationDate: Tue Jun 6 13:57:47 2000 +%%For: sean@host232.Sendmail.COM (Sean O'rourke,5400) +%%Orientation: Landscape +%%Pages: 1 +%%BoundingBox: 0 0 612 792 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%Magnification: 1.5000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 792 moveto 0 0 lineto 612 0 lineto 612 792 lineto closepath clip newpath +144.0 65.5 translate + 90 rotate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +%%Page: 1 1 +10 setmiterlimit + 0.09000 0.09000 sc +%%Page: 1 1 +/Times-Roman ff 180.00 scf sf +1500 3000 m +gs 1 -1 sc (header) col4 sh gr +/Times-Roman ff 240.00 scf sf +4350 1200 m +gs 1 -1 sc (xxfi_header callback) col1 sh gr +% Polyline +7.500 slw +n 4200 2250 m 6450 2250 l 6450 2700 l 4200 2700 l + cp gs col4 s gr +/Times-Roman ff 240.00 scf sf +4350 2550 m +gs 1 -1 sc (xxfi_header callback) col4 sh gr +% Polyline +15.000 slw +n 750 2250 m 1650 2250 l 1650 2700 l 750 2700 l + cp gs col4 s gr +/Times-Roman ff 300.00 scf sf +900 2550 m +gs 1 -1 sc (MTA) col4 sh gr +% Polyline +n 750 900 m 1650 900 l 1650 1350 l 750 1350 l + cp gs col1 s gr +/Times-Roman ff 300.00 scf sf +900 1200 m +gs 1 -1 sc (MTA) col1 sh gr +% Arc +7.500 slw +gs clippath +2713 1319 m 2667 1357 l 2761 1475 l 2710 1363 l 2808 1437 l cp +eoclip +n 2981.2 1200.0 318.8 -151.9 151.9 arc +gs col0 s gr + gr + +% arrowhead +n 2808 1437 m 2710 1363 l 2761 1475 l 2808 1437 l cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +gs clippath +3585 1140 m 3585 1260 l 3872 1260 l 3632 1200 l 3872 1140 l cp +eoclip +n 4200 1200 m + 3600 1200 l gs col1 s gr gr + +% arrowhead +n 3872 1140 m 3632 1200 l 3872 1260 l 3872 1140 l cp gs col1 1.00 shd ef gr col1 s +% Polyline +gs clippath +4065 960 m 4065 840 l 3778 840 l 4018 900 l 3778 960 l cp +eoclip +n 3450 900 m + 4050 900 l gs col1 s gr gr + +% arrowhead +n 3778 960 m 4018 900 l 3778 840 l 3778 960 l cp gs col1 1.00 shd ef gr col1 s +% Polyline +n 2400 300 m 6600 300 l 6600 3300 l 2400 3300 l + cp gs col0 s gr +% Polyline +7.500 slw +n 2550 750 m 3450 750 l 3450 2700 l 2550 2700 l + cp gs col0 s gr +% Polyline +15.000 slw +gs clippath +4065 2760 m 4065 2640 l 3778 2640 l 4018 2700 l 3778 2760 l cp +eoclip +n 3450 2700 m + 4050 2700 l gs col4 s gr gr + +% arrowhead +n 3778 2760 m 4018 2700 l 3778 2640 l 3778 2760 l cp gs col4 1.00 shd ef gr col4 s +% Polyline +gs clippath +3585 2340 m 3585 2460 l 3872 2460 l 3632 2400 l 3872 2340 l cp +eoclip +n 4200 2400 m + 3600 2400 l gs col4 s gr gr + +% arrowhead +n 3872 2340 m 3632 2400 l 3872 2460 l 3872 2340 l cp gs col4 1.00 shd ef gr col4 s +% Polyline +gs clippath +2265 2760 m 2265 2640 l 1978 2640 l 2218 2700 l 1978 2760 l cp +eoclip +n 1650 2700 m + 2250 2700 l gs col4 s gr gr + +% arrowhead +n 1978 2760 m 2218 2700 l 1978 2640 l 1978 2760 l cp gs col4 1.00 shd ef gr col4 s +% Polyline +gs clippath +1785 2340 m 1785 2460 l 2072 2460 l 1832 2400 l 2072 2340 l cp +eoclip +n 2400 2400 m + 1800 2400 l gs col4 s gr gr + +% arrowhead +n 2072 2340 m 1832 2400 l 2072 2460 l 2072 2340 l cp gs col4 1.00 shd ef gr col4 s +% Polyline +gs clippath +2265 960 m 2265 840 l 1978 840 l 2218 900 l 1978 960 l cp +eoclip +n 1650 900 m + 2250 900 l gs col1 s gr gr + +% arrowhead +n 1978 960 m 2218 900 l 1978 840 l 1978 960 l cp gs col1 1.00 shd ef gr col1 s +% Polyline +gs clippath +1785 1140 m 1785 1260 l 2072 1260 l 1832 1200 l 2072 1140 l cp +eoclip +n 2400 1200 m + 1800 1200 l gs col1 s gr gr + +% arrowhead +n 2072 1140 m 1832 1200 l 2072 1260 l 2072 1140 l cp gs col1 1.00 shd ef gr col1 s +/Times-Roman ff 300.00 scf sf +3900 600 m +gs 1 -1 sc (Filter) col0 sh gr +/Times-Roman ff 180.00 scf sf +3450 3000 m +gs 1 -1 sc (callback \(arguments\)) col4 sh gr +/Times-Roman ff 180.00 scf sf +3900 1950 m +gs 1 -1 sc (optional library calls,) col4 sh gr +/Times-Roman ff 180.00 scf sf +3900 2175 m +gs 1 -1 sc (return code) col4 sh gr +/Times-Roman ff 180.00 scf sf +1500 2100 m +gs 1 -1 sc (responses) col4 sh gr +/Times-Roman ff 240.00 scf sf +2700 2085 m +gs 1 -1 sc (Milter) col0 sh gr +/Times-Roman ff 240.00 scf sf +2700 2400 m +gs 1 -1 sc (library) col0 sh gr +% Polyline +7.500 slw +n 4200 900 m 6450 900 l 6450 1350 l 4200 1350 l + cp gs col1 s gr +$F2psEnd +rs +showpage diff --git a/contrib/sendmail/libmilter/docs/index.html b/contrib/sendmail/libmilter/docs/index.html new file mode 100644 index 0000000..517d2f6 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/index.html @@ -0,0 +1,92 @@ +<HTML> +<HEAD> +<TITLE>Filtering Mail with Sendmail</TITLE> +</HEAD> +<BODY> +<!-- +$Id: index.html,v 1.13 2006/08/08 20:55:57 ca Exp $ +--> + +<H1>Filtering Mail with Sendmail</H1> + +<!-- +<P><B>Disclaimer</B>: +This preliminary API description is provided for review only. This +specification may change based on feedback from reviewers, and does +not bind Sendmail to offer this functionality in any release. +--> + +<H2>Introduction</H2> + +<P> +Sendmail's Content Management API (milter) provides third-party +programs to access mail messages as they are being processed by the +Mail Transfer Agent (MTA), allowing them to examine and modify message +content and meta-information. Filtering policies implemented by +Milter-conformant filters may then be centrally configured and +composed in an end-user's MTA configuration file. + +<P> +Possible uses for filters include spam rejection, virus +filtering, and content control. In general, Milter seeks to address +site-wide filtering concerns in a scalable way. Individual users' mail +filtering needs (e.g. sorting messages by subject) are left to +client-level programs such as <A href="http://www.procmail.org">Procmail</A>. + +<P> +This document is a technical introduction intended for those +interested in developing Milter filters. It includes: +<UL> +<LI>A description of Milter's design goals. + +<LI>An explanation of Milter application architecture, including +interactions between the support library and user code, and between +filters and the MTA. + +<LI>A specification of the C application programming interface. +<LI>An example of a simple Milter filter. +</UL> + +<H2>Contents</H2> + +<UL> +<LI><A href="design.html">Architecture</A> +<UL> + <LI>Design Goals + <LI>Implementing Filtering Policies + <LI>MTA - Filter communication +</UL> +<LI><A href="overview.html">Technical Overview</A> +<UL> + <LI>Initialization + <LI>Control flow + <LI>Multithreading + <LI>Resource Management + <LI>Signal Handling +</UL> +<LI><A href="api.html">API Documentation</A> +<UL> + <LI>Library Control Functions + <LI>Data Access Functions + <LI>Message Modification Functions + <LI>Callbacks +</UL> +<LI><A href="installation.html">Installation and Configuration</A> +<UL> + <LI>Compiling and Installing Your Filter + <LI>Configuring Sendmail +</UL> +<LI><A href="sample.html">A Sample Filter</A> +<!-- <LI><A href="other.html">Other Sources of Information</A> --> +</UL> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2001, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/installation.html b/contrib/sendmail/libmilter/docs/installation.html new file mode 100644 index 0000000..07142e9 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/installation.html @@ -0,0 +1,165 @@ +<HTML> +<HEAD><TITLE>Installation and Configuration</TITLE> +</HEAD> +<BODY> +<!-- +$Id: installation.html,v 1.23 2006/08/31 17:16:03 ca Exp $ +--> +<H1>Installation</H1> +<H2>Contents</H2> +<UL> + <LI><A href="#compile">Compiling and Installing Your Filter</A> + <LI><A href="#config">Configuring Sendmail</A> +</UL> + +<H2><A name="compile">Compiling and Installing Your Filter</A></H2> + +To compile a filter, modify the Makefile provided with the sample program, or: +<UL> + <LI>Put the include and Sendmail directories in your include path + (e.g. -I/path/to/include -I/path/to/sendmail). + + <LI>Make sure libmilter.a is in your library path, and link your + application with it (e.g. "-lmilter"). + + <LI>Compile with pthreads, either by using -pthread for gcc, or + linking with a pthreads support library (-lpthread). +</UL> +Your compile command line will look like +<PRE> +cc -I/path/to/include -I/path/to/sendmail -c myfile.c +</PRE> +and your linking command line will look something like +<PRE> +cc -o myfilter [object-files] -L[library-location] -lmilter -pthread +</PRE> + +<H2><A name="config">Configuring Sendmail</A></H2> + +If you use a sendmail version older than 8.13 please see +the instructions for your version. +The default compilation options for sendmail enable support +for milters since 8.13. + +<P> +Next, you must add the desired filters to your sendmail configuration +(.mc) file. +Mail filters have three equates: +The required <CODE>S=</CODE> equate specifies the socket where +sendmail should look for the filter; the optional <CODE>F=</CODE> and +<CODE>T=</CODE> equates specify flags and timeouts, respectively. +All equates names, equate field names, and flag values are case sensitive. + +<P> +The current flags (<CODE>F=</CODE>) are: +<P> +<TABLE cellspacing="1" cellpadding=4 border=1> +<TR bgcolor="#dddddd" align=left valign=top> +<TH>Flag</TH> <TH align="center">Meaning</TH> +</TR> +<TR align="left" valign=top> +<TD>R</TD> <TD>Reject connection if filter unavailable</TD> +</TR> +<TR align="left" valign=top> +<TD>T</TD> <TD>Temporary fail connection if filter unavailable</TD> +</TR> +</TABLE> + +If a filter is unavailable or unresponsive and no flags have been +specified, the MTA will continue normal handling of the current +connection. +The MTA will try to contact the filter again on each new connection. + +<P> +There are three fields inside of the <CODE>T=</CODE> equate: S, R, and E. +Note the separator between each is a ";" (semicolon), as "," +(comma) already separates equates. +The value of each field is a decimal number followed by a single letter +designating the units ("s" for seconds, "m" for minutes). +The fields have the following meanings: +<P> +<TABLE cellspacing="1" cellpadding=4 border=1> +<TR bgcolor="#dddddd" align=left valign=top> +<TH>Flag</TH> <TH align="center">Meaning</TH> +</TR> +<TR align="left" valign=top> +<TD>C</TD> <TD>Timeout for connecting to a filter. If set to 0, the + system's <CODE>connect(2)</CODE> timeout will be used. + Default: 5m</TD> +</TR> +<TR align="left" valign=top> +<TD>S</TD> <TD>Timeout for sending information from the MTA to a + filter. Default: 10s</TD> +</TR> +<TR align="left" valign=top> +<TD>R</TD> <TD>Timeout for reading reply from the filter. Default: 10s</TD> +</TR> +<TR align="left" valign=top> +<TD>E</TD> <TD>Overall timeout between sending end-of-message to + filter and waiting for the final acknowledgment. Default: 5m</TD> +</TR> +</TABLE> + +<P> +The following sendmail.mc example specifies three filters. +The first two rendezvous on Unix-domain sockets in the /var/run directory; +the third uses an IP socket on port 999. +<PRE> + INPUT_MAIL_FILTER(`filter1', `S=unix:/var/run/f1.sock, F=R') + INPUT_MAIL_FILTER(`filter2', `S=unix:/var/run/f2.sock, F=T, T=S:1s;R:1s;E:5m') + INPUT_MAIL_FILTER(`filter3', `S=inet:999@localhost, T=C:2m') + + define(`confINPUT_MAIL_FILTERS', `filter2,filter1,filter3') +<HR width="30%"> + m4 ../m4/cf.m4 myconfig.mc > myconfig.cf +</PRE> +By default, the filters would be run in the order declared, +i.e. "filter1, filter2, filter3"; however, since +<CODE>confINPUT_MAIL_FILTERS</CODE> is defined, the filters will be +run "filter2, filter1, filter3". +Also note that a filter can be defined +without adding it to the input filter list by using +MAIL_FILTER() instead of INPUT_MAIL_FILTER(). + +<P> +The above macros will result in the following lines being added to +your .cf file: +<PRE> + Xfilter1, S=unix:/var/run/f1.sock, F=R + Xfilter2, S=unix:/var/run/f2.sock, F=T, T=S:1s;R:1s;E:5m + Xfilter3, S=inet:999@localhost, T=C:2m + + O InputMailFilters=filter2,filter1,filter3 +</PRE> +<P> +Finally, the sendmail macros accessible via +<A HREF="smfi_getsymval.html">smfi_getsymval</A> can be configured by +defining the following m4 variables (or cf options): +<TABLE cellspacing="1" cellpadding=4 border=1> +<TR bgcolor="#dddddd" align=left valign=top> +<TH align="center">In .mc file</TH> <TH align="center">In .cf file</TH> +<TH align="center">Default Value</TH> +</TR> +<TR><TD>confMILTER_MACROS_CONNECT</TD><TD>Milter.macros.connect</TD> +<TD><CODE>j, _, {daemon_name}, {if_name}, {if_addr}</CODE></TD></TR> +<TR><TD>confMILTER_MACROS_HELO</TD><TD>Milter.macros.helo</TD> +<TD><CODE>{tls_version}, {cipher}, {cipher_bits}, {cert_subject}, +{cert_issuer}</CODE></TD></TR> +<TR><TD>confMILTER_MACROS_ENVFROM</TD><TD>Milter.macros.envfrom</TD> +<TD><CODE>i, {auth_type}, {auth_authen}, {auth_ssf}, {auth_author}, +{mail_mailer}, {mail_host}, {mail_addr}</CODE></TD></TR> +<TR><TD>confMILTER_MACROS_ENVRCPT</TD><TD>Milter.macros.envrcpt</TD> +<TD><CODE>{rcpt_mailer}, {rcpt_host}, {rcpt_addr}</CODE></TD></TR> +</TABLE> +For information about available macros and their meanings, please +consult the sendmail documentation. +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/other.html b/contrib/sendmail/libmilter/docs/other.html new file mode 100644 index 0000000..c33b536 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/other.html @@ -0,0 +1,18 @@ +<HTML> +<HEAD><TITLE>Other Resources</TITLE> +</HEAD> +<BODY> +<!-- +$Id: other.html,v 1.6 2006/08/08 20:55:57 ca Exp $ +--> +FAQ? Mailing list? More sample filters? +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/overview.html b/contrib/sendmail/libmilter/docs/overview.html new file mode 100644 index 0000000..5c6f21c --- /dev/null +++ b/contrib/sendmail/libmilter/docs/overview.html @@ -0,0 +1,217 @@ +<HTML> +<HEAD> +<TITLE>Technical Overview</TITLE> +</HEAD> +<BODY> +<!-- +$Id: overview.html,v 1.20 2009/11/13 18:15:05 ca Exp $ +--> + +<H1>Technical Overview</H1> + +<H2>Contents</H2> + +<UL> + <LI><A HREF="#Initialization">Initialization</A> + <LI><A HREF="#ControlFlow">Control Flow</A> + <LI><A HREF="#Multithreading">Multithreading</A> + <LI><A HREF="#ResourceManagement">Resource Management</A> + <LI><A HREF="#SignalHandling">Signal Handling</A> +</UL> + +<H2><A NAME="Initialization">Initialization</A></H2> + +In addition to its own initialization, +libmilter expects a filter to initialize several parameters +before calling <A HREF="smfi_main.html">smfi_main</A>: +<UL> + <LI>The callbacks the filter wishes to be called, and the types of + message modification it intends to perform (required, see + <A HREF="smfi_register.html">smfi_register</A>). + + <LI>The socket address to be used when communicating with the MTA + (required, see <A HREF="smfi_setconn.html">smfi_setconn</A>). + + <LI>The number of seconds to wait for MTA connections before + timing out (optional, see + <A HREF="smfi_settimeout.html">smfi_settimeout</A>). +</UL> +<P> +If the filter fails to initialize libmilter, +or if one or more of the parameters it has passed are invalid, +a subsequent call to smfi_main will fail. + +<H2><A NAME="ControlFlow">Control Flow</A></H2> + +<P> +The following pseudocode describes the filtering process from the +perspective of a set of <CODE>N</CODE> MTA's, +each corresponding to a connection. +Callbacks are shown beside the processing stages in which they are invoked; +if no callbacks are defined for a particular stage, +that stage may be bypassed. +Though it is not shown, +processing may be aborted at any time during a message, +in which case the +<A HREF="xxfi_abort.html">xxfi_abort</A> callback is invoked and control +returns to <CODE>MESSAGE</CODE>. +<P> +<PRE> +For each of N connections +{ + For each filter + process connection (<A HREF="xxfi_connect.html">xxfi_connect</A>) + For each filter + process helo/ehlo (<A HREF="xxfi_helo.html">xxfi_helo</A>) +MESSAGE:For each message in this connection (sequentially) + { + For each filter + process sender (<A HREF="xxfi_envfrom.html">xxfi_envfrom</A>) + For each recipient + { + For each filter + process recipient (<A HREF="xxfi_envrcpt.html">xxfi_envrcpt</A>) + } + For each filter + { + process DATA (<A HREF="xxfi_data.html">xxfi_data</A>) + For each header + process header (<A HREF="xxfi_header.html">xxfi_header</A>) + process end of headers (<A HREF="xxfi_eoh.html">xxfi_eoh</A>) + For each body block + process this body block (<A HREF="xxfi_body.html">xxfi_body</A>) + process end of message (<A HREF="xxfi_eom.html">xxfi_eom</A>) + } + } + For each filter + process end of connection (<A HREF="xxfi_close.html">xxfi_close</A>) +} +</PRE> + +<P>Note: Filters are contacted in order defined in config file.</P> + +<P> +To write a filter, a vendor supplies callbacks to process relevant +parts of a message transaction. +The library then controls all sequencing, threading, +and protocol exchange with the MTA. +<A HREF="#figure-3">Figure 3</A> outlines control flow for a filter +process, showing where different callbacks are invoked. +</P> + +<DIV ALIGN="center"><A NAME="figure-3"></A> +<TABLE border=1 cellspacing=0 cellpadding=2 width="70%"> +<TR bgcolor="#dddddd"><TH>SMTP Commands</TH><TH>Milter Callbacks</TH></TR> +<TR><TD>(open SMTP connection)</TD><TD>xxfi_connect</TD></TR> +<TR><TD>HELO ...</TD><TD>xxfi_helo</TD></TR> +<TR><TD>MAIL From: ...</TD><TD>xxfi_envfrom</TD></TR> +<TR><TD>RCPT To: ...</TD><TD>xxfi_envrcpt</TD></TR> +<TR><TD>[more RCPTs]</TD><TD>[xxfi_envrcpt]</TD></TR> +<TR><TD>DATA</TD><TD>xxfi_data</TD></TR> +<TR><TD>Header: ...</TD><TD>xxfi_header</TD></TR> +<TR><TD>[more headers]</TD><TD>[xxfi_header]</TD></TR> +<TR><TD> </TD><TD>xxfi_eoh</TD></TR> +<TR><TD>body... </TD><TD>xxfi_body</TD></TR> +<TR><TD>[more body...]</TD><TD>[xxfi_body]</TD></TR> +<TR><TD>.</TD><TD>xxfi_eom</TD></TR> +<TR><TD>QUIT</TD><TD>xxfi_close</TD></TR> +<TR><TD>(close SMTP connection)</TD><TD> </TD></TR> +</TABLE> +<B>Figure 3: Milter callbacks related to an SMTP transaction.</B> +</DIV> + +<P> +Note that although only a single message is shown above, multiple +messages may be sent in a single connection. +Note also that a message or connection may be aborted by +either the remote host or the MTA +at any point during the SMTP transaction. +f this occurs during a message (between the MAIL command and the final "."), +the filter's +<A HREF="xxfi_abort.html">xxfi_abort</A> routine will be called. +<A HREF="xxfi_close.html">xxfi_close</A> is called any time the +connection closes. + +<H2><A NAME="Multithreading">Multithreading</A></H2> + +<P> +A single filter process may handle any number of connections +simultaneously. +All filtering callbacks must therefore be reentrant, +and use some appropriate external synchronization methods to access +global data. +Furthermore, since there is not a one-to-one correspondence +between threads and connections +(N connections mapped onto M threads, M <= N), +connection-specific data must be accessed +through the handles provided by the Milter library. +The programmer cannot rely on library-supplied thread-specific data blocks +(e.g., <CODE>pthread_getspecific(3)</CODE>) to store connection-specific data. +See the API documentation for +<A HREF="smfi_setpriv.html">smfi_setpriv</A> and +<A HREF="smfi_getpriv.html">smfi_getpriv</A> for details. + +<H2><A NAME="ResourceManagement">Resource Management</A></H2> + +Since filters are likely to be long-lived, +and to handle many connections, +proper deallocation of per-connection resources is important. +The lifetime of a connection is bracketed by calls to the +callbacks <A HREF="xxfi_connect.html">xxfi_connect</A> and +<A HREF="xxfi_close.html">xxfi_close</A>. +Therefore connection-specific +resources (accessed via <A HREF="smfi_getpriv.html">smfi_getpriv</A> +and <A HREF="smfi_setpriv.html">smfi_setpriv</A>) may be allocated in +<A HREF="xxfi_connect.html">xxfi_connect</A>, +and should be freed in +<A HREF="xxfi_close.html">xxfi_close</A>. +For further information see +the <A HREF="api.html#conn-msg">discussion</A> of message- versus +connection-oriented routines. +In particular, +note that there is only one connection-specific data pointer per connection. +<P> + +Each message is bracketed by calls to +<A HREF="xxfi_envfrom.html">xxfi_envfrom</A> and +<A HREF="xxfi_eom.html">xxfi_eom</A> (or +<A HREF="xxfi_abort.html">xxfi_abort</A>), +implying that message-specific resources can be allocated +and reclaimed in these routines. +Since the messages in a connection are processed sequentially by each filter, +there will be only one active message associated with a given +connection and filter (and connection-private data block). +These resources must still be accessed through +<A HREF="smfi_getpriv.html">smfi_getpriv</A> and +<A HREF="smfi_setpriv.html">smfi_setpriv</A>, +and must be reclaimed in +<A HREF="xxfi_abort.html">xxfi_abort</A>. + +<H2><A NAME="SignalHandling">Signal Handling</A></H2> + +libmilter takes care of signal handling, +the filters are not influenced directly by signals. +There are basically two types of signal handlers: + +<OL> +<LI><TT>Stop</TT>: no new connections from the MTA will be accepted, +but existing connections are allowed to continue. +<LI><TT>Abort</TT>: all filters will be stopped as soon as the next +communication with the MTA happens. +</OL> + +Filters are not terminated asynchronously +(except by signals that can't be caught). +In the case of <TT>Abort</TT> the +<A HREF="xxfi_abort.html">xxfi_abort</A> callback is invoked. + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2001, 2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/sample.html b/contrib/sendmail/libmilter/docs/sample.html new file mode 100644 index 0000000..48e25c5 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/sample.html @@ -0,0 +1,537 @@ +<HTML> +<HEAD><TITLE>A Sample Filter</TITLE></HEAD> +<BODY> +<!-- +$Id: sample.html,v 1.22 2006/10/09 23:14:51 ca Exp $ +--> +<H1>A Sample Filter</H1> + +The following sample logs each message to a separate temporary file, +adds a recipient given with the -a flag, +and rejects a disallowed recipient address given with the -r flag. +It recognizes the following options: +<P> +<CENTER> +<TABLE border="1" cellpadding=2 cellspacing=1> +<TR><TD><CODE>-p port</CODE></TD><TD>The port through which the MTA will connect to the filter.</TD></TR> +<TR><TD><CODE>-t sec</CODE></TD><TD>The timeout value.</TD></TR> +<TR><TD><CODE>-r addr</CODE></TD><TD>A recipient to reject.</TD></TR> +<TR><TD><CODE>-a addr</CODE></TD><TD>A recipient to add.</TD></TR> +</TABLE> +</CENTER> +<HR> +<PRE> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include "libmilter/mfapi.h" + +#ifndef bool +# define bool int +# define TRUE 1 +# define FALSE 0 +#endif /* ! bool */ + + +struct mlfiPriv +{ + char *mlfi_fname; + char *mlfi_connectfrom; + char *mlfi_helofrom; + FILE *mlfi_fp; +}; + +#define MLFIPRIV ((struct mlfiPriv *) <A href="smfi_getpriv.html">smfi_getpriv</A>(ctx)) + +extern sfsistat mlfi_cleanup(SMFICTX *, bool); + +/* recipients to add and reject (set with -a and -r options) */ +char *add = NULL; +char *reject = NULL; + +sfsistat +<A href="xxfi_connect.html">mlfi_connect</A>(ctx, hostname, hostaddr) + SMFICTX *ctx; + char *hostname; + _SOCK_ADDR *hostaddr; +{ + struct mlfiPriv *priv; + char *ident; + + /* allocate some private memory */ + priv = malloc(sizeof *priv); + if (priv == NULL) + { + /* can't accept this message right now */ + return SMFIS_TEMPFAIL; + } + memset(priv, '\0', sizeof *priv); + + /* save the private data */ + <A href="smfi_setpriv.html">smfi_setpriv</A>(ctx, priv); + + ident = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "_"); + if (ident == NULL) + ident = "???"; + if ((priv->mlfi_connectfrom = strdup(ident)) == NULL) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_helo.html">mlfi_helo</A>(ctx, helohost) + SMFICTX *ctx; + char *helohost; +{ + size_t len; + char *tls; + char *buf; + struct mlfiPriv *priv = MLFIPRIV; + + tls = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{tls_version}"); + if (tls == NULL) + tls = "No TLS"; + if (helohost == NULL) + helohost = "???"; + len = strlen(tls) + strlen(helohost) + 3; + if ((buf = (char*) malloc(len)) == NULL) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + snprintf(buf, len, "%s, %s", helohost, tls); + if (priv->mlfi_helofrom != NULL) + free(priv->mlfi_helofrom); + priv->mlfi_helofrom = buf; + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_envfrom.html">mlfi_envfrom</A>(ctx, argv) + SMFICTX *ctx; + char **argv; +{ + int fd = -1; + int argc = 0; + struct mlfiPriv *priv = MLFIPRIV; + char *mailaddr = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{mail_addr}"); + + /* open a file to store this message */ + if ((priv->mlfi_fname = strdup("/tmp/msg.XXXXXX")) == NULL) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + if ((fd = mkstemp(priv->mlfi_fname)) == -1) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + if ((priv->mlfi_fp = fdopen(fd, "w+")) == NULL) + { + (void) close(fd); + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* count the arguments */ + while (*argv++ != NULL) + ++argc; + + /* log the connection information we stored earlier: */ + if (fprintf(priv->mlfi_fp, "Connect from %s (%s)\n\n", + priv->mlfi_helofrom, priv->mlfi_connectfrom) == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + /* log the sender */ + if (fprintf(priv->mlfi_fp, "FROM %s (%d argument%s)\n", + mailaddr ? mailaddr : "???", argc, + (argc == 1) ? "" : "s") == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_envrcpt.html">mlfi_envrcpt</A>(ctx, argv) + SMFICTX *ctx; + char **argv; +{ + struct mlfiPriv *priv = MLFIPRIV; + char *rcptaddr = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{rcpt_addr}"); + int argc = 0; + + /* count the arguments */ + while (*argv++ != NULL) + ++argc; + + /* log this recipient */ + if (reject != NULL && rcptaddr != NULL && + (strcasecmp(rcptaddr, reject) == 0)) + { + if (fprintf(priv->mlfi_fp, "RCPT %s -- REJECTED\n", + rcptaddr) == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + return SMFIS_REJECT; + } + if (fprintf(priv->mlfi_fp, "RCPT %s (%d argument%s)\n", + rcptaddr ? rcptaddr : "???", argc, + (argc == 1) ? "" : "s") == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_header.html">mlfi_header</A>(ctx, headerf, headerv) + SMFICTX *ctx; + char *headerf; + unsigned char *headerv; +{ + /* write the header to the log file */ + if (fprintf(MLFIPRIV->mlfi_fp, "%s: %s\n", headerf, headerv) == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_eoh.html">mlfi_eoh</A>(ctx) + SMFICTX *ctx; +{ + /* output the blank line between the header and the body */ + if (fprintf(MLFIPRIV->mlfi_fp, "\n") == EOF) + { + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_body.html">mlfi_body</A>(ctx, bodyp, bodylen) + SMFICTX *ctx; + unsigned char *bodyp; + size_t bodylen; +{ + struct mlfiPriv *priv = MLFIPRIV; + + /* output body block to log file */ + if (fwrite(bodyp, bodylen, 1, priv->mlfi_fp) != 1) + { + /* write failed */ + fprintf(stderr, "Couldn't write file %s: %s\n", + priv->mlfi_fname, strerror(errno)); + (void) mlfi_cleanup(ctx, FALSE); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_eom.html">mlfi_eom</A>(ctx) + SMFICTX *ctx; +{ + bool ok = TRUE; + + /* change recipients, if requested */ + if (add != NULL) + ok = (<A href="smfi_addrcpt.html">smfi_addrcpt</A>(ctx, add) == MI_SUCCESS); + return mlfi_cleanup(ctx, ok); +} + +sfsistat +<A href="xxfi_abort.html">mlfi_abort</A>(ctx) + SMFICTX *ctx; +{ + return mlfi_cleanup(ctx, FALSE); +} + +sfsistat +mlfi_cleanup(ctx, ok) + SMFICTX *ctx; + bool ok; +{ + sfsistat rstat = SMFIS_CONTINUE; + struct mlfiPriv *priv = MLFIPRIV; + char *p; + char host[512]; + char hbuf[1024]; + + if (priv == NULL) + return rstat; + + /* close the archive file */ + if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) + { + /* failed; we have to wait until later */ + fprintf(stderr, "Couldn't close archive file %s: %s\n", + priv->mlfi_fname, strerror(errno)); + rstat = SMFIS_TEMPFAIL; + (void) unlink(priv->mlfi_fname); + } + else if (ok) + { + /* add a header to the message announcing our presence */ + if (gethostname(host, sizeof host) < 0) + snprintf(host, sizeof host, "localhost"); + p = strrchr(priv->mlfi_fname, '/'); + if (p == NULL) + p = priv->mlfi_fname; + else + p++; + snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); + if (<A href="smfi_addheader.html">smfi_addheader</A>(ctx, "X-Archived", hbuf) != MI_SUCCESS) + { + /* failed; we have to wait until later */ + fprintf(stderr, + "Couldn't add header: X-Archived: %s\n", + hbuf); + ok = FALSE; + rstat = SMFIS_TEMPFAIL; + (void) unlink(priv->mlfi_fname); + } + } + else + { + /* message was aborted -- delete the archive file */ + fprintf(stderr, "Message aborted. Removing %s\n", + priv->mlfi_fname); + rstat = SMFIS_TEMPFAIL; + (void) unlink(priv->mlfi_fname); + } + + /* release private memory */ + if (priv->mlfi_fname != NULL) + free(priv->mlfi_fname); + + /* return status */ + return rstat; +} + +sfsistat +<A href="xxfi_close.html">mlfi_close</A>(ctx) + SMFICTX *ctx; +{ + struct mlfiPriv *priv = MLFIPRIV; + + if (priv == NULL) + return SMFIS_CONTINUE; + if (priv->mlfi_connectfrom != NULL) + free(priv->mlfi_connectfrom); + if (priv->mlfi_helofrom != NULL) + free(priv->mlfi_helofrom); + free(priv); + <A href="smfi_setpriv.html">smfi_setpriv</A>(ctx, NULL); + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_unknown.html">mlfi_unknown</A>(ctx, cmd) + SMFICTX *ctx; + char *cmd; +{ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_data.html">mlfi_data</A>(ctx) + SMFICTX *ctx; +{ + return SMFIS_CONTINUE; +} + +sfsistat +<A href="xxfi_negotiate.html">mlfi_negotiate</A>(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3) + SMFICTX *ctx; + unsigned long f0; + unsigned long f1; + unsigned long f2; + unsigned long f3; + unsigned long *pf0; + unsigned long *pf1; + unsigned long *pf2; + unsigned long *pf3; +{ + return SMFIS_ALL_OPTS; +} + +struct smfiDesc smfilter = +{ + "SampleFilter", /* filter name */ + SMFI_VERSION, /* version code -- do not change */ + SMFIF_ADDHDRS|SMFIF_ADDRCPT, + /* flags */ + <A href="xxfi_connect.html">mlfi_connect</A>, /* connection info filter */ + <A href="xxfi_helo.html">mlfi_helo</A>, /* SMTP HELO command filter */ + <A href="xxfi_envfrom.html">mlfi_envfrom</A>, /* envelope sender filter */ + <A href="xxfi_envrcpt.html">mlfi_envrcpt</A>, /* envelope recipient filter */ + <A href="xxfi_header.html">mlfi_header</A>, /* header filter */ + <A href="xxfi_eoh.html">mlfi_eoh</A>, /* end of header */ + <A href="xxfi_body.html">mlfi_body</A>, /* body block filter */ + <A href="xxfi_eom.html">mlfi_eom</A>, /* end of message */ + <A href="xxfi_abort.html">mlfi_abort</A>, /* message aborted */ + <A href="xxfi_close.html">mlfi_close</A>, /* connection cleanup */ + <A href="xxfi_unknown.html">mlfi_unknown</A>, /* unknown SMTP commands */ + <A href="xxfi_data.html">mlfi_data</A>, /* DATA command */ + <A href="xxfi_negotiate.html">mlfi_negotiate</A> /* Once, at the start of each SMTP connection */ +}; + +static void +usage(prog) + char *prog; +{ + fprintf(stderr, + "Usage: %s -p socket-addr [-t timeout] [-r reject-addr] [-a add-addr]\n", + prog); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + bool setconn = FALSE; + int c; + const char *args = "p:t:r:a:h"; + extern char *optarg; + + /* Process command line options */ + while ((c = getopt(argc, argv, args)) != -1) + { + switch (c) + { + case 'p': + if (optarg == NULL || *optarg == '\0') + { + (void) fprintf(stderr, "Illegal conn: %s\n", + optarg); + exit(EX_USAGE); + } + if (<A href="smfi_setconn.html">smfi_setconn</A>(optarg) == MI_FAILURE) + { + (void) fprintf(stderr, + "smfi_setconn failed\n"); + exit(EX_SOFTWARE); + } + + /* + ** If we're using a local socket, make sure it + ** doesn't already exist. Don't ever run this + ** code as root!! + */ + + if (strncasecmp(optarg, "unix:", 5) == 0) + unlink(optarg + 5); + else if (strncasecmp(optarg, "local:", 6) == 0) + unlink(optarg + 6); + setconn = TRUE; + break; + + case 't': + if (optarg == NULL || *optarg == '\0') + { + (void) fprintf(stderr, "Illegal timeout: %s\n", + optarg); + exit(EX_USAGE); + } + if (<A href="smfi_settimeout.html">smfi_settimeout</A>(atoi(optarg)) == MI_FAILURE) + { + (void) fprintf(stderr, + "smfi_settimeout failed\n"); + exit(EX_SOFTWARE); + } + break; + + case 'r': + if (optarg == NULL) + { + (void) fprintf(stderr, + "Illegal reject rcpt: %s\n", + optarg); + exit(EX_USAGE); + } + reject = optarg; + break; + + case 'a': + if (optarg == NULL) + { + (void) fprintf(stderr, + "Illegal add rcpt: %s\n", + optarg); + exit(EX_USAGE); + } + add = optarg; + smfilter.xxfi_flags |= SMFIF_ADDRCPT; + break; + + case 'h': + default: + usage(argv[0]); + exit(EX_USAGE); + } + } + if (!setconn) + { + fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); + usage(argv[0]); + exit(EX_USAGE); + } + if (<A href="smfi_register.html">smfi_register</A>(smfilter) == MI_FAILURE) + { + fprintf(stderr, "smfi_register failed\n"); + exit(EX_UNAVAILABLE); + } + return <A href="smfi_main.html">smfi_main</A>(); +} + +/* eof */ + +</PRE> +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2004, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_addheader.html b/contrib/sendmail/libmilter/docs/smfi_addheader.html new file mode 100644 index 0000000..460b4ca --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_addheader.html @@ -0,0 +1,130 @@ +<HTML> +<HEAD><TITLE>smfi_addheader</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_addheader.html,v 1.20 2009/05/18 23:51:23 ca Exp $ +--> +<H1>smfi_addheader</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_addheader( + SMFICTX *ctx, + char *headerf, + char *headerv +); +</PRE> +Add a header to the current message. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Adds a header to the current message.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>headerf</TD> + <TD>The header name, a non-NULL, null-terminated string. + </TD></TR> + <TR valign="top"><TD>headerv</TD> + <TD>The header value to be added, a non-NULL, null-terminated string. + This may be the empty string. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_addheader returns MI_FAILURE if: +<UL><LI>headerf or headerv is NULL. + <LI>Adding headers in the current connection state is invalid. + <LI>Memory allocation fails. + <LI>A network error occurs. + <LI>SMFIF_ADDHDRS was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it returns MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL><LI>smfi_addheader does not change a message's existing headers. +To change a header's current value, use +<A HREF="smfi_chgheader.html">smfi_chgheader</A>. + <LI>A filter which calls smfi_addheader must have set the SMFIF_ADDHDRS + flag in the smfiDesc_str passed to + <A href="smfi_register.html">smfi_register</A>. + <LI>For smfi_addheader, filter order is important. + <B>Later filters will see the header changes made by earlier ones.</B> + <LI>Neither the name nor the value of the header is checked for + standards compliance. + However, 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 (ASCII 0x0a, or <TT>\n</TT> in C) + followed by at least one whitespace character + such as a space (ASCII 0x20) or tab (ASCII 0x09, or <TT>\t</TT> in C). + The line feed should NOT be preceded by a carriage return (ASCII 0x0d); + the MTA will add this automatically. + <B>It is the filter writer's responsibility to ensure that no standards + are violated.</B> + <LI>The MTA adds a leading space to an added header value unless + the flag +<A HREF="xxfi_negotiate.html#SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A> + is set, in which case the milter + must include any desired leading spaces itself. +</UL> +</TD> +</TR> + +<!----------- Example code ----------> +<TR> +<TH valign="top" align=left>EXAMPLE</TH> + +<TD> + <PRE> + int ret; + SMFICTX *ctx; + + ... + + ret = smfi_addheader(ctx, "Content-Type", + "multipart/mixed;\n\tboundary=\"foobar\""); + </PRE> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2003, 2006, 2009 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_addrcpt.html b/contrib/sendmail/libmilter/docs/smfi_addrcpt.html new file mode 100644 index 0000000..cf997e5 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_addrcpt.html @@ -0,0 +1,83 @@ +<HTML> +<HEAD><TITLE>smfi_addrcpt</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_addrcpt.html,v 1.11 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_addrcpt</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_addrcpt( + SMFICTX *ctx, + char *rcpt +); +</PRE> +Add a recipient for the current message. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Add a recipient to the message envelope.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>rcpt</TD> + <TD>The new recipient's address. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_addrcpt will fail and return MI_FAILURE if: +<UL><LI>rcpt is NULL. + <LI>Adding recipients in the current connection state is invalid. + <LI>A network error occurs. + <LI>SMFIF_ADDRCPT was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +A filter which calls smfi_addrcpt must have set the SMFIF_ADDRCPT flag +in the smfiDesc_str passed to +<A href="smfi_register.html">smfi_register</A>. +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_addrcpt_par.html b/contrib/sendmail/libmilter/docs/smfi_addrcpt_par.html new file mode 100644 index 0000000..776b02c --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_addrcpt_par.html @@ -0,0 +1,88 @@ +<HTML> +<HEAD><TITLE>smfi_addrcpt_par</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_addrcpt_par.html,v 1.4 2007/03/19 16:38:02 ca Exp $ +--> +<H1>smfi_addrcpt_par</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_addrcpt_par( + SMFICTX *ctx, + char *rcpt, + char *args +); +</PRE> +Add a recipient for the current message including ESMTP arguments. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Add a recipient to the message envelope.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>rcpt</TD> + <TD>The new recipient's address. + </TD></TR> + <TR valign="top"><TD>args</TD> + <TD>The new recipient's ESMTP parameters. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_addrcpt will fail and return MI_FAILURE if: +<UL><LI>rcpt is NULL. + <LI>Adding recipients in the current connection state is invalid. + <LI>A network error occurs. + <LI>SMFIF_ADDRCPT_PAR was not set when + <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +A filter which calls smfi_addrcpt must have set the SMFIF_ADDRCPT_PAR flag +in the smfiDesc_str passed to +<A href="smfi_register.html">smfi_register</A>. +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_chgfrom.html b/contrib/sendmail/libmilter/docs/smfi_chgfrom.html new file mode 100644 index 0000000..e8249e0 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_chgfrom.html @@ -0,0 +1,94 @@ +<HTML> +<HEAD><TITLE>smfi_chgfrom</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_chgfrom.html,v 1.3 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_chgfrom</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_chgfrom( + SMFICTX *ctx, + const char *mail, + char *args +); +</PRE> +Change the envelope sender (MAIL From) of the current message. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Change the envelope sender (MAIL From) of the current message.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>mail</TD> + <TD>The new sender address. + </TD></TR> + <TR valign="top"><TD>args</TD> + <TD>ESMTP arguments. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_chgfrom will fail and return MI_FAILURE if: +<UL><LI>mail is NULL. + <LI>Changing the sender in the current connection state is invalid. + <LI>A network error occurs. + <LI>SMFIF_CHGFROM was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +A filter which calls smfi_chgfrom must have set the SMFIF_CHGFROM flag +in the smfiDesc_str passed to +<A href="smfi_register.html">smfi_register</A>. +<BR> +Even though all ESMTP arguments could be set via this call, +it does not make sense to do so for many of them, +e.g., SIZE and BODY. +Setting those may cause problems, proper care must be taken. +Moreover, there is no feedback from the MTA to the milter +whether the call was successful. +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_chgheader.html b/contrib/sendmail/libmilter/docs/smfi_chgheader.html new file mode 100644 index 0000000..517b5ba --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_chgheader.html @@ -0,0 +1,125 @@ +<HTML> +<HEAD><TITLE>smfi_chgheader</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_chgheader.html,v 1.18 2009/05/18 23:51:23 ca Exp $ +--> +<H1>smfi_chgheader</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_chgheader( + SMFICTX *ctx, + char *headerf, + mi_int32 hdridx, + char *headerv +); +</PRE> +Change or delete a message header. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Changes a header's value for the current message.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>headerf</TD> + <TD>The header name, a non-NULL, null-terminated string. + </TD></TR> + <TR valign="top"><TD>hdridx</TD> + <TD>Header index value (1-based). A hdridx value of 1 will modify the first occurrence of a header named headerf. If hdridx is greater than the number of times headerf appears, a new copy of headerf will be added. + </TD></TR> + <TR valign="top"><TD>headerv</TD> + <TD>The new value of the given header. headerv == NULL implies that the header should be deleted. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD> +smfi_chgheader will return MI_FAILURE if +<UL><LI>headerf is NULL + <LI>Modifying headers in the current connection state is invalid. + <LI>Memory allocation fails. + <LI>A network error occurs. + <LI>SMFIF_CHGHDRS was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it returns MI_SUCCESS. +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL><LI>While smfi_chgheader may be used to add new headers, it is more efficient and far safer to use <A href="smfi_addheader.html">smfi_addheader</A>. + <LI>A filter which calls smfi_chgheader must have set the SMFIF_CHGHDRS flag in the smfiDesc_str passed to <A href="smfi_register.html">smfi_register</A>. + <LI>For smfi_chgheader, filter order is important. <B>Later filters will see the header changes made by earlier ones.</B> + <LI>Neither the name nor the value of the header is checked for + standards compliance. However, 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 (ASCII 0x0a, or <TT>\n</TT> in C) followed by at least + one whitespace character such as a space (ASCII 0x20) or tab (ASCII 0x09, + or <TT>\t</TT> in C). The line feed should NOT be preceded by a + carriage return (ASCII 0x0d); the MTA will add this automatically. + <B>It is the filter writer's responsibility to ensure that no standards + are violated.</B> + <LI>The MTA adds a leading space to a header value unless + the flag +<A HREF="xxfi_negotiate.html#SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A> + is set, in which case the milter + must include any desired leading spaces itself. +</UL> +</TD> +</TR> + +<!----------- Example code ----------> +<TR> +<TH valign="top" align=left>EXAMPLE</TH> + +<TD> + <PRE> + int ret; + SMFICTX *ctx; + + ... + + ret = smfi_chgheader(ctx, "Content-Type", 1, + "multipart/mixed;\n\tboundary=\"foobar\""); + </PRE> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2003, 2009 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_delrcpt.html b/contrib/sendmail/libmilter/docs/smfi_delrcpt.html new file mode 100644 index 0000000..c43dcd6 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_delrcpt.html @@ -0,0 +1,82 @@ +<HTML> +<HEAD><TITLE>smfi_delrcpt</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_delrcpt.html,v 1.11 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_delrcpt</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_delrcpt( + SMFICTX *ctx; + char *rcpt; +); +</PRE> +Remove a recipient from the current message's envelope. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_delrcpt removes the named recipient from the current message's envelope.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>rcpt</TD> + <TD>The recipient address to be removed, a non-NULL, null-terminated string. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_delrcpt will fail and return MI_FAILURE if: +<UL> + <LI>rcpt is NULL. + <LI>Deleting recipients in the current connection state is invalid. + <LI>A network error occurs. + <LI>SMFIF_DELRCPT was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +The addresses to be removed must match exactly. For example, an address and its expanded form do not match. +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_getpriv.html b/contrib/sendmail/libmilter/docs/smfi_getpriv.html new file mode 100644 index 0000000..9584b9e --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_getpriv.html @@ -0,0 +1,62 @@ +<HTML> +<HEAD><TITLE>smfi_getpriv</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_getpriv.html,v 1.9 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_getpriv</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +void* smfi_getpriv( + SMFICTX *ctx +); +</PRE> +Get the connection-specific data pointer for this connection. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_getpriv may be called in any of the xxfi_* callbacks.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>None.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_getpriv returns the private data pointer stored by a prior call to <A href="smfi_setpriv.html">smfi_setpriv</A>, or NULL if none has been set.</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_getsymval.html b/contrib/sendmail/libmilter/docs/smfi_getsymval.html new file mode 100644 index 0000000..671dbfa --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_getsymval.html @@ -0,0 +1,105 @@ +<HTML> +<HEAD><TITLE>smfi_getsymval</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_getsymval.html,v 1.15 2007/03/19 16:49:11 ca Exp $ +--> +<H1>smfi_getsymval</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +char* smfi_getsymval( + SMFICTX *ctx, + char *symname +); +</PRE> +Get the value of a sendmail macro. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_getsymval may be called from within any of the xxfi_* callbacks. Which macros are defined will depend on when it is called.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>None.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>The opaque context structure. + </TD></TR> + <TR valign="top"><TD>symname</TD> + <TD>The 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 + <TT>sendmail.cf</TT> file. + <A href="#notes">See below</A> for default macros. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_getsymval returns the value of the given macro as a null-terminated string, or NULL if the macro is not defined.</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH><A name="notes">NOTES</A></TH> +<TD> +By default, the following macros are valid in the given contexts: + +<TABLE border="1" cellspacing=0> +<TR bgcolor="#dddddd"><TH>Sent With</TH><TH>Macros</TH></TR> +<TR><TD>xxfi_connect</TD> <TD>daemon_name, if_name, if_addr, j, _</TD></TR> +<TR><TD>xxfi_helo</TD> <TD>tls_version, cipher, cipher_bits, cert_subject, cert_issuer</TD></TR> +<TR><TD>xxfi_envfrom</TD> <TD>i, auth_type, auth_authen, auth_ssf, auth_author, + mail_mailer, mail_host, mail_addr</TD></TR> +<TR><TD>xxfi_envrcpt</TD> <TD>rcpt_mailer, rcpt_host, rcpt_addr</TD></TR> + +<TR><TD>xxfi_data</TD> <TD>(none)</TD></TR> +<TR><TD>xxfi_eoh</TD> <TD>(none)</TD></TR> +<TR><TD>xxfi_eom</TD> <TD>msg_id</TD></TR> +</TABLE> +<P> +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 (xxfi_envfrom) and last (xxfi_eom), +and just for each recipient for xxfi_envrcpt. +<P> +The macro list can be changed using the confMILTER_MACROS_* options in +sendmail.mc. +The scopes of such macros will be determined by when they are set by sendmail. +For descriptions of macros' values, +please see the +"Sendmail Installation and Operation Guide" +provided with your sendmail distribution. + +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2002-2003, 2007 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_insheader.html b/contrib/sendmail/libmilter/docs/smfi_insheader.html new file mode 100644 index 0000000..5962e61 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_insheader.html @@ -0,0 +1,150 @@ +<HTML> +<HEAD><TITLE>smfi_insheader</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_insheader.html,v 1.10 2009/05/18 23:51:23 ca Exp $ +--> +<H1>smfi_insheader</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_insheader( + SMFICTX *ctx, + int hdridx, + char *headerf, + char *headerv +); +</PRE> +Prepend a header to the current message. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Prepends a header to the current message.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>hdridx</TD> + <TD>The location in the internal header list where this header should + be inserted; 0 makes it the topmost header, etc. + </TD></TR> + <TR valign="top"><TD>headerf</TD> + <TD>The header name, a non-NULL, null-terminated string. + </TD></TR> + <TR valign="top"><TD>headerv</TD> + <TD>The header value to be added, a non-NULL, null-terminated string. This may be the empty string. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_insheader returns MI_FAILURE if: +<UL><LI>headerf or headerv is NULL. + <LI>Adding headers in the current connection state is invalid. + <LI>Memory allocation fails. + <LI>A network error occurs. + <LI>SMFIF_ADDHDRS was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it returns MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL> + <LI>smfi_insheader does not change a message's existing headers. + To change a header's current value, use + <A HREF="smfi_chgheader.html">smfi_chgheader</A>. + <LI>A filter which calls smfi_insheader must have set the SMFIF_ADDHDRS + flag in the smfiDesc_str passed to + <A href="smfi_register.html">smfi_register</A>. + <LI>For smfi_insheader, filter order is important. + <B>Later filters will see the header changes made by earlier ones.</B> + <LI>A filter will receive <EM>only</EM> headers that have been sent + by the SMTP client and those header modifications by earlier filters. + It will <EM>not</EM> receive the headers that are inserted by sendmail + itself. + This makes the header insertion position highly dependent on + the headers that exist in the incoming message + and those that are configured to be added by sendmail. + For example, sendmail will always add a + <CODE>Received:</CODE> header to the beginning of the headers. + Setting <CODE>hdridx</CODE> to 0 will actually insert the header + before this <CODE>Received:</CODE> header. + However, later filters can be easily confused as they receive + the added header, but not the <CODE>Received:</CODE> header, + thus making it hard to insert a header at a fixed position. + <LI>If hdridx is a number larger than the number of headers in the message, + the header will simply be appended. + <LI>Neither the name nor the value of the header is checked for + standards compliance. + However, 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 (ASCII 0x0a, or <TT>\n</TT> in C) + followed by at least one whitespace character + such as a space (ASCII 0x20) or tab (ASCII 0x09, or <TT>\t</TT> in C). + The line feed should NOT be preceded by a carriage return (ASCII 0x0d); + the MTA will add this automatically. + <B>It is the filter writer's responsibility to ensure that no standards + are violated.</B> + <LI>The MTA adds a leading space to an inserted header value unless + the flag +<A HREF="xxfi_negotiate.html#SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A> + is set, in which case the milter + must include any desired leading spaces itself. +</UL> +</TD> +</TR> + +<!----------- Example code ----------> +<TR> +<TH valign="top" align=left>EXAMPLE</TH> + +<TD> + <PRE> + int ret; + SMFICTX *ctx; + + ... + + ret = smfi_insheader(ctx, 0, "First", "See me?"); + </PRE> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2004, 2006, 2009 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_main.html b/contrib/sendmail/libmilter/docs/smfi_main.html new file mode 100644 index 0000000..a749386 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_main.html @@ -0,0 +1,51 @@ +<HTML> +<HEAD><TITLE>smfi_main</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_main.html,v 1.9 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_main</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_main( +); +</PRE> +Hand control to libmilter event loop. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_main is called after a filter's initialization is complete.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_main hands control to the Milter event loop.</TD> +</TR> +</TABLE> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_main will return MI_FAILURE if it fails to establish a connection. This may occur for any of a variety of reasons (e.g. invalid address passed to <A href="smfi_setconn.html">smfi_setconn</A>). The reason for the failure will be logged. Otherwise, smfi_main will return MI_SUCCESS.</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_opensocket.html b/contrib/sendmail/libmilter/docs/smfi_opensocket.html new file mode 100644 index 0000000..53ea62b --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_opensocket.html @@ -0,0 +1,84 @@ +<HTML> +<HEAD><TITLE>smfi_opensocket</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_opensocket.html,v 1.7 2008/01/31 17:29:33 ca Exp $ +--> +<H1>smfi_opensocket</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_opensocket( + bool rmsocket +); +</PRE> +Attempt to create the interface socket MTAs will use to connect to the +filter. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from program mainline, +after calling <TT>smfi_setconn()</TT> and <TT>smfi_register()</TT>, +but before calling <TT>smfi_main()</TT>. +</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_opensocket attempts to create the socket specified previously by +a call to <TT>smfi_setconn()</TT> which will be the interface between MTAs +and the filter. +This allows the calling application to ensure that the +socket can be created. +If this is not called, +<TT>smfi_main()</TT> will do so implicitly. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>rmsocket</TD> + <TD>A flag indicating whether or not the library should try to + remove any existing UNIX domain socket before trying to create + a new one. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_opensocket will fail and return MI_FAILURE if: +<UL> + <LI>The interface socket could not be created for any reason. + <LI><TT>rmsocket</TT> was <TT>true</TT>, and either the socket could + not be examined, or exists and could not be removed. + <LI><TT>smfi_setconn()</TT> or <TT>smfi_register()</TT> + have not been called. +</UL> +Otherwise, it will return MI_SUCCESS +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2003, 2008 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_progress.html b/contrib/sendmail/libmilter/docs/smfi_progress.html new file mode 100644 index 0000000..801bdf3 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_progress.html @@ -0,0 +1,68 @@ +<HTML> +<HEAD><TITLE>smfi_progress</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_progress.html,v 1.5 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_progress</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_progress( + SMFICTX *ctx; +); +</PRE> +Notify the MTA that an operation is still in progress. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_progress notifies the MTA that the filter is still working +on a message, causing the MTA to re-start its timeouts.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_progress will fail and return MI_FAILURE if: +<UL> + <LI>A network error occurs. +</UL> +Otherwise, it will return MI_SUCCESS +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_quarantine.html b/contrib/sendmail/libmilter/docs/smfi_quarantine.html new file mode 100644 index 0000000..656a480 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_quarantine.html @@ -0,0 +1,73 @@ +<HTML> +<HEAD><TITLE>smfi_quarantine</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_quarantine.html,v 1.5 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_quarantine</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_quarantine( + SMFICTX *ctx; + char *reason; +); +</PRE> +Quarantine the message using the given reason. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_quarantine quarantines the message using the given reason.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>reason</TD> + <TD>The quarantine reason, a non-NULL and non-empty null-terminated string. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_quarantine will fail and return MI_FAILURE if: +<UL> + <LI>reason is NULL or empty. + <LI>A network error occurs. + <LI>SMFIF_QUARANTINE was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2002-2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_register.html b/contrib/sendmail/libmilter/docs/smfi_register.html new file mode 100644 index 0000000..1a35918 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_register.html @@ -0,0 +1,224 @@ +<HTML> +<HEAD><TITLE>smfi_register</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_register.html,v 1.18 2006/12/20 18:37:11 ca Exp $ +--> +<H1>smfi_register</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_register( + smfiDesc descr +); +</PRE> +Register a set of filter callbacks. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=1> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_register must be called before smfi_main</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_register creates a filter using the information given in the +smfiDesc argument. +Multiple (successful) calls to smfi_register within a +single process are not allowed, +i.e., only one filter can be successfully registered. +Note, however, that the library may not check whether this restriction +is obeyed. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>descr</TD> + <TD> +A filter descriptor of type smfiDesc describing the filter's functions. +<A NAME="smfiDesc">The structure</A> has the following members: +<PRE> +struct smfiDesc +{ + char *xxfi_name; /* filter name */ + int xxfi_version; /* version code -- do not change */ + unsigned long xxfi_flags; /* <A href="#flags">flags</A> */ + + /* connection info filter */ + sfsistat (*<A href="xxfi_connect.html">xxfi_connect</A>)(SMFICTX *, char *, _SOCK_ADDR *); + /* SMTP HELO command filter */ + sfsistat (*<A href="xxfi_helo.html">xxfi_helo</A>)(SMFICTX *, char *); + /* envelope sender filter */ + sfsistat (*<A href="xxfi_envfrom.html">xxfi_envfrom</A>)(SMFICTX *, char **); + /* envelope recipient filter */ + sfsistat (*<A href="xxfi_envrcpt.html">xxfi_envrcpt</A>)(SMFICTX *, char **); + /* header filter */ + sfsistat (*<A href="xxfi_header.html">xxfi_header</A>)(SMFICTX *, char *, char *); + /* end of header */ + sfsistat (*<A href="xxfi_eoh.html">xxfi_eoh</A>)(SMFICTX *); + /* body block */ + sfsistat (*<A href="xxfi_body.html">xxfi_body</A>)(SMFICTX *, unsigned char *, size_t); + /* end of message */ + sfsistat (*<A href="xxfi_eom.html">xxfi_eom</A>)(SMFICTX *); + /* message aborted */ + sfsistat (*<A href="xxfi_abort.html">xxfi_abort</A>)(SMFICTX *); + /* connection cleanup */ + sfsistat (*<A href="xxfi_close.html">xxfi_close</A>)(SMFICTX *); + + /* any unrecognized or unimplemented command filter */ + sfsistat (*xxfi_unknown)(SMFICTX *, const char *); + + /* SMTP DATA command filter */ + sfsistat (*xxfi_data)(SMFICTX *); + + /* negotiation callback */ + sfsistat (*<A HREF="xxfi_negotiate.html">xxfi_negotiate</A>)(SMFICTX *, + unsigned long, unsigned long, unsigned long, unsigned long, + unsigned long *, unsigned long *, unsigned long *, unsigned long *); +}; +</PRE> + +A NULL value for any callback function indicates that the filter +does not wish to process the given type of information, +simply returning SMFIS_CONTINUE. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD> +smfi_register may return MI_FAILURE for any of the following reasons: +<UL> +<LI>memory allocation failed. +<LI>incompatible version or illegal flags value. +</UL> + +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> + +<A NAME="flags">The xxfi_flags</A> +field should contain the bitwise OR of zero or more of +the following values, describing the actions the filter may take: +<TABLE BORDER CELLPADDING="1" cellspacing=1> +<TR valign="top" bgcolor="#dddddd"><TH align="left">Flag</TH><TH align="center">Description</TH></TR> + <TR align="left" valign=top> + <TD> + SMFIF_ADDHDRS + </TD> + <TD> + This filter may <A HREF="smfi_addheader.html">add headers</A>. + </TD> + </TR> + <TR align="left" valign=top> + <TD> + SMFIF_CHGHDRS + </TD> + <TD> + This filter may + <A HREF="smfi_chgheader.html">change and/or delete headers</A>. + </TD> + </TR> + <TR align="left" valign=top> + <TD VALIGN="TOP"> + SMFIF_CHGBODY + </TD> + <TD> + This filter may + <A HREF="smfi_replacebody.html">replace the body</A> during filtering. + This may have significant performance impact + if other filters do body filtering after this filter. + </TD> + </TR> + <TR> + <TD VALIGN="TOP"> + SMFIF_ADDRCPT + </TD> + <TD> + This filter may + <A HREF="smfi_addrcpt.html">add recipients</A> + to the message. + </TD> + </TR> + <TR> + <TD VALIGN="TOP"> + SMFIF_ADDRCPT_PAR + </TD> + <TD> + This filter may + <A HREF="smfi_addrcpt_par.html">add recipients including ESMTP args</A>. + </TD> + </TR> + <TR> + <TD VALIGN="TOP"> + SMFIF_DELRCPT + </TD> + <TD> + This filter may + <A HREF="smfi_delrcpt.html">remove recipients</A> from the message. + </TD> + </TR> + <TR> + <TD VALIGN="TOP"> + SMFIF_QUARANTINE + </TD> + <TD> + This filter may + <A HREF="smfi_quarantine.html">quarantine</A> a message. + </TD> + </TR> + + <TR> + <TD VALIGN="TOP"> + SMFIF_CHGFROM + </TD> + <TD> + This filter may + <A HREF="smfi_chgfrom.html">change the envelope sender</A> (MAIL). + </TD> + </TR> + + <TR> + <TD VALIGN="TOP"> + SMFIF_SETSYMLIST + </TD> + <TD> + This filter can + <A HREF="smfi_setsymlist.html">send a set of symbols (macros)</A> + that it wants. + </TD> + </TR> + +</TABLE> + +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2001, 2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_replacebody.html b/contrib/sendmail/libmilter/docs/smfi_replacebody.html new file mode 100644 index 0000000..bc8d5ac --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_replacebody.html @@ -0,0 +1,93 @@ +<HTML> +<HEAD><TITLE>smfi_replacebody</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_replacebody.html,v 1.15 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_replacebody</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_replacebody( + SMFICTX *ctx, + unsigned char *bodyp, + int bodylen +); +</PRE> +Replace message-body data. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>. smfi_replacebody may be called more than once.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_replacebody replaces the body of the current message. If called +more than once, subsequent calls result in data being appended to the new +body. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>bodyp</TD> + <TD>A pointer to the start of the new body data, which does not have to be null-terminated. If bodyp is NULL, it is treated as having length == 0. Body data should be in CR/LF form. + </TD></TR> + <TR valign="top"><TD>bodylen</TD> + <TD>The number of data bytes pointed to by bodyp. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_replacebody fails and returns MI_FAILURE if: +<UL> + <LI>bodyp == NULL and bodylen > 0. + <LI>Changing the body in the current connection state is invalid. + <LI>A network error occurs. + <LI>SMFIF_CHGBODY was not set when <A href="smfi_register.html">smfi_register</A> was called. +</UL> +Otherwise, it will return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL> + <LI>Since the message body may be very large, setting SMFIF_CHGBODY may significantly affect filter performance. + <LI>If a filter sets SMFIF_CHGBODY but does not call smfi_replacebody, the original body remains unchanged. + <LI>For smfi_replacebody, filter order is important. <B>Later filters will see the new body contents created by earlier ones.</B> +</UL> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2001, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setbacklog.html b/contrib/sendmail/libmilter/docs/smfi_setbacklog.html new file mode 100644 index 0000000..8353cac --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setbacklog.html @@ -0,0 +1,64 @@ +<HTML> +<HEAD><TITLE>smfi_setbacklog</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setbacklog.html,v 1.6 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setbacklog</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setbacklog( + int obacklog +); +</PRE> +Set the filter's <CODE>listen(2)</CODE> backlog value. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_setbacklog should only be called before <A href="smfi_main.html">smfi_main</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Sets the incoming socket backlog used by <CODE>listen(2)</CODE>. +If smfi_setbacklog is not called, the operating system default is used.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>obacklog</TD> + <TD>The number of incoming connections to allow in the listen queue. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setbacklog returns MI_FAILURE if obacklog is less than or equal +to zero.</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2002-2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setconn.html b/contrib/sendmail/libmilter/docs/smfi_setconn.html new file mode 100644 index 0000000..70a510e --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setconn.html @@ -0,0 +1,93 @@ +<HTML> +<HEAD><TITLE>smfi_setconn</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setconn.html,v 1.17 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setconn</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setconn( + char *oconn; +); +</PRE> +Set the socket through which this filter should communicate with sendmail. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_setconn must be called once before <A href="smfi_main.html">smfi_main</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Sets the socket through which the filter communicates with sendmail.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>oconn</TD> + <TD>The address of the desired communication socket. + The address should be a NULL-terminated string in "proto:address" + format: + <UL> + <LI><CODE>{unix|local}:/path/to/file</CODE> -- A named pipe. + <LI><CODE>inet:port@{hostname|ip-address}</CODE> -- An IPV4 socket. + <LI><CODE>inet6:port@{hostname|ip-address}</CODE> -- An IPV6 socket. + </UL> + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setconn will not fail on an invalid address. +The failure will only be detected in <A href="smfi_main.html">smfi_main</A>. +Nevertheless, smfi_setconn may fail for other reasons, e.g., +due to a lack of memory. +</TD> +</TR> + +<TR> +<TH valign="top" align=left>NOTES</TH> + +<TD> +<UL> + <LI>If possible, filters should not run as root when communicating + over unix/local domain sockets. + <LI>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 <CODE>umask</CODE>, which should be set to 007 or 077. + Note some operating systems (e.g, Solaris) don't use the + permissions of the socket. On those systems, place the socket in a + protected directory. +</UL> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setdbg.html b/contrib/sendmail/libmilter/docs/smfi_setdbg.html new file mode 100644 index 0000000..e001d3f --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setdbg.html @@ -0,0 +1,67 @@ +<HTML> +<HEAD><TITLE>smfi_setdbg</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setdbg.html,v 1.3 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setdbg</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setdbg( + int level; +); +</PRE> +Set the debugging (tracing) level for the milter library. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called from any any routine at any time.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>smfi_setdbg sets the milter library's internal debugging level +to a new level so that code details may be traced. +A level of zero turns off debugging. The greater +(more positive) the level the more detailed the debugging. Six is +the current, highest, useful value.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>level</TD> + <TD>The new debugging level + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setdbg returns MI_SUCCESS by default. +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setmlreply.html b/contrib/sendmail/libmilter/docs/smfi_setmlreply.html new file mode 100644 index 0000000..b01bacf --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setmlreply.html @@ -0,0 +1,145 @@ +<HTML> +<HEAD><TITLE>smfi_setmlreply</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setmlreply.html,v 1.4 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setmlreply</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setmlreply( + SMFICTX *ctx, + char *rcode, + char *xcode, + ... +); +</PRE> +Set the default SMTP error reply code to a multi-line response. Only 4XX +and 5XX replies are accepted. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_setmlreply may be called from any of the xxfi_ callbacks +other than xxfi_connect.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Directly set the SMTP error reply code for this connection to the given +lines after the xcode. The list of arguments must be NULL terminated. +This code will be used on subsequent error replies resulting from actions +taken by this filter.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>rcode</TD> + <TD>The three-digit (RFC 821/2821) SMTP reply code, as a + null-terminated string. rcode cannot be NULL, and must be a valid + 4XX or 5XX reply code. + </TD></TR> + <TR valign="top"><TD>xcode</TD> + <TD>The extended (RFC 1893/2034) reply code. If xcode is NULL, no + extended code is used. Otherwise, xcode must conform to RFC 1893/2034. + </TD></TR> + <TR valign="top"><TD>...</TD> + <TD>The remainder of the arguments are single lines of text, up to + 32 arguments, which will be used as the text part of the SMTP + reply. The list must be NULL terminated. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Example ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> +<TD> +For example, the code:<BR> +<PRE> + ret = smfi_setmlreply(ctx, "550", "5.7.0", + "Spammer access rejected", + "Please see our policy at:", + "http://www.example.com/spampolicy.html", + NULL); +</PRE> +<BR>would give the SMTP response:<BR> +<PRE> +550-5.7.0 Spammer access rejected +550-5.7.0 Please see our policy at: +550 5.7.0 http://www.example.com/spampolicy.html +</PRE> +</TD> +</TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setmlreply will fail and return MI_FAILURE if: +<UL> + <LI>The rcode or xcode argument is invalid. + <LI>A memory-allocation failure occurs. + <LI>If any text line contains a carraige return or line feed. + <LI>The length of any text line is more than MAXREPLYLEN (980). + <LI>More than 32 lines of text replies are given. +</UL> +Otherwise, it return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL> +<LI>Values passed to smfi_setmlreply are not checked for standards compliance. +<LI>The message parameter should contain only printable characters, +other characters may lead to undefined behavior. +For example, CR or LF will cause the call to fail, +single '%' characters will cause the text to be ignored +(if there really should be a '%' in the string, +use '%%' just like for <TT>printf(3)</TT>). +<LI>For details about reply codes and their meanings, please see RFC's +<A href="http://www.rfc-editor.org/rfc/rfc821.txt">821</A>/ +<A href="http://www.rfc-editor.org/rfc/rfc2821.txt">2821</A> +and +<A href="http://www.rfc-editor.org/rfc/rfc1893.txt">1893</A>/ +<A href="http://www.rfc-editor.org/rfc/rfc2034.txt">2034</A>. +<LI>If the reply code (rcode) given is a '4XX' code but SMFI_REJECT is used +for the message, the custom reply is not used. +<LI>Similarly, if the reply code (rcode) given is a '5XX' code but +SMFI_TEMPFAIL is used for the message, the custom reply is not used. +<BR> +Note: in neither of the last two cases an error is returned to the milter, +libmilter silently ignores the reply code. +<LI>If the milter returns SMFI_TEMPFAIL and sets the reply code to '421', +then the SMTP server will terminate the SMTP session with a 421 error code. +</UL> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2002-2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setpriv.html b/contrib/sendmail/libmilter/docs/smfi_setpriv.html new file mode 100644 index 0000000..1c287eb --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setpriv.html @@ -0,0 +1,80 @@ +<HTML> +<HEAD><TITLE>smfi_setpriv</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setpriv.html,v 1.11 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setpriv</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setpriv( + SMFICTX *ctx, + void *privatedata +); +</PRE> +Set the private data pointer for this connection. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_setpriv may be called in any of the xxfi_* callbacks.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Sets the private data pointer for the context ctx.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>privatedata</TD> + <TD>Pointer to private data. This value will be returned by subsequent calls to <A href="smfi_getpriv.html">smfi_getpriv</A> using ctx. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setpriv returns MI_FAILURE if ctx is an invalid context. +Otherwise, it returns MI_SUCCESS.</TD> +</TR> + +<TR> +<TH valign="top" align=left>NOTES</TH> + +<TD>There is only one private data pointer per connection; multiple +calls to smfi_setpriv with different values will cause previous values +to be lost. +<P> +Before a filter terminates it should release the private data +and set the pointer to NULL. +</TD> + +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2001, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setreply.html b/contrib/sendmail/libmilter/docs/smfi_setreply.html new file mode 100644 index 0000000..d857815 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setreply.html @@ -0,0 +1,117 @@ +<HTML> +<HEAD><TITLE>smfi_setreply</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setreply.html,v 1.17 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setreply</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setreply( + SMFICTX *ctx, + char *rcode, + char *xcode, + char *message +); +</PRE> +Set the default SMTP error reply code. Only 4XX and 5XX replies are accepted. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_setreply may be called from any of the xxfi_ callbacks +other than xxfi_connect.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Directly set the SMTP error reply code for this connection. This code +will be used on subsequent error replies resulting from actions taken by +this filter.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>rcode</TD> + <TD>The three-digit (RFC 821/2821) SMTP reply code, as a + null-terminated string. rcode cannot be NULL, and must be a valid + 4XX or 5XX reply code. + </TD></TR> + <TR valign="top"><TD>xcode</TD> + <TD>The extended (RFC 1893/2034) reply code. If xcode is NULL, no + extended code is used. Otherwise, xcode must conform to RFC 1893/2034. + </TD></TR> + <TR valign="top"><TD>message</TD> + <TD>The text part of the SMTP reply. If message is NULL, an empty message is used. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_setreply will fail and return MI_FAILURE if: +<UL> + <LI>The rcode or xcode argument is invalid. + <LI>A memory-allocation failure occurs. +</UL> +Otherwise, it return MI_SUCCESS. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD> +<UL> +<LI>Values passed to smfi_setreply are not checked for standards compliance. +<LI>The message parameter should contain only printable characters, +other characters may lead to undefined behavior. +For example, CR or LF will cause the call to fail, +single '%' characters will cause the text to be ignored +(if there really should be a '%' in the string, +use '%%' just like for <TT>printf(3)</TT>). +<LI>For details about reply codes and their meanings, please see RFC's +<A href="http://www.rfc-editor.org/rfc/rfc821.txt">821</A>/ +<A href="http://www.rfc-editor.org/rfc/rfc2821.txt">2821</A> +and +<A href="http://www.rfc-editor.org/rfc/rfc1893.txt">1893</A>/ +<A href="http://www.rfc-editor.org/rfc/rfc2034.txt">2034</A>. +<LI>If the reply code (rcode) given is a '4XX' code but SMFI_REJECT is used +for the message, the custom reply is not used. +<LI>Similarly, if the reply code (rcode) given is a '5XX' code but +SMFI_TEMPFAIL is used for the message, the custom reply is not used. +<BR> +Note: in neither of the last two cases an error is returned to the milter, +libmilter silently ignores the reply code. +<LI>If the milter returns SMFI_TEMPFAIL and sets the reply code to '421', +then the SMTP server will terminate the SMTP session with a 421 error code. +</UL> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2002-2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_setsymlist.html b/contrib/sendmail/libmilter/docs/smfi_setsymlist.html new file mode 100644 index 0000000..7e8edff --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_setsymlist.html @@ -0,0 +1,107 @@ +<HTML> +<HEAD><TITLE>smfi_setsymlist</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_setsymlist.html,v 1.5 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_setsymlist</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_setsymlist( + SMFICTX *ctx, + int stage, + char *macros +); +</PRE> +Set the list of macros that the milter wants to receive from the MTA +for a protocol stage. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>This function must only be called during +<A HREF="xxfi_negotiate.html">xxfi_negotiate()</A>. +</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>This function can be used to override the list of macros that the +milter wants to receive from the MTA. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + + <TR><TD>ctx</TD> + <TD>the opaque context structure. + </TD></TR> + + <TR><TD>stage</TD> + <TD>the protocol stage during which the macro list should be used. + See the file + <CODE>include/libmilter/mfapi.h</CODE> for legal values, + look for the C macros with the prefix + <CODE>SMFIM_</CODE>. + Available protocol stages are at least + the initial connection, HELO/EHLO, MAIL, RCPT, DATA, + end of header, and + the end of a message. + </TD></TR> + + <TR><TD>macros</TD> + <TD>list of macros (separated by space). + Example: "{rcpt_mailer} {rcpt_host}" + </TD></TR> + + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>MI_FAILURE is returned if +<UL> +<LI>there is not enough free memory to make a copy of the macro list, +<LI><CODE>macros</CODE> is <CODE>NULL</CODE> or empty, +<LI><CODE>stage</CODE> is not a valid protocol stage, +<LI>the macro list for +<CODE>stage</CODE> has been set before. +</UL> +Otherwise MI_SUCCESS is returned. +</TD> +</TR> + +<!----------- Notes ----------> +<TR align="left" valign=top> +<TH>NOTES</TH> +<TD>There is an internal limit on the number of macros that can be +set (currently 5), +however, this limit is not enforced by libmilter, only by the MTA, +but a possible violation of this restriction is not communicated back to +the milter.</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_settimeout.html b/contrib/sendmail/libmilter/docs/smfi_settimeout.html new file mode 100644 index 0000000..97d41cb --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_settimeout.html @@ -0,0 +1,66 @@ +<HTML> +<HEAD><TITLE>smfi_settimeout</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_settimeout.html,v 1.14 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_settimeout</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_settimeout( + int otimeout +); +</PRE> +Set the filter's I/O timeout value. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>smfi_settimeout should only be called before <A href="smfi_main.html">smfi_main</A>.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>Sets the number of seconds libmilter will wait +for an MTA communication (read or write) before timing out. +If smfi_settimeout is not called, a default timeout of 7210 seconds is used. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>otimeout</TD> + <TD>The number of seconds to wait before timing out (> 0). + Zero means no wait, <B>not</B> "wait forever". + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_settimeout always returns MI_SUCCESS.</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2002-2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_stop.html b/contrib/sendmail/libmilter/docs/smfi_stop.html new file mode 100644 index 0000000..87ecdb2 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_stop.html @@ -0,0 +1,74 @@ +<HTML> +<HEAD><TITLE>smfi_stop</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_stop.html,v 1.6 2006/12/21 18:30:35 ca Exp $ +--> +<H1>smfi_stop</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_stop(void); +</PRE> +Shutdown the milter. +No connections will be accepted after this call. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>Called from any of the <A href="api.html#Callbacks">Callback</A> routines +or any error-handling routines at any time.</TD> +</TR> +<TR align="left" valign=top> +<TH width="80">Effects</TH> +<TD>The smfi_stop routine prevents that new connections +will be accepted, +however, it does not wait for existing connections (threads) to terminate. +It will cause +<A href="smfi_main.html">smfi_main</A> to return to the calling program, +which may then exit or warm-restart. +</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>void</TD> + <TD>Takes no arguement. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>RETURN VALUES</TH> + +<TD>smfi_stop always returns SMFI_CONTINUE. But note: +<UL> + <LI>Another internal routine may already have asked the milter to abort. + <LI>Another routine may already have asked the milter to stop. + <LI>There is no way to cancel the stop process once it has begun. +</UL> +</TD> +</TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2003, 2005 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/smfi_version.html b/contrib/sendmail/libmilter/docs/smfi_version.html new file mode 100644 index 0000000..6dd451d --- /dev/null +++ b/contrib/sendmail/libmilter/docs/smfi_version.html @@ -0,0 +1,92 @@ +<HTML> +<HEAD><TITLE>smfi_version()</TITLE></HEAD> +<BODY> +<!-- +$Id: smfi_version.html,v 1.6 2008/05/02 23:06:26 ca Exp $ +--> +<H1>smfi_version()</H1> + +<TABLE BORDER="0" CELLSPACING=4 CELLPADDING=4> +<!---------- Synopsis -----------> +<TR><TH VALIGN="TOP" ALIGN=LEFT WIDTH=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +int smfi_version( + unsigned int *pmajor, + unsigned int *pminor, + unsigned int *ppl +); +</PRE> +Get the (runtime) version of libmilter. +</TD></TR> + +<!----------- Description ----------> +<TR><TH VALIGN="TOP" ALIGN=LEFT>DESCRIPTION</TH><TD> +<TABLE BORDER="1" CELLSPACING=1 CELLPADDING=4> +<TR ALIGN="LEFT" VALIGN=TOP> +<TH WIDTH="80">Called When</TH> +<TD>smfi_version may be called at any time.</TD> +</TR> +<TR ALIGN="LEFT" VALIGN=TOP> +<TH WIDTH="80">Effects</TH> +<TD>None.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH VALIGN="TOP" ALIGN=LEFT>ARGUMENTS</TH><TD> + <TABLE BORDER="1" CELLSPACING=0> + <TR BGCOLOR="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR VALIGN="TOP"><TD>pmajor</TD> + <TD>Pointer to an unsigned int variable to store major version number. + </TD></TR> + <TR VALIGN="TOP"><TD>pminor</TD> + <TD>Pointer to an unsigned int variable to store minor version number. + </TD></TR> + <TR VALIGN="TOP"><TD>ppl</TD> + <TD>Pointer to an unsigned int variable to store patch level number. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH VALIGN="TOP" ALIGN=LEFT>RETURN VALUES</TH> +<TD>smfi_version returns MI_SUCCESS.</TD> +</TR> + +</TABLE> + +Note: the compile time version of libmilter is available in the macro +<CODE>SMFI_VERSION</CODE>. +To extract the major and minor version as well as the current patch level +from this macro, the macros +<CODE>SM_LM_VRS_MAJOR(v)</CODE>, +<CODE>SM_LM_VRS_MINOR(v)</CODE>, and +<CODE>SM_LM_VRS_PLVL(v)</CODE> +can be used, respectively. +A milter can check the +<CODE>SMFI_VERSION</CODE> +macro to determine which functions to use +(at compile time via C preprocessor statements). +Using this macro and the +<CODE>smfi_version()</CODE> +function, +a milter can determine at runtime whether it has been (dynamically) +linked against the expected libmilter version. +Such a function should only compare the major and minor version, +not the patch level, +i.e., the libmilter library will be compatible despite +different patch levels. + + +<HR SIZE="1"> +<FONT SIZE="-1"> +Copyright (c) 2006-2008 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_abort.html b/contrib/sendmail/libmilter/docs/xxfi_abort.html new file mode 100644 index 0000000..0664dc1 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_abort.html @@ -0,0 +1,83 @@ +<HTML> +<HEAD><TITLE>xxfi_abort</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_abort.html,v 1.12 2006/12/21 18:30:35 ca Exp $ +--> +<H1>xxfi_abort</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_abort)( + SMFICTX *ctx +); +</PRE> +Handle the current message's being aborted. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_abort may be called at any time during message processing (i.e. between some message-oriented routine and <A href="xxfi_eom.html">xxfi_eom</A>).</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD> +<UL> +<LI>xxfi_abort must reclaim any resources allocated on a per-message +basis, and must be tolerant of being called between any two +message-oriented callbacks. + +<LI>Calls to xxfi_abort and <A href="xxfi_eom.html">xxfi_eom</A> are +mutually exclusive. + +<LI>xxfi_abort is not responsible for reclaiming connection-specific +data, since <A href="xxfi_close.html">xxfi_close</A> is always called +when a connection is closed. + +<LI>Since the current message is already being aborted, the return +value is currently ignored. + +<LI>xxfi_abort is only called if the message is aborted outside the +filter's control <B>and</B> the filter has not completed its +message-oriented processing. For example, if a filter has already +returned SMFIS_ACCEPT, SMFIS_REJECT, or SMFIS_DISCARD from a +message-oriented routine, xxfi_abort will not be called even if the +message is later aborted outside its control. +</UL> +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_body.html b/contrib/sendmail/libmilter/docs/xxfi_body.html new file mode 100644 index 0000000..0a5f0f3 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_body.html @@ -0,0 +1,97 @@ +<HTML> +<HEAD><TITLE>xxfi_body</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_body.html,v 1.17 2007/03/26 20:12:46 ca Exp $ +--> +<H1>xxfi_body</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_body)( + SMFICTX *ctx, + unsigned char *bodyp, + size_t len +); +</PRE> +Handle a piece of a message's body. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_body is called zero or more times between xxfi_eoh and xxfi_eom.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>bodyp</TD> + <TD>Pointer to the start of this block of body data. bodyp is not valid outside this call to xxfi_body. + </TD></TR> + <TR valign="top"><TD>len</TD> + <TD>The amount of data pointed to by bodyp. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD> +<UL> +<LI>bodyp points to a sequence of bytes. +It is <EM>not</EM> a C string (a sequence of characters that is terminated by '\0'). +Therefore, do not use the usual C string functions like <CODE>strlen(3)</CODE> +on this byte block. +Moreover, the byte sequence may contain '\0' characters inside the block. +Hence even if a trailing '\0' is added, C string functions may still fail +to work as expected. +<LI>Since message bodies can be very large, defining xxfi_body can +significantly impact filter performance. +<LI>End-of-lines are represented as received from SMTP (normally CR/LF). +<LI>Later filters will see body changes made by earlier ones. +<LI>Message bodies may be sent in multiple chunks, with one call to + xxfi_body per chunk. +<LI>Return +<A HREF="api.html#SMFIS_SKIP">SMFIS_SKIP</A> +if a milter has received sufficiently many +body chunks to make a decision, +but still wants to invoke +message modification functions that are only allowed to be called from +<A HREF="xxfi_eom.html">xxfi_eom()</A>. +Note: the milter <EM>must</EM> +<A HREF="xxfi_negotiate.html">negotiate</A> +this behavior with the MTA, i.e., it must check whether +the protocol action +<A HREF="xxfi_negotiate.html#SMFIP_SKIP"><CODE>SMFIP_SKIP</CODE></A> +is available and if so, the milter must request it. +</UL> +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2003, 2007 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_close.html b/contrib/sendmail/libmilter/docs/xxfi_close.html new file mode 100644 index 0000000..2c2ae77 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_close.html @@ -0,0 +1,81 @@ +<HTML> +<HEAD><TITLE>xxfi_close</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_close.html,v 1.13 2006/12/21 18:30:35 ca Exp $ +--> +<H1>xxfi_close</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_close)( + SMFICTX *ctx +); +</PRE> +The current connection is being closed. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_close is always called once at the end of each connection.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD> +<UL> +<LI>xxfi_close may be called "out-of-order", i.e. before even the +xxfi_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, xxfi_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 +xxfi_close code. +In particular, it is incorrect to assume the private context pointer +will be something other than NULL in this callback. +<LI>xxfi_close is called on close even if the previous mail +transaction was aborted. +<LI>xxfi_close is responsible for freeing any resources allocated on a +per-connection basis. +<LI>Since the connection is already closing, the return value is +currently ignored. +</UL> +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003, 2004 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_connect.html b/contrib/sendmail/libmilter/docs/xxfi_connect.html new file mode 100644 index 0000000..87d5eeb --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_connect.html @@ -0,0 +1,121 @@ +<HTML> +<HEAD><TITLE>xxfi_connect</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_connect.html,v 1.19 2007/01/15 22:24:45 ca Exp $ +--> +<H1>xxfi_connect</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_connect)( + SMFICTX *ctx, + char *hostname, + _SOCK_ADDR *hostaddr); +</PRE> +</TD></TR> +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR> +<TH valign="top" align=left width=80>Called When</TH> +<TD>Once, at the start of each SMTP connection.</TD> +</TR> +<TR> +<TH valign="top" align=left width=80>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> +<!-- +This callback function is invoked on each connection to the mail +filter program. +The callback is to be implemented by the Milter application developers. +The name of the callback can be any valid function name. +The function pointer is to be assigned to the +smfiDesc.xxfi_connect and the pointer to the smfiDesc structure +is passed to smfi_register(). +</TD></TR> +--> +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR><TD>ctx</TD> + <TD>the opaque context structure. + </TD></TR> + <TR><TD>hostname</TD> + <TD>the host name of the message sender, as determined by a + reverse lookup on the host address. + If the reverse lookup fails + or if none of the IP addresses of the resolved host name + matches the original IP address, + hostname will contain the message sender's IP + address enclosed in square brackets (e.g. `[a.b.c.d]'). + If the SMTP connection is made via stdin the value is + <CODE>localhost</CODE>. + </TD></TR> + <TR><TD>hostaddr</TD> + <TD>the host address, + as determined by a <CODE>getpeername(2)</CODE> call on the SMTP socket. + NULL if the type is not supported in the current version or if + the SMTP connection is made via stdin. + </TD></TR> + </TABLE> +</TD></TR> +<!----------- Return values ----------> +<!-- +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_ACCEPT</TD> + <TD>Accept all commands and messages from this client without any + further contact with the filter. </TD> + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_CONTINUE</TD> + <TD>Continue normal processing. </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_DISCARD</TD> + <TD>Undefined behaviour; do not use. </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Reject all commands and messages from this client with a + temporary failure reply code. + If also used in conjunction with <CODE>smfi_setreply()</CODE> + to set a reply whose SMTP code is 421, + the MTA will drop the connection immediately. </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Reject all commands and messages from this client with a + permanent failure reply code. </TD> + </TR> +</TABLE> +</TR> +--> +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>If an earlier filter rejects the connection in its xxfi_connect() +routine, this filter's xxfi_connect() will not be called.</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000-2001, 2003, 2007 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_data.html b/contrib/sendmail/libmilter/docs/xxfi_data.html new file mode 100644 index 0000000..2633ee5 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_data.html @@ -0,0 +1,89 @@ +<HTML> +<HEAD><TITLE>xxfi_data</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_data.html,v 1.4 2007/01/25 01:00:20 ca Exp $ +--> +<H1>xxfi_data</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_data)( + SMFICTX *ctx +); +</PRE> +Handle the DATA command. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_data is called when the client uses the DATA command. +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Reject this message with a temporary error. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Reject this message. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_DISCARD</TD> + <TD>Accept and silently discard this message. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_ACCEPT</TD> + <TD>Accept this message. + </TD> + </TR> +</TABLE> +</TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>For more details on ESMTP responses, please see RFC +<A href="http://www.rfc-editor.org/rfc/rfc1869.txt">1869</A>.</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_envfrom.html b/contrib/sendmail/libmilter/docs/xxfi_envfrom.html new file mode 100644 index 0000000..6ae88cf --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_envfrom.html @@ -0,0 +1,97 @@ +<HTML> +<HEAD><TITLE>xxfi_envfrom</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_envfrom.html,v 1.14 2007/01/25 01:00:20 ca Exp $ +--> +<H1>xxfi_envfrom</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_envfrom)( + SMFICTX *ctx, + char **argv +); +</PRE> +Handle the MAIL (envelope sender) command. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_envfrom is called once at the beginning of each message +(MAIL command), +before xxfi_envrcpt.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>argv</TD> + <TD>Null-terminated SMTP command arguments; + argv[0] is guaranteed to be the sender address. + Later arguments are the ESMTP arguments. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Reject this sender and message with a temporary error; a new sender (and hence a new message) may subsequently be specified. <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Reject this sender and message; a new sender/message may be specified. <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_DISCARD</TD> + <TD>Accept and silently discard this message. <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_ACCEPT</TD> + <TD>Accept this message. <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> +</TABLE> +</TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>For more details on ESMTP responses, please see RFC +<A href="http://www.rfc-editor.org/rfc/rfc1869.txt">1869</A>.</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html b/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html new file mode 100644 index 0000000..9fb4ce8 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_envrcpt.html @@ -0,0 +1,97 @@ +<HTML> +<HEAD><TITLE>xxfi_envrcpt</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_envrcpt.html,v 1.15 2007/01/25 01:00:20 ca Exp $ +--> +<H1>xxfi_envrcpt</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_envrcpt)( + SMFICTX *ctx, + char **argv +); +</PRE> +Handle the envelope RCPT command. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_envrcpt is called once per recipient, hence one or more times per message, immediately after xxfi_envfrom.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>argv</TD> + <TD>Null-terminated SMTP command arguments; + argv[0] is guaranteed to be the recipient address. + Later arguments are the ESMTP arguments. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Temporarily fail for this particular recipient; further recipients + may still be sent. <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Reject this particular recipient; further recipients may still be sent. + <A href="xxfi_abort.html">xxfi_abort</A> is not called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_DISCARD</TD> + <TD>Accept and discard the message. <A href="xxfi_abort.html">xxfi_abort</A> will be called. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_ACCEPT</TD> + <TD>Accept recipient. <A href="xxfi_abort.html">xxfi_abort</A> will not be called. + </TD> + </TR> +</TABLE> +</TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>For more details on ESMTP responses, please see RFC +<A href="http://www.rfc-editor.org/rfc/rfc1869.txt">1869</A>.</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_eoh.html b/contrib/sendmail/libmilter/docs/xxfi_eoh.html new file mode 100644 index 0000000..2a74e7a --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_eoh.html @@ -0,0 +1,56 @@ +<HTML> +<HEAD><TITLE>xxfi_eoh</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_eoh.html,v 1.11 2006/12/21 18:30:35 ca Exp $ +--> +<H1>xxfi_eoh</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_eoh)( + SMFICTX *ctx +); +</PRE> +Handle the end of message headers. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_eoh is called once after all headers have been sent and processed. +</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_eom.html b/contrib/sendmail/libmilter/docs/xxfi_eom.html new file mode 100644 index 0000000..b5aee8b --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_eom.html @@ -0,0 +1,62 @@ +<HTML> +<HEAD><TITLE>xxfi_eom</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_eom.html,v 1.12 2006/12/21 18:30:36 ca Exp $ +--> +<H1>xxfi_eom</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_eom)( + SMFICTX *ctx +); +</PRE> +End of a message. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_eom is called once after all calls to <A href="xxfi_body.html">xxfi_body</A> for a given message.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>A filter is required to make all its modifications to the message headers, body, and envelope in xxfi_eom. +Modifications are made via the smfi_* routines. +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_header.html b/contrib/sendmail/libmilter/docs/xxfi_header.html new file mode 100644 index 0000000..8a5462f --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_header.html @@ -0,0 +1,111 @@ +<HTML> +<HEAD><TITLE>xxfi_header</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_header.html,v 1.17 2006/12/21 18:30:36 ca Exp $ +--> +<H1>xxfi_header</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_header)( + SMFICTX *ctx, + char *headerf, + char *headerv +); +</PRE> +Handle a message header. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_header is called once for each message header.</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>headerf</TD> + <TD> Header field name. + </TD></TR> + <TR valign="top"><TD>headerv</TD> + <TD>Header field value. + The content of the header may include folded white space, + i.e., multiple lines with following white space + where lines are separated by LF (not CR/LF). + The trailing line terminator (CR/LF) is removed. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD> +<UL> +<LI>Starting with sendmail 8.14, spaces after the colon in a header +field are preserved if requested using the flag +<A HREF="xxfi_negotiate.html#SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A>. +That is, the header + +<PRE> +From: sender <f@example.com> +To: user <t@example.com> +Subject:no +</PRE> + +will be sent to a milter as + +<PRE> +"From", " sender <f@example.com>" +"To", " user <t@example.com>" +"Subject", "no" +</PRE> + +while previously +(or without the flag +<A HREF="xxfi_negotiate.html#SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A>) +it was: + +<PRE> +"From", "sender <f@example.com>" +"To", "user <t@example.com>" +"Subject", "no" +</PRE> + + +<LI>Later filters will see header changes/additions made by earlier ones. +<LI>For much more detail about header format, please see +RFC <A href="http://www.rfc-editor.org/rfc/rfc822.html">822</A> +and +RFC <A href="http://www.rfc-editor.org/rfc/rfc2822.html">2822</A> +</UL> +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003, 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_helo.html b/contrib/sendmail/libmilter/docs/xxfi_helo.html new file mode 100644 index 0000000..613cb19 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_helo.html @@ -0,0 +1,64 @@ +<HTML> +<HEAD><TITLE>xxfi_helo</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_helo.html,v 1.12 2006/12/21 18:30:36 ca Exp $ +--> +<H1>xxfi_helo</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_helo)( + SMFICTX *ctx, + char *helohost +); +</PRE> +Handle the HELO/EHLO command. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> <TD>xxfi_helo is called whenever the client +sends a HELO/EHLO command. +It may therefore be called several times or even not at all; +some restrictions can be imposed by the MTA configuration. +</TD> +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>helohost</TD> + <TD>Value passed to HELO/EHLO command, which should be + the domain name of the sending host (but is, in practice, + anything the sending host wants to send). + </TD></TR> + </TABLE> +</TD></TR> + +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2000, 2003, 2005 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_negotiate.html b/contrib/sendmail/libmilter/docs/xxfi_negotiate.html new file mode 100644 index 0000000..0f69f70 --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_negotiate.html @@ -0,0 +1,277 @@ +<HTML> +<HEAD><TITLE>xxfi_negotiate</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_negotiate.html,v 1.23 2006/12/20 18:57:08 ca Exp $ +--> +<H1>xxfi_negotiate</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +#include <libmilter/mfdef.h> +sfsistat (*xxfi_negotiate)( + SMFICTX *ctx, + unsigned long f0, + unsigned long f1, + unsigned long f2, + unsigned long f3, + unsigned long *pf0, + unsigned long *pf1, + unsigned long *pf2, + unsigned long *pf3); +</PRE> +</TD></TR> +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR> +<TH valign="top" align=left width=80>Called When</TH> +<TD>Once, at the start of each SMTP connection.</TD> +</TR> +<TR> +<TH valign="top" align=left width=80>Default Behavior</TH> +<TD>Return SMFIS_ALL_OPTS to change nothing.</TD> +</TR> +</TABLE> +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR><TD>ctx</TD> + <TD>the opaque context structure. + </TD></TR> + <TR><TD>f0</TD> + <TD>the actions offered by the MTA. + </TD></TR> + <TR><TD>f1</TD> + <TD>the protocol steps offered by the MTA. + <TR><TD>f2</TD> + <TD>for future extensions. + </TD></TR> + <TR><TD>f3</TD> + <TD>for future extensions. + </TD></TR> + <TR><TD>pf0</TD> + <TD>the actions requested by the milter. + </TD></TR> + <TR><TD>pf1</TD> + <TD>the protocol steps requested by the milter. + <TR><TD>pf2</TD> + <TD>for future extensions. + </TD></TR> + <TR><TD>pf3</TD> + <TD>for future extensions. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_ALL_OPTS</TD> + <TD> +If a milter just wants to inspect the available protocol steps +and actions, then it can return +SMFIS_ALL_OPTS +and the MTA will make all protocol steps and actions available +to the milter. +In this case, no values should be assigned to the output parameters +<CODE>pf0</CODE> - <CODE>pf3</CODE> +as they will be ignored. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Milter startup fails and it will not be contacted again +(for the current connection). + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_CONTINUE</TD> + <TD>Continue processing. + In this case the milter <EM>must</EM> set all output parameters + <CODE>pf0</CODE> - <CODE>pf3</CODE>. + See below for an explanation how to set those output parameters. + </TD> + </TR> +</TABLE> +</TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>This function allows a milter to dynamically determine and +request operations and actions during startup. +In previous versions, the actions (f0) were fixed in the +<A HREF="smfi_register.html#flags">flags</A> field of the +<A HREF="smfi_register.html#smfiDesc">smfiDesc</A> +structure +and the protocol steps (f1) were implicitly derived by checking whether +a callback was defined. +Due to the extensions in the new milter version, +such a static selection will not work if a milter requires +new actions that are not available when talking to an older MTA. +Hence in the negotiation callback a milter can determine +which operations are available and dynamically select +those which it needs and which are offered. +If some operations are not available, the milter may either fall back +to an older mode or abort the session and ask the user to upgrade. + +<!-- +<P> +The protocol steps are defined in +<CODE>include/libmilter/mfdef.h</CODE>: +the macros start with +<CODE>SMFIP_</CODE>. +--> + +<P> +Protocol steps +(<CODE>f1</CODE>, <CODE>*pf1</CODE>): +<UL> +<LI><A NAME="SMFIP_RCPT_REJ"><CODE>SMFIP_RCPT_REJ</CODE></A>: +By setting this bit, a milter can request that the +MTA should also send <CODE>RCPT</CODE> commands that have been rejected +because the user is unknown (or similar reasons), but not those +which have been rejected because of syntax errors etc. +If a milter requests this protocol step, +then it should check the macro +<CODE>{rcpt_mailer}</CODE>: +if that is set to +<CODE>error</CODE>, +then the recipient will be rejected by the MTA. +Usually the macros +<CODE>{rcpt_host}</CODE> and <CODE>{rcpt_addr}</CODE> +will contain an enhanced status code and an error text +in that case, respectively. + +<LI><A NAME="SMFIP_SKIP"><CODE>SMFIP_SKIP</CODE></A> +indicates that the MTA understand the +<A HREF="api.html#SMFIS_SKIP">SMFIS_SKIP</A> +return code. + +<LI><A NAME="SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A> +indicates that the MTA understand the +<A HREF="api.html#SMFIS_NOREPLY">SMFIS_NOREPLY</A> +return code. +There are flags for various protocol stages: + +<UL> + +<LI><A NAME="SMFIP_NR_CONN"><CODE>SMFIP_NR_CONN</CODE></A>: +<A HREF="xxfi_connect.html">xxfi_connect()</A> + +<LI><A NAME="SMFIP_NR_HELO"><CODE>SMFIP_NR_HELO</CODE></A>: +<A HREF="xxfi_helo.html">xxfi_helo()</A> + +<LI><A NAME="SMFIP_NR_MAIL"><CODE>SMFIP_NR_MAIL</CODE></A>: +<A HREF="xxfi_envfrom.html">xxfi_envfrom()</A> + +<LI><A NAME="SMFIP_NR_RCPT"><CODE>SMFIP_NR_RCPT</CODE></A>: +<A HREF="xxfi_envrcpt.html">xxfi_envrcpt()</A> + +<LI><A NAME="SMFIP_NR_DATA"><CODE>SMFIP_NR_DATA</CODE></A>: +<A HREF="xxfi_data.html">xxfi_data()</A> + +<LI><A NAME="SMFIP_NR_UNKN"><CODE>SMFIP_NR_UNKN</CODE></A>: +<A HREF="xxfi_unknown.html">xxfi_unknown()</A> + +<LI><A NAME="SMFIP_NR_EOH"><CODE>SMFIP_NR_EOH</CODE></A>: +<A HREF="xxfi_eoh.html">xxfi_eoh()</A> + +<LI><A NAME="SMFIP_NR_BODY"><CODE>SMFIP_NR_BODY</CODE></A>: +<A HREF="xxfi_body.html">xxfi_body()</A> + +<LI><A NAME="SMFIP_NR_HDR"><CODE>SMFIP_NR_HDR</CODE></A>: +<A HREF="xxfi_header.html">xxfi_header()</A> + +</UL> + +<LI><A NAME="SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A> +indicates that the MTA can send header values with leading space intact. +If this protocol step is requested, then the MTA will also not add a leading +space to headers when they are added, inserted, or changed. + +<!-- +:'a,.s;^#define \(SMFIP_NO[A-Z]*\)[ ].*;<LI><A NAME="\1"><CODE>\1</CODE></A>:; +--> +<LI>The MTA can be instructed not to send information about +various SMTP stages, these flags start with: +<A NAME="SMFIP_NO"><CODE>SMFIP_NO*</CODE></A>. +<UL> +<LI><A NAME="SMFIP_NOCONNECT"><CODE>SMFIP_NOCONNECT</CODE></A>: +<A HREF="xxfi_connect.html">xxfi_connect()</A> +<LI><A NAME="SMFIP_NOHELO"><CODE>SMFIP_NOHELO</CODE></A>: +<A HREF="xxfi_header.html">xxfi_header()</A> +<LI><A NAME="SMFIP_NOMAIL"><CODE>SMFIP_NOMAIL</CODE></A>: +<A HREF="xxfi_envfrom.html">xxfi_envfrom()</A> +<LI><A NAME="SMFIP_NORCPT"><CODE>SMFIP_NORCPT</CODE></A>: +<A HREF="xxfi_envrcpt.html">xxfi_envrcpt()</A> +<LI><A NAME="SMFIP_NOBODY"><CODE>SMFIP_NOBODY</CODE></A>: +<A HREF="xxfi_body.html">xxfi_body()</A> +<LI><A NAME="SMFIP_NOHDRS"><CODE>SMFIP_NOHDRS</CODE></A>: +<A HREF="xxfi_header.html">xxfi_header()</A> +<LI><A NAME="SMFIP_NOEOH"><CODE>SMFIP_NOEOH</CODE></A>: +<A HREF="xxfi_eoh.html">xxfi_eoh()</A> +<LI><A NAME="SMFIP_NOUNKNOWN"><CODE>SMFIP_NOUNKNOWN</CODE></A>: +<A HREF="xxfi_unknown.html">xxfi_unknown()</A> +<LI><A NAME="SMFIP_NODATA"><CODE>SMFIP_NODATA</CODE></A>: +<A HREF="xxfi_data.html">xxfi_data()</A> +</UL> + +For each of these xxfi_* callbacks that a milter does not use +the corresponding flag <EM>should</EM> be set in +<CODE>*pf1</CODE>. + +</UL> + +<P> +The available actions +(<CODE>f0</CODE>, <CODE>*pf0</CODE>) +are +<!-- +defined in +<CODE>include/libmilter/mfapi.h</CODE>: +the macros start with +<CODE>SMFIF_</CODE>; +these are +--> +described +<A HREF="smfi_register.html#flags">elsewhere (xxfi_flags)</A>. + +<P> +If a milter returns SMFIS_CONTINUE, then it <EM>must</EM> +set the desired actions and protocol steps +via the (output) parameters +<CODE>pf0</CODE> +and +<CODE>pf1</CODE> +(which correspond to +<CODE>f0</CODE> +and +<CODE>f1</CODE>, respectively). +The (output) parameters +<CODE>pf2</CODE> and +<CODE>pf3</CODE> +should be set to 0 for compatibility with future versions. + +</TD> +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/docs/xxfi_unknown.html b/contrib/sendmail/libmilter/docs/xxfi_unknown.html new file mode 100644 index 0000000..0455dfd --- /dev/null +++ b/contrib/sendmail/libmilter/docs/xxfi_unknown.html @@ -0,0 +1,84 @@ +<HTML> +<HEAD><TITLE>xxfi_unknown</TITLE></HEAD> +<BODY> +<!-- +$Id: xxfi_unknown.html,v 1.4 2007/04/23 16:30:42 ca Exp $ +--> +<H1>xxfi_unknown</H1> + +<TABLE border="0" cellspacing=4 cellpadding=4> +<!---------- Synopsis -----------> +<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD> +<PRE> +#include <libmilter/mfapi.h> +sfsistat (*xxfi_unknown)( + SMFICTX *ctx, + const char *arg +); +</PRE> +Handle unknown and unimplemented SMTP commands. +</TD></TR> + +<!----------- Description ----------> +<TR><TH valign="top" align=left>DESCRIPTION</TH><TD> +<TABLE border="1" cellspacing=1 cellpadding=4> +<TR align="left" valign=top> +<TH width="80">Called When</TH> +<TD>xxfi_unknown is called when the client uses an SMTP command +that is either unknown or not implemented by the MTA. +</TR> +<TR align="left" valign=top> +<TH>Default Behavior</TH> +<TD>Do nothing; return SMFIS_CONTINUE.</TD> +</TR> +</TABLE> + +<!----------- Arguments ----------> +<TR><TH valign="top" align=left>ARGUMENTS</TH><TD> + <TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR> + <TR valign="top"><TD>ctx</TD> + <TD>Opaque context structure. + </TD></TR> + <TR valign="top"><TD>arg</TD> + <TD>SMTP command including all arguments. + </TD></TR> + </TABLE> +</TD></TR> + +<!----------- Return values ----------> +<TR> +<TH valign="top" align=left>SPECIAL RETURN VALUES</TH> +<TD><TABLE border="1" cellspacing=0> + <TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR> + <TR valign="top"> + <TD>SMFIS_TEMPFAIL</TD> + <TD>Reject this command with a temporary error. + </TD> + </TR> + <TR valign="top"> + <TD>SMFIS_REJECT</TD> + <TD>Reject this command. + </TD> + </TR> +</TABLE> +</TR> + +<!----------- Notes ----------> +<TR> +<TH valign="top" align=left>NOTES</TH> +<TD>The SMTP command will always be rejected by the server, +it is only possible to return a different error code. +</TR> +</TABLE> + +<HR size="1"> +<FONT size="-1"> +Copyright (c) 2006 Sendmail, Inc. and its suppliers. +All rights reserved. +<BR> +By using this file, you agree to the terms and conditions set +forth in the LICENSE. +</FONT> +</BODY> +</HTML> diff --git a/contrib/sendmail/libmilter/engine.c b/contrib/sendmail/libmilter/engine.c new file mode 100644 index 0000000..a2d3e1e --- /dev/null +++ b/contrib/sendmail/libmilter/engine.c @@ -0,0 +1,1915 @@ +/* + * Copyright (c) 1999-2004, 2006-2008 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: engine.c,v 8.166 2009/11/06 00:57:07 ca Exp $") + +#include "libmilter.h" + +#if NETINET || NETINET6 +# include <arpa/inet.h> +#endif /* NETINET || NETINET6 */ + +/* generic argument for functions in the command table */ +struct arg_struct +{ + size_t a_len; /* length of buffer */ + char *a_buf; /* argument string */ + int a_idx; /* index for macro array */ + SMFICTX_PTR a_ctx; /* context */ +}; + +typedef struct arg_struct genarg; + +/* structure for commands received from MTA */ +struct cmdfct_t +{ + char cm_cmd; /* command */ + int cm_argt; /* type of arguments expected */ + int cm_next; /* next state */ + int cm_todo; /* what to do next */ + int cm_macros; /* index for macros */ + int (*cm_fct) __P((genarg *)); /* function to execute */ +}; + +typedef struct cmdfct_t cmdfct; + +/* possible values for cm_argt */ +#define CM_ARG0 0 /* no args */ +#define CM_ARG1 1 /* one arg (string) */ +#define CM_ARG2 2 /* two args (strings) */ +#define CM_ARGA 4 /* one string and _SOCK_ADDR */ +#define CM_ARGO 5 /* two integers */ +#define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ +#define CM_ARGN 9 /* \0 separated list of args (strings) */ + +/* possible values for cm_todo */ +#define CT_CONT 0x0000 /* continue reading commands */ +#define CT_IGNO 0x0001 /* continue even when error */ + +/* not needed right now, done via return code instead */ +#define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ +#define CT_END 0x0008 /* last command of session, stop replying */ + +/* index in macro array: macros only for these commands */ +#define CI_NONE (-1) +#define CI_CONN 0 +#define CI_HELO 1 +#define CI_MAIL 2 +#define CI_RCPT 3 +#define CI_DATA 4 +#define CI_EOM 5 +#define CI_EOH 6 +#define CI_LAST CI_EOH +#if CI_LAST < CI_DATA +ERROR: do not compile with CI_LAST < CI_DATA +#endif +#if CI_LAST < CI_EOM +ERROR: do not compile with CI_LAST < CI_EOM +#endif +#if CI_LAST < CI_EOH +ERROR: do not compile with CI_LAST < CI_EOH +#endif +#if CI_LAST < CI_ENVRCPT +ERROR: do not compile with CI_LAST < CI_ENVRCPT +#endif +#if CI_LAST < CI_ENVFROM +ERROR: do not compile with CI_LAST < CI_ENVFROM +#endif +#if CI_LAST < CI_HELO +ERROR: do not compile with CI_LAST < CI_HELO +#endif +#if CI_LAST < CI_CONNECT +ERROR: do not compile with CI_LAST < CI_CONNECT +#endif +#if CI_LAST >= MAX_MACROS_ENTRIES +ERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES +#endif + +/* function prototypes */ +static int st_abortfct __P((genarg *)); +static int st_macros __P((genarg *)); +static int st_optionneg __P((genarg *)); +static int st_bodychunk __P((genarg *)); +static int st_connectinfo __P((genarg *)); +static int st_bodyend __P((genarg *)); +static int st_helo __P((genarg *)); +static int st_header __P((genarg *)); +static int st_sender __P((genarg *)); +static int st_rcpt __P((genarg *)); +static int st_unknown __P((genarg *)); +static int st_data __P((genarg *)); +static int st_eoh __P((genarg *)); +static int st_quit __P((genarg *)); +static int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); +static void fix_stm __P((SMFICTX_PTR)); +static bool trans_ok __P((int, int)); +static char **dec_argv __P((char *, size_t)); +static int dec_arg2 __P((char *, size_t, char **, char **)); +static void mi_clr_symlist __P((SMFICTX_PTR)); + +#if _FFR_WORKERS_POOL +static bool mi_rd_socket_ready __P((int)); +#endif /* _FFR_WORKERS_POOL */ + +/* states */ +#define ST_NONE (-1) +#define ST_INIT 0 /* initial state */ +#define ST_OPTS 1 /* option negotiation */ +#define ST_CONN 2 /* connection info */ +#define ST_HELO 3 /* helo */ +#define ST_MAIL 4 /* mail from */ +#define ST_RCPT 5 /* rcpt to */ +#define ST_DATA 6 /* data */ +#define ST_HDRS 7 /* headers */ +#define ST_EOHS 8 /* end of headers */ +#define ST_BODY 9 /* body */ +#define ST_ENDM 10 /* end of message */ +#define ST_QUIT 11 /* quit */ +#define ST_ABRT 12 /* abort */ +#define ST_UNKN 13 /* unknown SMTP command */ +#define ST_Q_NC 14 /* quit, new connection follows */ +#define ST_LAST ST_Q_NC /* last valid state */ +#define ST_SKIP 16 /* not a state but required for the state table */ + +/* in a mail transaction? must be before eom according to spec. */ +#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) + +/* +** set of next states +** each state (ST_*) corresponds to bit in an int value (1 << state) +** each state has a set of allowed transitions ('or' of bits of states) +** so a state transition is valid if the mask of the next state +** is set in the NX_* value +** this function is coded in trans_ok(), see below. +*/ + +#define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ +#define NX_INIT (MI_MASK(ST_OPTS)) +#define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) +#define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) +#define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) +#define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) +#define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ + MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ + MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) +#define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) +#define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) +#define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) +#define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) +#define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ + MI_MASK(ST_Q_NC)) +#define NX_QUIT 0 +#define NX_ABRT 0 +#define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ + MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ + MI_MASK(ST_DATA) | \ + MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ + MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) +#define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) +#define NX_SKIP MI_MASK(ST_SKIP) + +static int next_states[] = +{ + NX_INIT + , NX_OPTS + , NX_CONN + , NX_HELO + , NX_MAIL + , NX_RCPT + , NX_DATA + , NX_HDRS + , NX_EOHS + , NX_BODY + , NX_ENDM + , NX_QUIT + , NX_ABRT + , NX_UNKN + , NX_Q_NC +}; + +#define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) + +/* commands received by milter */ +static cmdfct cmds[] = +{ + {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct } +, {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros } +, {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk } +, {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo } +, {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } +, {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo } +, {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header } +, {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender } +, {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg } +, {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_EOH, st_eoh } +, {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit } +, {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_DATA, st_data } +, {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } +, {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } +, {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC, CT_CONT, CI_NONE, st_quit } +}; + +/* +** Additional (internal) reply codes; +** must be coordinated wit libmilter/mfapi.h +*/ + +#define _SMFIS_KEEP 20 +#define _SMFIS_ABORT 21 +#define _SMFIS_OPTIONS 22 +#define _SMFIS_NOREPLY SMFIS_NOREPLY +#define _SMFIS_FAIL (-1) +#define _SMFIS_NONE (-2) + +/* +** MI_ENGINE -- receive commands and process them +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_FAILURE/MI_SUCCESS +*/ + +int +mi_engine(ctx) + SMFICTX_PTR ctx; +{ + size_t len; + int i; + socket_t sd; + int ret = MI_SUCCESS; + int ncmds = sizeof(cmds) / sizeof(cmdfct); + int curstate = ST_INIT; + int newstate; + bool call_abort; + sfsistat r; + char cmd; + char *buf = NULL; + genarg arg; + struct timeval timeout; + int (*f) __P((genarg *)); + sfsistat (*fi_abort) __P((SMFICTX *)); + sfsistat (*fi_close) __P((SMFICTX *)); + + arg.a_ctx = ctx; + sd = ctx->ctx_sd; + fi_abort = ctx->ctx_smfi->xxfi_abort; +#if _FFR_WORKERS_POOL + curstate = ctx->ctx_state; + if (curstate == ST_INIT) + { + mi_clr_macros(ctx, 0); + fix_stm(ctx); + } +#else /* _FFR_WORKERS_POOL */ + mi_clr_macros(ctx, 0); + fix_stm(ctx); +#endif /* _FFR_WORKERS_POOL */ + r = _SMFIS_NONE; + do + { + /* call abort only if in a mail transaction */ + call_abort = ST_IN_MAIL(curstate); + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + if (mi_stop() == MILTER_ABRT) + { + if (ctx->ctx_dbg > 3) + sm_dprintf("[%ld] milter_abort\n", + (long) ctx->ctx_id); + ret = MI_FAILURE; + break; + } + + /* + ** Notice: buf is allocated by mi_rd_cmd() and it will + ** usually be free()d after it has been used in f(). + ** However, if the function returns _SMFIS_KEEP then buf + ** contains macros and will not be free()d. + ** Hence r must be set to _SMFIS_NONE if a new buf is + ** allocated to avoid problem with housekeeping, esp. + ** if the code "break"s out of the loop. + */ + +#if _FFR_WORKERS_POOL + /* Is the socket ready to be read ??? */ + if (!mi_rd_socket_ready(sd)) + { + ret = MI_CONTINUE; + break; + } +#endif /* _FFR_WORKERS_POOL */ + + r = _SMFIS_NONE; + if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, + ctx->ctx_smfi->xxfi_name)) == NULL && + cmd < SMFIC_VALIDCMD) + { + if (ctx->ctx_dbg > 5) + sm_dprintf("[%ld] mi_engine: mi_rd_cmd error (%x)\n", + (long) ctx->ctx_id, (int) cmd); + + /* + ** eof is currently treated as failure -> + ** abort() instead of close(), otherwise use: + ** if (cmd != SMFIC_EOF) + */ + + ret = MI_FAILURE; + break; + } + if (ctx->ctx_dbg > 4) + sm_dprintf("[%ld] got cmd '%c' len %d\n", + (long) ctx->ctx_id, cmd, (int) len); + for (i = 0; i < ncmds; i++) + { + if (cmd == cmds[i].cm_cmd) + break; + } + if (i >= ncmds) + { + /* unknown command */ + if (ctx->ctx_dbg > 1) + sm_dprintf("[%ld] cmd '%c' unknown\n", + (long) ctx->ctx_id, cmd); + ret = MI_FAILURE; + break; + } + if ((f = cmds[i].cm_fct) == NULL) + { + /* stop for now */ + if (ctx->ctx_dbg > 1) + sm_dprintf("[%ld] cmd '%c' not impl\n", + (long) ctx->ctx_id, cmd); + ret = MI_FAILURE; + break; + } + + /* is new state ok? */ + newstate = cmds[i].cm_next; + if (ctx->ctx_dbg > 5) + sm_dprintf("[%ld] cur %x new %x nextmask %x\n", + (long) ctx->ctx_id, + curstate, newstate, next_states[curstate]); + + if (newstate != ST_NONE && !trans_ok(curstate, newstate)) + { + if (ctx->ctx_dbg > 1) + sm_dprintf("[%ld] abort: cur %d (%x) new %d (%x) next %x\n", + (long) ctx->ctx_id, + curstate, MI_MASK(curstate), + newstate, MI_MASK(newstate), + next_states[curstate]); + + /* call abort only if in a mail transaction */ + if (fi_abort != NULL && call_abort) + (void) (*fi_abort)(ctx); + + /* + ** try to reach the new state from HELO + ** if it can't be reached, ignore the command. + */ + + curstate = ST_HELO; + if (!trans_ok(curstate, newstate)) + { + if (buf != NULL) + { + free(buf); + buf = NULL; + } + continue; + } + } + arg.a_len = len; + arg.a_buf = buf; + if (newstate != ST_NONE) + { + curstate = newstate; + ctx->ctx_state = curstate; + } + arg.a_idx = cmds[i].cm_macros; + call_abort = ST_IN_MAIL(curstate); + + /* call function to deal with command */ + MI_MONITOR_BEGIN(ctx, cmd); + r = (*f)(&arg); + MI_MONITOR_END(ctx, cmd); + if (r != _SMFIS_KEEP && buf != NULL) + { + free(buf); + buf = NULL; + } + if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) + { + ret = MI_FAILURE; + break; + } + + if (r == SMFIS_ACCEPT) + { + /* accept mail, no further actions taken */ + curstate = ST_HELO; + } + else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || + r == SMFIS_TEMPFAIL) + { + /* + ** further actions depend on current state + ** if the IGNO bit is set: "ignore" the error, + ** i.e., stay in the current state + */ + if (!bitset(CT_IGNO, cmds[i].cm_todo)) + curstate = ST_HELO; + } + else if (r == _SMFIS_ABORT) + { + if (ctx->ctx_dbg > 5) + sm_dprintf("[%ld] function returned abort\n", + (long) ctx->ctx_id); + ret = MI_FAILURE; + break; + } + } while (!bitset(CT_END, cmds[i].cm_todo)); + + ctx->ctx_state = curstate; + + if (ret == MI_FAILURE) + { + /* call abort only if in a mail transaction */ + if (fi_abort != NULL && call_abort) + (void) (*fi_abort)(ctx); + } + + /* has close been called? */ + if (ctx->ctx_state != ST_QUIT +#if _FFR_WORKERS_POOL + && ret != MI_CONTINUE +#endif /* _FFR_WORKERS_POOL */ + ) + { + if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) + (void) (*fi_close)(ctx); + } + if (r != _SMFIS_KEEP && buf != NULL) + free(buf); +#if !_FFR_WORKERS_POOL + mi_clr_macros(ctx, 0); +#endif /* _FFR_WORKERS_POOL */ + return ret; +} + +static size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); + +static size_t +milter_addsymlist(ctx, buf, newbuf) + SMFICTX_PTR ctx; + char *buf; + char **newbuf; +{ + size_t len; + int i; + mi_int32 v; + char *buffer; + + SM_ASSERT(ctx != NULL); + SM_ASSERT(buf != NULL); + SM_ASSERT(newbuf != NULL); + len = 0; + for (i = 0; i < MAX_MACROS_ENTRIES; i++) + { + if (ctx->ctx_mac_list[i] != NULL) + { + len += strlen(ctx->ctx_mac_list[i]) + 1 + + MILTER_LEN_BYTES; + } + } + if (len > 0) + { + size_t offset; + + SM_ASSERT(len + MILTER_OPTLEN > len); + len += MILTER_OPTLEN; + buffer = malloc(len); + if (buffer != NULL) + { + (void) memcpy(buffer, buf, MILTER_OPTLEN); + offset = MILTER_OPTLEN; + for (i = 0; i < MAX_MACROS_ENTRIES; i++) + { + size_t l; + + if (ctx->ctx_mac_list[i] == NULL) + continue; + + SM_ASSERT(offset + MILTER_LEN_BYTES < len); + v = htonl(i); + (void) memcpy(buffer + offset, (void *) &v, + MILTER_LEN_BYTES); + offset += MILTER_LEN_BYTES; + l = strlen(ctx->ctx_mac_list[i]) + 1; + SM_ASSERT(offset + l <= len); + (void) memcpy(buffer + offset, + ctx->ctx_mac_list[i], l); + offset += l; + } + } + else + { + /* oops ... */ + } + } + else + { + len = MILTER_OPTLEN; + buffer = buf; + } + *newbuf = buffer; + return len; +} + +/* +** GET_NR_BIT -- get "no reply" bit matching state +** +** Parameters: +** state -- current protocol stage +** +** Returns: +** 0: no matching bit +** >0: the matching "no reply" bit +*/ + +static unsigned long get_nr_bit __P((int)); + +static unsigned long +get_nr_bit(state) + int state; +{ + unsigned long bit; + + switch (state) + { + case ST_CONN: + bit = SMFIP_NR_CONN; + break; + case ST_HELO: + bit = SMFIP_NR_HELO; + break; + case ST_MAIL: + bit = SMFIP_NR_MAIL; + break; + case ST_RCPT: + bit = SMFIP_NR_RCPT; + break; + case ST_DATA: + bit = SMFIP_NR_DATA; + break; + case ST_UNKN: + bit = SMFIP_NR_UNKN; + break; + case ST_HDRS: + bit = SMFIP_NR_HDR; + break; + case ST_EOHS: + bit = SMFIP_NR_EOH; + break; + case ST_BODY: + bit = SMFIP_NR_BODY; + break; + default: + bit = 0; + break; + } + return bit; +} + +/* +** SENDREPLY -- send a reply to the MTA +** +** Parameters: +** r -- reply code +** sd -- socket descriptor +** timeout_ptr -- (ptr to) timeout to use for sending +** ctx -- context structure +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +sendreply(r, sd, timeout_ptr, ctx) + sfsistat r; + socket_t sd; + struct timeval *timeout_ptr; + SMFICTX_PTR ctx; +{ + int ret; + unsigned long bit; + + ret = MI_SUCCESS; + + bit = get_nr_bit(ctx->ctx_state); + if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) + { + if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) + { + /* milter said it wouldn't reply, but it lied... */ + smi_log(SMI_LOG_ERR, + "%s: milter claimed not to reply in state %d but did anyway %d\n", + ctx->ctx_smfi->xxfi_name, + ctx->ctx_state, r); + + } + + /* + ** Force specified behavior, otherwise libmilter + ** and MTA will fail to communicate properly. + */ + + switch (r) + { + case SMFIS_CONTINUE: + case SMFIS_TEMPFAIL: + case SMFIS_REJECT: + case SMFIS_DISCARD: + case SMFIS_ACCEPT: + case SMFIS_SKIP: + case _SMFIS_OPTIONS: + r = SMFIS_NOREPLY; + break; + } + } + + switch (r) + { + case SMFIS_CONTINUE: + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); + break; + case SMFIS_TEMPFAIL: + case SMFIS_REJECT: + if (ctx->ctx_reply != NULL && + ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || + (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) + { + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, + ctx->ctx_reply, + strlen(ctx->ctx_reply) + 1); + free(ctx->ctx_reply); + ctx->ctx_reply = NULL; + } + else + { + ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? + SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); + } + break; + case SMFIS_DISCARD: + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); + break; + case SMFIS_ACCEPT: + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); + break; + case SMFIS_SKIP: + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); + break; + case _SMFIS_OPTIONS: + { + mi_int32 v; + size_t len; + char *buffer; + char buf[MILTER_OPTLEN]; + + v = htonl(ctx->ctx_prot_vers2mta); + (void) memcpy(&(buf[0]), (void *) &v, + MILTER_LEN_BYTES); + v = htonl(ctx->ctx_aflags); + (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, + MILTER_LEN_BYTES); + v = htonl(ctx->ctx_pflags2mta); + (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), + (void *) &v, MILTER_LEN_BYTES); + len = milter_addsymlist(ctx, buf, &buffer); + if (buffer != NULL) + ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, + buffer, len); + else + ret = MI_FAILURE; + } + break; + case SMFIS_NOREPLY: + if (bit != 0 && + (ctx->ctx_pflags & bit) != 0 && + (ctx->ctx_mta_pflags & bit) == 0) + { + /* + ** milter doesn't want to send a reply, + ** but the MTA doesn't have that feature: fake it. + */ + + ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, + 0); + } + break; + default: /* don't send a reply */ + break; + } + return ret; +} + +/* +** CLR_MACROS -- clear set of macros starting from a given index +** +** Parameters: +** ctx -- context structure +** m -- index from which to clear all macros +** +** Returns: +** None. +*/ + +void +mi_clr_macros(ctx, m) + SMFICTX_PTR ctx; + int m; +{ + int i; + + for (i = m; i < MAX_MACROS_ENTRIES; i++) + { + if (ctx->ctx_mac_ptr[i] != NULL) + { + free(ctx->ctx_mac_ptr[i]); + ctx->ctx_mac_ptr[i] = NULL; + } + if (ctx->ctx_mac_buf[i] != NULL) + { + free(ctx->ctx_mac_buf[i]); + ctx->ctx_mac_buf[i] = NULL; + } + } +} + +/* +** MI_CLR_SYMLIST -- clear list of macros +** +** Parameters: +** ctx -- context structure +** +** Returns: +** None. +*/ + +static void +mi_clr_symlist(ctx) + SMFICTX *ctx; +{ + int i; + + SM_ASSERT(ctx != NULL); + for (i = SMFIM_FIRST; i <= SMFIM_LAST; i++) + { + if (ctx->ctx_mac_list[i] != NULL) + { + free(ctx->ctx_mac_list[i]); + ctx->ctx_mac_list[i] = NULL; + } + } +} + +/* +** MI_CLR_CTX -- clear context +** +** Parameters: +** ctx -- context structure +** +** Returns: +** None. +*/ + +void +mi_clr_ctx(ctx) + SMFICTX *ctx; +{ + SM_ASSERT(ctx != NULL); + if (ValidSocket(ctx->ctx_sd)) + { + (void) closesocket(ctx->ctx_sd); + ctx->ctx_sd = INVALID_SOCKET; + } + if (ctx->ctx_reply != NULL) + { + free(ctx->ctx_reply); + ctx->ctx_reply = NULL; + } + if (ctx->ctx_privdata != NULL) + { + smi_log(SMI_LOG_WARN, + "%s: private data not NULL", + ctx->ctx_smfi->xxfi_name); + } + mi_clr_macros(ctx, 0); + mi_clr_symlist(ctx); + free(ctx); +} + +/* +** ST_OPTIONNEG -- negotiate options +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** abort/send options/continue +*/ + +static int +st_optionneg(g) + genarg *g; +{ + mi_int32 i, v, fake_pflags, internal_pflags; + SMFICTX_PTR ctx; +#if _FFR_MILTER_CHECK + bool testmode = false; +#endif /* _FFR_MILTER_CHECK */ + int (*fi_negotiate) __P((SMFICTX *, + unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long *, unsigned long *, + unsigned long *, unsigned long *)); + + if (g == NULL || g->a_ctx->ctx_smfi == NULL) + return SMFIS_CONTINUE; + ctx = g->a_ctx; + mi_clr_macros(ctx, g->a_idx + 1); + ctx->ctx_prot_vers = SMFI_PROT_VERSION; + + /* check for minimum length */ + if (g->a_len < MILTER_OPTLEN) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%ld]: len too short %d < %d", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, (int) g->a_len, + MILTER_OPTLEN); + return _SMFIS_ABORT; + } + + /* protocol version */ + (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); + v = ntohl(i); + +#define SMFI_PROT_VERSION_MIN 2 + + /* check for minimum version */ + if (v < SMFI_PROT_VERSION_MIN) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%ld]: protocol version too old %d < %d", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); + return _SMFIS_ABORT; + } + ctx->ctx_mta_prot_vers = v; + if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) + ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; + else + ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; + + (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), + MILTER_LEN_BYTES); + v = ntohl(i); + + /* no flags? set to default value for V1 actions */ + if (v == 0) + v = SMFI_V1_ACTS; + ctx->ctx_mta_aflags = v; /* MTA action flags */ + + internal_pflags = 0; + (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), + MILTER_LEN_BYTES); + v = ntohl(i); + + /* no flags? set to default value for V1 protocol */ + if (v == 0) + v = SMFI_V1_PROT; +#if _FFR_MDS_NEGOTIATE + else if (ctx->ctx_smfi->xxfi_version >= SMFI_VERSION_MDS) + { + /* + ** Allow changing the size only if milter is compiled + ** against a version that supports this. + ** If a milter is dynamically linked against a newer + ** libmilter version, we don't want to "surprise" + ** it with a larger buffer as it may rely on it + ** even though it is not documented as a limit. + */ + + if (bitset(SMFIP_MDS_1M, v)) + { + internal_pflags |= SMFIP_MDS_1M; + (void) smfi_setmaxdatasize(MILTER_MDS_1M); + } + else if (bitset(SMFIP_MDS_256K, v)) + { + internal_pflags |= SMFIP_MDS_256K; + (void) smfi_setmaxdatasize(MILTER_MDS_256K); + } + } +# if 0 + /* don't log this for now... */ + else if (ctx->ctx_smfi->xxfi_version < SMFI_VERSION_MDS && + bitset(SMFIP_MDS_1M|SMFIP_MDS_256K, v)) + { + smi_log(SMI_LOG_WARN, + "%s: st_optionneg[%ld]: milter version=%X, trying flags=%X", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, ctx->ctx_smfi->xxfi_version, v); + } +# endif /* 0 */ +#endif /* _FFR_MDS_NEGOTIATE */ + + /* + ** MTA protocol flags. + ** We pass the internal flags to the milter as "read only", + ** i.e., a milter can read them so it knows which size + ** will be used, but any changes by a milter will be ignored + ** (see below, search for SMFI_INTERNAL). + */ + + ctx->ctx_mta_pflags = (v & ~SMFI_INTERNAL) | internal_pflags; + + /* + ** Copy flags from milter struct into libmilter context; + ** this variable will be used later on to check whether + ** the MTA "actions" can fulfill the milter requirements, + ** but it may be overwritten by the negotiate callback. + */ + + ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; + fake_pflags = SMFIP_NR_CONN + |SMFIP_NR_HELO + |SMFIP_NR_MAIL + |SMFIP_NR_RCPT + |SMFIP_NR_DATA + |SMFIP_NR_UNKN + |SMFIP_NR_HDR + |SMFIP_NR_EOH + |SMFIP_NR_BODY + ; + + if (g->a_ctx->ctx_smfi != NULL && + g->a_ctx->ctx_smfi->xxfi_version > 4 && + (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) + { + int r; + unsigned long m_aflags, m_pflags, m_f2, m_f3; + + /* + ** let milter decide whether the features offered by the + ** MTA are "good enough". + ** Notes: + ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) + ** - m_f2, m_f3 are for future extensions + */ + + m_f2 = m_f3 = 0; + m_aflags = ctx->ctx_mta_aflags; + m_pflags = ctx->ctx_pflags; + if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) + m_pflags |= SMFIP_SKIP; + r = fi_negotiate(g->a_ctx, + ctx->ctx_mta_aflags, + ctx->ctx_mta_pflags|fake_pflags, + 0, 0, + &m_aflags, &m_pflags, &m_f2, &m_f3); + +#if _FFR_MILTER_CHECK + testmode = bitset(SMFIP_TEST, m_pflags); + if (testmode) + m_pflags &= ~SMFIP_TEST; +#endif /* _FFR_MILTER_CHECK */ + + /* + ** Types of protocol flags (pflags): + ** 1. do NOT send protocol step X + ** 2. MTA can do/understand something extra (SKIP, + ** send unknown RCPTs) + ** 3. MTA can deal with "no reply" for various protocol steps + ** Note: this mean that it isn't possible to simply set all + ** flags to get "everything": + ** setting a flag of type 1 turns off a step + ** (it should be the other way around: + ** a flag means a protocol step can be sent) + ** setting a flag of type 3 requires that milter + ** never sends a reply for the corresponding step. + ** Summary: the "negation" of protocol flags is causing + ** problems, but at least for type 3 there is no simple + ** solution. + ** + ** What should "all options" mean? + ** send all protocol steps _except_ those for which there is + ** no callback (currently registered in ctx_pflags) + ** expect SKIP as return code? Yes + ** send unknown RCPTs? No, + ** must be explicitly requested? + ** "no reply" for some protocol steps? No, + ** must be explicitly requested. + */ + + if (SMFIS_ALL_OPTS == r) + { + ctx->ctx_aflags = ctx->ctx_mta_aflags; + ctx->ctx_pflags2mta = ctx->ctx_pflags; + if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) + ctx->ctx_pflags2mta |= SMFIP_SKIP; + } + else if (r != SMFIS_CONTINUE) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, + ctx->ctx_mta_aflags); + return _SMFIS_ABORT; + } + else + { + ctx->ctx_aflags = m_aflags; + ctx->ctx_pflags = m_pflags; + ctx->ctx_pflags2mta = m_pflags; + } + + /* check whether some flags need to be "faked" */ + i = ctx->ctx_pflags2mta; + if ((ctx->ctx_mta_pflags & i) != i) + { + unsigned int idx; + unsigned long b; + + /* + ** If some behavior can be faked (set in fake_pflags), + ** but the MTA doesn't support it, then unset + ** that flag in the value that is sent to the MTA. + */ + + for (idx = 0; idx < 32; idx++) + { + b = 1 << idx; + if ((ctx->ctx_mta_pflags & b) != b && + (fake_pflags & b) == b) + ctx->ctx_pflags2mta &= ~b; + } + } + } + else + { + /* + ** Set the protocol flags based on the values determined + ** in mi_listener() which checked the defined callbacks. + */ + + ctx->ctx_pflags2mta = ctx->ctx_pflags; + } + + /* check whether actions and protocol requirements can be satisfied */ + i = ctx->ctx_aflags; + if ((i & ctx->ctx_mta_aflags) != i) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); + return _SMFIS_ABORT; + } + + i = ctx->ctx_pflags2mta; + if ((ctx->ctx_mta_pflags & i) != i) + { + /* + ** Older MTAs do not support some protocol steps. + ** As this protocol is a bit "wierd" (it asks for steps + ** NOT to be taken/sent) we have to check whether we + ** should turn off those "negative" requests. + ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. + */ + + if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && + !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) + ctx->ctx_pflags2mta &= ~SMFIP_NODATA; + if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && + !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) + ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; + i = ctx->ctx_pflags2mta; + } + + if ((ctx->ctx_mta_pflags & i) != i) + { + smi_log(SMI_LOG_ERR, + "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", + ctx->ctx_smfi->xxfi_name, + (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); + return _SMFIS_ABORT; + } + fix_stm(ctx); + + if (ctx->ctx_dbg > 3) + sm_dprintf("[%ld] milter_negotiate:" + " mta_actions=0x%lx, mta_flags=0x%lx" + " actions=0x%lx, flags=0x%lx\n" + , (long) ctx->ctx_id + , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags + , ctx->ctx_aflags, ctx->ctx_pflags); + +#if _FFR_MILTER_CHECK + if (ctx->ctx_dbg > 3) + sm_dprintf("[%ld] milter_negotiate:" + " testmode=%d, pflags2mta=%X, internal_pflags=%X\n" + , (long) ctx->ctx_id, testmode + , ctx->ctx_pflags2mta, internal_pflags); + + /* in test mode: take flags without further modifications */ + if (!testmode) + /* Warning: check statement below! */ +#endif /* _FFR_MILTER_CHECK */ + + /* + ** Remove the internal flags that might have been set by a milter + ** and set only those determined above. + */ + + ctx->ctx_pflags2mta = (ctx->ctx_pflags2mta & ~SMFI_INTERNAL) + | internal_pflags; + return _SMFIS_OPTIONS; +} + +/* +** ST_CONNECTINFO -- receive connection information +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_connectinfo(g) + genarg *g; +{ + size_t l; + size_t i; + char *s, family; + unsigned short port = 0; + _SOCK_ADDR sockaddr; + sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); + + if (g == NULL) + return _SMFIS_ABORT; + mi_clr_macros(g->a_ctx, g->a_idx + 1); + if (g->a_ctx->ctx_smfi == NULL || + (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) + return SMFIS_CONTINUE; + + s = g->a_buf; + i = 0; + l = g->a_len; + while (s[i] != '\0' && i <= l) + ++i; + if (i + 1 >= l) + return _SMFIS_ABORT; + + /* Move past trailing \0 in host string */ + i++; + family = s[i++]; + (void) memset(&sockaddr, '\0', sizeof sockaddr); + if (family != SMFIA_UNKNOWN) + { + if (i + sizeof port >= l) + { + smi_log(SMI_LOG_ERR, + "%s: connect[%ld]: wrong len %d >= %d", + g->a_ctx->ctx_smfi->xxfi_name, + (long) g->a_ctx->ctx_id, (int) i, (int) l); + return _SMFIS_ABORT; + } + (void) memcpy((void *) &port, (void *) (s + i), + sizeof port); + i += sizeof port; + + /* make sure string is terminated */ + if (s[l - 1] != '\0') + return _SMFIS_ABORT; +# if NETINET + if (family == SMFIA_INET) + { + if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) + != 1) + { + smi_log(SMI_LOG_ERR, + "%s: connect[%ld]: inet_aton failed", + g->a_ctx->ctx_smfi->xxfi_name, + (long) g->a_ctx->ctx_id); + return _SMFIS_ABORT; + } + sockaddr.sa.sa_family = AF_INET; + if (port > 0) + sockaddr.sin.sin_port = port; + } + else +# endif /* NETINET */ +# if NETINET6 + if (family == SMFIA_INET6) + { + if (mi_inet_pton(AF_INET6, s + i, + &sockaddr.sin6.sin6_addr) != 1) + { + smi_log(SMI_LOG_ERR, + "%s: connect[%ld]: mi_inet_pton failed", + g->a_ctx->ctx_smfi->xxfi_name, + (long) g->a_ctx->ctx_id); + return _SMFIS_ABORT; + } + sockaddr.sa.sa_family = AF_INET6; + if (port > 0) + sockaddr.sin6.sin6_port = port; + } + else +# endif /* NETINET6 */ +# if NETUNIX + if (family == SMFIA_UNIX) + { + if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, + sizeof sockaddr.sunix.sun_path) >= + sizeof sockaddr.sunix.sun_path) + { + smi_log(SMI_LOG_ERR, + "%s: connect[%ld]: path too long", + g->a_ctx->ctx_smfi->xxfi_name, + (long) g->a_ctx->ctx_id); + return _SMFIS_ABORT; + } + sockaddr.sunix.sun_family = AF_UNIX; + } + else +# endif /* NETUNIX */ + { + smi_log(SMI_LOG_ERR, + "%s: connect[%ld]: unknown family %d", + g->a_ctx->ctx_smfi->xxfi_name, + (long) g->a_ctx->ctx_id, family); + return _SMFIS_ABORT; + } + } + return (*fi_connect)(g->a_ctx, g->a_buf, + family != SMFIA_UNKNOWN ? &sockaddr : NULL); +} + +/* +** ST_EOH -- end of headers +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_eoh(g) + genarg *g; +{ + sfsistat (*fi_eoh) __P((SMFICTX *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi != NULL && + (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) + return (*fi_eoh)(g->a_ctx); + return SMFIS_CONTINUE; +} + +/* +** ST_DATA -- DATA command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_data(g) + genarg *g; +{ + sfsistat (*fi_data) __P((SMFICTX *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi != NULL && + g->a_ctx->ctx_smfi->xxfi_version > 3 && + (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) + return (*fi_data)(g->a_ctx); + return SMFIS_CONTINUE; +} + +/* +** ST_HELO -- helo/ehlo command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_helo(g) + genarg *g; +{ + sfsistat (*fi_helo) __P((SMFICTX *, char *)); + + if (g == NULL) + return _SMFIS_ABORT; + mi_clr_macros(g->a_ctx, g->a_idx + 1); + if (g->a_ctx->ctx_smfi != NULL && + (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) + { + /* paranoia: check for terminating '\0' */ + if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') + return MI_FAILURE; + return (*fi_helo)(g->a_ctx, g->a_buf); + } + return SMFIS_CONTINUE; +} + +/* +** ST_HEADER -- header line +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_header(g) + genarg *g; +{ + char *hf, *hv; + sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi == NULL || + (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) + return SMFIS_CONTINUE; + if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) + return (*fi_header)(g->a_ctx, hf, hv); + else + return _SMFIS_ABORT; +} + +#define ARGV_FCT(lf, rf, idx) \ + char **argv; \ + sfsistat (*lf) __P((SMFICTX *, char **)); \ + int r; \ + \ + if (g == NULL) \ + return _SMFIS_ABORT; \ + mi_clr_macros(g->a_ctx, g->a_idx + 1); \ + if (g->a_ctx->ctx_smfi == NULL || \ + (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ + return SMFIS_CONTINUE; \ + if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ + return _SMFIS_ABORT; \ + r = (*lf)(g->a_ctx, argv); \ + free(argv); \ + return r; + +/* +** ST_SENDER -- MAIL FROM command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_sender(g) + genarg *g; +{ + ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) +} + +/* +** ST_RCPT -- RCPT TO command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_rcpt(g) + genarg *g; +{ + ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) +} + +/* +** ST_UNKNOWN -- unrecognized or unimplemented command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_unknown(g) + genarg *g; +{ + sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi != NULL && + g->a_ctx->ctx_smfi->xxfi_version > 2 && + (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) + return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); + return SMFIS_CONTINUE; +} + +/* +** ST_MACROS -- deal with macros received from the MTA +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue/keep +** +** Side effects: +** set pointer in macro array to current values. +*/ + +static int +st_macros(g) + genarg *g; +{ + int i; + char **argv; + + if (g == NULL || g->a_len < 1) + return _SMFIS_FAIL; + if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) + return _SMFIS_FAIL; + switch (g->a_buf[0]) + { + case SMFIC_CONNECT: + i = CI_CONN; + break; + case SMFIC_HELO: + i = CI_HELO; + break; + case SMFIC_MAIL: + i = CI_MAIL; + break; + case SMFIC_RCPT: + i = CI_RCPT; + break; + case SMFIC_DATA: + i = CI_DATA; + break; + case SMFIC_BODYEOB: + i = CI_EOM; + break; + case SMFIC_EOH: + i = CI_EOH; + break; + default: + free(argv); + return _SMFIS_FAIL; + } + if (g->a_ctx->ctx_mac_ptr[i] != NULL) + free(g->a_ctx->ctx_mac_ptr[i]); + if (g->a_ctx->ctx_mac_buf[i] != NULL) + free(g->a_ctx->ctx_mac_buf[i]); + g->a_ctx->ctx_mac_ptr[i] = argv; + g->a_ctx->ctx_mac_buf[i] = g->a_buf; + return _SMFIS_KEEP; +} + +/* +** ST_QUIT -- quit command +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** noreply +*/ + +/* ARGSUSED */ +static int +st_quit(g) + genarg *g; +{ + sfsistat (*fi_close) __P((SMFICTX *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi != NULL && + (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) + (void) (*fi_close)(g->a_ctx); + mi_clr_macros(g->a_ctx, 0); + return _SMFIS_NOREPLY; +} + +/* +** ST_BODYCHUNK -- deal with a piece of the mail body +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +*/ + +static int +st_bodychunk(g) + genarg *g; +{ + sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g->a_ctx->ctx_smfi != NULL && + (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) + return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, + g->a_len); + return SMFIS_CONTINUE; +} + +/* +** ST_BODYEND -- deal with the last piece of the mail body +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** continue or filter-specified value +** +** Side effects: +** sends a reply for the body part (if non-empty). +*/ + +static int +st_bodyend(g) + genarg *g; +{ + sfsistat r; + sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); + sfsistat (*fi_eom) __P((SMFICTX *)); + + if (g == NULL) + return _SMFIS_ABORT; + r = SMFIS_CONTINUE; + if (g->a_ctx->ctx_smfi != NULL) + { + if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && + g->a_len > 0) + { + socket_t sd; + struct timeval timeout; + + timeout.tv_sec = g->a_ctx->ctx_timeout; + timeout.tv_usec = 0; + sd = g->a_ctx->ctx_sd; + r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, + g->a_len); + if (r != SMFIS_CONTINUE && + sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) + return _SMFIS_ABORT; + } + } + if (r == SMFIS_CONTINUE && + (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) + return (*fi_eom)(g->a_ctx); + return r; +} + +/* +** ST_ABORTFCT -- deal with aborts +** +** Parameters: +** g -- generic argument structure +** +** Returns: +** abort or filter-specified value +*/ + +static int +st_abortfct(g) + genarg *g; +{ + sfsistat (*fi_abort) __P((SMFICTX *)); + + if (g == NULL) + return _SMFIS_ABORT; + if (g != NULL && g->a_ctx->ctx_smfi != NULL && + (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) + (void) (*fi_abort)(g->a_ctx); + return _SMFIS_NOREPLY; +} + +/* +** TRANS_OK -- is the state transition ok? +** +** Parameters: +** old -- old state +** new -- new state +** +** Returns: +** state transition ok +*/ + +static bool +trans_ok(old, new) + int old, new; +{ + int s, n; + + s = old; + if (s >= SIZE_NEXT_STATES) + return false; + do + { + /* is this state transition allowed? */ + if ((MI_MASK(new) & next_states[s]) != 0) + return true; + + /* + ** no: try next state; + ** this works since the relevant states are ordered + ** strict sequentially + */ + + n = s + 1; + if (n >= SIZE_NEXT_STATES) + return false; + + /* + ** can we actually "skip" this state? + ** see fix_stm() which sets this bit for those + ** states which the filter program is not interested in + */ + + if (bitset(NX_SKIP, next_states[n])) + s = n; + else + return false; + } while (s < SIZE_NEXT_STATES); + return false; +} + +/* +** FIX_STM -- add "skip" bits to the state transition table +** +** Parameters: +** ctx -- context structure +** +** Returns: +** None. +** +** Side effects: +** may change state transition table. +*/ + +static void +fix_stm(ctx) + SMFICTX_PTR ctx; +{ + unsigned long fl; + + if (ctx == NULL || ctx->ctx_smfi == NULL) + return; + fl = ctx->ctx_pflags; + if (bitset(SMFIP_NOCONNECT, fl)) + next_states[ST_CONN] |= NX_SKIP; + if (bitset(SMFIP_NOHELO, fl)) + next_states[ST_HELO] |= NX_SKIP; + if (bitset(SMFIP_NOMAIL, fl)) + next_states[ST_MAIL] |= NX_SKIP; + if (bitset(SMFIP_NORCPT, fl)) + next_states[ST_RCPT] |= NX_SKIP; + if (bitset(SMFIP_NOHDRS, fl)) + next_states[ST_HDRS] |= NX_SKIP; + if (bitset(SMFIP_NOEOH, fl)) + next_states[ST_EOHS] |= NX_SKIP; + if (bitset(SMFIP_NOBODY, fl)) + next_states[ST_BODY] |= NX_SKIP; + if (bitset(SMFIP_NODATA, fl)) + next_states[ST_DATA] |= NX_SKIP; + if (bitset(SMFIP_NOUNKNOWN, fl)) + next_states[ST_UNKN] |= NX_SKIP; +} + +/* +** DEC_ARGV -- split a buffer into a list of strings, NULL terminated +** +** Parameters: +** buf -- buffer with several strings +** len -- length of buffer +** +** Returns: +** array of pointers to the individual strings +*/ + +static char ** +dec_argv(buf, len) + char *buf; + size_t len; +{ + char **s; + size_t i; + int elem, nelem; + + nelem = 0; + for (i = 0; i < len; i++) + { + if (buf[i] == '\0') + ++nelem; + } + if (nelem == 0) + return NULL; + + /* last entry is only for the name */ + s = (char **)malloc((nelem + 1) * (sizeof *s)); + if (s == NULL) + return NULL; + s[0] = buf; + for (i = 0, elem = 0; i < len && elem < nelem; i++) + { + if (buf[i] == '\0') + { + ++elem; + if (i + 1 >= len) + s[elem] = NULL; + else + s[elem] = &(buf[i + 1]); + } + } + + /* overwrite last entry (already done above, just paranoia) */ + s[elem] = NULL; + return s; +} + +/* +** DEC_ARG2 -- split a buffer into two strings +** +** Parameters: +** buf -- buffer with two strings +** len -- length of buffer +** s1,s2 -- pointer to result strings +** +** Returns: +** MI_FAILURE/MI_SUCCESS +*/ + +static int +dec_arg2(buf, len, s1, s2) + char *buf; + size_t len; + char **s1; + char **s2; +{ + size_t i; + + /* paranoia: check for terminating '\0' */ + if (len == 0 || buf[len - 1] != '\0') + return MI_FAILURE; + *s1 = buf; + for (i = 1; i < len && buf[i] != '\0'; i++) + continue; + if (i >= len - 1) + return MI_FAILURE; + *s2 = buf + i + 1; + return MI_SUCCESS; +} + +/* +** SENDOK -- is it ok for the filter to send stuff to the MTA? +** +** Parameters: +** ctx -- context structure +** flag -- flag to check +** +** Returns: +** sending allowed (in current state) +*/ + +bool +mi_sendok(ctx, flag) + SMFICTX_PTR ctx; + int flag; +{ + if (ctx == NULL || ctx->ctx_smfi == NULL) + return false; + + /* did the milter request this operation? */ + if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) + return false; + + /* are we in the correct state? It must be "End of Message". */ + return ctx->ctx_state == ST_ENDM; +} + +#if _FFR_WORKERS_POOL +/* +** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) +** +** Parameters: +** sd -- socket_t +** +** Returns: +** true iff socket is ready for read(2) +*/ + +#define MI_RD_CMD_TO 1 +#define MI_RD_MAX_ERR 16 + +static bool +mi_rd_socket_ready (sd) + socket_t sd; +{ + int n; + int nerr = 0; +#if SM_CONF_POLL + struct pollfd pfd; +#else /* SM_CONF_POLL */ + fd_set rd_set, exc_set; +#endif /* SM_CONF_POLL */ + + do + { +#if SM_CONF_POLL + pfd.fd = sd; + pfd.events = POLLIN; + pfd.revents = 0; + + n = poll(&pfd, 1, MI_RD_CMD_TO); +#else /* SM_CONF_POLL */ + struct timeval timeout; + + FD_ZERO(&rd_set); + FD_ZERO(&exc_set); + FD_SET(sd, &rd_set); + FD_SET(sd, &exc_set); + + timeout.tv_sec = MI_RD_CMD_TO / 1000; + timeout.tv_usec = 0; + n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); +#endif /* SM_CONF_POLL */ + + if (n < 0) + { + if (errno == EINTR) + { + nerr++; + continue; + } + return true; + } + + if (n == 0) + return false; + break; + } while (nerr < MI_RD_MAX_ERR); + if (nerr >= MI_RD_MAX_ERR) + return false; + +#if SM_CONF_POLL + return (pfd.revents != 0); +#else /* SM_CONF_POLL */ + return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); +#endif /* SM_CONF_POLL */ +} +#endif /* _FFR_WORKERS_POOL */ diff --git a/contrib/sendmail/libmilter/example.c b/contrib/sendmail/libmilter/example.c new file mode 100644 index 0000000..cef4b0f --- /dev/null +++ b/contrib/sendmail/libmilter/example.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + * $Id: example.c,v 8.4 2008/07/22 15:12:47 ca Exp $ + */ + +/* +** A trivial example filter that logs all email to a file. +** This milter also has some callbacks which it does not really use, +** but they are defined to serve as an example. +*/ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include "libmilter/mfapi.h" +#include "libmilter/mfdef.h" + +#ifndef true +# define false 0 +# define true 1 +#endif /* ! true */ + +struct mlfiPriv +{ + char *mlfi_fname; + FILE *mlfi_fp; +}; + +#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) + +static unsigned long mta_caps = 0; + +sfsistat +mlfi_cleanup(ctx, ok) + SMFICTX *ctx; + bool ok; +{ + sfsistat rstat = SMFIS_CONTINUE; + struct mlfiPriv *priv = MLFIPRIV; + char *p; + char host[512]; + char hbuf[1024]; + + if (priv == NULL) + return rstat; + + /* close the archive file */ + if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) + { + /* failed; we have to wait until later */ + rstat = SMFIS_TEMPFAIL; + (void) unlink(priv->mlfi_fname); + } + else if (ok) + { + /* add a header to the message announcing our presence */ + if (gethostname(host, sizeof host) < 0) + snprintf(host, sizeof host, "localhost"); + p = strrchr(priv->mlfi_fname, '/'); + if (p == NULL) + p = priv->mlfi_fname; + else + p++; + snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); + smfi_addheader(ctx, "X-Archived", hbuf); + } + else + { + /* message was aborted -- delete the archive file */ + (void) unlink(priv->mlfi_fname); + } + + /* release private memory */ + free(priv->mlfi_fname); + free(priv); + smfi_setpriv(ctx, NULL); + + /* return status */ + return rstat; +} + + +sfsistat +mlfi_envfrom(ctx, envfrom) + SMFICTX *ctx; + char **envfrom; +{ + struct mlfiPriv *priv; + int fd = -1; + + /* allocate some private memory */ + priv = malloc(sizeof *priv); + if (priv == NULL) + { + /* can't accept this message right now */ + return SMFIS_TEMPFAIL; + } + memset(priv, '\0', sizeof *priv); + + /* open a file to store this message */ + priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX"); + if (priv->mlfi_fname == NULL) + { + free(priv); + return SMFIS_TEMPFAIL; + } + if ((fd = mkstemp(priv->mlfi_fname)) < 0 || + (priv->mlfi_fp = fdopen(fd, "w+")) == NULL) + { + if (fd >= 0) + (void) close(fd); + free(priv->mlfi_fname); + free(priv); + return SMFIS_TEMPFAIL; + } + + /* save the private data */ + smfi_setpriv(ctx, priv); + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +mlfi_header(ctx, headerf, headerv) + SMFICTX *ctx; + char *headerf; + char *headerv; +{ + /* write the header to the log file */ + fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv); + + /* continue processing */ + return ((mta_caps & SMFIP_NR_HDR) != 0) + ? SMFIS_NOREPLY : SMFIS_CONTINUE; +} + +sfsistat +mlfi_eoh(ctx) + SMFICTX *ctx; +{ + /* output the blank line between the header and the body */ + fprintf(MLFIPRIV->mlfi_fp, "\r\n"); + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +mlfi_body(ctx, bodyp, bodylen) + SMFICTX *ctx; + u_char *bodyp; + size_t bodylen; +{ + /* output body block to log file */ + if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0) + { + /* write failed */ + (void) mlfi_cleanup(ctx, false); + return SMFIS_TEMPFAIL; + } + + /* continue processing */ + return SMFIS_CONTINUE; +} + +sfsistat +mlfi_eom(ctx) + SMFICTX *ctx; +{ + return mlfi_cleanup(ctx, true); +} + +sfsistat +mlfi_close(ctx) + SMFICTX *ctx; +{ + return SMFIS_ACCEPT; +} + +sfsistat +mlfi_abort(ctx) + SMFICTX *ctx; +{ + return mlfi_cleanup(ctx, false); +} + +sfsistat +mlfi_unknown(ctx, cmd) + SMFICTX *ctx; + char *cmd; +{ + return SMFIS_CONTINUE; +} + +sfsistat +mlfi_data(ctx) + SMFICTX *ctx; +{ + return SMFIS_CONTINUE; +} + +sfsistat +mlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3) + SMFICTX *ctx; + unsigned long f0; + unsigned long f1; + unsigned long f2; + unsigned long f3; + unsigned long *pf0; + unsigned long *pf1; + unsigned long *pf2; + unsigned long *pf3; +{ + /* milter actions: add headers */ + *pf0 = SMFIF_ADDHDRS; + + /* milter protocol steps: all but connect, HELO, RCPT */ + *pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT; + mta_caps = f1; + if ((mta_caps & SMFIP_NR_HDR) != 0) + *pf1 |= SMFIP_NR_HDR; + *pf2 = 0; + *pf3 = 0; + return SMFIS_CONTINUE; +} + +struct smfiDesc smfilter = +{ + "SampleFilter", /* filter name */ + SMFI_VERSION, /* version code -- do not change */ + SMFIF_ADDHDRS, /* flags */ + NULL, /* connection info filter */ + NULL, /* SMTP HELO command filter */ + mlfi_envfrom, /* envelope sender filter */ + NULL, /* envelope recipient filter */ + mlfi_header, /* header filter */ + mlfi_eoh, /* end of header */ + mlfi_body, /* body block filter */ + mlfi_eom, /* end of message */ + mlfi_abort, /* message aborted */ + mlfi_close, /* connection cleanup */ + mlfi_unknown, /* unknown/unimplemented SMTP commands */ + mlfi_data, /* DATA command filter */ + mlfi_negotiate /* option negotiation at connection startup */ +}; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + bool setconn; + int c; + + setconn = false; + + /* Process command line options */ + while ((c = getopt(argc, argv, "p:")) != -1) + { + switch (c) + { + case 'p': + if (optarg == NULL || *optarg == '\0') + { + (void) fprintf(stderr, "Illegal conn: %s\n", + optarg); + exit(EX_USAGE); + } + (void) smfi_setconn(optarg); + setconn = true; + break; + + } + } + if (!setconn) + { + fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); + exit(EX_USAGE); + } + if (smfi_register(smfilter) == MI_FAILURE) + { + fprintf(stderr, "smfi_register failed\n"); + exit(EX_UNAVAILABLE); + } + return smfi_main(); +} + diff --git a/contrib/sendmail/libmilter/handler.c b/contrib/sendmail/libmilter/handler.c new file mode 100644 index 0000000..2c34f1f --- /dev/null +++ b/contrib/sendmail/libmilter/handler.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1999-2003, 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: handler.c,v 8.39 2008/11/25 01:14:16 ca Exp $") + +#include "libmilter.h" + +#if !_FFR_WORKERS_POOL +/* +** HANDLE_SESSION -- Handle a connected session in its own context +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_handle_session(ctx) + SMFICTX_PTR ctx; +{ + int ret; + + if (ctx == NULL) + return MI_FAILURE; + ctx->ctx_id = (sthread_t) sthread_get_id(); + + /* + ** Detach so resources are free when the thread returns. + ** If we ever "wait" for threads, this call must be removed. + */ + + if (pthread_detach(ctx->ctx_id) != 0) + ret = MI_FAILURE; + else + ret = mi_engine(ctx); + mi_clr_ctx(ctx); + ctx = NULL; + return ret; +} +#endif /* !_FFR_WORKERS_POOL */ diff --git a/contrib/sendmail/libmilter/libmilter.h b/contrib/sendmail/libmilter/libmilter.h new file mode 100644 index 0000000..5824151 --- /dev/null +++ b/contrib/sendmail/libmilter/libmilter.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1999-2003, 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + */ + +/* +** LIBMILTER.H -- include file for mail filter library functions +*/ + +#ifndef _LIBMILTER_H +# define _LIBMILTER_H 1 + +#include <sm/gen.h> + +#ifdef _DEFINE +# define EXTERN +# define INIT(x) = x +SM_IDSTR(MilterlId, "@(#)$Id: libmilter.h,v 8.77 2008/11/25 18:28:18 ca Exp $") +#else /* _DEFINE */ +# define EXTERN extern +# define INIT(x) +#endif /* _DEFINE */ + + +#include "sm/tailq.h" + +#define NOT_SENDMAIL 1 +#define _SOCK_ADDR union bigsockaddr +#include "sendmail.h" + +#ifdef SM_ASSERT +#undef SM_ASSERT +#endif +#ifndef SM_ASSERT +#include <assert.h> +#define SM_ASSERT(x) assert(x) +#endif + +#include "libmilter/milter.h" + +#define MAX_MACROS_ENTRIES 7 /* max size of macro pointer array */ + +typedef SM_TAILQ_HEAD(, smfi_str) smfi_hd_T; +typedef struct smfi_str smfi_str_S; + +/* +** Context for one milter session. +** +** Notes: +** There is a 1-1 correlation between a sendmail SMTP server process, +** an SMTP session, and an milter context. Due to the nature of SMTP +** session handling in sendmail 8, this libmilter implementation deals +** only with a single SMTP session per MTA - libmilter connection. +** +** There is no "global" context for libmilter, global variables are +** just that (they are not "collected" in a context). +** +** Implementation hint: +** macros are stored in mac_buf[] as sequence of: +** macro_name \0 macro_value +** (just as read from the MTA) +** mac_ptr is a list of pointers into mac_buf to the beginning of each +** entry, i.e., macro_name, macro_value, ... +*/ + +struct smfi_str +{ + sthread_t ctx_id; /* thread id */ + socket_t ctx_sd; /* socket descriptor */ + int ctx_dbg; /* debug level */ + time_t ctx_timeout; /* timeout */ + int ctx_state; /* state */ + smfiDesc_ptr ctx_smfi; /* filter description */ + + int ctx_prot_vers; /* libmilter protocol version */ + unsigned long ctx_aflags; /* milter action flags */ + + unsigned long ctx_pflags; /* milter protocol flags */ + + /* + ** milter protocol flags that are sent to the MTA; + ** this is the same as ctx_pflags except for those flags that + ** are not offered by the MTA but emulated in libmilter. + */ + + unsigned long ctx_pflags2mta; + + /* + ** milter protocol version that is sent to the MTA; + ** this is the same as ctx_prot_vers unless the + ** MTA protocol version (ctx_mta_prot_vers) is smaller + ** but still "acceptable". + */ + + int ctx_prot_vers2mta; + + char **ctx_mac_ptr[MAX_MACROS_ENTRIES]; + char *ctx_mac_buf[MAX_MACROS_ENTRIES]; + char *ctx_mac_list[MAX_MACROS_ENTRIES]; + char *ctx_reply; /* reply code */ + void *ctx_privdata; /* private data */ + + int ctx_mta_prot_vers; /* MTA protocol version */ + unsigned long ctx_mta_pflags; /* MTA protocol flags */ + unsigned long ctx_mta_aflags; /* MTA action flags */ + +#if _FFR_THREAD_MONITOR + time_t ctx_start; /* start time of thread */ + SM_TAILQ_ENTRY(smfi_str) ctx_mon_link; +#endif /* _FFR_THREAD_MONITOR */ + +#if _FFR_WORKERS_POOL + long ctx_sid; /* session identifier */ + int ctx_wstate; /* state of the session (worker pool) */ + int ctx_wait; /* elapsed time waiting for sm cmd */ + SM_TAILQ_ENTRY(smfi_str) ctx_link; +#endif /* _FFR_WORKERS_POOL */ +}; + +# define ValidSocket(sd) ((sd) >= 0) +# define INVALID_SOCKET (-1) +# define closesocket close +# define MI_SOCK_READ(s, b, l) read(s, b, l) +# define MI_SOCK_READ_FAIL(x) ((x) < 0) +# define MI_SOCK_WRITE(s, b, l) write(s, b, l) + +# define thread_create(ptid,wr,arg) pthread_create(ptid, NULL, wr, arg) +# define sthread_get_id() pthread_self() + +typedef pthread_mutex_t smutex_t; +# define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) +# define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) +# define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) +# define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) +# define smutex_trylock(mp) (pthread_mutex_trylock(mp) == 0) + +#if _FFR_WORKERS_POOL +/* SM_CONF_POLL shall be defined with _FFR_WORKERS_POOL */ +# if !SM_CONF_POLL +# define SM_CONF_POLL 1 +# endif /* SM_CONF_POLL */ +#endif /* _FFR_WORKERS_POOL */ + +typedef pthread_cond_t scond_t; +#define scond_init(cp) pthread_cond_init(cp, NULL) +#define scond_destroy(cp) pthread_cond_destroy(cp) +#define scond_wait(cp, mp) pthread_cond_wait(cp, mp) +#define scond_signal(cp) pthread_cond_signal(cp) +#define scond_broadcast(cp) pthread_cond_broadcast(cp) +#define scond_timedwait(cp, mp, to) \ + do \ + { \ + struct timespec timeout; \ + struct timeval now; \ + gettimeofday(&now, NULL); \ + timeout.tv_sec = now.tv_sec + to; \ + timeout.tv_nsec = now.tv_usec / 1000; \ + r = pthread_cond_timedwait(cp,mp,&timeout); \ + if (r != 0 && r != ETIMEDOUT) \ + smi_log(SMI_LOG_ERR, \ + "pthread_cond_timedwait error %d", r); \ + } while (0) + + +#if SM_CONF_POLL + +# include <poll.h> +# define MI_POLLSELECT "poll" + +# define MI_POLL_RD_FLAGS (POLLIN | POLLPRI) +# define MI_POLL_WR_FLAGS (POLLOUT) +# define MI_MS(timeout) (((timeout)->tv_sec * 1000) + (timeout)->tv_usec) + +# define FD_RD_VAR(rds, excs) struct pollfd rds +# define FD_WR_VAR(wrs) struct pollfd wrs + +# define FD_RD_INIT(sd, rds, excs) \ + (rds).fd = (sd); \ + (rds).events = MI_POLL_RD_FLAGS; \ + (rds).revents = 0 + +# define FD_WR_INIT(sd, wrs) \ + (wrs).fd = (sd); \ + (wrs).events = MI_POLL_WR_FLAGS; \ + (wrs).revents = 0 + +# define FD_IS_RD_EXC(sd, rds, excs) \ + (((rds).revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) + +# define FD_IS_WR_RDY(sd, wrs) \ + (((wrs).revents & MI_POLL_WR_FLAGS) != 0) + +# define FD_IS_RD_RDY(sd, rds, excs) \ + (((rds).revents & MI_POLL_RD_FLAGS) != 0) + +# define FD_WR_READY(sd, excs, timeout) \ + poll(&(wrs), 1, MI_MS(timeout)) + +# define FD_RD_READY(sd, rds, excs, timeout) \ + poll(&(rds), 1, MI_MS(timeout)) + +#else /* SM_CONF_POLL */ + +# include <sm/fdset.h> +# define MI_POLLSELECT "select" + +# define FD_RD_VAR(rds, excs) fd_set rds, excs +# define FD_WR_VAR(wrs) fd_set wrs + +# define FD_RD_INIT(sd, rds, excs) \ + FD_ZERO(&(rds)); \ + FD_SET((unsigned int) (sd), &(rds)); \ + FD_ZERO(&(excs)); \ + FD_SET((unsigned int) (sd), &(excs)) + +# define FD_WR_INIT(sd, wrs) \ + FD_ZERO(&(wrs)); \ + FD_SET((unsigned int) (sd), &(wrs)) + +# define FD_IS_RD_EXC(sd, rds, excs) FD_ISSET(sd, &(excs)) +# define FD_IS_WR_RDY(sd, wrs) FD_ISSET((sd), &(wrs)) +# define FD_IS_RD_RDY(sd, rds, excs) FD_ISSET((sd), &(rds)) + +# define FD_WR_READY(sd, wrs, timeout) \ + select((sd) + 1, NULL, &(wrs), NULL, (timeout)) +# define FD_RD_READY(sd, rds, excs, timeout) \ + select((sd) + 1, &(rds), NULL, &(excs), (timeout)) + +#endif /* SM_CONF_POLL */ + +#include <sys/time.h> + +/* some defaults */ +#define MI_TIMEOUT 7210 /* default timeout for read/write */ +#define MI_CHK_TIME 5 /* checking whether to terminate */ + +#ifndef MI_SOMAXCONN +# if SOMAXCONN > 20 +# define MI_SOMAXCONN SOMAXCONN +# else /* SOMAXCONN */ +# define MI_SOMAXCONN 20 +# endif /* SOMAXCONN */ +#endif /* ! MI_SOMAXCONN */ + +/* maximum number of repeated failures in mi_listener() */ +#define MAX_FAILS_M 16 /* malloc() */ +#define MAX_FAILS_T 16 /* thread creation */ +#define MAX_FAILS_A 16 /* accept() */ +#define MAX_FAILS_S 16 /* select() */ + +/* internal "commands", i.e., error codes */ +#define SMFIC_TIMEOUT ((char) 1) /* timeout */ +#define SMFIC_SELECT ((char) 2) /* select error */ +#define SMFIC_MALLOC ((char) 3) /* malloc error */ +#define SMFIC_RECVERR ((char) 4) /* recv() error */ +#define SMFIC_EOF ((char) 5) /* eof */ +#define SMFIC_UNKNERR ((char) 6) /* unknown error */ +#define SMFIC_TOOBIG ((char) 7) /* body chunk too big */ +#define SMFIC_VALIDCMD ' ' /* first valid command */ + +/* hack */ +#define smi_log syslog +#define sm_dprintf (void) printf +#define milter_ret int +#define SMI_LOG_ERR LOG_ERR +#define SMI_LOG_FATAL LOG_ERR +#define SMI_LOG_WARN LOG_WARNING +#define SMI_LOG_INFO LOG_INFO +#define SMI_LOG_DEBUG LOG_DEBUG + +/* stop? */ +#define MILTER_CONT 0 +#define MILTER_STOP 1 +#define MILTER_ABRT 2 + +/* functions */ +extern int mi_handle_session __P((SMFICTX_PTR)); +extern int mi_engine __P((SMFICTX_PTR)); +extern int mi_listener __P((char *, int, smfiDesc_ptr, time_t, int)); +extern void mi_clr_macros __P((SMFICTX_PTR, int)); +extern void mi_clr_ctx __P((SMFICTX_PTR)); +extern int mi_stop __P((void)); +extern int mi_control_startup __P((char *)); +extern void mi_stop_milters __P((int)); +extern void mi_clean_signals __P((void)); +extern struct hostent *mi_gethostbyname __P((char *, int)); +extern int mi_inet_pton __P((int, const char *, void *)); +extern void mi_closener __P((void)); +extern int mi_opensocket __P((char *, int, int, bool, smfiDesc_ptr)); + +/* communication functions */ +extern char *mi_rd_cmd __P((socket_t, struct timeval *, char *, size_t *, char *)); +extern int mi_wr_cmd __P((socket_t, struct timeval *, int, char *, size_t)); +extern bool mi_sendok __P((SMFICTX_PTR, int)); + + +#if _FFR_THREAD_MONITOR +extern bool Monitor; + +#define MI_MONITOR_INIT() mi_monitor_init() +#define MI_MONITOR_BEGIN(ctx, cmd) \ + do \ + { \ + if (Monitor) \ + mi_monitor_work_begin(ctx, cmd);\ + } while (0) + +#define MI_MONITOR_END(ctx, cmd) \ + do \ + { \ + if (Monitor) \ + mi_monitor_work_end(ctx, cmd); \ + } while (0) + +int mi_monitor_init __P((void)); +int mi_monitor_work_begin __P((SMFICTX_PTR, int)); +int mi_monitor_work_end __P((SMFICTX_PTR, int)); + +#else /* _FFR_THREAD_MONITOR */ +#define MI_MONITOR_INIT() MI_SUCCESS +#define MI_MONITOR_BEGIN(ctx, cmd) +#define MI_MONITOR_END(ctx, cmd) +#endif /* _FFR_THREAD_MONITOR */ + +#if _FFR_WORKERS_POOL +extern int mi_pool_manager_init __P((void)); +extern int mi_pool_controller_init __P((void)); +extern int mi_start_session __P((SMFICTX_PTR)); +#endif /* _FFR_WORKERS_POOL */ + +#endif /* ! _LIBMILTER_H */ diff --git a/contrib/sendmail/libmilter/listener.c b/contrib/sendmail/libmilter/listener.c new file mode 100644 index 0000000..48c552f --- /dev/null +++ b/contrib/sendmail/libmilter/listener.c @@ -0,0 +1,974 @@ +/* + * Copyright (c) 1999-2007 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: listener.c,v 8.126 2009/12/16 16:40:23 ca Exp $") + +/* +** listener.c -- threaded network listener +*/ + +#include "libmilter.h" +#include <sm/errstring.h> + +#include <sys/types.h> +#include <sys/stat.h> + + +# if NETINET || NETINET6 +# include <arpa/inet.h> +# endif /* NETINET || NETINET6 */ +# if SM_CONF_POLL +# undef SM_FD_OK_SELECT +# define SM_FD_OK_SELECT(fd) true +# endif /* SM_CONF_POLL */ + +static smutex_t L_Mutex; +static int L_family; +static SOCKADDR_LEN_T L_socksize; +static socket_t listenfd = INVALID_SOCKET; + +static socket_t mi_milteropen __P((char *, int, bool, char *)); +#if !_FFR_WORKERS_POOL +static void *mi_thread_handle_wrapper __P((void *)); +#endif /* !_FFR_WORKERS_POOL */ + +/* +** MI_OPENSOCKET -- create the socket where this filter and the MTA will meet +** +** Parameters: +** conn -- connection description +** backlog -- listen backlog +** dbg -- debug level +** rmsocket -- if true, try to unlink() the socket first +** (UNIX domain sockets only) +** smfi -- filter structure to use +** +** Return value: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_opensocket(conn, backlog, dbg, rmsocket, smfi) + char *conn; + int backlog; + int dbg; + bool rmsocket; + smfiDesc_ptr smfi; +{ + if (smfi == NULL || conn == NULL) + return MI_FAILURE; + + if (ValidSocket(listenfd)) + return MI_SUCCESS; + + if (dbg > 0) + { + smi_log(SMI_LOG_DEBUG, + "%s: Opening listen socket on conn %s", + smfi->xxfi_name, conn); + } + (void) smutex_init(&L_Mutex); + (void) smutex_lock(&L_Mutex); + listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name); + if (!ValidSocket(listenfd)) + { + smi_log(SMI_LOG_FATAL, + "%s: Unable to create listening socket on conn %s", + smfi->xxfi_name, conn); + (void) smutex_unlock(&L_Mutex); + return MI_FAILURE; + } + if (!SM_FD_OK_SELECT(listenfd)) + { + smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", + smfi->xxfi_name, listenfd, FD_SETSIZE); + (void) smutex_unlock(&L_Mutex); + return MI_FAILURE; + } + (void) smutex_unlock(&L_Mutex); + return MI_SUCCESS; +} + +/* +** MI_MILTEROPEN -- setup socket to listen on +** +** Parameters: +** conn -- connection description +** backlog -- listen backlog +** rmsocket -- if true, try to unlink() the socket first +** (UNIX domain sockets only) +** name -- name for logging +** +** Returns: +** socket upon success, error code otherwise. +** +** Side effect: +** sets sockpath if UNIX socket. +*/ + +#if NETUNIX +static char *sockpath = NULL; +#endif /* NETUNIX */ + +static socket_t +mi_milteropen(conn, backlog, rmsocket, name) + char *conn; + int backlog; + bool rmsocket; + char *name; +{ + socket_t sock; + int sockopt = 1; + int fdflags; + size_t len = 0; + char *p; + char *colon; + char *at; + SOCKADDR addr; + + if (conn == NULL || conn[0] == '\0') + { + smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", + name); + return INVALID_SOCKET; + } + (void) memset(&addr, '\0', sizeof addr); + + /* protocol:filename or protocol:port@host */ + p = conn; + colon = strchr(p, ':'); + if (colon != NULL) + { + *colon = '\0'; + + if (*p == '\0') + { +#if NETUNIX + /* default to AF_UNIX */ + addr.sa.sa_family = AF_UNIX; + L_socksize = sizeof (struct sockaddr_un); +#else /* NETUNIX */ +# if NETINET + /* default to AF_INET */ + addr.sa.sa_family = AF_INET; + L_socksize = sizeof addr.sin; +# else /* NETINET */ +# if NETINET6 + /* default to AF_INET6 */ + addr.sa.sa_family = AF_INET6; + L_socksize = sizeof addr.sin6; +# else /* NETINET6 */ + /* no protocols available */ + smi_log(SMI_LOG_ERR, + "%s: no valid socket protocols available", + name); + return INVALID_SOCKET; +# endif /* NETINET6 */ +# endif /* NETINET */ +#endif /* NETUNIX */ + } +#if NETUNIX + else if (strcasecmp(p, "unix") == 0 || + strcasecmp(p, "local") == 0) + { + addr.sa.sa_family = AF_UNIX; + L_socksize = sizeof (struct sockaddr_un); + } +#endif /* NETUNIX */ +#if NETINET + else if (strcasecmp(p, "inet") == 0) + { + addr.sa.sa_family = AF_INET; + L_socksize = sizeof addr.sin; + } +#endif /* NETINET */ +#if NETINET6 + else if (strcasecmp(p, "inet6") == 0) + { + addr.sa.sa_family = AF_INET6; + L_socksize = sizeof addr.sin6; + } +#endif /* NETINET6 */ + else + { + smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", + name, p); + return INVALID_SOCKET; + } + *colon++ = ':'; + } + else + { + colon = p; +#if NETUNIX + /* default to AF_UNIX */ + addr.sa.sa_family = AF_UNIX; + L_socksize = sizeof (struct sockaddr_un); +#else /* NETUNIX */ +# if NETINET + /* default to AF_INET */ + addr.sa.sa_family = AF_INET; + L_socksize = sizeof addr.sin; +# else /* NETINET */ +# if NETINET6 + /* default to AF_INET6 */ + addr.sa.sa_family = AF_INET6; + L_socksize = sizeof addr.sin6; +# else /* NETINET6 */ + smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", + name, p); + return INVALID_SOCKET; +# endif /* NETINET6 */ +# endif /* NETINET */ +#endif /* NETUNIX */ + } + +#if NETUNIX + if (addr.sa.sa_family == AF_UNIX) + { +# if 0 + long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; +# endif /* 0 */ + + at = colon; + len = strlen(colon) + 1; + if (len >= sizeof addr.sunix.sun_path) + { + errno = EINVAL; + smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", + name, colon); + return INVALID_SOCKET; + } + (void) sm_strlcpy(addr.sunix.sun_path, colon, + sizeof addr.sunix.sun_path); +# if 0 + errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, + S_IRUSR|S_IWUSR, NULL); + + /* if not safe, don't create */ + if (errno != 0) + { + smi_log(SMI_LOG_ERR, + "%s: UNIX socket name %s unsafe", + name, colon); + return INVALID_SOCKET; + } +# endif /* 0 */ + } +#endif /* NETUNIX */ + +#if NETINET || NETINET6 + if ( +# if NETINET + addr.sa.sa_family == AF_INET +# endif /* NETINET */ +# if NETINET && NETINET6 + || +# endif /* NETINET && NETINET6 */ +# if NETINET6 + addr.sa.sa_family == AF_INET6 +# endif /* NETINET6 */ + ) + { + unsigned short port; + + /* Parse port@host */ + at = strchr(colon, '@'); + if (at == NULL) + { + switch (addr.sa.sa_family) + { +# if NETINET + case AF_INET: + addr.sin.sin_addr.s_addr = INADDR_ANY; + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + addr.sin6.sin6_addr = in6addr_any; + break; +# endif /* NETINET6 */ + } + } + else + *at = '\0'; + + if (isascii(*colon) && isdigit(*colon)) + port = htons((unsigned short) atoi(colon)); + else + { +# ifdef NO_GETSERVBYNAME + smi_log(SMI_LOG_ERR, "%s: invalid port number %s", + name, colon); + return INVALID_SOCKET; +# else /* NO_GETSERVBYNAME */ + register struct servent *sp; + + sp = getservbyname(colon, "tcp"); + if (sp == NULL) + { + smi_log(SMI_LOG_ERR, + "%s: unknown port name %s", + name, colon); + return INVALID_SOCKET; + } + port = sp->s_port; +# endif /* NO_GETSERVBYNAME */ + } + if (at != NULL) + { + *at++ = '@'; + if (*at == '[') + { + char *end; + + end = strchr(at, ']'); + if (end != NULL) + { + bool found = false; +# if NETINET + unsigned long hid = INADDR_NONE; +# endif /* NETINET */ +# if NETINET6 + struct sockaddr_in6 hid6; +# endif /* NETINET6 */ + + *end = '\0'; +# if NETINET + if (addr.sa.sa_family == AF_INET && + (hid = inet_addr(&at[1])) != INADDR_NONE) + { + addr.sin.sin_addr.s_addr = hid; + addr.sin.sin_port = port; + found = true; + } +# endif /* NETINET */ +# if NETINET6 + (void) memset(&hid6, '\0', sizeof hid6); + if (addr.sa.sa_family == AF_INET6 && + mi_inet_pton(AF_INET6, &at[1], + &hid6.sin6_addr) == 1) + { + addr.sin6.sin6_addr = hid6.sin6_addr; + addr.sin6.sin6_port = port; + found = true; + } +# endif /* NETINET6 */ + *end = ']'; + if (!found) + { + smi_log(SMI_LOG_ERR, + "%s: Invalid numeric domain spec \"%s\"", + name, at); + return INVALID_SOCKET; + } + } + else + { + smi_log(SMI_LOG_ERR, + "%s: Invalid numeric domain spec \"%s\"", + name, at); + return INVALID_SOCKET; + } + } + else + { + struct hostent *hp = NULL; + + hp = mi_gethostbyname(at, addr.sa.sa_family); + if (hp == NULL) + { + smi_log(SMI_LOG_ERR, + "%s: Unknown host name %s", + name, at); + return INVALID_SOCKET; + } + addr.sa.sa_family = hp->h_addrtype; + switch (hp->h_addrtype) + { +# if NETINET + case AF_INET: + (void) memmove(&addr.sin.sin_addr, + hp->h_addr, + INADDRSZ); + addr.sin.sin_port = port; + break; +# endif /* NETINET */ + +# if NETINET6 + case AF_INET6: + (void) memmove(&addr.sin6.sin6_addr, + hp->h_addr, + IN6ADDRSZ); + addr.sin6.sin6_port = port; + break; +# endif /* NETINET6 */ + + default: + smi_log(SMI_LOG_ERR, + "%s: Unknown protocol for %s (%d)", + name, at, hp->h_addrtype); + return INVALID_SOCKET; + } +# if NETINET6 + freehostent(hp); +# endif /* NETINET6 */ + } + } + else + { + switch (addr.sa.sa_family) + { +# if NETINET + case AF_INET: + addr.sin.sin_port = port; + break; +# endif /* NETINET */ +# if NETINET6 + case AF_INET6: + addr.sin6.sin6_port = port; + break; +# endif /* NETINET6 */ + } + } + } +#endif /* NETINET || NETINET6 */ + + sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); + if (!ValidSocket(sock)) + { + smi_log(SMI_LOG_ERR, + "%s: Unable to create new socket: %s", + name, sm_errstring(errno)); + return INVALID_SOCKET; + } + + if ((fdflags = fcntl(sock, F_GETFD, 0)) == -1 || + fcntl(sock, F_SETFD, fdflags | FD_CLOEXEC) == -1) + { + smi_log(SMI_LOG_ERR, + "%s: Unable to set close-on-exec: %s", name, + sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + + if ( +#if NETUNIX + addr.sa.sa_family != AF_UNIX && +#endif /* NETUNIX */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, + sizeof(sockopt)) == -1) + { + smi_log(SMI_LOG_ERR, + "%s: set reuseaddr failed (%s)", name, + sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + +#if NETUNIX + if (addr.sa.sa_family == AF_UNIX && rmsocket) + { + struct stat s; + + if (stat(colon, &s) != 0) + { + if (errno != ENOENT) + { + smi_log(SMI_LOG_ERR, + "%s: Unable to stat() %s: %s", + name, colon, sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + } + else if (!S_ISSOCK(s.st_mode)) + { + smi_log(SMI_LOG_ERR, + "%s: %s is not a UNIX domain socket", + name, colon); + (void) closesocket(sock); + return INVALID_SOCKET; + } + else if (unlink(colon) != 0) + { + smi_log(SMI_LOG_ERR, + "%s: Unable to remove %s: %s", + name, colon, sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + } +#endif /* NETUNIX */ + + if (bind(sock, &addr.sa, L_socksize) < 0) + { + smi_log(SMI_LOG_ERR, + "%s: Unable to bind to port %s: %s", + name, conn, sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + + if (listen(sock, backlog) < 0) + { + smi_log(SMI_LOG_ERR, + "%s: listen call failed: %s", name, + sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + +#if NETUNIX + if (addr.sa.sa_family == AF_UNIX && len > 0) + { + /* + ** Set global variable sockpath so the UNIX socket can be + ** unlink()ed at exit. + */ + + sockpath = (char *) malloc(len); + if (sockpath != NULL) + (void) sm_strlcpy(sockpath, colon, len); + else + { + smi_log(SMI_LOG_ERR, + "%s: can't malloc(%d) for sockpath: %s", + name, (int) len, sm_errstring(errno)); + (void) closesocket(sock); + return INVALID_SOCKET; + } + } +#endif /* NETUNIX */ + L_family = addr.sa.sa_family; + return sock; +} + +#if !_FFR_WORKERS_POOL +/* +** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session +** +** Parameters: +** arg -- argument to pass to mi_handle_session() +** +** Returns: +** results from mi_handle_session() +*/ + +static void * +mi_thread_handle_wrapper(arg) + void *arg; +{ + /* + ** Note: on some systems this generates a compiler warning: + ** cast to pointer from integer of different size + ** You can safely ignore this warning as the result of this function + ** is not used anywhere. + */ + + return (void *) mi_handle_session(arg); +} +#endif /* _FFR_WORKERS_POOL */ + +/* +** MI_CLOSENER -- close listen socket +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +mi_closener() +{ + (void) smutex_lock(&L_Mutex); + if (ValidSocket(listenfd)) + { +#if NETUNIX + bool removable; + struct stat sockinfo; + struct stat fileinfo; + + removable = sockpath != NULL && + geteuid() != 0 && + fstat(listenfd, &sockinfo) == 0 && + (S_ISFIFO(sockinfo.st_mode) +# ifdef S_ISSOCK + || S_ISSOCK(sockinfo.st_mode) +# endif /* S_ISSOCK */ + ); +#endif /* NETUNIX */ + + (void) closesocket(listenfd); + listenfd = INVALID_SOCKET; + +#if NETUNIX + /* XXX sleep() some time before doing this? */ + if (sockpath != NULL) + { + if (removable && + stat(sockpath, &fileinfo) == 0 && + ((fileinfo.st_dev == sockinfo.st_dev && + fileinfo.st_ino == sockinfo.st_ino) +# ifdef S_ISSOCK + || S_ISSOCK(fileinfo.st_mode) +# endif /* S_ISSOCK */ + ) + && + (S_ISFIFO(fileinfo.st_mode) +# ifdef S_ISSOCK + || S_ISSOCK(fileinfo.st_mode) +# endif /* S_ISSOCK */ + )) + (void) unlink(sockpath); + free(sockpath); + sockpath = NULL; + } +#endif /* NETUNIX */ + } + (void) smutex_unlock(&L_Mutex); +} + +/* +** MI_LISTENER -- Generic listener harness +** +** Open up listen port +** Wait for connections +** +** Parameters: +** conn -- connection description +** dbg -- debug level +** smfi -- filter structure to use +** timeout -- timeout for reads/writes +** backlog -- listen queue backlog size +** +** Returns: +** MI_SUCCESS -- Exited normally +** (session finished or we were told to exit) +** MI_FAILURE -- Network initialization failed. +*/ + +#if BROKEN_PTHREAD_SLEEP + +/* +** Solaris 2.6, perhaps others, gets an internal threads library panic +** when sleep() is used: +** +** thread_create() failed, returned 11 (EINVAL) +** co_enable, thr_create() returned error = 24 +** libthread panic: co_enable failed (PID: 17793 LWP 1) +** stacktrace: +** ef526b10 +** ef52646c +** ef534cbc +** 156a4 +** 14644 +** 1413c +** 135e0 +** 0 +*/ + +# define MI_SLEEP(s) \ +{ \ + int rs = 0; \ + struct timeval st; \ + \ + st.tv_sec = (s); \ + st.tv_usec = 0; \ + if (st.tv_sec > 0) \ + { \ + for (;;) \ + { \ + rs = select(0, NULL, NULL, NULL, &st); \ + if (rs < 0 && errno == EINTR) \ + continue; \ + if (rs != 0) \ + { \ + smi_log(SMI_LOG_ERR, \ + "MI_SLEEP(): select() returned non-zero result %d, errno = %d", \ + rs, errno); \ + } \ + break; \ + } \ + } \ +} +#else /* BROKEN_PTHREAD_SLEEP */ +# define MI_SLEEP(s) sleep((s)) +#endif /* BROKEN_PTHREAD_SLEEP */ + +int +mi_listener(conn, dbg, smfi, timeout, backlog) + char *conn; + int dbg; + smfiDesc_ptr smfi; + time_t timeout; + int backlog; +{ + socket_t connfd = INVALID_SOCKET; +#if _FFR_DUP_FD + socket_t dupfd = INVALID_SOCKET; +#endif /* _FFR_DUP_FD */ + int sockopt = 1; + int r, mistop; + int ret = MI_SUCCESS; + int mcnt = 0; /* error count for malloc() failures */ + int tcnt = 0; /* error count for thread_create() failures */ + int acnt = 0; /* error count for accept() failures */ + int scnt = 0; /* error count for select() failures */ + int save_errno = 0; +#if !_FFR_WORKERS_POOL + sthread_t thread_id; +#endif /* !_FFR_WORKERS_POOL */ + _SOCK_ADDR cliaddr; + SOCKADDR_LEN_T clilen; + SMFICTX_PTR ctx; + FD_RD_VAR(rds, excs); + struct timeval chktime; + + if (mi_opensocket(conn, backlog, dbg, false, smfi) == MI_FAILURE) + return MI_FAILURE; + +#if _FFR_WORKERS_POOL + if (mi_pool_controller_init() == MI_FAILURE) + return MI_FAILURE; +#endif /* _FFR_WORKERS_POOL */ + + clilen = L_socksize; + while ((mistop = mi_stop()) == MILTER_CONT) + { + (void) smutex_lock(&L_Mutex); + if (!ValidSocket(listenfd)) + { + ret = MI_FAILURE; + smi_log(SMI_LOG_ERR, + "%s: listenfd=%d corrupted, terminating, errno=%d", + smfi->xxfi_name, listenfd, errno); + (void) smutex_unlock(&L_Mutex); + break; + } + + /* select on interface ports */ + FD_RD_INIT(listenfd, rds, excs); + chktime.tv_sec = MI_CHK_TIME; + chktime.tv_usec = 0; + r = FD_RD_READY(listenfd, rds, excs, &chktime); + if (r == 0) /* timeout */ + { + (void) smutex_unlock(&L_Mutex); + continue; /* just check mi_stop() */ + } + if (r < 0) + { + save_errno = errno; + (void) smutex_unlock(&L_Mutex); + if (save_errno == EINTR) + continue; + scnt++; + smi_log(SMI_LOG_ERR, + "%s: %s() failed (%s), %s", + smfi->xxfi_name, MI_POLLSELECT, + sm_errstring(save_errno), + scnt >= MAX_FAILS_S ? "abort" : "try again"); + MI_SLEEP(scnt); + if (scnt >= MAX_FAILS_S) + { + ret = MI_FAILURE; + break; + } + continue; + } + if (!FD_IS_RD_RDY(listenfd, rds, excs)) + { + /* some error: just stop for now... */ + ret = MI_FAILURE; + (void) smutex_unlock(&L_Mutex); + smi_log(SMI_LOG_ERR, + "%s: %s() returned exception for socket, abort", + smfi->xxfi_name, MI_POLLSELECT); + break; + } + scnt = 0; /* reset error counter for select() */ + + (void) memset(&cliaddr, '\0', sizeof cliaddr); + connfd = accept(listenfd, (struct sockaddr *) &cliaddr, + &clilen); + save_errno = errno; + (void) smutex_unlock(&L_Mutex); + + /* + ** If remote side closes before accept() finishes, + ** sockaddr might not be fully filled in. + */ + + if (ValidSocket(connfd) && + (clilen == 0 || +# ifdef BSD4_4_SOCKADDR + cliaddr.sa.sa_len == 0 || +# endif /* BSD4_4_SOCKADDR */ + cliaddr.sa.sa_family != L_family)) + { + (void) closesocket(connfd); + connfd = INVALID_SOCKET; + save_errno = EINVAL; + } + + /* check if acceptable for select() */ + if (ValidSocket(connfd) && !SM_FD_OK_SELECT(connfd)) + { + (void) closesocket(connfd); + connfd = INVALID_SOCKET; + save_errno = ERANGE; + } + + if (!ValidSocket(connfd)) + { + if (save_errno == EINTR +#ifdef EAGAIN + || save_errno == EAGAIN +#endif /* EAGAIN */ +#ifdef ECONNABORTED + || save_errno == ECONNABORTED +#endif /* ECONNABORTED */ +#ifdef EMFILE + || save_errno == EMFILE +#endif /* EMFILE */ +#ifdef ENFILE + || save_errno == ENFILE +#endif /* ENFILE */ +#ifdef ENOBUFS + || save_errno == ENOBUFS +#endif /* ENOBUFS */ +#ifdef ENOMEM + || save_errno == ENOMEM +#endif /* ENOMEM */ +#ifdef ENOSR + || save_errno == ENOSR +#endif /* ENOSR */ +#ifdef EWOULDBLOCK + || save_errno == EWOULDBLOCK +#endif /* EWOULDBLOCK */ + ) + continue; + acnt++; + smi_log(SMI_LOG_ERR, + "%s: accept() returned invalid socket (%s), %s", + smfi->xxfi_name, sm_errstring(save_errno), + acnt >= MAX_FAILS_A ? "abort" : "try again"); + MI_SLEEP(acnt); + if (acnt >= MAX_FAILS_A) + { + ret = MI_FAILURE; + break; + } + continue; + } + acnt = 0; /* reset error counter for accept() */ +#if _FFR_DUP_FD + dupfd = fcntl(connfd, F_DUPFD, 256); + if (ValidSocket(dupfd) && SM_FD_OK_SELECT(dupfd)) + { + close(connfd); + connfd = dupfd; + dupfd = INVALID_SOCKET; + } +#endif /* _FFR_DUP_FD */ + + if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, + (void *) &sockopt, sizeof sockopt) < 0) + { + smi_log(SMI_LOG_WARN, + "%s: set keepalive failed (%s)", + smfi->xxfi_name, sm_errstring(errno)); + /* XXX: continue? */ + } + if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) + { + (void) closesocket(connfd); + mcnt++; + smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed (%s), %s", + smfi->xxfi_name, sm_errstring(save_errno), + mcnt >= MAX_FAILS_M ? "abort" : "try again"); + MI_SLEEP(mcnt); + if (mcnt >= MAX_FAILS_M) + { + ret = MI_FAILURE; + break; + } + continue; + } + mcnt = 0; /* reset error counter for malloc() */ + (void) memset(ctx, '\0', sizeof *ctx); + ctx->ctx_sd = connfd; + ctx->ctx_dbg = dbg; + ctx->ctx_timeout = timeout; + ctx->ctx_smfi = smfi; + if (smfi->xxfi_connect == NULL) + ctx->ctx_pflags |= SMFIP_NOCONNECT; + if (smfi->xxfi_helo == NULL) + ctx->ctx_pflags |= SMFIP_NOHELO; + if (smfi->xxfi_envfrom == NULL) + ctx->ctx_pflags |= SMFIP_NOMAIL; + if (smfi->xxfi_envrcpt == NULL) + ctx->ctx_pflags |= SMFIP_NORCPT; + if (smfi->xxfi_header == NULL) + ctx->ctx_pflags |= SMFIP_NOHDRS; + if (smfi->xxfi_eoh == NULL) + ctx->ctx_pflags |= SMFIP_NOEOH; + if (smfi->xxfi_body == NULL) + ctx->ctx_pflags |= SMFIP_NOBODY; + if (smfi->xxfi_version <= 3 || smfi->xxfi_data == NULL) + ctx->ctx_pflags |= SMFIP_NODATA; + if (smfi->xxfi_version <= 2 || smfi->xxfi_unknown == NULL) + ctx->ctx_pflags |= SMFIP_NOUNKNOWN; + +#if _FFR_WORKERS_POOL +# define LOG_CRT_FAIL "%s: mi_start_session() failed: %d, %s" + if ((r = mi_start_session(ctx)) != MI_SUCCESS) +#else /* _FFR_WORKERS_POOL */ +# define LOG_CRT_FAIL "%s: thread_create() failed: %d, %s" + if ((r = thread_create(&thread_id, + mi_thread_handle_wrapper, + (void *) ctx)) != 0) +#endif /* _FFR_WORKERS_POOL */ + { + tcnt++; + smi_log(SMI_LOG_ERR, + LOG_CRT_FAIL, + smfi->xxfi_name, r, + tcnt >= MAX_FAILS_T ? "abort" : "try again"); + MI_SLEEP(tcnt); + (void) closesocket(connfd); + free(ctx); + if (tcnt >= MAX_FAILS_T) + { + ret = MI_FAILURE; + break; + } + continue; + } + tcnt = 0; + } + if (ret != MI_SUCCESS) + mi_stop_milters(MILTER_ABRT); + else + { + if (mistop != MILTER_CONT) + smi_log(SMI_LOG_INFO, "%s: mi_stop=%d", + smfi->xxfi_name, mistop); + mi_closener(); + } + (void) smutex_destroy(&L_Mutex); + return ret; +} diff --git a/contrib/sendmail/libmilter/main.c b/contrib/sendmail/libmilter/main.c new file mode 100644 index 0000000..d6e7279 --- /dev/null +++ b/contrib/sendmail/libmilter/main.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1999-2003, 2006, 2007 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: main.c,v 8.84 2008/09/02 05:37:06 ca Exp $") + +#define _DEFINE 1 +#include "libmilter.h" +#include <fcntl.h> +#include <sys/stat.h> + + +static smfiDesc_ptr smfi = NULL; + +/* +** SMFI_REGISTER -- register a filter description +** +** Parameters: +** smfilter -- description of filter to register +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_register(smfilter) + smfiDesc_str smfilter; +{ + size_t len; + + if (smfi == NULL) + { + smfi = (smfiDesc_ptr) malloc(sizeof *smfi); + if (smfi == NULL) + return MI_FAILURE; + } + (void) memcpy(smfi, &smfilter, sizeof *smfi); + if (smfilter.xxfi_name == NULL) + smfilter.xxfi_name = "Unknown"; + + len = strlen(smfilter.xxfi_name) + 1; + smfi->xxfi_name = (char *) malloc(len); + if (smfi->xxfi_name == NULL) + return MI_FAILURE; + (void) sm_strlcpy(smfi->xxfi_name, smfilter.xxfi_name, len); + + /* compare milter version with hard coded version */ + if ((SM_LM_VRS_MAJOR(smfi->xxfi_version) != SM_LM_VRS_MAJOR(SMFI_VERSION) || + SM_LM_VRS_MINOR(smfi->xxfi_version) != SM_LM_VRS_MINOR(SMFI_VERSION)) && + smfi->xxfi_version != 2 && + smfi->xxfi_version != 3 && + smfi->xxfi_version != 4) + { + /* hard failure for now! */ + smi_log(SMI_LOG_ERR, + "%s: smfi_register: version mismatch application: %d != milter: %d", + smfi->xxfi_name, smfi->xxfi_version, + (int) SMFI_VERSION); + + /* XXX how about smfi? */ + free(smfi->xxfi_name); + return MI_FAILURE; + } + + return MI_SUCCESS; +} + +/* +** SMFI_STOP -- stop milter +** +** Parameters: +** none. +** +** Returns: +** success. +*/ + +int +smfi_stop() +{ + mi_stop_milters(MILTER_STOP); + return MI_SUCCESS; +} + +/* +** Default values for some variables. +** Most of these can be changed with the functions below. +*/ + +static int dbg = 0; +static char *conn = NULL; +static int timeout = MI_TIMEOUT; +static int backlog = MI_SOMAXCONN; + +/* +** SMFI_OPENSOCKET -- try the socket setup to make sure we'll be +** able to start up +** +** Parameters: +** rmsocket -- if true, instructs libmilter to attempt +** to remove the socket before creating it; +** only applies for "local:" or "unix:" sockets +** +** Return: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_opensocket(rmsocket) + bool rmsocket; +{ + if (smfi == NULL || conn == NULL) + return MI_FAILURE; + + return mi_opensocket(conn, backlog, dbg, rmsocket, smfi); +} + +/* +** SMFI_SETDBG -- set debug level. +** +** Parameters: +** odbg -- new debug level. +** +** Returns: +** MI_SUCCESS +*/ + +int +smfi_setdbg(odbg) + int odbg; +{ + dbg = odbg; + return MI_SUCCESS; +} + +/* +** SMFI_SETTIMEOUT -- set timeout (for read/write). +** +** Parameters: +** otimeout -- new timeout. +** +** Returns: +** MI_SUCCESS +*/ + +int +smfi_settimeout(otimeout) + int otimeout; +{ + timeout = otimeout; + return MI_SUCCESS; +} + +/* +** SMFI_SETCONN -- set connection information (socket description) +** +** Parameters: +** oconn -- new connection information. +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_setconn(oconn) + char *oconn; +{ + size_t l; + + if (oconn == NULL || *oconn == '\0') + return MI_FAILURE; + l = strlen(oconn) + 1; + if ((conn = (char *) malloc(l)) == NULL) + return MI_FAILURE; + if (sm_strlcpy(conn, oconn, l) >= l) + return MI_FAILURE; + return MI_SUCCESS; +} + +/* +** SMFI_SETBACKLOG -- set backlog +** +** Parameters: +** obacklog -- new backlog. +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_setbacklog(obacklog) + int obacklog; +{ + if (obacklog <= 0) + return MI_FAILURE; + backlog = obacklog; + return MI_SUCCESS; +} + + +/* +** SMFI_MAIN -- setup milter connnection and start listener. +** +** Parameters: +** none. +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_main() +{ + int r; + + (void) signal(SIGPIPE, SIG_IGN); + if (conn == NULL) + { + smi_log(SMI_LOG_FATAL, "%s: missing connection information", + smfi->xxfi_name); + return MI_FAILURE; + } + + (void) atexit(mi_clean_signals); + if (mi_control_startup(smfi->xxfi_name) != MI_SUCCESS) + { + smi_log(SMI_LOG_FATAL, + "%s: Couldn't start signal thread", + smfi->xxfi_name); + return MI_FAILURE; + } + r = MI_MONITOR_INIT(); + + /* Startup the listener */ + if (mi_listener(conn, dbg, smfi, timeout, backlog) != MI_SUCCESS) + r = MI_FAILURE; + + return r; +} + diff --git a/contrib/sendmail/libmilter/monitor.c b/contrib/sendmail/libmilter/monitor.c new file mode 100644 index 0000000..366cf75 --- /dev/null +++ b/contrib/sendmail/libmilter/monitor.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: monitor.c,v 8.7 2007/04/23 16:26:28 ca Exp $") +#include "libmilter.h" + +#if _FFR_THREAD_MONITOR + +/* +** Thread Monitoring +** Todo: more error checking (return code from function calls) +** add comments. +*/ + +bool Monitor = false; /* use monitoring? */ +static unsigned int Mon_exec_time = 0; + +/* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */ +static smutex_t Mon_mutex; +static scond_t Mon_cv; + +/* +** Current ctx to monitor. +** Invariant: +** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest +** time ago. +** +** Basically the entries in the list are ordered by time because new +** entries are appended at the end. However, due to the concurrent +** execution (multi-threaded) and no guaranteed order of wakeups +** after a mutex_lock() attempt, the order might not be strict, +** i.e., if the list contains e1 and e2 (in that order) then +** the the start time of e2 can be (slightly) smaller than that of e1. +** However, this slight inaccurracy should not matter for the proper +** working of this algorithm. +*/ + +static SMFICTX_PTR Mon_cur_ctx = NULL; +static smfi_hd_T Mon_ctx_head; /* head of the linked list of active contexts */ + +/* +** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread +** +** Parameters: +** tm -- maximum execution time for a thread +** +** Returns: +** MI_SUCCESS +*/ + +int +smfi_set_max_exec_time(tm) + unsigned int tm; +{ + Mon_exec_time = tm; + return MI_SUCCESS; +} + +/* +** MI_MONITOR_THREAD -- monitoring thread +** +** Parameters: +** arg -- ignored (required by pthread_create()) +** +** Returns: +** NULL on termination. +*/ + +static void * +mi_monitor_thread(arg) + void *arg; +{ + sthread_t tid; + int r; + time_t now, end; + + SM_ASSERT(Monitor); + SM_ASSERT(Mon_exec_time > 0); + tid = (sthread_t) sthread_get_id(); + if (pthread_detach(tid) != 0) + { + /* log an error */ + return (void *)1; + } + +/* +** NOTE: this is "flow through" code, +** do NOT use do { } while ("break" is used here!) +*/ + +#define MON_CHK_STOP \ + now = time(NULL); \ + end = Mon_cur_ctx->ctx_start + Mon_exec_time; \ + if (now > end) \ + { \ + smi_log(SMI_LOG_ERR, \ + "WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\ + (long) now, (long) end, \ + (long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\ + mi_stop_milters(MILTER_STOP); \ + break; \ + } + + (void) smutex_lock(&Mon_mutex); + while (mi_stop() == MILTER_CONT) + { + if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0) + { + struct timespec abstime; + + MON_CHK_STOP; + abstime.tv_sec = end; + abstime.tv_nsec = 0; + r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex, + &abstime); + } + else + r = pthread_cond_wait(&Mon_cv, &Mon_mutex); + if (mi_stop() != MILTER_CONT) + break; + if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0) + { + MON_CHK_STOP; + } + } + (void) smutex_unlock(&Mon_mutex); + + return NULL; +} + +/* +** MI_MONITOR_INIT -- initialize monitoring thread +** +** Parameters: none +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_monitor_init() +{ + int r; + sthread_t tid; + + SM_ASSERT(!Monitor); + if (Mon_exec_time <= 0) + return MI_SUCCESS; + Monitor = true; + if (!smutex_init(&Mon_mutex)) + return MI_FAILURE; + if (scond_init(&Mon_cv) != 0) + return MI_FAILURE; + SM_TAILQ_INIT(&Mon_ctx_head); + + r = thread_create(&tid, mi_monitor_thread, (void *)NULL); + if (r != 0) + return r; + return MI_SUCCESS; +} + +/* +** MI_MONITOR_WORK_BEGIN -- record start of thread execution +** +** Parameters: +** ctx -- session context +** cmd -- milter command char +** +** Returns: +** 0 +*/ + +int +mi_monitor_work_begin(ctx, cmd) + SMFICTX_PTR ctx; + int cmd; +{ + (void) smutex_lock(&Mon_mutex); + if (NULL == Mon_cur_ctx) + { + Mon_cur_ctx = ctx; + (void) scond_signal(&Mon_cv); + } + ctx->ctx_start = time(NULL); + SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link); + (void) smutex_unlock(&Mon_mutex); + return 0; +} + +/* +** MI_MONITOR_WORK_END -- record end of thread execution +** +** Parameters: +** ctx -- session context +** cmd -- milter command char +** +** Returns: +** 0 +*/ + +int +mi_monitor_work_end(ctx, cmd) + SMFICTX_PTR ctx; + int cmd; +{ + (void) smutex_lock(&Mon_mutex); + ctx->ctx_start = 0; + SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link); + if (Mon_cur_ctx == ctx) + { + if (SM_TAILQ_EMPTY(&Mon_ctx_head)) + Mon_cur_ctx = NULL; + else + Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head); + } + (void) smutex_unlock(&Mon_mutex); + return 0; +} +#endif /* _FFR_THREAD_MONITOR */ diff --git a/contrib/sendmail/libmilter/signal.c b/contrib/sendmail/libmilter/signal.c new file mode 100644 index 0000000..ad68469 --- /dev/null +++ b/contrib/sendmail/libmilter/signal.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: signal.c,v 8.44 2006/03/03 03:42:04 ca Exp $") + +#include "libmilter.h" + +/* +** thread to handle signals +*/ + +static smutex_t M_Mutex; + +static int MilterStop = MILTER_CONT; + +static void *mi_signal_thread __P((void *)); +static int mi_spawn_signal_thread __P((char *)); + +/* +** MI_STOP -- return value of MilterStop +** +** Parameters: +** none. +** +** Returns: +** value of MilterStop +*/ + +int +mi_stop() +{ + return MilterStop; +} +/* +** MI_STOP_MILTERS -- set value of MilterStop +** +** Parameters: +** v -- new value for MilterStop. +** +** Returns: +** none. +*/ + +void +mi_stop_milters(v) + int v; +{ + (void) smutex_lock(&M_Mutex); + if (MilterStop < v) + MilterStop = v; + + /* close listen socket */ + mi_closener(); + (void) smutex_unlock(&M_Mutex); +} +/* +** MI_CLEAN_SIGNALS -- clean up signal handler thread +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +mi_clean_signals() +{ + (void) smutex_destroy(&M_Mutex); +} +/* +** MI_SIGNAL_THREAD -- thread to deal with signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** NULL +*/ + +static void * +mi_signal_thread(name) + void *name; +{ + int sig, errs, sigerr; + sigset_t set; + + (void) sigemptyset(&set); + (void) sigaddset(&set, SIGHUP); + (void) sigaddset(&set, SIGTERM); + + /* Handle Ctrl-C gracefully for debugging */ + (void) sigaddset(&set, SIGINT); + errs = 0; + + for (;;) + { + sigerr = sig = 0; +#if defined(SOLARIS) || defined(__svr5__) + if ((sig = sigwait(&set)) < 0) +#else /* defined(SOLARIS) || defined(__svr5__) */ + if ((sigerr = sigwait(&set, &sig)) != 0) +#endif /* defined(SOLARIS) || defined(__svr5__) */ + { + /* some OS return -1 and set errno: copy it */ + if (sigerr <= 0) + sigerr = errno; + + /* this can happen on OSF/1 (at least) */ + if (sigerr == EINTR) + continue; + smi_log(SMI_LOG_ERR, + "%s: sigwait returned error: %d", + (char *)name, sigerr); + if (++errs > MAX_FAILS_T) + { + mi_stop_milters(MILTER_ABRT); + return NULL; + } + continue; + } + errs = 0; + + switch (sig) + { + case SIGHUP: + case SIGTERM: + mi_stop_milters(MILTER_STOP); + return NULL; + case SIGINT: + mi_stop_milters(MILTER_ABRT); + return NULL; + default: + smi_log(SMI_LOG_ERR, + "%s: sigwait returned unmasked signal: %d", + (char *)name, sig); + break; + } + } + /* NOTREACHED */ +} +/* +** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +mi_spawn_signal_thread(name) + char *name; +{ + sthread_t tid; + int r; + sigset_t set; + + /* Mask HUP and KILL signals */ + (void) sigemptyset(&set); + (void) sigaddset(&set, SIGHUP); + (void) sigaddset(&set, SIGTERM); + (void) sigaddset(&set, SIGINT); + + if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't mask HUP and KILL signals", name); + return MI_FAILURE; + } + r = thread_create(&tid, mi_signal_thread, (void *)name); + if (r != 0) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't start signal thread: %d", + name, r); + return MI_FAILURE; + } + return MI_SUCCESS; +} +/* +** MI_CONTROL_STARTUP -- startup for thread to handle signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_control_startup(name) + char *name; +{ + + if (!smutex_init(&M_Mutex)) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't initialize control pipe mutex", name); + return MI_FAILURE; + } + + /* + ** spawn_signal_thread must happen before other threads are spawned + ** off so that it can mask the right signals and other threads + ** will inherit that mask. + */ + if (mi_spawn_signal_thread(name) == MI_FAILURE) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't spawn signal thread", name); + (void) smutex_destroy(&M_Mutex); + return MI_FAILURE; + } + return MI_SUCCESS; +} diff --git a/contrib/sendmail/libmilter/sm_gethost.c b/contrib/sendmail/libmilter/sm_gethost.c new file mode 100644 index 0000000..5706b89 --- /dev/null +++ b/contrib/sendmail/libmilter/sm_gethost.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1999-2001, 2004 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: sm_gethost.c,v 8.27 2004/08/20 21:12:37 ca Exp $") + +#include <sendmail.h> +#if NETINET || NETINET6 +# include <arpa/inet.h> +#endif /* NETINET || NETINET6 */ +#include "libmilter.h" + +/* +** MI_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX +** +** Some operating systems have wierd problems with the gethostbyXXX +** routines. For example, Solaris versions at least through 2.3 +** don't properly deliver a canonical h_name field. This tries to +** work around these problems. +** +** Support IPv6 as well as IPv4. +*/ + +#if NETINET6 && NEEDSGETIPNODE + +static struct hostent *getipnodebyname __P((char *, int, int, int *)); + +# ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 /* dummy */ +# endif /* ! AI_ADDRCONFIG */ +# ifndef AI_ALL +# define AI_ALL 0 /* dummy */ +# endif /* ! AI_ALL */ +# ifndef AI_DEFAULT +# define AI_DEFAULT 0 /* dummy */ +# endif /* ! AI_DEFAULT */ + +static struct hostent * +getipnodebyname(name, family, flags, err) + char *name; + int family; + int flags; + int *err; +{ + bool resv6 = true; + struct hostent *h; + + if (family == AF_INET6) + { + /* From RFC2133, section 6.1 */ + resv6 = bitset(RES_USE_INET6, _res.options); + _res.options |= RES_USE_INET6; + } + SM_SET_H_ERRNO(0); + h = gethostbyname(name); + if (family == AF_INET6 && !resv6) + _res.options &= ~RES_USE_INET6; + *err = h_errno; + return h; +} + +void +freehostent(h) + struct hostent *h; +{ + /* + ** Stub routine -- if they don't have getipnodeby*(), + ** they probably don't have the free routine either. + */ + + return; +} +#endif /* NEEDSGETIPNODE && NETINET6 */ + +struct hostent * +mi_gethostbyname(name, family) + char *name; + int family; +{ + struct hostent *h = NULL; +#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) +# if SOLARIS == 20300 || SOLARIS == 203 + static struct hostent hp; + static char buf[1000]; + extern struct hostent *_switch_gethostbyname_r(); + + h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); +# else /* SOLARIS == 20300 || SOLARIS == 203 */ + extern struct hostent *__switch_gethostbyname(); + + h = __switch_gethostbyname(name); +# endif /* SOLARIS == 20300 || SOLARIS == 203 */ +#else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ +# if NETINET6 + int flags = AI_DEFAULT|AI_ALL; + int err; +# endif /* NETINET6 */ + +# if NETINET6 +# if ADDRCONFIG_IS_BROKEN + flags &= ~AI_ADDRCONFIG; +# endif /* ADDRCONFIG_IS_BROKEN */ + h = getipnodebyname(name, family, flags, &err); + SM_SET_H_ERRNO(err); +# else /* NETINET6 */ + h = gethostbyname(name); +# endif /* NETINET6 */ + +#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ + return h; +} + +#if NETINET6 +/* +** MI_INET_PTON -- convert printed form to network address. +** +** Wrapper for inet_pton() which handles IPv6: labels. +** +** Parameters: +** family -- address family +** src -- string +** dst -- destination address structure +** +** Returns: +** 1 if the address was valid +** 0 if the address wasn't parseable +** -1 if error +*/ + +int +mi_inet_pton(family, src, dst) + int family; + const char *src; + void *dst; +{ + if (family == AF_INET6 && + strncasecmp(src, "IPv6:", 5) == 0) + src += 5; + return inet_pton(family, src, dst); +} +#endif /* NETINET6 */ diff --git a/contrib/sendmail/libmilter/smfi.c b/contrib/sendmail/libmilter/smfi.c new file mode 100644 index 0000000..138623e --- /dev/null +++ b/contrib/sendmail/libmilter/smfi.c @@ -0,0 +1,889 @@ +/* + * Copyright (c) 1999-2007 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 ca Exp $") +#include <sm/varargs.h> +#include "libmilter.h" + +static int smfi_header __P((SMFICTX *, int, int, char *, char *)); +static int myisenhsc __P((const char *, int)); + +/* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */ +#define MAXREPLYLEN 980 /* max. length of a reply string */ +#define MAXREPLIES 32 /* max. number of reply strings */ + +/* +** SMFI_HEADER -- send a header to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** cmd -- Header modification command +** hdridx -- Header index +** headerf -- Header field name +** headerv -- Header field value +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +smfi_header(ctx, cmd, hdridx, headerf, headerv) + SMFICTX *ctx; + int cmd; + int hdridx; + char *headerf; + char *headerv; +{ + size_t len, l1, l2, offset; + int r; + mi_int32 v; + char *buf; + struct timeval timeout; + + if (headerf == NULL || *headerf == '\0' || headerv == NULL) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + l1 = strlen(headerf) + 1; + l2 = strlen(headerv) + 1; + len = l1 + l2; + if (hdridx >= 0) + len += MILTER_LEN_BYTES; + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; + offset = 0; + if (hdridx >= 0) + { + v = htonl(hdridx); + (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); + offset += MILTER_LEN_BYTES; + } + (void) memcpy(buf + offset, headerf, l1); + (void) memcpy(buf + offset + l1, headerv, l2); + r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); + free(buf); + return r; +} + +/* +** SMFI_ADDHEADER -- send a new header to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** headerf -- Header field name +** headerv -- Header field value +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_addheader(ctx, headerf, headerv) + SMFICTX *ctx; + char *headerf; + char *headerv; +{ + if (!mi_sendok(ctx, SMFIF_ADDHDRS)) + return MI_FAILURE; + + return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv); +} + +/* +** SMFI_INSHEADER -- send a new header to the MTA (to be inserted) +** +** Parameters: +** ctx -- Opaque context structure +** hdridx -- index into header list where insertion should occur +** headerf -- Header field name +** headerv -- Header field value +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_insheader(ctx, hdridx, headerf, headerv) + SMFICTX *ctx; + int hdridx; + char *headerf; + char *headerv; +{ + if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0) + return MI_FAILURE; + + return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv); +} + +/* +** SMFI_CHGHEADER -- send a changed header to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** headerf -- Header field name +** hdridx -- Header index value +** headerv -- Header field value +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_chgheader(ctx, headerf, hdridx, headerv) + SMFICTX *ctx; + char *headerf; + mi_int32 hdridx; + char *headerv; +{ + if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0) + return MI_FAILURE; + if (headerv == NULL) + headerv = ""; + + return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv); +} + +#if 0 +/* +** BUF_CRT_SEND -- construct buffer to send from arguments +** +** Parameters: +** ctx -- Opaque context structure +** cmd -- command +** arg0 -- first argument +** argv -- list of arguments (NULL terminated) +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +buf_crt_send __P((SMFICTX *, int cmd, char *, char **)); + +static int +buf_crt_send(ctx, cmd, arg0, argv) + SMFICTX *ctx; + int cmd; + char *arg0; + char **argv; +{ + size_t len, l0, l1, offset; + int r; + char *buf, *arg, **argvl; + struct timeval timeout; + + if (arg0 == NULL || *arg0 == '\0') + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + l0 = strlen(arg0) + 1; + len = l0; + argvl = argv; + while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0') + { + l1 = strlen(arg) + 1; + len += l1; + SM_ASSERT(len > l1); + } + + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; + (void) memcpy(buf, arg0, l0); + offset = l0; + + argvl = argv; + while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0') + { + l1 = strlen(arg) + 1; + SM_ASSERT(offset < len); + SM_ASSERT(offset + l1 <= len); + (void) memcpy(buf + offset, arg, l1); + offset += l1; + SM_ASSERT(offset > l1); + } + + r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); + free(buf); + return r; +} +#endif /* 0 */ + +/* +** SEND2 -- construct buffer to send from arguments +** +** Parameters: +** ctx -- Opaque context structure +** cmd -- command +** arg0 -- first argument +** argv -- list of arguments (NULL terminated) +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +send2 __P((SMFICTX *, int cmd, char *, char *)); + +static int +send2(ctx, cmd, arg0, arg1) + SMFICTX *ctx; + int cmd; + char *arg0; + char *arg1; +{ + size_t len, l0, l1, offset; + int r; + char *buf; + struct timeval timeout; + + if (arg0 == NULL || *arg0 == '\0') + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + l0 = strlen(arg0) + 1; + len = l0; + if (arg1 != NULL) + { + l1 = strlen(arg1) + 1; + len += l1; + SM_ASSERT(len > l1); + } + + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; + (void) memcpy(buf, arg0, l0); + offset = l0; + + if (arg1 != NULL) + { + l1 = strlen(arg1) + 1; + SM_ASSERT(offset < len); + SM_ASSERT(offset + l1 <= len); + (void) memcpy(buf + offset, arg1, l1); + offset += l1; + SM_ASSERT(offset > l1); + } + + r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); + free(buf); + return r; +} + +/* +** SMFI_CHGFROM -- change enveloper sender ("from") address +** +** Parameters: +** ctx -- Opaque context structure +** from -- new envelope sender address ("MAIL From") +** args -- ESMTP arguments +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_chgfrom(ctx, from, args) + SMFICTX *ctx; + char *from; + char *args; +{ + if (from == NULL || *from == '\0') + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_CHGFROM)) + return MI_FAILURE; + return send2(ctx, SMFIR_CHGFROM, from, args); +} + +/* +** SMFI_SETSYMLIST -- set list of macros that the MTA should send. +** +** Parameters: +** ctx -- Opaque context structure +** where -- SMTP stage +** macros -- list of macros +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_setsymlist(ctx, where, macros) + SMFICTX *ctx; + int where; + char *macros; +{ + SM_ASSERT(ctx != NULL); + + if (macros == NULL || *macros == '\0') + return MI_FAILURE; + if (where < SMFIM_FIRST || where > SMFIM_LAST) + return MI_FAILURE; + if (where < 0 || where >= MAX_MACROS_ENTRIES) + return MI_FAILURE; + + if (ctx->ctx_mac_list[where] != NULL) + return MI_FAILURE; + + ctx->ctx_mac_list[where] = strdup(macros); + if (ctx->ctx_mac_list[where] == NULL) + return MI_FAILURE; + + return MI_SUCCESS; +} + +/* +** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** rcpt -- recipient address +** args -- ESMTP arguments +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_addrcpt_par(ctx, rcpt, args) + SMFICTX *ctx; + char *rcpt; + char *args; +{ + if (rcpt == NULL || *rcpt == '\0') + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR)) + return MI_FAILURE; + return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args); +} + +/* +** SMFI_ADDRCPT -- send an additional recipient to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** rcpt -- recipient address +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_addrcpt(ctx, rcpt) + SMFICTX *ctx; + char *rcpt; +{ + size_t len; + struct timeval timeout; + + if (rcpt == NULL || *rcpt == '\0') + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_ADDRCPT)) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + len = strlen(rcpt) + 1; + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); +} + +/* +** SMFI_DELRCPT -- send a recipient to be removed to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** rcpt -- recipient address +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_delrcpt(ctx, rcpt) + SMFICTX *ctx; + char *rcpt; +{ + size_t len; + struct timeval timeout; + + if (rcpt == NULL || *rcpt == '\0') + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_DELRCPT)) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + len = strlen(rcpt) + 1; + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); +} + +/* +** SMFI_REPLACEBODY -- send a body chunk to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** bodyp -- body chunk +** bodylen -- length of body chunk +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_replacebody(ctx, bodyp, bodylen) + SMFICTX *ctx; + unsigned char *bodyp; + int bodylen; +{ + int len, off, r; + struct timeval timeout; + + if (bodylen < 0 || + (bodyp == NULL && bodylen > 0)) + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_CHGBODY)) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + + /* split body chunk if necessary */ + off = 0; + do + { + len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : + bodylen; + if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, + (char *) (bodyp + off), len)) != MI_SUCCESS) + return r; + off += len; + bodylen -= len; + } while (bodylen > 0); + return MI_SUCCESS; +} + +/* +** SMFI_QUARANTINE -- quarantine an envelope +** +** Parameters: +** ctx -- Opaque context structure +** reason -- why? +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_quarantine(ctx, reason) + SMFICTX *ctx; + char *reason; +{ + size_t len; + int r; + char *buf; + struct timeval timeout; + + if (reason == NULL || *reason == '\0') + return MI_FAILURE; + if (!mi_sendok(ctx, SMFIF_QUARANTINE)) + return MI_FAILURE; + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + len = strlen(reason) + 1; + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; + (void) memcpy(buf, reason, len); + r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len); + free(buf); + return r; +} + +/* +** MYISENHSC -- check whether a string contains an enhanced status code +** +** Parameters: +** s -- string with possible enhanced status code. +** delim -- delim for enhanced status code. +** +** Returns: +** 0 -- no enhanced status code. +** >4 -- length of enhanced status code. +** +** Side Effects: +** none. +*/ + +static int +myisenhsc(s, delim) + const char *s; + int delim; +{ + int l, h; + + if (s == NULL) + return 0; + if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) + return 0; + h = 0; + l = 2; + while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) + ++h; + if (h == 0 || s[l + h] != '.') + return 0; + l += h + 1; + h = 0; + while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) + ++h; + if (h == 0 || s[l + h] != delim) + return 0; + return l + h; +} + +/* +** SMFI_SETREPLY -- set the reply code for the next reply to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** rcode -- The three-digit (RFC 821) SMTP reply code. +** xcode -- The extended (RFC 2034) reply code. +** message -- The text part of the SMTP reply. +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_setreply(ctx, rcode, xcode, message) + SMFICTX *ctx; + char *rcode; + char *xcode; + char *message; +{ + size_t len; + char *buf; + + if (rcode == NULL || ctx == NULL) + return MI_FAILURE; + + /* ### <sp> \0 */ + len = strlen(rcode) + 2; + if (len != 5) + return MI_FAILURE; + if ((rcode[0] != '4' && rcode[0] != '5') || + !isascii(rcode[1]) || !isdigit(rcode[1]) || + !isascii(rcode[2]) || !isdigit(rcode[2])) + return MI_FAILURE; + if (xcode != NULL) + { + if (!myisenhsc(xcode, '\0')) + return MI_FAILURE; + len += strlen(xcode) + 1; + } + if (message != NULL) + { + size_t ml; + + /* XXX check also for unprintable chars? */ + if (strpbrk(message, "\r\n") != NULL) + return MI_FAILURE; + ml = strlen(message); + if (ml > MAXREPLYLEN) + return MI_FAILURE; + len += ml + 1; + } + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; /* oops */ + (void) sm_strlcpy(buf, rcode, len); + (void) sm_strlcat(buf, " ", len); + if (xcode != NULL) + (void) sm_strlcat(buf, xcode, len); + if (message != NULL) + { + if (xcode != NULL) + (void) sm_strlcat(buf, " ", len); + (void) sm_strlcat(buf, message, len); + } + if (ctx->ctx_reply != NULL) + free(ctx->ctx_reply); + ctx->ctx_reply = buf; + return MI_SUCCESS; +} + +/* +** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA +** +** Parameters: +** ctx -- Opaque context structure +** rcode -- The three-digit (RFC 821) SMTP reply code. +** xcode -- The extended (RFC 2034) reply code. +** txt, ... -- The text part of the SMTP reply, +** MUST be terminated with NULL. +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +#if SM_VA_STD +smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...) +#else /* SM_VA_STD */ +smfi_setmlreply(ctx, rcode, xcode, va_alist) + SMFICTX *ctx; + const char *rcode; + const char *xcode; + va_dcl +#endif /* SM_VA_STD */ +{ + size_t len; + size_t rlen; + int args; + char *buf, *txt; + const char *xc; + char repl[16]; + SM_VA_LOCAL_DECL + + if (rcode == NULL || ctx == NULL) + return MI_FAILURE; + + /* ### <sp> */ + len = strlen(rcode) + 1; + if (len != 4) + return MI_FAILURE; + if ((rcode[0] != '4' && rcode[0] != '5') || + !isascii(rcode[1]) || !isdigit(rcode[1]) || + !isascii(rcode[2]) || !isdigit(rcode[2])) + return MI_FAILURE; + if (xcode != NULL) + { + if (!myisenhsc(xcode, '\0')) + return MI_FAILURE; + xc = xcode; + } + else + { + if (rcode[0] == '4') + xc = "4.0.0"; + else + xc = "5.0.0"; + } + + /* add trailing space */ + len += strlen(xc) + 1; + rlen = len; + args = 0; + SM_VA_START(ap, xcode); + while ((txt = SM_VA_ARG(ap, char *)) != NULL) + { + size_t tl; + + tl = strlen(txt); + if (tl > MAXREPLYLEN) + break; + + /* this text, reply codes, \r\n */ + len += tl + 2 + rlen; + if (++args > MAXREPLIES) + break; + + /* XXX check also for unprintable chars? */ + if (strpbrk(txt, "\r\n") != NULL) + break; + } + SM_VA_END(ap); + if (txt != NULL) + return MI_FAILURE; + + /* trailing '\0' */ + ++len; + buf = malloc(len); + if (buf == NULL) + return MI_FAILURE; /* oops */ + (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc); + (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-", + xc, " "); + SM_VA_START(ap, xcode); + txt = SM_VA_ARG(ap, char *); + if (txt != NULL) + { + (void) sm_strlcat2(buf, " ", txt, len); + while ((txt = SM_VA_ARG(ap, char *)) != NULL) + { + if (--args <= 1) + repl[3] = ' '; + (void) sm_strlcat2(buf, "\r\n", repl, len); + (void) sm_strlcat(buf, txt, len); + } + } + if (ctx->ctx_reply != NULL) + free(ctx->ctx_reply); + ctx->ctx_reply = buf; + SM_VA_END(ap); + return MI_SUCCESS; +} + +/* +** SMFI_SETPRIV -- set private data +** +** Parameters: +** ctx -- Opaque context structure +** privatedata -- pointer to private data +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_setpriv(ctx, privatedata) + SMFICTX *ctx; + void *privatedata; +{ + if (ctx == NULL) + return MI_FAILURE; + ctx->ctx_privdata = privatedata; + return MI_SUCCESS; +} + +/* +** SMFI_GETPRIV -- get private data +** +** Parameters: +** ctx -- Opaque context structure +** +** Returns: +** pointer to private data +*/ + +void * +smfi_getpriv(ctx) + SMFICTX *ctx; +{ + if (ctx == NULL) + return NULL; + return ctx->ctx_privdata; +} + +/* +** SMFI_GETSYMVAL -- get the value of a macro +** +** See explanation in mfapi.h about layout of the structures. +** +** Parameters: +** ctx -- Opaque context structure +** symname -- name of macro +** +** Returns: +** value of macro (NULL in case of failure) +*/ + +char * +smfi_getsymval(ctx, symname) + SMFICTX *ctx; + char *symname; +{ + int i; + char **s; + char one[2]; + char braces[4]; + + if (ctx == NULL || symname == NULL || *symname == '\0') + return NULL; + + if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') + { + one[0] = symname[1]; + one[1] = '\0'; + } + else + one[0] = '\0'; + if (strlen(symname) == 1) + { + braces[0] = '{'; + braces[1] = *symname; + braces[2] = '}'; + braces[3] = '\0'; + } + else + braces[0] = '\0'; + + /* search backwards through the macro array */ + for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) + { + if ((s = ctx->ctx_mac_ptr[i]) == NULL || + ctx->ctx_mac_buf[i] == NULL) + continue; + while (s != NULL && *s != NULL) + { + if (strcmp(*s, symname) == 0) + return *++s; + if (one[0] != '\0' && strcmp(*s, one) == 0) + return *++s; + if (braces[0] != '\0' && strcmp(*s, braces) == 0) + return *++s; + ++s; /* skip over macro value */ + ++s; /* points to next macro name */ + } + } + return NULL; +} + +/* +** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature +** timeouts during long milter-side operations +** +** Parameters: +** ctx -- Opaque context structure +** +** Return value: +** MI_SUCCESS/MI_FAILURE +*/ + +int +smfi_progress(ctx) + SMFICTX *ctx; +{ + struct timeval timeout; + + if (ctx == NULL) + return MI_FAILURE; + + timeout.tv_sec = ctx->ctx_timeout; + timeout.tv_usec = 0; + + return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); +} + +/* +** SMFI_VERSION -- return (runtime) version of libmilter +** +** Parameters: +** major -- (pointer to) major version +** minor -- (pointer to) minor version +** patchlevel -- (pointer to) patchlevel version +** +** Return value: +** MI_SUCCESS +*/ + +int +smfi_version(major, minor, patchlevel) + unsigned int *major; + unsigned int *minor; + unsigned int *patchlevel; +{ + if (major != NULL) + *major = SM_LM_VRS_MAJOR(SMFI_VERSION); + if (minor != NULL) + *minor = SM_LM_VRS_MINOR(SMFI_VERSION); + if (patchlevel != NULL) + *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION); + return MI_SUCCESS; +} diff --git a/contrib/sendmail/libmilter/worker.c b/contrib/sendmail/libmilter/worker.c new file mode 100644 index 0000000..28d404f --- /dev/null +++ b/contrib/sendmail/libmilter/worker.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2003-2004, 2007, 2009 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris + * Jose-Marcio.Martins@ensmp.fr + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: worker.c,v 8.17 2009/06/15 15:34:54 ca Exp $") + +#include "libmilter.h" + +#if _FFR_WORKERS_POOL + +typedef struct taskmgr_S taskmgr_T; + +#define TM_SIGNATURE 0x23021957 + +struct taskmgr_S +{ + long tm_signature; /* has the controller been initialized */ + sthread_t tm_tid; /* thread id of controller */ + smfi_hd_T tm_ctx_head; /* head of the linked list of contexts */ + + int tm_nb_workers; /* number of workers in the pool */ + int tm_nb_idle; /* number of workers waiting */ + + int tm_p[2]; /* poll control pipe */ + + smutex_t tm_w_mutex; /* linked list access mutex */ + scond_t tm_w_cond; /* */ +}; + +static taskmgr_T Tskmgr = {0}; + +#define WRK_CTX_HEAD Tskmgr.tm_ctx_head + +#define RD_PIPE (Tskmgr.tm_p[0]) +#define WR_PIPE (Tskmgr.tm_p[1]) + +#define PIPE_SEND_SIGNAL() \ + do \ + { \ + char evt = 0x5a; \ + int fd = WR_PIPE; \ + if (write(fd, &evt, sizeof(evt)) != sizeof(evt)) \ + smi_log(SMI_LOG_ERR, \ + "Error writing to event pipe: %s", \ + sm_errstring(errno)); \ + } while (0) + +#ifndef USE_PIPE_WAKE_POLL +# define USE_PIPE_WAKE_POLL 1 +#endif /* USE_PIPE_WAKE_POLL */ + +/* poll check periodicity (default 10000 - 10 s) */ +#define POLL_TIMEOUT 10000 + +/* worker conditional wait timeout (default 10 s) */ +#define COND_TIMEOUT 10 + +/* functions */ +static int mi_close_session __P((SMFICTX_PTR)); + +static void *mi_worker __P((void *)); +static void *mi_pool_controller __P((void *)); + +static int mi_list_add_ctx __P((SMFICTX_PTR)); +static int mi_list_del_ctx __P((SMFICTX_PTR)); + +/* +** periodicity of cleaning up old sessions (timedout) +** sessions list will be checked to find old inactive +** sessions each DT_CHECK_OLD_SESSIONS sec +*/ + +#define DT_CHECK_OLD_SESSIONS 600 + +#ifndef OLD_SESSION_TIMEOUT +# define OLD_SESSION_TIMEOUT ctx->ctx_timeout +#endif /* OLD_SESSION_TIMEOUT */ + +/* session states - with respect to the pool of workers */ +#define WKST_INIT 0 /* initial state */ +#define WKST_READY_TO_RUN 1 /* command ready do be read */ +#define WKST_RUNNING 2 /* session running on a worker */ +#define WKST_READY_TO_WAIT 3 /* session just finished by a worker */ +#define WKST_WAITING 4 /* waiting for new command */ +#define WKST_CLOSING 5 /* session finished */ + +#ifndef MIN_WORKERS +# define MIN_WORKERS 2 /* minimum number of threads to keep around */ +#endif + +#define MIN_IDLE 1 /* minimum number of idle threads */ + + +/* +** Macros for threads and mutex management +*/ + +#define TASKMGR_LOCK() \ + do \ + { \ + if (!smutex_lock(&Tskmgr.tm_w_mutex)) \ + smi_log(SMI_LOG_ERR, "TASKMGR_LOCK error"); \ + } while (0) + +#define TASKMGR_UNLOCK() \ + do \ + { \ + if (!smutex_unlock(&Tskmgr.tm_w_mutex)) \ + smi_log(SMI_LOG_ERR, "TASKMGR_UNLOCK error"); \ + } while (0) + +#define TASKMGR_COND_WAIT() \ + scond_timedwait(&Tskmgr.tm_w_cond, &Tskmgr.tm_w_mutex, COND_TIMEOUT) + +#define TASKMGR_COND_SIGNAL() \ + do \ + { \ + if (scond_signal(&Tskmgr.tm_w_cond) != 0) \ + smi_log(SMI_LOG_ERR, "TASKMGR_COND_SIGNAL error"); \ + } while (0) + +#define LAUNCH_WORKER(ctx) \ + do \ + { \ + int r; \ + sthread_t tid; \ + \ + if ((r = thread_create(&tid, mi_worker, ctx)) != 0) \ + smi_log(SMI_LOG_ERR, "LAUNCH_WORKER error: %s",\ + sm_errstring(r)); \ + } while (0) + +#if POOL_DEBUG +# define POOL_LEV_DPRINTF(lev, x) \ + do { \ + if ((lev) < ctx->ctx_dbg) \ + sm_dprintf x; \ + } while (0) +#else /* POOL_DEBUG */ +# define POOL_LEV_DPRINTF(lev, x) +#endif /* POOL_DEBUG */ + +/* +** MI_START_SESSION -- Start a session in the pool of workers +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_start_session(ctx) + SMFICTX_PTR ctx; +{ + static long id = 0; + + SM_ASSERT(Tskmgr.tm_signature == TM_SIGNATURE); + SM_ASSERT(ctx != NULL); + POOL_LEV_DPRINTF(4, ("PIPE r=[%d] w=[%d]", RD_PIPE, WR_PIPE)); + TASKMGR_LOCK(); + + if (mi_list_add_ctx(ctx) != MI_SUCCESS) + { + TASKMGR_UNLOCK(); + return MI_FAILURE; + } + + ctx->ctx_sid = id++; + + /* if there is an idle worker, signal it, otherwise start new worker */ + if (Tskmgr.tm_nb_idle > 0) + { + ctx->ctx_wstate = WKST_READY_TO_RUN; + TASKMGR_COND_SIGNAL(); + } + else + { + ctx->ctx_wstate = WKST_RUNNING; + LAUNCH_WORKER(ctx); + } + TASKMGR_UNLOCK(); + return MI_SUCCESS; +} + +/* +** MI_CLOSE_SESSION -- Close a session and clean up data structures +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +mi_close_session(ctx) + SMFICTX_PTR ctx; +{ + SM_ASSERT(ctx != NULL); + + (void) mi_list_del_ctx(ctx); + mi_clr_ctx(ctx); + + return MI_SUCCESS; +} + +/* +** MI_POOL_CONTROLER_INIT -- Launch the worker pool controller +** Must be called before starting sessions. +** +** Parameters: +** none +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_pool_controller_init() +{ + sthread_t tid; + int r, i; + + if (Tskmgr.tm_signature == TM_SIGNATURE) + return MI_SUCCESS; + + SM_TAILQ_INIT(&WRK_CTX_HEAD); + Tskmgr.tm_tid = (sthread_t) -1; + Tskmgr.tm_nb_workers = 0; + Tskmgr.tm_nb_idle = 0; + + if (pipe(Tskmgr.tm_p) != 0) + { + smi_log(SMI_LOG_ERR, "can't create event pipe: %s", + sm_errstring(errno)); + return MI_FAILURE; + } + + (void) smutex_init(&Tskmgr.tm_w_mutex); + (void) scond_init(&Tskmgr.tm_w_cond); + + /* Launch the pool controller */ + if ((r = thread_create(&tid, mi_pool_controller, (void *) NULL)) != 0) + { + smi_log(SMI_LOG_ERR, "can't create controller thread: %s", + sm_errstring(r)); + return MI_FAILURE; + } + Tskmgr.tm_tid = tid; + Tskmgr.tm_signature = TM_SIGNATURE; + + /* Create the pool of workers */ + for (i = 0; i < MIN_WORKERS; i++) + { + if ((r = thread_create(&tid, mi_worker, (void *) NULL)) != 0) + { + smi_log(SMI_LOG_ERR, "can't create workers crew: %s", + sm_errstring(r)); + return MI_FAILURE; + } + } + + return MI_SUCCESS; +} + +/* +** MI_POOL_CONTROLLER -- manage the pool of workers +** This thread must be running when listener begins +** starting sessions +** +** Parameters: +** arg -- unused +** +** Returns: +** NULL +** +** Control flow: +** for (;;) +** Look for timed out sessions +** Select sessions to wait for sendmail command +** Poll set of file descriptors +** if timeout +** continue +** For each file descriptor ready +** launch new thread if no worker available +** else +** signal waiting worker +*/ + +/* Poll structure array (pollfd) size step */ +#define PFD_STEP 256 + +#define WAIT_FD(i) (pfd[i].fd) +#define WAITFN "POLL" + +static void * +mi_pool_controller(arg) + void *arg; +{ + struct pollfd *pfd = NULL; + int dim_pfd = 0; + bool rebuild_set = true; + int pcnt = 0; /* error count for poll() failures */ + time_t lastcheck; + + Tskmgr.tm_tid = sthread_get_id(); + if (pthread_detach(Tskmgr.tm_tid) != 0) + { + smi_log(SMI_LOG_ERR, "Failed to detach pool controller thread"); + return NULL; + } + + pfd = (struct pollfd *) malloc(PFD_STEP * sizeof(struct pollfd)); + if (pfd == NULL) + { + smi_log(SMI_LOG_ERR, "Failed to malloc pollfd array: %s", + sm_errstring(errno)); + return NULL; + } + dim_pfd = PFD_STEP; + + lastcheck = time(NULL); + for (;;) + { + SMFICTX_PTR ctx; + int nfd, rfd, i; + time_t now; + + POOL_LEV_DPRINTF(4, ("Let's %s again...", WAITFN)); + + if (mi_stop() != MILTER_CONT) + break; + + TASKMGR_LOCK(); + + now = time(NULL); + + /* check for timed out sessions? */ + if (lastcheck + DT_CHECK_OLD_SESSIONS < now) + { + ctx = SM_TAILQ_FIRST(&WRK_CTX_HEAD); + while (ctx != SM_TAILQ_END(&WRK_CTX_HEAD)) + { + SMFICTX_PTR ctx_nxt; + + ctx_nxt = SM_TAILQ_NEXT(ctx, ctx_link); + if (ctx->ctx_wstate == WKST_WAITING) + { + if (ctx->ctx_wait == 0) + ctx->ctx_wait = now; + else if (ctx->ctx_wait + OLD_SESSION_TIMEOUT + < now) + { + /* if session timed out, close it */ + sfsistat (*fi_close) __P((SMFICTX *)); + + POOL_LEV_DPRINTF(4, + ("Closing old connection: sd=%d id=%d", + ctx->ctx_sd, + ctx->ctx_sid)); + + if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) + (void) (*fi_close)(ctx); + + mi_close_session(ctx); + } + } + ctx = ctx_nxt; + } + lastcheck = now; + } + + if (rebuild_set) + { + /* + ** Initialize poll set. + ** Insert into the poll set the file descriptors of + ** all sessions waiting for a command from sendmail. + */ + + nfd = 0; + + /* begin with worker pipe */ + pfd[nfd].fd = RD_PIPE; + pfd[nfd].events = MI_POLL_RD_FLAGS; + pfd[nfd].revents = 0; + nfd++; + + SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link) + { + /* + ** update ctx_wait - start of wait moment - + ** for timeout + */ + + if (ctx->ctx_wstate == WKST_READY_TO_WAIT) + ctx->ctx_wait = now; + + /* add the session to the pollfd array? */ + if ((ctx->ctx_wstate == WKST_READY_TO_WAIT) || + (ctx->ctx_wstate == WKST_WAITING)) + { + /* + ** Resize the pollfd array if it + ** isn't large enough. + */ + + if (nfd >= dim_pfd) + { + struct pollfd *tpfd; + size_t new; + + new = (dim_pfd + PFD_STEP) * + sizeof(*tpfd); + tpfd = (struct pollfd *) + realloc(pfd, new); + if (tpfd != NULL) + { + pfd = tpfd; + dim_pfd += PFD_STEP; + } + else + { + smi_log(SMI_LOG_ERR, + "Failed to realloc pollfd array:%s", + sm_errstring(errno)); + } + } + + /* add the session to pollfd array */ + if (nfd < dim_pfd) + { + ctx->ctx_wstate = WKST_WAITING; + pfd[nfd].fd = ctx->ctx_sd; + pfd[nfd].events = MI_POLL_RD_FLAGS; + pfd[nfd].revents = 0; + nfd++; + } + } + } + rebuild_set = false; + } + + TASKMGR_UNLOCK(); + + /* Everything is ready, let's wait for an event */ + rfd = poll(pfd, nfd, POLL_TIMEOUT); + + POOL_LEV_DPRINTF(4, ("%s returned: at epoch %d value %d", + WAITFN, now, nfd)); + + /* timeout */ + if (rfd == 0) + continue; + + rebuild_set = true; + + /* error */ + if (rfd < 0) + { + if (errno == EINTR) + continue; + pcnt++; + smi_log(SMI_LOG_ERR, + "%s() failed (%s), %s", + WAITFN, sm_errstring(errno), + pcnt >= MAX_FAILS_S ? "abort" : "try again"); + + if (pcnt >= MAX_FAILS_S) + goto err; + } + pcnt = 0; + + /* something happened */ + for (i = 0; i < nfd; i++) + { + if (pfd[i].revents == 0) + continue; + + POOL_LEV_DPRINTF(4, ("%s event on pfd[%d/%d]=%d ", + WAITFN, i, nfd, + WAIT_FD(i))); + + /* has a worker signaled an end of task ? */ + if (WAIT_FD(i) == RD_PIPE) + { + char evt = 0; + int r = 0; + + POOL_LEV_DPRINTF(4, + ("PIPE WILL READ evt = %08X %08X", + pfd[i].events, pfd[i].revents)); + + if ((pfd[i].revents & MI_POLL_RD_FLAGS) != 0) + { + r = read(RD_PIPE, &evt, sizeof(evt)); + if (r == sizeof(evt)) + { + /* Do nothing */ + } + } + + POOL_LEV_DPRINTF(4, + ("PIPE DONE READ i=[%d] fd=[%d] r=[%d] evt=[%d]", + i, RD_PIPE, r, evt)); + + if ((pfd[i].revents & ~MI_POLL_RD_FLAGS) != 0) + { + /* Exception handling */ + } + continue; + } + + /* no ! sendmail wants to send a command */ + SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link) + { + if (ctx->ctx_wstate != WKST_WAITING) + continue; + + POOL_LEV_DPRINTF(4, + ("Checking context sd=%d - fd=%d ", + ctx->ctx_sd , WAIT_FD(i))); + + if (ctx->ctx_sd == pfd[i].fd) + { + TASKMGR_LOCK(); + + POOL_LEV_DPRINTF(4, + ("TASK: found %d for fd[%d]=%d", + ctx->ctx_sid, i, WAIT_FD(i))); + + if (Tskmgr.tm_nb_idle > 0) + { + ctx->ctx_wstate = WKST_READY_TO_RUN; + TASKMGR_COND_SIGNAL(); + } + else + { + ctx->ctx_wstate = WKST_RUNNING; + LAUNCH_WORKER(ctx); + } + TASKMGR_UNLOCK(); + break; + } + } + + POOL_LEV_DPRINTF(4, + ("TASK %s FOUND - Checking PIPE for fd[%d]", + ctx != NULL ? "" : "NOT", WAIT_FD(i))); + } + } + + err: + if (pfd != NULL) + free(pfd); + + Tskmgr.tm_signature = 0; + for (;;) + { + SMFICTX_PTR ctx; + + ctx = SM_TAILQ_FIRST(&WRK_CTX_HEAD); + if (ctx == NULL) + break; + mi_close_session(ctx); + } + + (void) smutex_destroy(&Tskmgr.tm_w_mutex); + (void) scond_destroy(&Tskmgr.tm_w_cond); + + return NULL; +} + +/* +** Look for a task ready to run. +** Value of ctx is NULL or a pointer to a task ready to run. +*/ + +#define GET_TASK_READY_TO_RUN() \ + SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link) \ + { \ + if (ctx->ctx_wstate == WKST_READY_TO_RUN) \ + { \ + ctx->ctx_wstate = WKST_RUNNING; \ + break; \ + } \ + } + +/* +** MI_WORKER -- worker thread +** executes tasks distributed by the mi_pool_controller +** or by mi_start_session +** +** Parameters: +** arg -- pointer to context structure +** +** Returns: +** NULL pointer +*/ + +static void * +mi_worker(arg) + void *arg; +{ + SMFICTX_PTR ctx; + bool done; + sthread_t t_id; + int r; + + ctx = (SMFICTX_PTR) arg; + done = false; + if (ctx != NULL) + ctx->ctx_wstate = WKST_RUNNING; + + t_id = sthread_get_id(); + if (pthread_detach(t_id) != 0) + { + smi_log(SMI_LOG_ERR, "Failed to detach worker thread"); + if (ctx != NULL) + ctx->ctx_wstate = WKST_READY_TO_RUN; + return NULL; + } + + TASKMGR_LOCK(); + Tskmgr.tm_nb_workers++; + TASKMGR_UNLOCK(); + + while (!done) + { + if (mi_stop() != MILTER_CONT) + break; + + /* let's handle next task... */ + if (ctx != NULL) + { + int res; + + POOL_LEV_DPRINTF(4, + ("worker %d: new task -> let's handle it", + t_id)); + res = mi_engine(ctx); + POOL_LEV_DPRINTF(4, + ("worker %d: mi_engine returned %d", t_id, res)); + + TASKMGR_LOCK(); + if (res != MI_CONTINUE) + { + ctx->ctx_wstate = WKST_CLOSING; + + /* + ** Delete context from linked list of + ** sessions and close session. + */ + + mi_close_session(ctx); + } + else + { + ctx->ctx_wstate = WKST_READY_TO_WAIT; + + POOL_LEV_DPRINTF(4, + ("writing to event pipe...")); + + /* + ** Signal task controller to add new session + ** to poll set. + */ + + PIPE_SEND_SIGNAL(); + } + TASKMGR_UNLOCK(); + ctx = NULL; + + } + + /* check if there is any task waiting to be served */ + TASKMGR_LOCK(); + + GET_TASK_READY_TO_RUN(); + + /* Got a task? */ + if (ctx != NULL) + { + TASKMGR_UNLOCK(); + continue; + } + + /* + ** if not, let's check if there is enough idle workers + ** if yes: quit + */ + + if (Tskmgr.tm_nb_workers > MIN_WORKERS && + Tskmgr.tm_nb_idle > MIN_IDLE) + done = true; + + POOL_LEV_DPRINTF(4, ("worker %d: checking ... %d %d", t_id, + Tskmgr.tm_nb_workers, Tskmgr.tm_nb_idle + 1)); + + if (done) + { + POOL_LEV_DPRINTF(4, ("worker %d: quitting... ", t_id)); + Tskmgr.tm_nb_workers--; + TASKMGR_UNLOCK(); + continue; + } + + /* + ** if no task ready to run, wait for another one + */ + + Tskmgr.tm_nb_idle++; + TASKMGR_COND_WAIT(); + Tskmgr.tm_nb_idle--; + + /* look for a task */ + GET_TASK_READY_TO_RUN(); + + TASKMGR_UNLOCK(); + } + return NULL; +} + +/* +** MI_LIST_ADD_CTX -- add new session to linked list +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_FAILURE/MI_SUCCESS +*/ + +static int +mi_list_add_ctx(ctx) + SMFICTX_PTR ctx; +{ + SM_ASSERT(ctx != NULL); + SM_TAILQ_INSERT_TAIL(&WRK_CTX_HEAD, ctx, ctx_link); + return MI_SUCCESS; +} + +/* +** MI_LIST_DEL_CTX -- remove session from linked list when finished +** +** Parameters: +** ctx -- context structure +** +** Returns: +** MI_FAILURE/MI_SUCCESS +*/ + +static int +mi_list_del_ctx(ctx) + SMFICTX_PTR ctx; +{ + SM_ASSERT(ctx != NULL); + if (SM_TAILQ_EMPTY(&WRK_CTX_HEAD)) + return MI_FAILURE; + + SM_TAILQ_REMOVE(&WRK_CTX_HEAD, ctx, ctx_link); + return MI_SUCCESS; +} +#endif /* _FFR_WORKERS_POOL */ |