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