sample.html revision 90792
190792Sgshapiro<html> 290792Sgshapiro<head><title>A Sample Filter</title></head> 390792Sgshapiro<body> 490792Sgshapiro<h1>A Sample Filter</h1> 590792Sgshapiro 690792SgshapiroThe following sample logs each message to a separate temporary file, 790792Sgshapiroadds a recipient given with the -a flag, and rejects a disallowed 890792Sgshapirorecipient address given with the -r flag. It recognizes the following 990792Sgshapirooptions: 1090792Sgshapiro<p> 1190792Sgshapiro<center> 1290792Sgshapiro<table border="1" cellpadding=2 cellspacing=1> 1390792Sgshapiro<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr> 1490792Sgshapiro<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr> 1590792Sgshapiro<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr> 1690792Sgshapiro<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr> 1790792Sgshapiro</table> 1890792Sgshapiro</center> 1990792Sgshapiro<hr> 2090792Sgshapiro<pre> 2190792Sgshapiro#include "mfapi.h" 2290792Sgshapiro 2390792Sgshapiro#include <stdio.h> 2490792Sgshapiro#include <stdlib.h> 2590792Sgshapiro#include <string.h> 2690792Sgshapiro#include <sys/types.h> 2790792Sgshapiro#include <sys/stat.h> 2890792Sgshapiro#include <sysexits.h> 2990792Sgshapiro#include <unistd.h> 3090792Sgshapiro#ifndef bool 3190792Sgshapiro#define bool char 3290792Sgshapiro#define TRUE 1 3390792Sgshapiro#define FALSE 0 3490792Sgshapiro#endif 3590792Sgshapiro 3690792Sgshapiroextern int errno; 3790792Sgshapiro 3890792Sgshapiro 3990792Sgshapirostruct mlfiPriv 4090792Sgshapiro{ 4190792Sgshapiro char *mlfi_fname; 4290792Sgshapiro char *mlfi_connectfrom; 4390792Sgshapiro char *mlfi_helofrom; 4490792Sgshapiro FILE *mlfi_fp; 4590792Sgshapiro}; 4690792Sgshapiro 4790792Sgshapiro#define MLFIPRIV ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx)) 4890792Sgshapiro 4990792Sgshapiroextern sfsistat mlfi_cleanup(SMFICTX *, bool); 5090792Sgshapiro/* recipients to add and reject (set with -a and -r options) */ 5190792Sgshapirochar *add, *reject; 5290792Sgshapiro 5390792Sgshapirosfsistat 5490792Sgshapiro<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr) 5590792Sgshapiro SMFICTX *ctx; 5690792Sgshapiro char *hostname; 5790792Sgshapiro _SOCK_ADDR *hostaddr; 5890792Sgshapiro{ 5990792Sgshapiro struct mlfiPriv *priv; 6090792Sgshapiro char *ident; 6190792Sgshapiro 6290792Sgshapiro /* allocate some private memory */ 6390792Sgshapiro priv = malloc(sizeof *priv); 6490792Sgshapiro if (priv == NULL) 6590792Sgshapiro { 6690792Sgshapiro /* can't accept this message right now */ 6790792Sgshapiro return SMFIS_TEMPFAIL; 6890792Sgshapiro } 6990792Sgshapiro memset(priv, '\0', sizeof *priv); 7090792Sgshapiro 7190792Sgshapiro /* save the private data */ 7290792Sgshapiro <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv); 7390792Sgshapiro 7490792Sgshapiro ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_"); 7590792Sgshapiro if(!ident) ident = "???"; 7690792Sgshapiro if(!(priv->mlfi_connectfrom = strdup(ident))) { 7790792Sgshapiro return SMFIS_TEMPFAIL; 7890792Sgshapiro } 7990792Sgshapiro /* Continue processing. */ 8090792Sgshapiro return SMFIS_CONTINUE; 8190792Sgshapiro} 8290792Sgshapiro 8390792Sgshapirosfsistat 8490792Sgshapiro<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost) 8590792Sgshapiro SMFICTX *ctx; 8690792Sgshapiro char *helohost; 8790792Sgshapiro{ 8890792Sgshapiro char *tls; 8990792Sgshapiro char *buf; 9090792Sgshapiro struct mlfiPriv *priv = MLFIPRIV; 9190792Sgshapiro tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}"); 9290792Sgshapiro if(!tls) tls = "No TLS"; 9390792Sgshapiro if(!helohost) helohost = "???"; 9490792Sgshapiro if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) { 9590792Sgshapiro return SMFIS_TEMPFAIL; 9690792Sgshapiro } 9790792Sgshapiro sprintf(buf, "%s, %s", helohost, tls); 9890792Sgshapiro if(priv->mlfi_helofrom) 9990792Sgshapiro free(priv->mlfi_helofrom); 10090792Sgshapiro priv->mlfi_helofrom = buf; 10190792Sgshapiro /* Continue processing. */ 10290792Sgshapiro return SMFIS_CONTINUE; 10390792Sgshapiro} 10490792Sgshapiro 10590792Sgshapirosfsistat 10690792Sgshapiro<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv) 10790792Sgshapiro SMFICTX *ctx; 10890792Sgshapiro char **argv; 10990792Sgshapiro{ 11090792Sgshapiro struct mlfiPriv *priv = MLFIPRIV; 11190792Sgshapiro char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}"); 11290792Sgshapiro int argc = 0; 11390792Sgshapiro 11490792Sgshapiro /* open a file to store this message */ 11590792Sgshapiro priv->mlfi_fname = strdup("/tmp/msg.XXXXXX"); 11690792Sgshapiro mkstemp(priv->mlfi_fname); 11790792Sgshapiro if (priv->mlfi_fname == NULL) 11890792Sgshapiro return SMFIS_TEMPFAIL; 11990792Sgshapiro if ((priv->mlfi_fp = fopen(priv->mlfi_fname, "w+")) == NULL) 12090792Sgshapiro { 12190792Sgshapiro free(priv->mlfi_fname); 12290792Sgshapiro return SMFIS_TEMPFAIL; 12390792Sgshapiro } 12490792Sgshapiro 12590792Sgshapiro /* count the arguments */ 12690792Sgshapiro while(*argv++) ++argc; 12790792Sgshapiro /* log the connection information we stored earlier: */ 12890792Sgshapiro if(fprintf(priv->mlfi_fp, "Connect from %s (%s)\n\n", 12990792Sgshapiro priv->mlfi_helofrom, priv->mlfi_connectfrom) == EOF) { 13090792Sgshapiro (void) mlfi_cleanup(ctx, FALSE); 13190792Sgshapiro return SMFIS_TEMPFAIL; 13290792Sgshapiro } 13390792Sgshapiro /* log the sender */ 13490792Sgshapiro if(fprintf(priv->mlfi_fp, "FROM %s (%d argument%s)\n", 13590792Sgshapiro mailaddr?mailaddr:"???", argc, 13690792Sgshapiro (argc == 1)?"":"s") 13790792Sgshapiro == EOF) { 13890792Sgshapiro (void) mlfi_cleanup(ctx, FALSE); 13990792Sgshapiro return SMFIS_TEMPFAIL; 14090792Sgshapiro } 14190792Sgshapiro /* continue processing */ 14290792Sgshapiro return SMFIS_CONTINUE; 14390792Sgshapiro} 14490792Sgshapiro 14590792Sgshapirosfsistat 14690792Sgshapiro<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv) 14790792Sgshapiro SMFICTX *ctx; 14890792Sgshapiro char **argv; 14990792Sgshapiro{ 15090792Sgshapiro struct mlfiPriv *priv = MLFIPRIV; 15190792Sgshapiro char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}"); 15290792Sgshapiro int argc = 0; 15390792Sgshapiro /* count the arguments */ 15490792Sgshapiro while(*argv++) ++argc; 15590792Sgshapiro /* log this recipient */ 15690792Sgshapiro if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) { 15790792Sgshapiro if(fprintf(priv->mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr) 15890792Sgshapiro == EOF) { 15990792Sgshapiro (void) mlfi_cleanup(ctx, FALSE); 16090792Sgshapiro return SMFIS_TEMPFAIL; 16190792Sgshapiro } 16290792Sgshapiro return SMFIS_REJECT; 16390792Sgshapiro } 16490792Sgshapiro if(fprintf(priv->mlfi_fp, "RCPT %s (%d argument%s)\n", 16590792Sgshapiro rcptaddr?rcptaddr:"???", argc, 16690792Sgshapiro (argc == 1)?"":"s") 16790792Sgshapiro == EOF) { 16890792Sgshapiro (void) mlfi_cleanup(ctx, FALSE); 16990792Sgshapiro return SMFIS_TEMPFAIL; 17090792Sgshapiro } 17190792Sgshapiro /* continue processing */ 17290792Sgshapiro return SMFIS_CONTINUE; 17390792Sgshapiro} 17490792Sgshapiro 17590792Sgshapirosfsistat 17690792Sgshapiro<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv) 17790792Sgshapiro SMFICTX *ctx; 17890792Sgshapiro char *headerf; 17990792Sgshapiro unsigned char *headerv; 18090792Sgshapiro{ 18190792Sgshapiro /* write the header to the log file */ 18290792Sgshapiro fprintf(MLFIPRIV->mlfi_fp, "%s: %s\n", headerf, headerv); 18390792Sgshapiro 18490792Sgshapiro /* continue processing */ 18590792Sgshapiro return SMFIS_CONTINUE; 18690792Sgshapiro} 18790792Sgshapiro 18890792Sgshapirosfsistat 18990792Sgshapiro<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx) 19090792Sgshapiro SMFICTX *ctx; 19190792Sgshapiro{ 19290792Sgshapiro /* output the blank line between the header and the body */ 19390792Sgshapiro fprintf(MLFIPRIV->mlfi_fp, "\n"); 19490792Sgshapiro 19590792Sgshapiro /* continue processing */ 19690792Sgshapiro return SMFIS_CONTINUE; 19790792Sgshapiro} 19890792Sgshapiro 19990792Sgshapirosfsistat 20090792Sgshapiro<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen) 20190792Sgshapiro SMFICTX *ctx; 20290792Sgshapiro unsigned char *bodyp; 20390792Sgshapiro size_t bodylen; 20490792Sgshapiro{ 20590792Sgshapiro /* output body block to log file */ 20690792Sgshapiro int nwritten; 20790792Sgshapiro if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp)) != 1) 20890792Sgshapiro { 20990792Sgshapiro /* write failed */ 21090792Sgshapiro perror("error logging body"); 21190792Sgshapiro (void) mlfi_cleanup(ctx, FALSE); 21290792Sgshapiro return SMFIS_TEMPFAIL; 21390792Sgshapiro } 21490792Sgshapiro 21590792Sgshapiro /* continue processing */ 21690792Sgshapiro return SMFIS_CONTINUE; 21790792Sgshapiro} 21890792Sgshapiro 21990792Sgshapirosfsistat 22090792Sgshapiro<a href="xxfi_eom.html">mlfi_eom</a>(ctx) 22190792Sgshapiro SMFICTX *ctx; 22290792Sgshapiro{ 22390792Sgshapiro bool ok = TRUE; 22490792Sgshapiro /* change recipients, if requested */ 22590792Sgshapiro if(add) 22690792Sgshapiro ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS); 22790792Sgshapiro return mlfi_cleanup(ctx, ok); 22890792Sgshapiro} 22990792Sgshapiro 23090792Sgshapirosfsistat 23190792Sgshapiro<a href="xxfi_abort.html">mlfi_abort</a>(ctx) 23290792Sgshapiro SMFICTX *ctx; 23390792Sgshapiro{ 23490792Sgshapiro return mlfi_cleanup(ctx, FALSE); 23590792Sgshapiro} 23690792Sgshapiro 23790792Sgshapirosfsistat 23890792Sgshapiromlfi_cleanup(ctx, ok) 23990792Sgshapiro SMFICTX *ctx; 24090792Sgshapiro bool ok; 24190792Sgshapiro{ 24290792Sgshapiro sfsistat rstat = SMFIS_CONTINUE; 24390792Sgshapiro struct mlfiPriv *priv = MLFIPRIV; 24490792Sgshapiro char *p; 24590792Sgshapiro char host[512]; 24690792Sgshapiro char hbuf[1024]; 24790792Sgshapiro 24890792Sgshapiro if (priv == NULL) 24990792Sgshapiro return rstat; 25090792Sgshapiro 25190792Sgshapiro /* close the archive file */ 25290792Sgshapiro if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) 25390792Sgshapiro { 25490792Sgshapiro /* failed; we have to wait until later */ 25590792Sgshapiro fprintf(stderr, "Couldn't close archive file %s: %s\n", 25690792Sgshapiro priv->mlfi_fname, strerror(errno)); 25790792Sgshapiro rstat = SMFIS_TEMPFAIL; 25890792Sgshapiro (void) unlink(priv->mlfi_fname); 25990792Sgshapiro } 26090792Sgshapiro else if (ok) 26190792Sgshapiro { 26290792Sgshapiro /* add a header to the message announcing our presence */ 26390792Sgshapiro if (gethostname(host, sizeof host) < 0) 26490792Sgshapiro strncpy(host, "localhost", sizeof host); 26590792Sgshapiro p = strrchr(priv->mlfi_fname, '/'); 26690792Sgshapiro if (p == NULL) 26790792Sgshapiro p = priv->mlfi_fname; 26890792Sgshapiro else 26990792Sgshapiro p++; 27090792Sgshapiro snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); 27190792Sgshapiro <a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf); 27290792Sgshapiro } 27390792Sgshapiro else 27490792Sgshapiro { 27590792Sgshapiro /* message was aborted -- delete the archive file */ 27690792Sgshapiro fprintf(stderr, "Message aborted. Removing %s\n", 27790792Sgshapiro priv->mlfi_fname); 27890792Sgshapiro rstat = SMFIS_TEMPFAIL; 27990792Sgshapiro (void) unlink(priv->mlfi_fname); 28090792Sgshapiro } 28190792Sgshapiro 28290792Sgshapiro /* release private memory */ 28390792Sgshapiro free(priv->mlfi_fname); 28490792Sgshapiro 28590792Sgshapiro /* return status */ 28690792Sgshapiro return rstat; 28790792Sgshapiro} 28890792Sgshapiro 28990792Sgshapirosfsistat 29090792Sgshapiro<a href="xxfi_close.html">mlfi_close</a>(ctx) 29190792Sgshapiro SMFICTX *ctx; 29290792Sgshapiro{ 29390792Sgshapiro struct mlfiPriv *priv = MLFIPRIV; 29490792Sgshapiro if(priv->mlfi_connectfrom) 29590792Sgshapiro free(priv->mlfi_connectfrom); 29690792Sgshapiro if(priv->mlfi_helofrom) 29790792Sgshapiro free(priv->mlfi_helofrom); 29890792Sgshapiro free(priv); 29990792Sgshapiro <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL); 30090792Sgshapiro return SMFIS_CONTINUE; 30190792Sgshapiro} 30290792Sgshapiro 30390792Sgshapirostruct smfiDesc smfilter = 30490792Sgshapiro{ 30590792Sgshapiro "SampleFilter", /* filter name */ 30690792Sgshapiro SMFI_VERSION, /* version code -- do not change */ 30790792Sgshapiro SMFIF_ADDHDRS, /* flags */ 30890792Sgshapiro <a href="xxfi_connect.html">mlfi_connect</a>, /* connection info filter */ 30990792Sgshapiro <a href="xxfi_helo.html">mlfi_helo</a>, /* SMTP HELO command filter */ 31090792Sgshapiro <a href="xxfi_envfrom.html">mlfi_envfrom</a>, /* envelope sender filter */ 31190792Sgshapiro <a href="xxfi_envrcpt.html">mlfi_envrcpt</a>, /* envelope recipient filter */ 31290792Sgshapiro <a href="xxfi_header.html">mlfi_header</a>, /* header filter */ 31390792Sgshapiro <a href="xxfi_eoh.html">mlfi_eoh</a>, /* end of header */ 31490792Sgshapiro <a href="xxfi_body.html">mlfi_body</a>, /* body block filter */ 31590792Sgshapiro <a href="xxfi_eom.html">mlfi_eom</a>, /* end of message */ 31690792Sgshapiro <a href="xxfi_abort.html">mlfi_abort</a>, /* message aborted */ 31790792Sgshapiro <a href="xxfi_close.html">mlfi_close</a>, /* connection cleanup */ 31890792Sgshapiro}; 31990792Sgshapiro 32090792Sgshapirostatic void 32190792Sgshapirousage() 32290792Sgshapiro{ 32390792Sgshapiro fprintf(stderr, 32490792Sgshapiro "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\ 32590792Sgshapiro\t[-a accept-addr]\n"); 32690792Sgshapiro} 32790792Sgshapiro 32890792Sgshapiroint 32990792Sgshapiromain(argc, argv) 33090792Sgshapiro int argc; 33190792Sgshapiro char *argv[]; 33290792Sgshapiro{ 33390792Sgshapiro int retval; 33490792Sgshapiro char c; 33590792Sgshapiro const char *args = "p:t:r:a:h"; 33690792Sgshapiro extern char *optarg; 33790792Sgshapiro 33890792Sgshapiro /* Process command line options */ 33990792Sgshapiro while ((c = getopt(argc, argv, args)) != (char)EOF) 34090792Sgshapiro { 34190792Sgshapiro switch (c) 34290792Sgshapiro { 34390792Sgshapiro case 'p': 34490792Sgshapiro if (optarg == NULL || *optarg == '\0') 34590792Sgshapiro { 34690792Sgshapiro (void) fprintf(stderr, "Illegal conn: %s\n", 34790792Sgshapiro optarg); 34890792Sgshapiro exit(EX_USAGE); 34990792Sgshapiro } 35090792Sgshapiro if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE) 35190792Sgshapiro { 35290792Sgshapiro (void) fputs("smfi_setconn failed", stderr); 35390792Sgshapiro exit(EX_SOFTWARE); 35490792Sgshapiro } 35590792Sgshapiro /* 35690792Sgshapiro ** If we're using a local socket, make sure it doesn't 35790792Sgshapiro ** already exist. 35890792Sgshapiro */ 35990792Sgshapiro if(strncmp(optarg, "unix:", 5) == 0) 36090792Sgshapiro unlink(optarg + 5); 36190792Sgshapiro else if(strncmp(optarg, "local:", 6) == 0) 36290792Sgshapiro unlink(optarg + 6); 36390792Sgshapiro break; 36490792Sgshapiro 36590792Sgshapiro case 't': 36690792Sgshapiro if (optarg == NULL || *optarg == '\0') 36790792Sgshapiro { 36890792Sgshapiro (void) fprintf(stderr, "Illegal timeout: %s\n", 36990792Sgshapiro optarg); 37090792Sgshapiro exit(EX_USAGE); 37190792Sgshapiro } 37290792Sgshapiro if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE) 37390792Sgshapiro { 37490792Sgshapiro (void) fputs("smfi_settimeout failed", stderr); 37590792Sgshapiro exit(EX_SOFTWARE); 37690792Sgshapiro } 37790792Sgshapiro break; 37890792Sgshapiro 37990792Sgshapiro case 'r': 38090792Sgshapiro if (optarg == NULL) 38190792Sgshapiro { 38290792Sgshapiro (void) fprintf(stderr, "Illegal reject rcpt: %s\n", 38390792Sgshapiro optarg); 38490792Sgshapiro exit(EX_USAGE); 38590792Sgshapiro } 38690792Sgshapiro reject = optarg; 38790792Sgshapiro break; 38890792Sgshapiro 38990792Sgshapiro case 'a': 39090792Sgshapiro if (optarg == NULL) 39190792Sgshapiro { 39290792Sgshapiro (void) fprintf(stderr, "Illegal add rcpt: %s\n", 39390792Sgshapiro optarg); 39490792Sgshapiro exit(EX_USAGE); 39590792Sgshapiro } 39690792Sgshapiro add = optarg; 39790792Sgshapiro smfilter.xxfi_flags |= SMFIF_ADDRCPT; 39890792Sgshapiro break; 39990792Sgshapiro case 'h': 40090792Sgshapiro default: 40190792Sgshapiro usage(); 40290792Sgshapiro exit(0); 40390792Sgshapiro } 40490792Sgshapiro } 40590792Sgshapiro if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE) 40690792Sgshapiro { 40790792Sgshapiro fprintf(stderr, "smfi_register failed\n"); 40890792Sgshapiro exit(EX_UNAVAILABLE); 40990792Sgshapiro } 41090792Sgshapiro retval = <a href="smfi_main.html">smfi_main</a>(); 41190792Sgshapiro return retval; 41290792Sgshapiro} 41390792Sgshapiro 41490792Sgshapiro/* eof */ 41590792Sgshapiro 41690792Sgshapiro</pre> 41790792Sgshapiro<hr size="1"> 41890792Sgshapiro<font size="-1"> 41990792SgshapiroCopyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 42090792SgshapiroAll rights reserved. 42190792Sgshapiro<br> 42290792SgshapiroBy using this file, you agree to the terms and conditions set 42390792Sgshapiroforth in the <a href="LICENSE.txt">LICENSE</a>. 42490792Sgshapiro</font> 42590792Sgshapiro</body> 42690792Sgshapiro</html> 427