example.c revision 302408
1230557Sjimharris/* 2230557Sjimharris * Copyright (c) 2006 Proofpoint, Inc. and its suppliers. 3230557Sjimharris * All rights reserved. 4230557Sjimharris * 5230557Sjimharris * By using this file, you agree to the terms and conditions set 6230557Sjimharris * forth in the LICENSE file which can be found at the top level of 7230557Sjimharris * the sendmail distribution. 8230557Sjimharris * 9230557Sjimharris * $Id: example.c,v 8.5 2013-11-22 20:51:36 ca Exp $ 10230557Sjimharris */ 11230557Sjimharris 12230557Sjimharris/* 13230557Sjimharris** A trivial example filter that logs all email to a file. 14230557Sjimharris** This milter also has some callbacks which it does not really use, 15230557Sjimharris** but they are defined to serve as an example. 16230557Sjimharris*/ 17230557Sjimharris 18230557Sjimharris#include <sys/types.h> 19230557Sjimharris#include <stdio.h> 20230557Sjimharris#include <stdlib.h> 21230557Sjimharris#include <string.h> 22230557Sjimharris#include <sysexits.h> 23230557Sjimharris#include <unistd.h> 24230557Sjimharris 25230557Sjimharris#include "libmilter/mfapi.h" 26230557Sjimharris#include "libmilter/mfdef.h" 27230557Sjimharris 28230557Sjimharris#ifndef true 29230557Sjimharris# define false 0 30230557Sjimharris# define true 1 31230557Sjimharris#endif /* ! true */ 32230557Sjimharris 33230557Sjimharrisstruct mlfiPriv 34230557Sjimharris{ 35230557Sjimharris char *mlfi_fname; 36230557Sjimharris FILE *mlfi_fp; 37230557Sjimharris}; 38230557Sjimharris 39230557Sjimharris#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) 40230557Sjimharris 41230557Sjimharrisstatic unsigned long mta_caps = 0; 42230557Sjimharris 43230557Sjimharrissfsistat 44230557Sjimharrismlfi_cleanup(ctx, ok) 45230557Sjimharris SMFICTX *ctx; 46230557Sjimharris bool ok; 47230557Sjimharris{ 48230557Sjimharris sfsistat rstat = SMFIS_CONTINUE; 49230557Sjimharris struct mlfiPriv *priv = MLFIPRIV; 50230557Sjimharris char *p; 51230557Sjimharris char host[512]; 52230557Sjimharris char hbuf[1024]; 53230557Sjimharris 54230557Sjimharris if (priv == NULL) 55230557Sjimharris return rstat; 56230557Sjimharris 57230557Sjimharris /* close the archive file */ 58230557Sjimharris if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) 59230557Sjimharris { 60230557Sjimharris /* failed; we have to wait until later */ 61230557Sjimharris rstat = SMFIS_TEMPFAIL; 62230557Sjimharris (void) unlink(priv->mlfi_fname); 63230557Sjimharris } 64230557Sjimharris else if (ok) 65230557Sjimharris { 66230557Sjimharris /* add a header to the message announcing our presence */ 67230557Sjimharris if (gethostname(host, sizeof host) < 0) 68230557Sjimharris snprintf(host, sizeof host, "localhost"); 69230557Sjimharris p = strrchr(priv->mlfi_fname, '/'); 70230557Sjimharris if (p == NULL) 71230557Sjimharris p = priv->mlfi_fname; 72230557Sjimharris else 73230557Sjimharris p++; 74230557Sjimharris snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); 75230557Sjimharris smfi_addheader(ctx, "X-Archived", hbuf); 76230557Sjimharris } 77230557Sjimharris else 78230557Sjimharris { 79230557Sjimharris /* message was aborted -- delete the archive file */ 80230557Sjimharris (void) unlink(priv->mlfi_fname); 81230557Sjimharris } 82230557Sjimharris 83230557Sjimharris /* release private memory */ 84230557Sjimharris free(priv->mlfi_fname); 85230557Sjimharris free(priv); 86230557Sjimharris smfi_setpriv(ctx, NULL); 87230557Sjimharris 88230557Sjimharris /* return status */ 89230557Sjimharris return rstat; 90230557Sjimharris} 91230557Sjimharris 92230557Sjimharris 93230557Sjimharrissfsistat 94230557Sjimharrismlfi_envfrom(ctx, envfrom) 95230557Sjimharris SMFICTX *ctx; 96230557Sjimharris char **envfrom; 97230557Sjimharris{ 98230557Sjimharris struct mlfiPriv *priv; 99230557Sjimharris int fd = -1; 100230557Sjimharris 101230557Sjimharris /* allocate some private memory */ 102230557Sjimharris priv = malloc(sizeof *priv); 103230557Sjimharris if (priv == NULL) 104230557Sjimharris { 105230557Sjimharris /* can't accept this message right now */ 106230557Sjimharris return SMFIS_TEMPFAIL; 107230557Sjimharris } 108230557Sjimharris memset(priv, '\0', sizeof *priv); 109230557Sjimharris 110230557Sjimharris /* open a file to store this message */ 111230557Sjimharris priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX"); 112230557Sjimharris if (priv->mlfi_fname == NULL) 113230557Sjimharris { 114230557Sjimharris free(priv); 115230557Sjimharris return SMFIS_TEMPFAIL; 116230557Sjimharris } 117230557Sjimharris if ((fd = mkstemp(priv->mlfi_fname)) < 0 || 118230557Sjimharris (priv->mlfi_fp = fdopen(fd, "w+")) == NULL) 119230557Sjimharris { 120230557Sjimharris if (fd >= 0) 121230557Sjimharris (void) close(fd); 122230557Sjimharris free(priv->mlfi_fname); 123230557Sjimharris free(priv); 124230557Sjimharris return SMFIS_TEMPFAIL; 125230557Sjimharris } 126230557Sjimharris 127230557Sjimharris /* save the private data */ 128230557Sjimharris smfi_setpriv(ctx, priv); 129230557Sjimharris 130230557Sjimharris /* continue processing */ 131230557Sjimharris return SMFIS_CONTINUE; 132230557Sjimharris} 133230557Sjimharris 134230557Sjimharrissfsistat 135230557Sjimharrismlfi_header(ctx, headerf, headerv) 136230557Sjimharris SMFICTX *ctx; 137230557Sjimharris char *headerf; 138230557Sjimharris char *headerv; 139230557Sjimharris{ 140230557Sjimharris /* write the header to the log file */ 141230557Sjimharris fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv); 142230557Sjimharris 143230557Sjimharris /* continue processing */ 144230557Sjimharris return ((mta_caps & SMFIP_NR_HDR) != 0) 145230557Sjimharris ? SMFIS_NOREPLY : SMFIS_CONTINUE; 146230557Sjimharris} 147230557Sjimharris 148230557Sjimharrissfsistat 149230557Sjimharrismlfi_eoh(ctx) 150230557Sjimharris SMFICTX *ctx; 151230557Sjimharris{ 152230557Sjimharris /* output the blank line between the header and the body */ 153230557Sjimharris fprintf(MLFIPRIV->mlfi_fp, "\r\n"); 154230557Sjimharris 155230557Sjimharris /* continue processing */ 156230557Sjimharris return SMFIS_CONTINUE; 157230557Sjimharris} 158230557Sjimharris 159230557Sjimharrissfsistat 160230557Sjimharrismlfi_body(ctx, bodyp, bodylen) 161230557Sjimharris SMFICTX *ctx; 162230557Sjimharris u_char *bodyp; 163230557Sjimharris size_t bodylen; 164230557Sjimharris{ 165230557Sjimharris /* output body block to log file */ 166230557Sjimharris if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0) 167230557Sjimharris { 168230557Sjimharris /* write failed */ 169230557Sjimharris (void) mlfi_cleanup(ctx, false); 170230557Sjimharris return SMFIS_TEMPFAIL; 171230557Sjimharris } 172230557Sjimharris 173230557Sjimharris /* continue processing */ 174230557Sjimharris return SMFIS_CONTINUE; 175230557Sjimharris} 176230557Sjimharris 177230557Sjimharrissfsistat 178230557Sjimharrismlfi_eom(ctx) 179230557Sjimharris SMFICTX *ctx; 180230557Sjimharris{ 181230557Sjimharris return mlfi_cleanup(ctx, true); 182230557Sjimharris} 183230557Sjimharris 184230557Sjimharrissfsistat 185230557Sjimharrismlfi_close(ctx) 186230557Sjimharris SMFICTX *ctx; 187230557Sjimharris{ 188230557Sjimharris return SMFIS_ACCEPT; 189230557Sjimharris} 190230557Sjimharris 191230557Sjimharrissfsistat 192230557Sjimharrismlfi_abort(ctx) 193230557Sjimharris SMFICTX *ctx; 194230557Sjimharris{ 195230557Sjimharris return mlfi_cleanup(ctx, false); 196230557Sjimharris} 197230557Sjimharris 198230557Sjimharrissfsistat 199230557Sjimharrismlfi_unknown(ctx, cmd) 200230557Sjimharris SMFICTX *ctx; 201230557Sjimharris char *cmd; 202230557Sjimharris{ 203230557Sjimharris return SMFIS_CONTINUE; 204230557Sjimharris} 205230557Sjimharris 206230557Sjimharrissfsistat 207230557Sjimharrismlfi_data(ctx) 208230557Sjimharris SMFICTX *ctx; 209230557Sjimharris{ 210230557Sjimharris return SMFIS_CONTINUE; 211230557Sjimharris} 212230557Sjimharris 213230557Sjimharrissfsistat 214230557Sjimharrismlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3) 215230557Sjimharris SMFICTX *ctx; 216230557Sjimharris unsigned long f0; 217230557Sjimharris unsigned long f1; 218230557Sjimharris unsigned long f2; 219230557Sjimharris unsigned long f3; 220230557Sjimharris unsigned long *pf0; 221230557Sjimharris unsigned long *pf1; 222230557Sjimharris unsigned long *pf2; 223230557Sjimharris unsigned long *pf3; 224230557Sjimharris{ 225230557Sjimharris /* milter actions: add headers */ 226230557Sjimharris *pf0 = SMFIF_ADDHDRS; 227230557Sjimharris 228230557Sjimharris /* milter protocol steps: all but connect, HELO, RCPT */ 229230557Sjimharris *pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT; 230230557Sjimharris mta_caps = f1; 231230557Sjimharris if ((mta_caps & SMFIP_NR_HDR) != 0) 232230557Sjimharris *pf1 |= SMFIP_NR_HDR; 233230557Sjimharris *pf2 = 0; 234230557Sjimharris *pf3 = 0; 235230557Sjimharris return SMFIS_CONTINUE; 236230557Sjimharris} 237230557Sjimharris 238230557Sjimharrisstruct smfiDesc smfilter = 239230557Sjimharris{ 240230557Sjimharris "SampleFilter", /* filter name */ 241230557Sjimharris SMFI_VERSION, /* version code -- do not change */ 242230557Sjimharris SMFIF_ADDHDRS, /* flags */ 243230557Sjimharris NULL, /* connection info filter */ 244230557Sjimharris NULL, /* SMTP HELO command filter */ 245230557Sjimharris mlfi_envfrom, /* envelope sender filter */ 246230557Sjimharris NULL, /* envelope recipient filter */ 247230557Sjimharris mlfi_header, /* header filter */ 248230557Sjimharris mlfi_eoh, /* end of header */ 249230557Sjimharris mlfi_body, /* body block filter */ 250230557Sjimharris mlfi_eom, /* end of message */ 251230557Sjimharris mlfi_abort, /* message aborted */ 252230557Sjimharris mlfi_close, /* connection cleanup */ 253230557Sjimharris mlfi_unknown, /* unknown/unimplemented SMTP commands */ 254230557Sjimharris mlfi_data, /* DATA command filter */ 255230557Sjimharris mlfi_negotiate /* option negotiation at connection startup */ 256230557Sjimharris}; 257230557Sjimharris 258230557Sjimharrisint 259230557Sjimharrismain(argc, argv) 260230557Sjimharris int argc; 261230557Sjimharris char *argv[]; 262230557Sjimharris{ 263230557Sjimharris bool setconn; 264230557Sjimharris int c; 265230557Sjimharris 266230557Sjimharris setconn = false; 267230557Sjimharris 268230557Sjimharris /* Process command line options */ 269230557Sjimharris while ((c = getopt(argc, argv, "p:")) != -1) 270230557Sjimharris { 271 switch (c) 272 { 273 case 'p': 274 if (optarg == NULL || *optarg == '\0') 275 { 276 (void) fprintf(stderr, "Illegal conn: %s\n", 277 optarg); 278 exit(EX_USAGE); 279 } 280 (void) smfi_setconn(optarg); 281 setconn = true; 282 break; 283 284 } 285 } 286 if (!setconn) 287 { 288 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); 289 exit(EX_USAGE); 290 } 291 if (smfi_register(smfilter) == MI_FAILURE) 292 { 293 fprintf(stderr, "smfi_register failed\n"); 294 exit(EX_UNAVAILABLE); 295 } 296 return smfi_main(); 297} 298 299