Browse code

Allow From addresses to be whitelisted

git-svn: trunk@2710

Nigel Horne authored on 2007/02/13 00:02:48
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Mon Feb 12 15:02:13 GMT 2007 (njh)
2
+----------------------------------
3
+  * clamav-milter/clamav-milter.c:	Allow From addresses to be whitelisted
4
+
1 5
 Mon Feb 12 14:58:57 CET 2007 (tk)
2 6
 ---------------------------------
3 7
   * docs/signatures.pdf: fix some typos (bb#285), thanks to Aeriana
... ...
@@ -24,9 +24,9 @@
24 24
  *
25 25
  * For installation instructions see the file INSTALL that came with this file
26 26
  */
27
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.310 2007/01/17 20:50:10 njh Exp $";
27
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.311 2007/02/12 15:01:50 njh Exp $";
28 28
 
29
-#define	CM_VERSION	"devel-170107"
29
+#define	CM_VERSION	"devel-120207"
30 30
 
31 31
 #if HAVE_CONFIG_H
32 32
 #include "clamav-config.h"
... ...
@@ -48,9 +48,11 @@ static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.310 2007/01/17 20:50:10 nj
48 48
 
49 49
 #include <stdio.h>
50 50
 #include <sysexits.h>
51
+#ifdef	HAVE_SYS_STAT_H
51 52
 #include <sys/stat.h>
53
+#endif
52 54
 #include <syslog.h>
53
-#if	HAVE_STDINT_H
55
+#if	HAVE_STDLIB_H
54 56
 #include <stdlib.h>
55 57
 #endif
56 58
 #if	HAVE_MEMORY_H
... ...
@@ -90,6 +92,7 @@ static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.310 2007/01/17 20:50:10 nj
90 90
 #ifdef	HAVE_UNISTD_H
91 91
 #include <unistd.h>
92 92
 #endif
93
+#include <ctype.h>
93 94
 
94 95
 #if HAVE_MMAP
95 96
 #if HAVE_SYS_MMAN_H
... ...
@@ -177,8 +180,9 @@ typedef	unsigned int	in_addr_t;
177 177
  *	sockets is better
178 178
  * TODO: Test with IPv6
179 179
  * TODO: Load balancing, allow local machine to talk via UNIX domain socket.
180
- * TODO: allow each line in the whitelist file to specify a quarantine email
180
+ * TODO: allow each To: line in the whitelist file to specify a quarantine email
181 181
  *	address
182
+ * TODO: optionally use zlib to compress data sent to remote hosts
182 183
  */
183 184
 
184 185
 struct header_node_t {
... ...
@@ -211,7 +215,7 @@ static struct cidr_net {	/* don't make this const because of -I flag */
211 211
 	{ PACKADDR(192, 168,   0,   0), MAKEMASK(16) },	/* 192.168.0.0/16 */
212 212
 	{ PACKADDR( 10,   0,   0,   0), MAKEMASK(24) },	/*    10.0.0.0/24 */
213 213
 	{ PACKADDR(172,  16,   0,   0), MAKEMASK(20) },	/*  172.16.0.0/20 */
214
-	{ PACKADDR(169,  254,  0,   0), MAKEMASK(16) },	/* 169.254.0.0/16 */
214
+	{ PACKADDR(169, 254,   0,   0), MAKEMASK(16) },	/* 169.254.0.0/16 */
215 215
 	{ 0, 0 },	/* space to put one more via -I addr */
216 216
 	{ 0, 0 }
217 217
 };
... ...
@@ -526,7 +530,7 @@ static	void	print_trace(void);
526 526
 #endif
527 527
 
528 528
 static	int	verifyIncomingSocketName(const char *sockName);
529
-static	int	isWhitelisted(const char *emailaddress);
529
+static	int	isWhitelisted(const char *emailaddress, int to);
530 530
 static	int	isBlacklisted(const char *ip_address);
531 531
 static	void	mx(void);
532 532
 #ifdef	HAVE_RESOLV_H
... ...
@@ -2613,6 +2617,11 @@ clamfi_envfrom(SMFICTX *ctx, char **argv)
2613 2613
 
2614 2614
 	logg("*clamfi_envfrom: %s\n", argv[0]);
2615 2615
 
2616
+	if(isWhitelisted(argv[0], 0)) {
2617
+		logg(_("*clamfi_envfrom: ignoring whitelisted message"));
2618
+		return SMFIS_ACCEPT;
2619
+	}
2620
+
2616 2621
 	if(strcmp(argv[0], "<>") == 0) {
2617 2622
 		mailaddr = smfi_getsymval(ctx, "{mail_addr}");
2618 2623
 		if(mailaddr == NULL)
... ...
@@ -2838,7 +2847,7 @@ clamfi_eoh(SMFICTX *ctx)
2838 2838
 #if	0
2839 2839
 	/* Mailing lists often say our own posts are from us */
2840 2840
 	if(detect_forged_local_address && privdata->from &&
2841
-	   (!privdata->sender) && !isWhitelisted(privdata->from)) {
2841
+	   (!privdata->sender) && !isWhitelisted(privdata->from, 1)) {
2842 2842
 		char me[MAXHOSTNAMELEN + 1];
2843 2843
 		const char *ptr;
2844 2844
 
... ...
@@ -2887,7 +2896,7 @@ clamfi_eoh(SMFICTX *ctx)
2887 2887
 	 * ENDFOR
2888 2888
 	 */
2889 2889
 	for(to = privdata->to; *to; to++)
2890
-		if(!isWhitelisted(*to))
2890
+		if(!isWhitelisted(*to, 1))
2891 2891
 			/*
2892 2892
 			 * This recipient is not on the whitelist,
2893 2893
 			 * no need to check any further
... ...
@@ -2898,11 +2907,7 @@ clamfi_eoh(SMFICTX *ctx)
2898 2898
 	 * Didn't find a recipient who is not on the white list, so all
2899 2899
 	 * must be on the white list, so just accept the e-mail
2900 2900
 	 */
2901
-	if(use_syslog)
2902
-		syslog(LOG_NOTICE, _("clamfi_eoh: ignoring whitelisted message"));
2903
-#ifdef	CL_DEBUG
2904
-	cli_dbgmsg(_("clamfi_eoh: ignoring whitelisted message\n"));
2905
-#endif
2901
+	logg(_("*clamfi_enveoh: ignoring whitelisted message"));
2906 2902
 	clamfi_cleanup(ctx);
2907 2903
 
2908 2904
 	return SMFIS_ACCEPT;
... ...
@@ -5546,9 +5551,10 @@ verifyIncomingSocketName(const char *sockName)
5546 5546
  *	to that domain are to be whitelisted
5547 5547
  */
5548 5548
 static int
5549
-isWhitelisted(const char *emailaddress)
5549
+isWhitelisted(const char *emailaddress, int to)
5550 5550
 {
5551
-	static table_t *whitelist;	/* never freed */
5551
+	static table_t *to_whitelist, *from_whitelist;	/* never freed */
5552
+	table_t *table;
5552 5553
 
5553 5554
 	cli_dbgmsg("isWhitelisted %s\n", emailaddress);
5554 5555
 
... ...
@@ -5558,7 +5564,7 @@ isWhitelisted(const char *emailaddress)
5558 5558
 	if(quarantine && (strcasecmp(quarantine, emailaddress) == 0))
5559 5559
 		return 1;
5560 5560
 
5561
-	if((whitelist == NULL) && whitelistFile) {
5561
+	if((to_whitelist == NULL) && whitelistFile) {
5562 5562
 		FILE *fin;
5563 5563
 		char buf[BUFSIZ + 1];
5564 5564
 
... ...
@@ -5571,16 +5577,26 @@ isWhitelisted(const char *emailaddress)
5571 5571
 					whitelistFile);
5572 5572
 			return 0;
5573 5573
 		}
5574
-		whitelist = tableCreate();
5574
+		to_whitelist = tableCreate();
5575
+		from_whitelist = tableCreate();
5575 5576
 
5576
-		if(whitelist == NULL) {
5577
+		if((to_whitelist == NULL) || (from_whitelist == NULL)) {
5577 5578
 			if(use_syslog)
5578 5579
 				syslog(LOG_ERR, _("Can't create whitelist table"));
5580
+			if(to_whitelist) {
5581
+				tableDestroy(to_whitelist);
5582
+				to_whitelist = NULL;
5583
+			} else {
5584
+				tableDestroy(from_whitelist);
5585
+				from_whitelist = NULL;
5586
+			}
5579 5587
 			fclose(fin);
5580 5588
 			return 0;
5581 5589
 		}
5582 5590
 
5583 5591
 		while(fgets(buf, sizeof(buf), fin) != NULL) {
5592
+			const char *ptr;
5593
+
5584 5594
 			/* comment line? */
5585 5595
 			switch(buf[0]) {
5586 5596
 				case '#':
... ...
@@ -5588,12 +5604,33 @@ isWhitelisted(const char *emailaddress)
5588 5588
 				case ':':
5589 5589
 					continue;
5590 5590
 			}
5591
-			if(cli_chomp(buf) > 0)
5592
-				(void)tableInsert(whitelist, buf, 1);
5591
+			if(cli_chomp(buf) > 0) {
5592
+				if((ptr = strchr(buf, ':')) != NULL) {
5593
+					do
5594
+						ptr++;
5595
+					while(*ptr && isspace(*ptr));
5596
+
5597
+					if(*ptr == '\0') {
5598
+						logg("*Ignoring bad line '%s'\n",
5599
+							buf);
5600
+						continue;
5601
+					}
5602
+				} else
5603
+					ptr = buf;
5604
+
5605
+				if(strncasecmp(buf, "From:", 5) == 0)
5606
+					table = from_whitelist;
5607
+				else
5608
+					table = to_whitelist;
5609
+
5610
+				(void)tableInsert(table, ptr, 1);
5611
+			}
5593 5612
 		}
5594 5613
 		fclose(fin);
5595 5614
 	}
5596
-	if(whitelist && (tableFind(whitelist, emailaddress) == 1))
5615
+	table = (to) ? to_whitelist : from_whitelist;
5616
+
5617
+	if(table && (tableFind(table, emailaddress) == 1))
5597 5618
 		/*
5598 5619
 		 * This recipient is on the whitelist
5599 5620
 		 */
... ...
@@ -269,11 +269,16 @@ local domain.
269 269
 .TP
270 270
 \fB\-\-whitelist-file=FILE, \-W file\fR
271 271
 This option specifies a file which contains a list of e-mail addresses.
272
-E-mails sent to these addresses will NOT be checked.
272
+E-mails sent to or from these addresses will NOT be checked.
273 273
 While this is not an Anti-Virus function, it is quite useful for some systems.
274
-The address given to the \-\-quarantine directive is always white-listed.
274
+The address given to the \-\-quarantine directive is always whitelisted.
275
+.IP
275 276
 The file consists of a list of addresses, each address on a line enclosed
276 277
 in angle brackets (e.g. <foo@bar.com>).
278
+Optionally each line can start with the string \fITo:\fR or \fIFrom:\fR
279
+indicating if it is the sender or recipient that is to be whitelisted. If the
280
+field is missing, the default is \fITo\fR.
281
+Lines starting with #, : or ! are ignored.
277 282
 .TP
278 283
 \fB\-\-sendmail-cf=FILE\fR
279 284
 When starting, clamav\-milter runs some sanity checks against the sendmail.cf