Browse code

Better Template Handling

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@726 77e5149b-7576-45b1-b177-96237e5ba77b

Nigel Horne authored on 2004/08/05 16:46:51
Showing 4 changed files
... ...
@@ -1,3 +1,16 @@
1
+Thu Aug  5 08:44:51 BST 2004 (njh)
2
+----------------------------------
3
+  * clamav-milter:	Handle more variants of gethostbyname_r
4
+  			Try harder to get fully qualified hostname
5
+			Template files can now contain more than one variable
6
+			Template files sendmail variables handling changed to
7
+				allow access to variables not in braces. All
8
+				sendmail variables are now delimeted by
9
+				dollars, e.g.  ${j}$
10
+			Better local IP table by Damian Menscher
11
+				<menscher@uiuc.edu> and Andy Fiddaman
12
+				<clam@fiddaman.net>
13
+
1 14
 Thu Aug  5 03:10:32 CEST 2004 (tk)
2 15
 ----------------------------------
3 16
   * libclamav: include FSG unpacker from aCaB
... ...
@@ -143,6 +143,9 @@ When using UNIX domain sockets via the LocalSocket option of clamav.conf,
143 143
 we recommend that you use the --quarantine-dir option since that may improve
144 144
 performance.
145 145
 
146
+To test that your clamAV system is now intercepting viruses, visit
147
+http://www.testvirus.org
148
+
146 149
 CHANGE HISTORY
147 150
 
148 151
 Changes
... ...
@@ -449,6 +452,15 @@ Changes
449 449
 		Use HAVE_GETHOSTBYNAME_R_6
450 450
 0.75d	29/7/04	Don't say "waiting for some to exit" if --dont-wait
451 451
 0.75e	30/7/04	Handle new clamd message when StreamMaxLength is exceeded
452
+0.75f	02/8/04	Use HAVE_GETHOSTBYNAME_R_5 and HAVE_GETHOSTBYNAME_R_3
453
+		Try to ensure that the fully qualified domain name is used idea
454
+		by christian laubscher <christian.laubscher@tiscalinet.ch>
455
+		Template files can now contain more than one variable
456
+		Template files sendmail variables handling changed to allow
457
+			access to variables not in braces. All sendmail
458
+			variables are now delimeted by dollars, e.g.  ${j}$
459
+		Better local IP table by Damian Menscher <menscher@uiuc.edu> and
460
+			Andy Fiddaman <clam@fiddaman.net>
452 461
 
453 462
 BUG REPORTS
454 463
 
... ...
@@ -26,6 +26,9 @@
26 26
  *
27 27
  * Change History:
28 28
  * $Log: clamav-milter.c,v $
29
+ * Revision 1.114  2004/08/05 07:44:28  nigelhorne
30
+ * Better Template Handling
31
+ *
29 32
  * Revision 1.113  2004/07/30 14:34:56  nigelhorne
30 33
  * Handle changed clamd message
31 34
  *
... ...
@@ -350,9 +353,9 @@
350 350
  * Revision 1.6  2003/09/28 16:37:23  nigelhorne
351 351
  * Added -f flag use MaxThreads if --max-children not set
352 352
  */
353
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.113 2004/07/30 14:34:56 nigelhorne Exp $";
353
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.114 2004/08/05 07:44:28 nigelhorne Exp $";
354 354
 
355
-#define	CM_VERSION	"0.75e"
355
+#define	CM_VERSION	"0.75f"
356 356
 
357 357
 /*#define	CONFDIR	"/usr/local/etc"*/
358 358
 
... ...
@@ -500,6 +503,7 @@ static	int	connect2clamd(struct privdata *privdata);
500 500
 static	void	checkClamd(void);
501 501
 static	int	sendtemplate(SMFICTX *ctx, const char *filename, FILE *sendmail, const char *virusname);
502 502
 static	void	setsubject(SMFICTX *ctx, const char *virusname);
503
+static	int	clamfi_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len);
503 504
 
504 505
 static	char	clamav_version[128];
505 506
 static	int	fflag = 0;	/* force a scan, whatever */
... ...
@@ -1534,69 +1538,44 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1534 1534
 	 */
1535 1535
 	if(strncasecmp(port, "inet:", 5) == 0) {
1536 1536
 		const char *hostmail;
1537
-		/*
1538
-		 * TODO: gethostbyname_r is non-standard so different operating
1539
-		 * systems do it in different ways. Need more examples
1540
-		 */
1541
-#ifdef	HAVE_GETHOSTBYNAME_R_6
1542
-		struct hostent *hp, hostent;
1543
-		char buf[BUFSIZ];
1544
-		int ret;
1545
-#else
1546
-		const struct hostent *hp2, *hp;
1547 1537
 		struct hostent hostent;
1548
-		static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
1549
-#endif
1538
+		char buf[BUFSIZ];
1550 1539
 
1551 1540
 		/*
1552 1541
 		 * Using TCP/IP for the sendmail->clamav-milter connection
1553 1542
 		 */
1554 1543
 		if((hostmail = smfi_getsymval(ctx, "{if_name}")) == NULL) {
1555 1544
 			if(use_syslog)
1556
-				syslog(LOG_WARNING, "Can't get sendmail hostname");
1557
-			hostmail = "unknown";
1558
-		}
1559
-
1560
-#ifdef	HAVE_GETHOSTBYNAME_R_6
1561
-		if(gethostbyname_r(hostmail, &hostent, buf, sizeof(buf), &hp, &ret) != 0) {
1562
-			if(use_syslog)
1563
-				syslog(LOG_WARNING, "Access Denied: Host Unknown (%s)", hostname);
1545
+				syslog(LOG_ERR, "Can't get sendmail hostname");
1564 1546
 			return cl_error;
1565 1547
 		}
1566
-#else
1567
-		pthread_mutex_lock(&hostent_mutex);
1568
-		if((hp2 = gethostbyname(hostmail)) == NULL) {
1569
-			pthread_mutex_unlock(&hostent_mutex);
1548
+		if(clamfi_gethostbyname(hostmail, &hostent, buf, sizeof(buf)) != 0) {
1570 1549
 			if(use_syslog)
1571 1550
 				syslog(LOG_WARNING, "Access Denied: Host Unknown (%s)", hostname);
1572 1551
 			return cl_error;
1573 1552
 		}
1574
-		memcpy(&hostent, hp2, sizeof(struct hostent));
1575
-		pthread_mutex_unlock(&hostent_mutex);
1576
-		hp = &hostent;
1577
-#endif
1578 1553
 
1579 1554
 #ifdef HAVE_INET_NTOP
1580
-		if(hp->h_addr &&
1581
-		   (inet_ntop(AF_INET, (struct in_addr *)hp->h_addr, ip, sizeof(ip)) == NULL)) {
1582
-			perror(hp->h_name);
1555
+		if(hostent.h_addr &&
1556
+		   (inet_ntop(AF_INET, (struct in_addr *)hostent.h_addr, ip, sizeof(ip)) == NULL)) {
1557
+			perror(hostent.h_name);
1583 1558
 			/*if(use_syslog)
1584
-				syslog(LOG_WARNING, "Can't get IP address for (%s)", hp->h_name);
1585
-			strcpy(ip, (char *)inet_ntoa(*(struct in_addr *)hp->h_addr));*/
1559
+				syslog(LOG_WARNING, "Can't get IP address for (%s)", hostent.h_name);
1560
+			strcpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr));*/
1586 1561
 			if(use_syslog)
1587
-				syslog(LOG_WARNING, "Access Denied: Can't get IP address for (%s)", hp->h_name);
1562
+				syslog(LOG_WARNING, "Access Denied: Can't get IP address for (%s)", hostent.h_name);
1588 1563
 			return cl_error;
1589 1564
 		}
1590 1565
 #else
1591
-		strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hp->h_addr), sizeof(ip));
1566
+		strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip));
1592 1567
 #endif
1593 1568
 
1594 1569
 		/*
1595 1570
 		 * Ask is this is a allowed name or IP number
1596 1571
 		 */
1597
-		if(!hosts_ctl("clamav-milter", hp->h_name, ip, STRING_UNKNOWN)) {
1572
+		if(!hosts_ctl("clamav-milter", hostent.h_name, ip, STRING_UNKNOWN)) {
1598 1573
 			if(use_syslog)
1599
-				syslog(LOG_WARNING, "Access Denied for %s[%s]", hp->h_name, ip);
1574
+				syslog(LOG_WARNING, "Access Denied for %s[%s]", hostent.h_name, ip);
1600 1575
 			return SMFIS_TEMPFAIL;
1601 1576
 		}
1602 1577
 	}
... ...
@@ -1624,12 +1603,20 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1624 1624
 		 * local machines are not scanned.
1625 1625
 		 *
1626 1626
 		 * TODO: read these from clamav.conf
1627
+		 *
1628
+		 * Better table by Damian Menscher <menscher@uiuc.edu>
1629
+		 *
1630
+		 * Andy Fiddaman <clam@fiddaman.net> added
1631
+		 *	169.254.0.0/16 (Microsoft default DHCP)
1627 1632
 		 */
1628 1633
 		static const char *localAddresses[] = {
1629
-			/*"^192\\.168\\.[0-9]+\\.[0-9]+$",*/
1630
-			"^192\\.168\\.[0-9]*\\.[0-9]*$",
1631
-			"^10\\.0\\.0\\.[0-9]*$",
1632
-			"127.0.0.1",
1634
+			"^127\\.0\\.0\\.1$",
1635
+			"^192\\.168\\.[0-9]+\\.[0-9]+$",
1636
+			"^10\\.[0-9]*\\.[0-9]*\\.[0-9]*$",
1637
+			"^172\\.1[6-9]\\.[0-9]*\\.[0-9]*$",
1638
+			"^172\\.2[0-9]\\.[0-9]*\\.[0-9]*$",
1639
+			"^172\\.3[0-1]\\.[0-9]*\\.[0-9]*$",
1640
+			"^169\\.254\\.[0-9]+\\.[0-9]+$",
1633 1641
 			NULL
1634 1642
 		};
1635 1643
 		const char **possible;
... ...
@@ -1638,7 +1625,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1638 1638
 			int rc;
1639 1639
 			regex_t reg;
1640 1640
 
1641
-			if(regcomp(&reg, *possible, 0) != 0) {
1641
+			if(regcomp(&reg, *possible, REG_EXTENDED) != 0) {
1642 1642
 				if(use_syslog)
1643 1643
 					syslog(LOG_ERR, "Couldn't parse local regexp");
1644 1644
 				return cl_error;
... ...
@@ -2070,10 +2057,24 @@ clamfi_eom(SMFICTX *ctx)
2070 2070
 		if(localSocket) {
2071 2071
 			char hostname[32];
2072 2072
 
2073
-			if(gethostname(hostname, sizeof(hostname)) < 0)
2074
-				strncpy(hostname,
2075
-					smfi_getsymval(ctx, "{j}"),
2076
-					sizeof(hostname) - 1);
2073
+			if(gethostname(hostname, sizeof(hostname)) < 0) {
2074
+				const char *ptr = smfi_getsymval(ctx, "{j}");
2075
+
2076
+				if(ptr)
2077
+					strncpy(hostname, ptr,
2078
+						sizeof(hostname) - 1);
2079
+				else
2080
+					strcpy(buf, "Error determining host");
2081
+			} else if(strchr(hostname, '.') == NULL) {
2082
+				/*
2083
+				 * Determine fully qualified name
2084
+				 */
2085
+				struct hostent hostent;
2086
+				char buf[BUFSIZ];
2087
+
2088
+				if(clamfi_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0)
2089
+					strncpy(hostname, hostent.h_name, sizeof(hostname));
2090
+			}
2077 2091
 
2078 2092
 			snprintf(buf, sizeof(buf) - 1, "%s\n\ton %s",
2079 2093
 				clamav_version, hostname);
... ...
@@ -2149,7 +2150,10 @@ clamfi_eom(SMFICTX *ctx)
2149 2149
 		char reject[1024];
2150 2150
 		char **to, *virusname;
2151 2151
 
2152
-		*ptr = '\0';	/* Remove the "FOUND" word */
2152
+		/*
2153
+		 Remove the "FOUND" word, and the space before it
2154
+		 */
2155
+		*--ptr = '\0';
2153 2156
 
2154 2157
 		/* skip over 'stream/filename: ' at the start */
2155 2158
 		if((virusname = strchr(mess, ':')) != NULL)
... ...
@@ -2296,7 +2300,7 @@ clamfi_eom(SMFICTX *ctx)
2296 2296
 
2297 2297
 					for(to = privdata->to; *to; to++)
2298 2298
 						fprintf(sendmail, "\t%s\n", *to);
2299
-					fprintf(sendmail, "contained %sand has not been delivered.\n", virusname);
2299
+					fprintf(sendmail, "contained %s and has not been delivered.\n", virusname);
2300 2300
 
2301 2301
 					if(privdata->filename != NULL)
2302 2302
 						fprintf(sendmail, "\nThe message in question has been quarantined as %s\n", privdata->filename);
... ...
@@ -2370,7 +2374,7 @@ clamfi_eom(SMFICTX *ctx)
2370 2370
 		} else
2371 2371
 			rc = SMFIS_DISCARD;
2372 2372
 
2373
-		snprintf(reject, sizeof(reject) - 1, "%sdetected by ClamAV - http://www.clamav.net", virusname);
2373
+		snprintf(reject, sizeof(reject) - 1, "%s detected by ClamAV - http://www.clamav.net", virusname);
2374 2374
 		smfi_setreply(ctx, (char *)privdata->rejectCode, "5.7.1", reject);
2375 2375
 	}
2376 2376
 	clamfi_cleanup(ctx);
... ...
@@ -3044,22 +3048,18 @@ checkClamd(void)
3044 3044
 /*
3045 3045
  * Send a templated message about an intercepted message. Very basic for
3046 3046
  * now, just to prove it works, will enhance the flexability later, only
3047
- * supports %v and {sendmail_variables} at present. And only one instance of
3048
- * %v or {sendmail_variable} at that.
3047
+ * supports %v and $sendmail_variables$ at present.
3049 3048
  *
3050 3049
  * TODO: more template features
3051 3050
  * TODO: allow filename to start with a '|' taken to mean the output of
3052 3051
  *	a program
3053
- * TODO: allow { to be escaped with a \ character
3054
- * TODO: allow more than one substitution in a file
3055 3052
  */
3056 3053
 static int
3057 3054
 sendtemplate(SMFICTX *ctx, const char *filename, FILE *sendmail, const char *virusname)
3058 3055
 {
3059 3056
 	FILE *fin = fopen(filename, "r");
3060 3057
 	struct stat statb;
3061
-	char *buf, *ptr, *ptr2;
3062
-	int rc;
3058
+	char *buf, *ptr /* , *ptr2 */;
3063 3059
 
3064 3060
 	if(fin == NULL) {
3065 3061
 		perror(filename);
... ...
@@ -3088,41 +3088,53 @@ sendtemplate(SMFICTX *ctx, const char *filename, FILE *sendmail, const char *vir
3088 3088
 	fread(buf, sizeof(char), statb.st_size, fin);
3089 3089
 	fclose(fin);
3090 3090
 	buf[statb.st_size] = '\0';
3091
-	rc = 0;
3092 3091
 
3093
-	/* FIXME: \%v should be %%v */
3094
-	if(((ptr = strstr(buf, "%v")) != NULL) && (strstr(buf, "\\%v") == NULL)) {
3095
-		*ptr = '\0';
3096
-		ptr = &ptr[2];
3097
-		fputs(buf, sendmail);
3098
-		fputs(virusname, sendmail);
3099
-		rc = (fputs(ptr, sendmail) == EOF) ? -1 : 0;
3100
-	} else if((ptr = strchr(buf, '{')) && (ptr2 = strchr(ptr, '}'))) {
3101
-		char *var;
3102
-
3103
-		*ptr++ = '\0';
3104
-		fputs(buf, sendmail);
3105
-		*ptr2++ = '\0';
3106
-
3107
-		if((var = cli_malloc(strlen(ptr) + 3)) != NULL) {
3108
-			sprintf(var, "{%s}", ptr);
3109
-			if((ptr = smfi_getsymval(ctx, var)) != NULL)
3110
-				fputs(ptr, sendmail);
3111
-			else if(use_syslog) {
3112
-				fputs(var, sendmail);
3092
+	for(ptr = buf; *ptr; ptr++)
3093
+		if(*ptr == '\\') {
3094
+			if(*++ptr == '\0')
3095
+				break;
3096
+			putc(*ptr, sendmail);
3097
+		} else if(*ptr == '%') {
3098
+			/* clamAV variable */
3099
+			if(*++ptr == 'v')
3100
+				fputs(virusname, sendmail);
3101
+			else if(*ptr == '%')
3102
+				putc('%', sendmail);
3103
+			else if(*ptr == '\0')
3104
+				break;
3105
+			else if(use_syslog)
3113 3106
 				syslog(LOG_ERR,
3114
-					"%s: Unknown sendmail variable \"%s\"\n",
3115
-					filename, var);
3107
+					"%s: Unknown clamAV variable \"%c\"\n",
3108
+					filename, *ptr);
3109
+		} else if(*ptr == '$') {
3110
+			const char *val;
3111
+			char *end = strchr(++ptr, '$');
3112
+
3113
+			if(end == NULL) {
3114
+				syslog(LOG_ERR,
3115
+					"%s: Unterminated sendmail variable \"%s\"\n",
3116
+						filename, ptr);
3117
+				continue;
3116 3118
 			}
3117
-			free(var);
3118
-		}
3119
-		fputs(ptr2, sendmail);
3120
-	} else
3121
-		rc = (fputs(buf, sendmail) == EOF) ? -1 : 0;
3119
+			*end = '\0';
3120
+
3121
+			val = smfi_getsymval(ctx, ptr);
3122
+			if(val == NULL) {
3123
+				if(use_syslog) {
3124
+					fputs(ptr, sendmail);
3125
+					syslog(LOG_ERR,
3126
+						"%s: Unknown sendmail variable \"%s\"\n",
3127
+						filename, ptr);
3128
+				}
3129
+			} else
3130
+				fputs(val, sendmail);
3131
+			ptr = end;
3132
+		} else
3133
+			putc(*ptr, sendmail);
3122 3134
 
3123 3135
 	free(buf);
3124 3136
 
3125
-	return rc;
3137
+	return 0;
3126 3138
 }
3127 3139
 
3128 3140
 /*
... ...
@@ -3139,3 +3151,55 @@ setsubject(SMFICTX *ctx, const char *virusname)
3139 3139
 	snprintf(subject, sizeof(subject) - 1, "[Virus] %s", virusname);
3140 3140
 	smfi_chgheader(ctx, "Subject", 1, subject);
3141 3141
 }
3142
+
3143
+/*
3144
+ * TODO: gethostbyname_r is non-standard so different operating
3145
+ * systems do it in different ways. Need more examples
3146
+ *
3147
+ * Returns 0 for success
3148
+ */
3149
+static int
3150
+clamfi_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len)
3151
+{
3152
+#if	defined(HAVE_GETHOSTBYNAME_R_6)
3153
+	/* e.g. Linux */
3154
+	struct hostent *hp2;
3155
+	int ret;
3156
+
3157
+	if((hostname == NULL) || (hp == NULL))
3158
+		return -1;
3159
+	if(gethostbyname_r(hostname, hp, buf, len, &hp2, &ret) < 0)
3160
+		return errno;
3161
+#elif	defined(HAVE_GETHOSTBYNAME_R_5)
3162
+	/* e.g. BSD, Solaris, Cygwin */
3163
+	int ret;
3164
+
3165
+	if((hostname == NULL) || (hp == NULL))
3166
+		return -1;
3167
+	if(gethostbyname_r(hostname, hp, buf, len, &ret) == NULL)
3168
+		return errno;
3169
+#elif	defined(HAVE_GETHOSTBYNAME_R_3)
3170
+	/* e.g. HP/UX, AIX */
3171
+	if((hostname == NULL) || (hp == NULL))
3172
+		return -1;
3173
+	if(gethostbyname_r(hostname, &hp, (struct hostent_data *)buf) < 0)
3174
+		return errno;
3175
+#else
3176
+	/* Single thread the code */
3177
+	struct hostent *hp2;
3178
+	static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
3179
+
3180
+	if((hostname == NULL) || (hp == NULL))
3181
+		return -1;
3182
+
3183
+	pthread_mutex_lock(&hostent_mutex);
3184
+	if((hp2 = gethostbyname(hostname)) == NULL) {
3185
+		pthread_mutex_unlock(&hostent_mutex);
3186
+		return errno;
3187
+	}
3188
+	memcpy(hp, hp2, sizeof(struct hostent));
3189
+	pthread_mutex_unlock(&hostent_mutex);
3190
+#endif
3191
+
3192
+	return 0;
3193
+}
... ...
@@ -162,11 +162,11 @@ will inform the remote SMTP client to retry later.
162 162
 \fB\-\-template\-file=file \-t file\fR
163 163
 File points to a file whose contents is sent as the warning message whenever a
164 164
 virus is intercepted.
165
-The first occurance of %v within the file is replaced with the message
165
+Occurances of %v within the file is replaced with the message
166 166
 returned from clamd, which includes the name of the virus.
167
-The %v string can be escaped, thus \\%v, to send the string %v.
168
-Any occurance of strings in braces are replaced with the appropriate
169
-{sendmail-variable}.
167
+The %v string can be escaped thus, \\%v, to send the string %v.
168
+Any occurance of strings in dollar signs are replaced with the appropriate
169
+sendmail-variable, e.g. ${if_addr}$.
170 170
 If the \-t option is not given, clamav\-milter defaults to a hardcoded message.
171 171
 .TP
172 172
 \fB\-\-timeout=n \-T n\fR