-p port | The port through which the MTA will connect to the filter. |
-t sec | The timeout value. |
-r addr | A recipient to reject. |
-a addr | A recipient to add. |
#include "mfapi.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sysexits.h> #include <unistd.h> #ifndef bool #define bool char #define TRUE 1 #define FALSE 0 #endif extern int errno; struct mlfiPriv { char *mlfi_fname; char *mlfi_connectfrom; char *mlfi_helofrom; FILE *mlfi_fp; }; #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) extern sfsistat mlfi_cleanup(SMFICTX *, bool); /* recipients to add and reject (set with -a and -r options) */ char *add, *reject; sfsistat mlfi_connect(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 */ smfi_setpriv(ctx, priv); ident = smfi_getsymval(ctx, "_"); if(!ident) ident = "???"; if(!(priv->mlfi_connectfrom = strdup(ident))) { return SMFIS_TEMPFAIL; } /* Continue processing. */ return SMFIS_CONTINUE; } sfsistat mlfi_helo(ctx, helohost) SMFICTX *ctx; char *helohost; { char *tls; char *buf; struct mlfiPriv *priv = MLFIPRIV; tls = smfi_getsymval(ctx, "{tls_version}"); if(!tls) tls = "No TLS"; if(!helohost) helohost = "???"; if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) { return SMFIS_TEMPFAIL; } sprintf(buf, "%s, %s", helohost, tls); if(priv->mlfi_helofrom) free(priv->mlfi_helofrom); priv->mlfi_helofrom = buf; /* Continue processing. */ return SMFIS_CONTINUE; } sfsistat mlfi_envfrom(ctx, argv) SMFICTX *ctx; char **argv; { struct mlfiPriv *priv = MLFIPRIV; char *mailaddr = smfi_getsymval(ctx, "{mail_addr}"); int argc = 0; /* open a file to store this message */ priv->mlfi_fname = strdup("/tmp/msg.XXXXXX"); mkstemp(priv->mlfi_fname); if (priv->mlfi_fname == NULL) return SMFIS_TEMPFAIL; if ((priv->mlfi_fp = fopen(priv->mlfi_fname, "w+")) == NULL) { free(priv->mlfi_fname); return SMFIS_TEMPFAIL; } /* count the arguments */ while(*argv++) ++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 mlfi_envrcpt(ctx, argv) SMFICTX *ctx; char **argv; { struct mlfiPriv *priv = MLFIPRIV; char *rcptaddr = smfi_getsymval(ctx, "{rcpt_addr}"); int argc = 0; /* count the arguments */ while(*argv++) ++argc; /* log this recipient */ if(reject && rcptaddr && (strcmp(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 mlfi_header(ctx, headerf, headerv) SMFICTX *ctx; char *headerf; unsigned char *headerv; { /* write the header to the log file */ fprintf(MLFIPRIV->mlfi_fp, "%s: %s\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, "\n"); /* continue processing */ return SMFIS_CONTINUE; } sfsistat mlfi_body(ctx, bodyp, bodylen) SMFICTX *ctx; unsigned char *bodyp; size_t bodylen; { /* output body block to log file */ int nwritten; if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp)) != 1) { /* write failed */ perror("error logging body"); (void) mlfi_cleanup(ctx, FALSE); return SMFIS_TEMPFAIL; } /* continue processing */ return SMFIS_CONTINUE; } sfsistat mlfi_eom(ctx) SMFICTX *ctx; { bool ok = TRUE; /* change recipients, if requested */ if(add) ok = ok && (smfi_addrcpt(ctx, add) == MI_SUCCESS); return mlfi_cleanup(ctx, ok); } 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 */ 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) strncpy(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 */ fprintf(stderr, "Message aborted. Removing %s\n", priv->mlfi_fname); rstat = SMFIS_TEMPFAIL; (void) unlink(priv->mlfi_fname); } /* release private memory */ free(priv->mlfi_fname); /* return status */ return rstat; } sfsistat mlfi_close(ctx) SMFICTX *ctx; { struct mlfiPriv *priv = MLFIPRIV; if(priv->mlfi_connectfrom) free(priv->mlfi_connectfrom); if(priv->mlfi_helofrom) free(priv->mlfi_helofrom); free(priv); smfi_setpriv(ctx, NULL); return SMFIS_CONTINUE; } struct smfiDesc smfilter = { "SampleFilter", /* filter name */ SMFI_VERSION, /* version code -- do not change */ SMFIF_ADDHDRS, /* flags */ mlfi_connect, /* connection info filter */ mlfi_helo, /* SMTP HELO command filter */ mlfi_envfrom, /* envelope sender filter */ mlfi_envrcpt, /* 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 */ }; static void usage() { fprintf(stderr, "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\ \t[-a accept-addr]\n"); } int main(argc, argv) int argc; char *argv[]; { int retval; char c; const char *args = "p:t:r:a:h"; extern char *optarg; /* Process command line options */ while ((c = getopt(argc, argv, args)) != (char)EOF) { switch (c) { case 'p': if (optarg == NULL || *optarg == '\0') { (void) fprintf(stderr, "Illegal conn: %s\n", optarg); exit(EX_USAGE); } if(smfi_setconn(optarg) == MI_FAILURE) { (void) fputs("smfi_setconn failed", stderr); exit(EX_SOFTWARE); } /* ** If we're using a local socket, make sure it doesn't ** already exist. */ if(strncmp(optarg, "unix:", 5) == 0) unlink(optarg + 5); else if(strncmp(optarg, "local:", 6) == 0) unlink(optarg + 6); break; case 't': if (optarg == NULL || *optarg == '\0') { (void) fprintf(stderr, "Illegal timeout: %s\n", optarg); exit(EX_USAGE); } if(smfi_settimeout(atoi(optarg)) == MI_FAILURE) { (void) fputs("smfi_settimeout failed", stderr); 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(); exit(0); } } if (smfi_register(smfilter) == MI_FAILURE) { fprintf(stderr, "smfi_register failed\n"); exit(EX_UNAVAILABLE); } retval = smfi_main(); return retval; } /* eof */