sample.html revision 168515
1292920Sdim<HTML> 2292920Sdim<HEAD><TITLE>A Sample Filter</TITLE></HEAD> 3292920Sdim<BODY> 4292920Sdim<!-- 5292920Sdim$Id: sample.html,v 1.22 2006/10/09 23:14:51 ca Exp $ 6292920Sdim--> 7292920Sdim<H1>A Sample Filter</H1> 8292920Sdim 9292920SdimThe following sample logs each message to a separate temporary file, 10292920Sdimadds a recipient given with the -a flag, 11292920Sdimand rejects a disallowed recipient address given with the -r flag. 12292920SdimIt recognizes the following options: 13292920Sdim<P> 14292920Sdim<CENTER> 15292920Sdim<TABLE border="1" cellpadding=2 cellspacing=1> 16292920Sdim<TR><TD><CODE>-p port</CODE></TD><TD>The port through which the MTA will connect to the filter.</TD></TR> 17292920Sdim<TR><TD><CODE>-t sec</CODE></TD><TD>The timeout value.</TD></TR> 18292920Sdim<TR><TD><CODE>-r addr</CODE></TD><TD>A recipient to reject.</TD></TR> 19292920Sdim<TR><TD><CODE>-a addr</CODE></TD><TD>A recipient to add.</TD></TR> 20292920Sdim</TABLE> 21292920Sdim</CENTER> 22292920Sdim<HR> 23292920Sdim<PRE> 24292920Sdim#include <sys/types.h> 25292920Sdim#include <sys/stat.h> 26292920Sdim#include <errno.h> 27292920Sdim#include <stdio.h> 28292920Sdim#include <stdlib.h> 29292920Sdim#include <string.h> 30292920Sdim#include <sysexits.h> 31292920Sdim#include <unistd.h> 32292920Sdim 33292920Sdim#include "libmilter/mfapi.h" 34292920Sdim 35292920Sdim#ifndef bool 36292920Sdim# define bool int 37292920Sdim# define TRUE 1 38292920Sdim# define FALSE 0 39292920Sdim#endif /* ! bool */ 40292920Sdim 41292920Sdim 42292920Sdimstruct mlfiPriv 43292920Sdim{ 44292920Sdim char *mlfi_fname; 45292920Sdim char *mlfi_connectfrom; 46292920Sdim char *mlfi_helofrom; 47292920Sdim FILE *mlfi_fp; 48292920Sdim}; 49292920Sdim 50292920Sdim#define MLFIPRIV ((struct mlfiPriv *) <A href="smfi_getpriv.html">smfi_getpriv</A>(ctx)) 51292920Sdim 52292920Sdimextern sfsistat mlfi_cleanup(SMFICTX *, bool); 53292920Sdim 54292920Sdim/* recipients to add and reject (set with -a and -r options) */ 55292920Sdimchar *add = NULL; 56292920Sdimchar *reject = NULL; 57292920Sdim 58292920Sdimsfsistat 59292920Sdim<A href="xxfi_connect.html">mlfi_connect</A>(ctx, hostname, hostaddr) 60292920Sdim SMFICTX *ctx; 61292920Sdim char *hostname; 62292920Sdim _SOCK_ADDR *hostaddr; 63292920Sdim{ 64292920Sdim struct mlfiPriv *priv; 65292920Sdim char *ident; 66292920Sdim 67292920Sdim /* allocate some private memory */ 68292920Sdim priv = malloc(sizeof *priv); 69292920Sdim if (priv == NULL) 70292920Sdim { 71292920Sdim /* can't accept this message right now */ 72292920Sdim return SMFIS_TEMPFAIL; 73292920Sdim } 74292920Sdim memset(priv, '\0', sizeof *priv); 75292920Sdim 76292920Sdim /* save the private data */ 77292920Sdim <A href="smfi_setpriv.html">smfi_setpriv</A>(ctx, priv); 78292920Sdim 79292920Sdim ident = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "_"); 80292920Sdim if (ident == NULL) 81292920Sdim ident = "???"; 82292920Sdim if ((priv->mlfi_connectfrom = strdup(ident)) == NULL) 83292920Sdim { 84292920Sdim (void) mlfi_cleanup(ctx, FALSE); 85292920Sdim return SMFIS_TEMPFAIL; 86292920Sdim } 87292920Sdim 88292920Sdim /* continue processing */ 89292920Sdim return SMFIS_CONTINUE; 90292920Sdim} 91292920Sdim 92292920Sdimsfsistat 93292920Sdim<A href="xxfi_helo.html">mlfi_helo</A>(ctx, helohost) 94292920Sdim SMFICTX *ctx; 95292920Sdim char *helohost; 96292920Sdim{ 97292920Sdim size_t len; 98292920Sdim char *tls; 99292920Sdim char *buf; 100292920Sdim struct mlfiPriv *priv = MLFIPRIV; 101292920Sdim 102292920Sdim tls = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{tls_version}"); 103292920Sdim if (tls == NULL) 104292920Sdim tls = "No TLS"; 105292920Sdim if (helohost == NULL) 106292920Sdim helohost = "???"; 107292920Sdim len = strlen(tls) + strlen(helohost) + 3; 108292920Sdim if ((buf = (char*) malloc(len)) == NULL) 109292920Sdim { 110292920Sdim (void) mlfi_cleanup(ctx, FALSE); 111292920Sdim return SMFIS_TEMPFAIL; 112292920Sdim } 113292920Sdim snprintf(buf, len, "%s, %s", helohost, tls); 114292920Sdim if (priv->mlfi_helofrom != NULL) 115292920Sdim free(priv->mlfi_helofrom); 116292920Sdim priv->mlfi_helofrom = buf; 117292920Sdim 118292920Sdim /* continue processing */ 119292920Sdim return SMFIS_CONTINUE; 120292920Sdim} 121292920Sdim 122292920Sdimsfsistat 123292920Sdim<A href="xxfi_envfrom.html">mlfi_envfrom</A>(ctx, argv) 124292920Sdim SMFICTX *ctx; 125292920Sdim char **argv; 126292920Sdim{ 127292920Sdim int fd = -1; 128292920Sdim int argc = 0; 129292920Sdim struct mlfiPriv *priv = MLFIPRIV; 130292920Sdim char *mailaddr = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{mail_addr}"); 131292920Sdim 132292920Sdim /* open a file to store this message */ 133292920Sdim if ((priv->mlfi_fname = strdup("/tmp/msg.XXXXXX")) == NULL) 134292920Sdim { 135292920Sdim (void) mlfi_cleanup(ctx, FALSE); 136292920Sdim return SMFIS_TEMPFAIL; 137292920Sdim } 138292920Sdim 139292920Sdim if ((fd = mkstemp(priv->mlfi_fname)) == -1) 140292920Sdim { 141292920Sdim (void) mlfi_cleanup(ctx, FALSE); 142292920Sdim return SMFIS_TEMPFAIL; 143292920Sdim } 144292920Sdim 145292920Sdim if ((priv->mlfi_fp = fdopen(fd, "w+")) == NULL) 146292920Sdim { 147292920Sdim (void) close(fd); 148292920Sdim (void) mlfi_cleanup(ctx, FALSE); 149292920Sdim return SMFIS_TEMPFAIL; 150292920Sdim } 151292920Sdim 152292920Sdim /* count the arguments */ 153292920Sdim while (*argv++ != NULL) 154292920Sdim ++argc; 155292920Sdim 156292920Sdim /* log the connection information we stored earlier: */ 157292920Sdim if (fprintf(priv->mlfi_fp, "Connect from %s (%s)\n\n", 158292920Sdim priv->mlfi_helofrom, priv->mlfi_connectfrom) == EOF) 159292920Sdim { 160292920Sdim (void) mlfi_cleanup(ctx, FALSE); 161292920Sdim return SMFIS_TEMPFAIL; 162292920Sdim } 163292920Sdim /* log the sender */ 164292920Sdim if (fprintf(priv->mlfi_fp, "FROM %s (%d argument%s)\n", 165292920Sdim mailaddr ? mailaddr : "???", argc, 166292920Sdim (argc == 1) ? "" : "s") == EOF) 167292920Sdim { 168292920Sdim (void) mlfi_cleanup(ctx, FALSE); 169292920Sdim return SMFIS_TEMPFAIL; 170292920Sdim } 171292920Sdim 172292920Sdim /* continue processing */ 173292920Sdim return SMFIS_CONTINUE; 174292920Sdim} 175292920Sdim 176292920Sdimsfsistat 177292920Sdim<A href="xxfi_envrcpt.html">mlfi_envrcpt</A>(ctx, argv) 178292920Sdim SMFICTX *ctx; 179292920Sdim char **argv; 180292920Sdim{ 181292920Sdim struct mlfiPriv *priv = MLFIPRIV; 182292920Sdim char *rcptaddr = <A href="smfi_getsymval.html">smfi_getsymval</A>(ctx, "{rcpt_addr}"); 183292920Sdim int argc = 0; 184292920Sdim 185292920Sdim /* count the arguments */ 186292920Sdim while (*argv++ != NULL) 187292920Sdim ++argc; 188292920Sdim 189292920Sdim /* log this recipient */ 190292920Sdim if (reject != NULL && rcptaddr != NULL && 191292920Sdim (strcasecmp(rcptaddr, reject) == 0)) 192292920Sdim { 193292920Sdim if (fprintf(priv->mlfi_fp, "RCPT %s -- REJECTED\n", 194292920Sdim rcptaddr) == EOF) 195292920Sdim { 196292920Sdim (void) mlfi_cleanup(ctx, FALSE); 197292920Sdim return SMFIS_TEMPFAIL; 198292920Sdim } 199292920Sdim return SMFIS_REJECT; 200292920Sdim } 201292920Sdim if (fprintf(priv->mlfi_fp, "RCPT %s (%d argument%s)\n", 202292920Sdim rcptaddr ? rcptaddr : "???", argc, 203292920Sdim (argc == 1) ? "" : "s") == EOF) 204292920Sdim { 205292920Sdim (void) mlfi_cleanup(ctx, FALSE); 206292920Sdim return SMFIS_TEMPFAIL; 207292920Sdim } 208292920Sdim 209292920Sdim /* continue processing */ 210292920Sdim return SMFIS_CONTINUE; 211292920Sdim} 212292920Sdim 213292920Sdimsfsistat 214292920Sdim<A href="xxfi_header.html">mlfi_header</A>(ctx, headerf, headerv) 215292920Sdim SMFICTX *ctx; 216292920Sdim char *headerf; 217292920Sdim unsigned char *headerv; 218292920Sdim{ 219292920Sdim /* write the header to the log file */ 220292920Sdim if (fprintf(MLFIPRIV->mlfi_fp, "%s: %s\n", headerf, headerv) == EOF) 221292920Sdim { 222292920Sdim (void) mlfi_cleanup(ctx, FALSE); 223292920Sdim return SMFIS_TEMPFAIL; 224292920Sdim } 225292920Sdim 226292920Sdim /* continue processing */ 227292920Sdim return SMFIS_CONTINUE; 228292920Sdim} 229292920Sdim 230292920Sdimsfsistat 231292920Sdim<A href="xxfi_eoh.html">mlfi_eoh</A>(ctx) 232292920Sdim SMFICTX *ctx; 233292920Sdim{ 234292920Sdim /* output the blank line between the header and the body */ 235292920Sdim if (fprintf(MLFIPRIV->mlfi_fp, "\n") == EOF) 236292920Sdim { 237292920Sdim (void) mlfi_cleanup(ctx, FALSE); 238292920Sdim return SMFIS_TEMPFAIL; 239292920Sdim } 240292920Sdim 241292920Sdim /* continue processing */ 242292920Sdim return SMFIS_CONTINUE; 243292920Sdim} 244292920Sdim 245292920Sdimsfsistat 246292920Sdim<A href="xxfi_body.html">mlfi_body</A>(ctx, bodyp, bodylen) 247292920Sdim SMFICTX *ctx; 248292920Sdim unsigned char *bodyp; 249292920Sdim size_t bodylen; 250292920Sdim{ 251292920Sdim struct mlfiPriv *priv = MLFIPRIV; 252292920Sdim 253292920Sdim /* output body block to log file */ 254292920Sdim if (fwrite(bodyp, bodylen, 1, priv->mlfi_fp) != 1) 255292920Sdim { 256292920Sdim /* write failed */ 257292920Sdim fprintf(stderr, "Couldn't write file %s: %s\n", 258292920Sdim priv->mlfi_fname, strerror(errno)); 259292920Sdim (void) mlfi_cleanup(ctx, FALSE); 260292920Sdim return SMFIS_TEMPFAIL; 261292920Sdim } 262292920Sdim 263292920Sdim /* continue processing */ 264292920Sdim return SMFIS_CONTINUE; 265292920Sdim} 266292920Sdim 267292920Sdimsfsistat 268292920Sdim<A href="xxfi_eom.html">mlfi_eom</A>(ctx) 269292920Sdim SMFICTX *ctx; 270292920Sdim{ 271292920Sdim bool ok = TRUE; 272292920Sdim 273292920Sdim /* change recipients, if requested */ 274292920Sdim if (add != NULL) 275292920Sdim ok = (<A href="smfi_addrcpt.html">smfi_addrcpt</A>(ctx, add) == MI_SUCCESS); 276292920Sdim return mlfi_cleanup(ctx, ok); 277292920Sdim} 278292920Sdim 279292920Sdimsfsistat 280292920Sdim<A href="xxfi_abort.html">mlfi_abort</A>(ctx) 281292920Sdim SMFICTX *ctx; 282292920Sdim{ 283292920Sdim return mlfi_cleanup(ctx, FALSE); 284292920Sdim} 285292920Sdim 286292920Sdimsfsistat 287292920Sdimmlfi_cleanup(ctx, ok) 288292920Sdim SMFICTX *ctx; 289292920Sdim bool ok; 290292920Sdim{ 291292920Sdim sfsistat rstat = SMFIS_CONTINUE; 292292920Sdim struct mlfiPriv *priv = MLFIPRIV; 293292920Sdim char *p; 294292920Sdim char host[512]; 295292920Sdim char hbuf[1024]; 296292920Sdim 297292920Sdim if (priv == NULL) 298292920Sdim return rstat; 299292920Sdim 300292920Sdim /* close the archive file */ 301292920Sdim if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) 302292920Sdim { 303292920Sdim /* failed; we have to wait until later */ 304292920Sdim fprintf(stderr, "Couldn't close archive file %s: %s\n", 305292920Sdim priv->mlfi_fname, strerror(errno)); 306292920Sdim rstat = SMFIS_TEMPFAIL; 307292920Sdim (void) unlink(priv->mlfi_fname); 308292920Sdim } 309292920Sdim else if (ok) 310292920Sdim { 311292920Sdim /* add a header to the message announcing our presence */ 312292920Sdim if (gethostname(host, sizeof host) < 0) 313292920Sdim snprintf(host, sizeof host, "localhost"); 314292920Sdim p = strrchr(priv->mlfi_fname, '/'); 315292920Sdim if (p == NULL) 316292920Sdim p = priv->mlfi_fname; 317292920Sdim else 318292920Sdim p++; 319292920Sdim snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); 320292920Sdim if (<A href="smfi_addheader.html">smfi_addheader</A>(ctx, "X-Archived", hbuf) != MI_SUCCESS) 321292920Sdim { 322292920Sdim /* failed; we have to wait until later */ 323292920Sdim fprintf(stderr, 324292920Sdim "Couldn't add header: X-Archived: %s\n", 325292920Sdim hbuf); 326292920Sdim ok = FALSE; 327292920Sdim rstat = SMFIS_TEMPFAIL; 328292920Sdim (void) unlink(priv->mlfi_fname); 329292920Sdim } 330292920Sdim } 331 else 332 { 333 /* message was aborted -- delete the archive file */ 334 fprintf(stderr, "Message aborted. Removing %s\n", 335 priv->mlfi_fname); 336 rstat = SMFIS_TEMPFAIL; 337 (void) unlink(priv->mlfi_fname); 338 } 339 340 /* release private memory */ 341 if (priv->mlfi_fname != NULL) 342 free(priv->mlfi_fname); 343 344 /* return status */ 345 return rstat; 346} 347 348sfsistat 349<A href="xxfi_close.html">mlfi_close</A>(ctx) 350 SMFICTX *ctx; 351{ 352 struct mlfiPriv *priv = MLFIPRIV; 353 354 if (priv == NULL) 355 return SMFIS_CONTINUE; 356 if (priv->mlfi_connectfrom != NULL) 357 free(priv->mlfi_connectfrom); 358 if (priv->mlfi_helofrom != NULL) 359 free(priv->mlfi_helofrom); 360 free(priv); 361 <A href="smfi_setpriv.html">smfi_setpriv</A>(ctx, NULL); 362 return SMFIS_CONTINUE; 363} 364 365sfsistat 366<A href="xxfi_unknown.html">mlfi_unknown</A>(ctx, cmd) 367 SMFICTX *ctx; 368 char *cmd; 369{ 370 return SMFIS_CONTINUE; 371} 372 373sfsistat 374<A href="xxfi_data.html">mlfi_data</A>(ctx) 375 SMFICTX *ctx; 376{ 377 return SMFIS_CONTINUE; 378} 379 380sfsistat 381<A href="xxfi_negotiate.html">mlfi_negotiate</A>(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3) 382 SMFICTX *ctx; 383 unsigned long f0; 384 unsigned long f1; 385 unsigned long f2; 386 unsigned long f3; 387 unsigned long *pf0; 388 unsigned long *pf1; 389 unsigned long *pf2; 390 unsigned long *pf3; 391{ 392 return SMFIS_ALL_OPTS; 393} 394 395struct smfiDesc smfilter = 396{ 397 "SampleFilter", /* filter name */ 398 SMFI_VERSION, /* version code -- do not change */ 399 SMFIF_ADDHDRS|SMFIF_ADDRCPT, 400 /* flags */ 401 <A href="xxfi_connect.html">mlfi_connect</A>, /* connection info filter */ 402 <A href="xxfi_helo.html">mlfi_helo</A>, /* SMTP HELO command filter */ 403 <A href="xxfi_envfrom.html">mlfi_envfrom</A>, /* envelope sender filter */ 404 <A href="xxfi_envrcpt.html">mlfi_envrcpt</A>, /* envelope recipient filter */ 405 <A href="xxfi_header.html">mlfi_header</A>, /* header filter */ 406 <A href="xxfi_eoh.html">mlfi_eoh</A>, /* end of header */ 407 <A href="xxfi_body.html">mlfi_body</A>, /* body block filter */ 408 <A href="xxfi_eom.html">mlfi_eom</A>, /* end of message */ 409 <A href="xxfi_abort.html">mlfi_abort</A>, /* message aborted */ 410 <A href="xxfi_close.html">mlfi_close</A>, /* connection cleanup */ 411 <A href="xxfi_unknown.html">mlfi_unknown</A>, /* unknown SMTP commands */ 412 <A href="xxfi_data.html">mlfi_data</A>, /* DATA command */ 413 <A href="xxfi_negotiate.html">mlfi_negotiate</A> /* Once, at the start of each SMTP connection */ 414}; 415 416static void 417usage(prog) 418 char *prog; 419{ 420 fprintf(stderr, 421 "Usage: %s -p socket-addr [-t timeout] [-r reject-addr] [-a add-addr]\n", 422 prog); 423} 424 425int 426main(argc, argv) 427 int argc; 428 char **argv; 429{ 430 bool setconn = FALSE; 431 int c; 432 const char *args = "p:t:r:a:h"; 433 extern char *optarg; 434 435 /* Process command line options */ 436 while ((c = getopt(argc, argv, args)) != -1) 437 { 438 switch (c) 439 { 440 case 'p': 441 if (optarg == NULL || *optarg == '\0') 442 { 443 (void) fprintf(stderr, "Illegal conn: %s\n", 444 optarg); 445 exit(EX_USAGE); 446 } 447 if (<A href="smfi_setconn.html">smfi_setconn</A>(optarg) == MI_FAILURE) 448 { 449 (void) fprintf(stderr, 450 "smfi_setconn failed\n"); 451 exit(EX_SOFTWARE); 452 } 453 454 /* 455 ** If we're using a local socket, make sure it 456 ** doesn't already exist. Don't ever run this 457 ** code as root!! 458 */ 459 460 if (strncasecmp(optarg, "unix:", 5) == 0) 461 unlink(optarg + 5); 462 else if (strncasecmp(optarg, "local:", 6) == 0) 463 unlink(optarg + 6); 464 setconn = TRUE; 465 break; 466 467 case 't': 468 if (optarg == NULL || *optarg == '\0') 469 { 470 (void) fprintf(stderr, "Illegal timeout: %s\n", 471 optarg); 472 exit(EX_USAGE); 473 } 474 if (<A href="smfi_settimeout.html">smfi_settimeout</A>(atoi(optarg)) == MI_FAILURE) 475 { 476 (void) fprintf(stderr, 477 "smfi_settimeout failed\n"); 478 exit(EX_SOFTWARE); 479 } 480 break; 481 482 case 'r': 483 if (optarg == NULL) 484 { 485 (void) fprintf(stderr, 486 "Illegal reject rcpt: %s\n", 487 optarg); 488 exit(EX_USAGE); 489 } 490 reject = optarg; 491 break; 492 493 case 'a': 494 if (optarg == NULL) 495 { 496 (void) fprintf(stderr, 497 "Illegal add rcpt: %s\n", 498 optarg); 499 exit(EX_USAGE); 500 } 501 add = optarg; 502 smfilter.xxfi_flags |= SMFIF_ADDRCPT; 503 break; 504 505 case 'h': 506 default: 507 usage(argv[0]); 508 exit(EX_USAGE); 509 } 510 } 511 if (!setconn) 512 { 513 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); 514 usage(argv[0]); 515 exit(EX_USAGE); 516 } 517 if (<A href="smfi_register.html">smfi_register</A>(smfilter) == MI_FAILURE) 518 { 519 fprintf(stderr, "smfi_register failed\n"); 520 exit(EX_UNAVAILABLE); 521 } 522 return <A href="smfi_main.html">smfi_main</A>(); 523} 524 525/* eof */ 526 527</PRE> 528<HR size="1"> 529<FONT size="-1"> 530Copyright (c) 2000-2004, 2006 Sendmail, Inc. and its suppliers. 531All rights reserved. 532<BR> 533By using this file, you agree to the terms and conditions set 534forth in the LICENSE. 535</FONT> 536</BODY> 537</HTML> 538