summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/libmilter/README
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/libmilter/README')
-rw-r--r--contrib/sendmail/libmilter/README408
1 files changed, 408 insertions, 0 deletions
diff --git a/contrib/sendmail/libmilter/README b/contrib/sendmail/libmilter/README
new file mode 100644
index 0000000..7166b40
--- /dev/null
+++ b/contrib/sendmail/libmilter/README
@@ -0,0 +1,408 @@
+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 .
+
+NOTE: Both libmilter and the callouts in sendmail are marked as an FFR (For
+Future Release). If you intend to use them in 8.10.X, you must compiled
+both libmilter and sendmail with -D_FFR_MILTER defined. You can do this by
+adding the following to your devtools/Site/site.config.m4 file:
+
+ dnl Milter
+ APPENDDEF(`conf_sendmail_ENVDEF', `-D_FFR_MILTER=1')
+ APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER=1')
+
+You will also need to define _FFR_MILTER when building your .cf file using
+m4.
+
++-------------------+
+| 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../../sendmail -I../../include -o sample sample.c libmilter.a ../libsmutil/libsmutil.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 OS 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.
+
+
++----------------------------------------+
+| 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=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=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
+
+Finally, you can override the default timeouts used by sendmail when
+talking to the filters using the T= equate. There are three fields inside
+of the T= equate:
+
+Letter Meaning
+ 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=S:10s;R:10s;E:5m
+
+where 's' is seconds and 'm' is minutes.
+
+Actual sequencing is handled by the InputMailFilters option which 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.10.0.Beta8/8.10.0.Beta8; Mon, 6 Dec 1999 19:34:23 -0800 (PST)
+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.
+
+
++--------------------------+
+| SOURCE FOR SAMPLE FILTER |
++--------------------------+
+
+/* A trivial filter that logs all email to a file. */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "libmilter/mfapi.h"
+
+typedef int bool;
+
+#ifndef FALSE
+# define FALSE 0
+#endif /* ! FALSE*/
+#ifndef TRUE
+# define TRUE 1
+#endif /* ! TRUE*/
+
+struct mlfiPriv
+{
+ char *mlfi_fname;
+ FILE *mlfi_fp;
+};
+
+#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
+
+extern sfsistat mlfi_cleanup(SMFICTX *, bool);
+
+sfsistat
+mlfi_envfrom(ctx, envfrom)
+ SMFICTX *ctx;
+ char **envfrom;
+{
+ struct mlfiPriv *priv;
+ int fd;
+
+ /* 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)
+ {
+ 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 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_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)
+ strlcpy(host, "localhost", sizeof host);
+ 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;
+}
+
+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 */
+};
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ const char *args = "p:";
+
+ /* 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);
+ }
+ (void) smfi_setconn(optarg);
+ break;
+
+ }
+ }
+ if (smfi_register(smfilter) == MI_FAILURE)
+ {
+ fprintf(stderr, "smfi_register failed\n");
+ exit(EX_UNAVAILABLE);
+ }
+ return smfi_main();
+}
+
+/* eof */
+
+$Revision: 8.9.2.1.2.8 $, Last updated $Date: 2000/07/18 15:43:26 $
OpenPOWER on IntegriCloud