1<html> 2<head><title>A Sample Filter</title></head> 3<body> 4<h1>A Sample Filter</h1> 5 6The following sample logs each message to a separate temporary file, 7adds a recipient given with the -a flag, and rejects a disallowed 8recipient address given with the -r flag. It recognizes the following 9options: 10<p> 11<center> 12<table border="1" cellpadding=2 cellspacing=1> 13<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr> 14<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr> 15<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr> 16<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr> 17</table> 18</center> 19<hr> 20<pre> 21#include "mfapi.h" 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26#include <sys/types.h> 27#include <sys/stat.h> 28#include <sysexits.h> 29#include <unistd.h> 30#ifndef bool 31#define bool char 32#define TRUE 1 33#define FALSE 0 34#endif 35 36extern int errno; 37 38 39struct mlfiPriv 40{ 41 char *mlfi_fname; 42 char *mlfi_connectfrom; 43 char *mlfi_helofrom; 44 FILE *mlfi_fp; 45}; 46 47#define MLFIPRIV ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx)) 48 49extern sfsistat mlfi_cleanup(SMFICTX *, bool); 50/* recipients to add and reject (set with -a and -r options) */ 51char *add, *reject; 52 53sfsistat 54<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr) 55 SMFICTX *ctx; 56 char *hostname; 57 _SOCK_ADDR *hostaddr; 58{ 59 struct mlfiPriv *priv; 60 char *ident; 61 62 /* allocate some private memory */ 63 priv = malloc(sizeof *priv); 64 if (priv == NULL) 65 { 66 /* can't accept this message right now */ 67 return SMFIS_TEMPFAIL; 68 } 69 memset(priv, '\0', sizeof *priv); 70 71 /* save the private data */ 72 <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv); 73 74 ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_"); 75 if(!ident) ident = "???"; 76 if(!(priv->mlfi_connectfrom = strdup(ident))) { 77 return SMFIS_TEMPFAIL; 78 } 79 /* Continue processing. */ 80 return SMFIS_CONTINUE; 81} 82 83sfsistat 84<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost) 85 SMFICTX *ctx; 86 char *helohost; 87{ 88 char *tls; 89 char *buf; 90 struct mlfiPriv *priv = MLFIPRIV; 91 tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}"); 92 if(!tls) tls = "No TLS"; 93 if(!helohost) helohost = "???"; 94 if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) { 95 return SMFIS_TEMPFAIL; 96 } 97 sprintf(buf, "%s, %s", helohost, tls); 98 if(priv->mlfi_helofrom) 99 free(priv->mlfi_helofrom); 100 priv->mlfi_helofrom = buf; 101 /* Continue processing. */ 102 return SMFIS_CONTINUE; 103} 104 105sfsistat 106<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv) 107 SMFICTX *ctx; 108 char **argv; 109{ 110 struct mlfiPriv *priv = MLFIPRIV; 111 char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}"); 112 int argc = 0; 113 114 /* open a file to store this message */ 115 priv->mlfi_fname = strdup("/tmp/msg.XXXXXX"); 116 mkstemp(priv->mlfi_fname); 117 if (priv->mlfi_fname == NULL) 118 return SMFIS_TEMPFAIL; 119 if ((priv->mlfi_fp = fopen(priv->mlfi_fname, "w+")) == NULL) 120 { 121 free(priv->mlfi_fname); 122 return SMFIS_TEMPFAIL; 123 } 124 125 /* count the arguments */ 126 while(*argv++) ++argc; 127 /* log the connection information we stored earlier: */ 128 if(fprintf(priv->mlfi_fp, "Connect from %s (%s)\n\n", 129 priv->mlfi_helofrom, priv->mlfi_connectfrom) == EOF) { 130 (void) mlfi_cleanup(ctx, FALSE); 131 return SMFIS_TEMPFAIL; 132 } 133 /* log the sender */ 134 if(fprintf(priv->mlfi_fp, "FROM %s (%d argument%s)\n", 135 mailaddr?mailaddr:"???", argc, 136 (argc == 1)?"":"s") 137 == EOF) { 138 (void) mlfi_cleanup(ctx, FALSE); 139 return SMFIS_TEMPFAIL; 140 } 141 /* continue processing */ 142 return SMFIS_CONTINUE; 143} 144 145sfsistat 146<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv) 147 SMFICTX *ctx; 148 char **argv; 149{ 150 struct mlfiPriv *priv = MLFIPRIV; 151 char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}"); 152 int argc = 0; 153 /* count the arguments */ 154 while(*argv++) ++argc; 155 /* log this recipient */ 156 if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) { 157 if(fprintf(priv->mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr) 158 == EOF) { 159 (void) mlfi_cleanup(ctx, FALSE); 160 return SMFIS_TEMPFAIL; 161 } 162 return SMFIS_REJECT; 163 } 164 if(fprintf(priv->mlfi_fp, "RCPT %s (%d argument%s)\n", 165 rcptaddr?rcptaddr:"???", argc, 166 (argc == 1)?"":"s") 167 == EOF) { 168 (void) mlfi_cleanup(ctx, FALSE); 169 return SMFIS_TEMPFAIL; 170 } 171 /* continue processing */ 172 return SMFIS_CONTINUE; 173} 174 175sfsistat 176<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv) 177 SMFICTX *ctx; 178 char *headerf; 179 unsigned char *headerv; 180{ 181 /* write the header to the log file */ 182 fprintf(MLFIPRIV->mlfi_fp, "%s: %s\n", headerf, headerv); 183 184 /* continue processing */ 185 return SMFIS_CONTINUE; 186} 187 188sfsistat 189<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx) 190 SMFICTX *ctx; 191{ 192 /* output the blank line between the header and the body */ 193 fprintf(MLFIPRIV->mlfi_fp, "\n"); 194 195 /* continue processing */ 196 return SMFIS_CONTINUE; 197} 198 199sfsistat 200<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen) 201 SMFICTX *ctx; 202 unsigned char *bodyp; 203 size_t bodylen; 204{ 205 /* output body block to log file */ 206 int nwritten; 207 if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp)) != 1) 208 { 209 /* write failed */ 210 perror("error logging body"); 211 (void) mlfi_cleanup(ctx, FALSE); 212 return SMFIS_TEMPFAIL; 213 } 214 215 /* continue processing */ 216 return SMFIS_CONTINUE; 217} 218 219sfsistat 220<a href="xxfi_eom.html">mlfi_eom</a>(ctx) 221 SMFICTX *ctx; 222{ 223 bool ok = TRUE; 224 /* change recipients, if requested */ 225 if(add) 226 ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS); 227 return mlfi_cleanup(ctx, ok); 228} 229 230sfsistat 231<a href="xxfi_abort.html">mlfi_abort</a>(ctx) 232 SMFICTX *ctx; 233{ 234 return mlfi_cleanup(ctx, FALSE); 235} 236 237sfsistat 238mlfi_cleanup(ctx, ok) 239 SMFICTX *ctx; 240 bool ok; 241{ 242 sfsistat rstat = SMFIS_CONTINUE; 243 struct mlfiPriv *priv = MLFIPRIV; 244 char *p; 245 char host[512]; 246 char hbuf[1024]; 247 248 if (priv == NULL) 249 return rstat; 250 251 /* close the archive file */ 252 if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) 253 { 254 /* failed; we have to wait until later */ 255 fprintf(stderr, "Couldn't close archive file %s: %s\n", 256 priv->mlfi_fname, strerror(errno)); 257 rstat = SMFIS_TEMPFAIL; 258 (void) unlink(priv->mlfi_fname); 259 } 260 else if (ok) 261 { 262 /* add a header to the message announcing our presence */ 263 if (gethostname(host, sizeof host) < 0) 264 strncpy(host, "localhost", sizeof host); 265 p = strrchr(priv->mlfi_fname, '/'); 266 if (p == NULL) 267 p = priv->mlfi_fname; 268 else 269 p++; 270 snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); 271 <a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf); 272 } 273 else 274 { 275 /* message was aborted -- delete the archive file */ 276 fprintf(stderr, "Message aborted. Removing %s\n", 277 priv->mlfi_fname); 278 rstat = SMFIS_TEMPFAIL; 279 (void) unlink(priv->mlfi_fname); 280 } 281 282 /* release private memory */ 283 free(priv->mlfi_fname); 284 285 /* return status */ 286 return rstat; 287} 288 289sfsistat 290<a href="xxfi_close.html">mlfi_close</a>(ctx) 291 SMFICTX *ctx; 292{ 293 struct mlfiPriv *priv = MLFIPRIV; 294 if(priv->mlfi_connectfrom) 295 free(priv->mlfi_connectfrom); 296 if(priv->mlfi_helofrom) 297 free(priv->mlfi_helofrom); 298 free(priv); 299 <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL); 300 return SMFIS_CONTINUE; 301} 302 303struct smfiDesc smfilter = 304{ 305 "SampleFilter", /* filter name */ 306 SMFI_VERSION, /* version code -- do not change */ 307 SMFIF_ADDHDRS, /* flags */ 308 <a href="xxfi_connect.html">mlfi_connect</a>, /* connection info filter */ 309 <a href="xxfi_helo.html">mlfi_helo</a>, /* SMTP HELO command filter */ 310 <a href="xxfi_envfrom.html">mlfi_envfrom</a>, /* envelope sender filter */ 311 <a href="xxfi_envrcpt.html">mlfi_envrcpt</a>, /* envelope recipient filter */ 312 <a href="xxfi_header.html">mlfi_header</a>, /* header filter */ 313 <a href="xxfi_eoh.html">mlfi_eoh</a>, /* end of header */ 314 <a href="xxfi_body.html">mlfi_body</a>, /* body block filter */ 315 <a href="xxfi_eom.html">mlfi_eom</a>, /* end of message */ 316 <a href="xxfi_abort.html">mlfi_abort</a>, /* message aborted */ 317 <a href="xxfi_close.html">mlfi_close</a>, /* connection cleanup */ 318}; 319 320static void 321usage() 322{ 323 fprintf(stderr, 324 "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\ 325\t[-a accept-addr]\n"); 326} 327 328int 329main(argc, argv) 330 int argc; 331 char *argv[]; 332{ 333 int retval; 334 char c; 335 const char *args = "p:t:r:a:h"; 336 extern char *optarg; 337 338 /* Process command line options */ 339 while ((c = getopt(argc, argv, args)) != (char)EOF) 340 { 341 switch (c) 342 { 343 case 'p': 344 if (optarg == NULL || *optarg == '\0') 345 { 346 (void) fprintf(stderr, "Illegal conn: %s\n", 347 optarg); 348 exit(EX_USAGE); 349 } 350 if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE) 351 { 352 (void) fputs("smfi_setconn failed", stderr); 353 exit(EX_SOFTWARE); 354 } 355 /* 356 ** If we're using a local socket, make sure it doesn't 357 ** already exist. 358 */ 359 if(strncmp(optarg, "unix:", 5) == 0) 360 unlink(optarg + 5); 361 else if(strncmp(optarg, "local:", 6) == 0) 362 unlink(optarg + 6); 363 break; 364 365 case 't': 366 if (optarg == NULL || *optarg == '\0') 367 { 368 (void) fprintf(stderr, "Illegal timeout: %s\n", 369 optarg); 370 exit(EX_USAGE); 371 } 372 if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE) 373 { 374 (void) fputs("smfi_settimeout failed", stderr); 375 exit(EX_SOFTWARE); 376 } 377 break; 378 379 case 'r': 380 if (optarg == NULL) 381 { 382 (void) fprintf(stderr, "Illegal reject rcpt: %s\n", 383 optarg); 384 exit(EX_USAGE); 385 } 386 reject = optarg; 387 break; 388 389 case 'a': 390 if (optarg == NULL) 391 { 392 (void) fprintf(stderr, "Illegal add rcpt: %s\n", 393 optarg); 394 exit(EX_USAGE); 395 } 396 add = optarg; 397 smfilter.xxfi_flags |= SMFIF_ADDRCPT; 398 break; 399 case 'h': 400 default: 401 usage(); 402 exit(0); 403 } 404 } 405 if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE) 406 { 407 fprintf(stderr, "smfi_register failed\n"); 408 exit(EX_UNAVAILABLE); 409 } 410 retval = <a href="smfi_main.html">smfi_main</a>(); 411 return retval; 412} 413 414/* eof */ 415 416</pre> 417<hr size="1"> 418<font size="-1"> 419Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 420All rights reserved. 421<br> 422By using this file, you agree to the terms and conditions set 423forth in the <a href="LICENSE.txt">LICENSE</a>. 424</font> 425</body> 426</html> 427