diff options
Diffstat (limited to 'contrib/sendmail/libmilter/docs/sample.html')
-rw-r--r-- | contrib/sendmail/libmilter/docs/sample.html | 537 |
1 files changed, 537 insertions, 0 deletions
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> |