git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@2080 77e5149b-7576-45b1-b177-96237e5ba77b
Nigel Horne authored on 2006/07/14 21:16:23... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Fri Jul 14 13:14:13 BST 2006 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav/table.c: Added tableIterate |
|
4 |
+ * clamav-milter: Added black hole mode and IP blacklist support |
|
5 |
+ |
|
1 | 6 |
Fri Jul 14 08:45:04 BST 2006 (njh) |
2 | 7 |
---------------------------------- |
3 | 8 |
* libclamav/table: Added helper routines to delete items |
... | ... |
@@ -109,7 +109,7 @@ See http://www.nmt.edu/~wcolburn/sendmail-8.12.5/libmilter/docs/sample.html |
109 | 109 |
Installations for RedHat Linux and it's derivatives such as YellowDog: |
110 | 110 |
Ensure that you have the sendmail-devel RPM installed |
111 | 111 |
Add to /etc/mail/sendmail.mc before the MAILER statement: |
112 |
- INPUT_MAIL_FILTER(`clamav', `S=local:/var/run/clamav/clmilter.sock, F=, T=S:4m;R:4m')dnl |
|
112 |
+ INPUT_MAIL_FILTER(`clamav', `S=local:/var/run/clamav/clmilter.sock, F=, T=S:4m;R:4m;C:30s;E:10m')dnl |
|
113 | 113 |
define(`confINPUT_MAIL_FILTERS', `clamav') |
114 | 114 |
|
115 | 115 |
Note that the INPUT_MAIL_FILTER line must come before the |
... | ... |
@@ -23,28 +23,9 @@ |
23 | 23 |
* |
24 | 24 |
* For installation instructions see the file INSTALL that came with this file |
25 | 25 |
*/ |
26 |
-static char const rcsid[] = "$Id: clamav-milter.c,v 1.253 2006/07/13 07:59:22 njh Exp $"; |
|
26 |
+static char const rcsid[] = "$Id: clamav-milter.c,v 1.254 2006/07/14 12:15:26 njh Exp $"; |
|
27 | 27 |
|
28 |
-#define CM_VERSION "devel-120706" |
|
29 |
- |
|
30 |
-/*#define DONT_SCAN_BLACK_HOLES /* |
|
31 |
- * Don't scan emails to addresses set to |
|
32 |
- * /dev/null in /etc/aliases |
|
33 |
- * |
|
34 |
- * Since sendmail calls its milters before it |
|
35 |
- * looks in /etc/aliases we can spend time |
|
36 |
- * looking for malware that's going to be |
|
37 |
- * thrown away even if the message is clean. |
|
38 |
- * Enable this #define to not scan these |
|
39 |
- * messages. |
|
40 |
- * Note that this needs -ldb to be added to |
|
41 |
- * the link line, which isn't usually done. |
|
42 |
- * You will also need the db4 SDK |
|
43 |
- * |
|
44 |
- * TODO: Handle virtusertable, using |
|
45 |
- * sendmail -bv should help that and remove the |
|
46 |
- * db4 dependancy. |
|
47 |
- */ |
|
28 |
+#define CM_VERSION "devel-130706" |
|
48 | 29 |
|
49 | 30 |
#if HAVE_CONFIG_H |
50 | 31 |
#include "clamav-config.h" |
... | ... |
@@ -104,15 +85,6 @@ static char const rcsid[] = "$Id: clamav-milter.c,v 1.253 2006/07/13 07:59:22 nj |
104 | 104 |
#include <sys/param.h> |
105 | 105 |
#endif |
106 | 106 |
|
107 |
-#ifdef DONT_SCAN_BLACK_HOLES |
|
108 |
-#include <db.h> |
|
109 |
- |
|
110 |
-#define ALIASES "/etc/aliases.db" /* some use /etc/mail/aliases.db */ |
|
111 |
- |
|
112 |
-typedef struct __db DB; |
|
113 |
-static DB *db; |
|
114 |
-#endif |
|
115 |
- |
|
116 | 107 |
#if HAVE_MMAP |
117 | 108 |
#if HAVE_SYS_MMAN_H |
118 | 109 |
#include <sys/mman.h> |
... | ... |
@@ -317,6 +289,8 @@ static void setsubject(SMFICTX *ctx, const char *virusname); |
317 | 317 |
static int isLocalAddr(in_addr_t addr); |
318 | 318 |
static void clamdIsDown(void); |
319 | 319 |
static void *watchdog(void *a); |
320 |
+static int check_and_reload_database(void); |
|
321 |
+static void timeoutBlacklist(char *ip_address, int time_of_blacklist); |
|
320 | 322 |
static int logg_facility(const char *name); |
321 | 323 |
static void quit(void); |
322 | 324 |
static void broadcast(const char *mess); |
... | ... |
@@ -492,6 +466,20 @@ static const char *whitelistFile; /* |
492 | 492 |
*/ |
493 | 493 |
static const char *sendmailCF; /* location of sendmail.cf to verify */ |
494 | 494 |
static const char *pidfile; |
495 |
+static int black_hole_mode; /* |
|
496 |
+ * Since sendmail calls its milters before it |
|
497 |
+ * looks in /etc/aliases we can spend time |
|
498 |
+ * looking for malware that's going to be |
|
499 |
+ * thrown away even if the message is clean. |
|
500 |
+ * Enable this to not scan these messages. |
|
501 |
+ * Sadly, because these days sendmail -bv |
|
502 |
+ * only works as root, you can't use this with |
|
503 |
+ * the User directive, which some won't like |
|
504 |
+ * |
|
505 |
+ * TODO: Investigate |
|
506 |
+ * smfi_getsymval(ctx, "{rcpt_addr}") |
|
507 |
+ * which also may contain the real target name |
|
508 |
+ */ |
|
495 | 509 |
|
496 | 510 |
static table_t *blacklist; /* never freed */ |
497 | 511 |
static int blacklist_time; /* How long to blacklist an IP */ |
... | ... |
@@ -520,6 +508,7 @@ static int isBlacklisted(const char *ip_address); |
520 | 520 |
static void logger(const char *mess); |
521 | 521 |
static void mx(void); |
522 | 522 |
static void resolve(const char *host); |
523 |
+static sfsistat black_hole(const struct privdata *privdata); |
|
523 | 524 |
|
524 | 525 |
short logg_time, logg_lock, logok; |
525 | 526 |
int logg_size; |
... | ... |
@@ -532,6 +521,7 @@ help(void) |
532 | 532 |
|
533 | 533 |
puts(_("\t--advisory\t\t-A\tFlag viruses rather than deleting them.")); |
534 | 534 |
puts(_("\t--blacklist=time\t-k\tTime (in seconds) to blacklist an IP.")); |
535 |
+ puts(_("\t--black-hole-mode\t\tDon't scan messages aliased to /dev/null.")); |
|
535 | 536 |
puts(_("\t--bounce\t\t-b\tSend a failure message to the sender.")); |
536 | 537 |
puts(_("\t--broadcast\t\t-B [IFACE]\tBroadcast to a network manager when a virus is found.")); |
537 | 538 |
puts(_("\t--config-file=FILE\t-c FILE\tRead configuration from FILE.")); |
... | ... |
@@ -639,9 +629,9 @@ main(int argc, char **argv) |
639 | 639 |
struct cidr_net *net; |
640 | 640 |
struct in_addr ignoreIP; |
641 | 641 |
#ifdef CL_DEBUG |
642 |
- const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:x:0:"; |
|
642 |
+ const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:x:0:1:2"; |
|
643 | 643 |
#else |
644 |
- const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:0:"; |
|
644 |
+ const char *args = "a:AbB:c:CdDefF:I:k:lLm:M:nNop:PqQ:hHs:St:T:U:VwW:0:1:2"; |
|
645 | 645 |
#endif |
646 | 646 |
|
647 | 647 |
static struct option long_options[] = { |
... | ... |
@@ -756,6 +746,9 @@ main(int argc, char **argv) |
756 | 756 |
{ |
757 | 757 |
"version", 0, NULL, 'V' |
758 | 758 |
}, |
759 |
+ { |
|
760 |
+ "black-hole-mode", 0, NULL, '2' |
|
761 |
+ }, |
|
759 | 762 |
#ifdef CL_DEBUG |
760 | 763 |
{ |
761 | 764 |
"debug-level", 1, NULL, 'x' |
... | ... |
@@ -904,6 +897,9 @@ main(int argc, char **argv) |
904 | 904 |
case '1': /* headers for the template file */ |
905 | 905 |
templateHeaders = optarg; |
906 | 906 |
break; |
907 |
+ case '2': |
|
908 |
+ black_hole_mode++; |
|
909 |
+ break; |
|
907 | 910 |
case 'T': /* time to wait for child to die */ |
908 | 911 |
child_timeout = atoi(optarg); |
909 | 912 |
break; |
... | ... |
@@ -1021,19 +1017,6 @@ main(int argc, char **argv) |
1021 | 1021 |
consolefd = open(console, O_WRONLY); |
1022 | 1022 |
#endif |
1023 | 1023 |
|
1024 |
-#ifdef DONT_SCAN_BLACK_HOLES |
|
1025 |
- if(db_create(&db, NULL, 0) == 0) { |
|
1026 |
- int ret = db->open(db, NULL, ALIASES, NULL, DB_HASH, |
|
1027 |
- DB_RDONLY, 0644); |
|
1028 |
- |
|
1029 |
- if(ret != 0) { |
|
1030 |
- perror(ALIASES); |
|
1031 |
- return EX_OSFILE; |
|
1032 |
- } |
|
1033 |
- } else |
|
1034 |
- db = NULL; |
|
1035 |
-#endif |
|
1036 |
- |
|
1037 | 1024 |
if(getuid() == 0) { |
1038 | 1025 |
if(iface) { |
1039 | 1026 |
#ifdef SO_BINDTODEVICE |
... | ... |
@@ -1079,14 +1062,22 @@ main(int argc, char **argv) |
1079 | 1079 |
#endif |
1080 | 1080 |
} |
1081 | 1081 |
|
1082 |
+ if(black_hole_mode && (user->pw_uid != 0)) { |
|
1083 |
+ fprintf(stderr, _("%s: You cannot use black hole mode unless you are root\n"), |
|
1084 |
+ argv[0]); |
|
1085 |
+ return EX_CONFIG; |
|
1086 |
+ } |
|
1087 |
+ |
|
1082 | 1088 |
setgid(user->pw_gid); |
1089 |
+ |
|
1083 | 1090 |
if(setuid(user->pw_uid) < 0) |
1084 | 1091 |
perror(cpt->strarg); |
1085 | 1092 |
else |
1086 | 1093 |
cli_dbgmsg(_("Running as user %s (UID %d, GID %d)\n"), |
1087 | 1094 |
cpt->strarg, user->pw_uid, user->pw_gid); |
1088 |
- } else |
|
1095 |
+ } else if(!black_hole_mode) |
|
1089 | 1096 |
fprintf(stderr, _("%s: running as root is not recommended (check \"User\" in %s)\n"), argv[0], cfgfile); |
1097 |
+ |
|
1090 | 1098 |
} else if(iface) { |
1091 | 1099 |
fprintf(stderr, _("%s: Only root can set an interface for --broadcast\n"), argv[0]); |
1092 | 1100 |
return EX_USAGE; |
... | ... |
@@ -1638,11 +1629,7 @@ main(int argc, char **argv) |
1638 | 1638 |
} |
1639 | 1639 |
} |
1640 | 1640 |
|
1641 |
-#ifdef SESSION |
|
1642 |
- /* FIXME: add localSocket support to watchdog */ |
|
1643 |
- if((localSocket == NULL) || external) |
|
1644 |
-#endif |
|
1645 |
- pthread_create(&tid, NULL, watchdog, NULL); |
|
1641 |
+ pthread_create(&tid, NULL, watchdog, NULL); |
|
1646 | 1642 |
|
1647 | 1643 |
if(((cpt = cfgopt(copt, "PidFile")) != NULL) && cpt->enabled) |
1648 | 1644 |
pidFile = cpt->strarg; |
... | ... |
@@ -2362,10 +2349,18 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) |
2362 | 2362 |
*/ |
2363 | 2363 |
smfi_setreply(ctx, "550", "5.7.1", _("Your IP is blacklisted")); |
2364 | 2364 |
broadcast(_("Blacklisted IP detected")); |
2365 |
+ |
|
2366 |
+ /* |
|
2367 |
+ * Keep them blacklisted |
|
2368 |
+ */ |
|
2369 |
+ pthread_mutex_lock(&blacklist_mutex); |
|
2370 |
+ (void)tableUpdate(blacklist, remoteIP, (int)time((time_t *)0)); |
|
2371 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
2372 |
+ |
|
2365 | 2373 |
return SMFIS_REJECT; |
2366 | 2374 |
} |
2367 | 2375 |
if(smfi_getpriv(ctx) != NULL) { |
2368 |
- /* More than one MAIL FROM command, "can't happen" */ |
|
2376 |
+ /* More than one connection command, "can't happen" */ |
|
2369 | 2377 |
cli_warnmsg("clamfi_connect: called more than once\n"); |
2370 | 2378 |
return SMFIS_TEMPFAIL; |
2371 | 2379 |
} |
... | ... |
@@ -2380,7 +2375,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) |
2380 | 2380 |
return SMFIS_CONTINUE; |
2381 | 2381 |
} |
2382 | 2382 |
|
2383 |
- clamfi_free(privdata); |
|
2383 |
+ free(privdata); |
|
2384 | 2384 |
|
2385 | 2385 |
return cl_error; |
2386 | 2386 |
} |
... | ... |
@@ -2695,28 +2690,14 @@ clamfi_eoh(SMFICTX *ctx) |
2695 | 2695 |
return cl_error; |
2696 | 2696 |
} |
2697 | 2697 |
|
2698 |
-#ifdef DONT_SCAN_BLACK_HOLES |
|
2699 |
- for(to = privdata->to; *to; to++) { |
|
2700 |
- DBT key, data; |
|
2701 |
- |
|
2702 |
- memset(&key, '\0', sizeof(DBT)); |
|
2703 |
- memset(&data, '\0', sizeof(DBT)); |
|
2698 |
+ if(black_hole_mode) { |
|
2699 |
+ sfsistat rc = black_hole(privdata); |
|
2704 | 2700 |
|
2705 |
- key.data = (char *)*to; |
|
2706 |
- key.size = strlen(key.data) + 1; |
|
2707 |
- |
|
2708 |
- if(db->get(db, NULL, &key, &data, 0) == 0) |
|
2709 |
- /* FIXME: The result may be aliased as well */ |
|
2710 |
- if(strcmp(data.data, "/dev/null") == 0) |
|
2711 |
- continue; |
|
2712 |
- break; |
|
2713 |
- } |
|
2714 |
- if(*to == NULL) { |
|
2715 |
- /* All recipients map to /dev/null */ |
|
2716 |
- syslog(LOG_NOTICE, "discarded, since all recipients are /dev/null"); |
|
2717 |
- return SMFIS_DISCARD; |
|
2701 |
+ if(rc != SMFIS_CONTINUE) { |
|
2702 |
+ clamfi_cleanup(ctx); |
|
2703 |
+ return rc; |
|
2704 |
+ } |
|
2718 | 2705 |
} |
2719 |
-#endif |
|
2720 | 2706 |
|
2721 | 2707 |
/* |
2722 | 2708 |
* See if the e-mail is only going to members of the list |
... | ... |
@@ -4853,8 +4834,6 @@ watchdog(void *a) |
4853 | 4853 |
{ |
4854 | 4854 |
static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER; |
4855 | 4855 |
|
4856 |
- assert((!external) || (sessions != NULL)); |
|
4857 |
- |
|
4858 | 4856 |
while(!quitting) { |
4859 | 4857 |
unsigned int i; |
4860 | 4858 |
struct timespec ts; |
... | ... |
@@ -4882,32 +4861,11 @@ watchdog(void *a) |
4882 | 4882 |
cli_dbgmsg("watchdog wakes\n"); |
4883 | 4883 |
pthread_mutex_unlock(&watchdog_mutex); |
4884 | 4884 |
|
4885 |
- if(!external) { |
|
4886 |
- /* |
|
4887 |
- * Re-load the database if needed |
|
4888 |
- */ |
|
4889 |
- switch(cl_statchkdir(&dbstat)) { |
|
4890 |
- case 1: |
|
4891 |
- cli_dbgmsg("Database has changed\n"); |
|
4892 |
- cl_statfree(&dbstat); |
|
4893 |
- if(use_syslog) |
|
4894 |
- syslog(LOG_WARNING, _("Loading new database")); |
|
4895 |
- if(loadDatabase() != 0) { |
|
4896 |
- smfi_stop(); |
|
4897 |
- cli_errmsg("Failed to load updated database\n"); |
|
4898 |
- return NULL; |
|
4899 |
- } |
|
4900 |
- break; |
|
4901 |
- case 0: |
|
4902 |
- cli_dbgmsg("Database has not changed\n"); |
|
4903 |
- break; |
|
4904 |
- default: |
|
4905 |
- smfi_stop(); |
|
4906 |
- cli_errmsg("Database error - %s is stopping\n", progname); |
|
4907 |
- return NULL; |
|
4908 |
- } |
|
4909 |
- continue; |
|
4885 |
+ if(check_and_reload_database() != 0) { |
|
4886 |
+ smfi_stop(); |
|
4887 |
+ return NULL; |
|
4910 | 4888 |
} |
4889 |
+ |
|
4911 | 4890 |
i = 0; |
4912 | 4891 |
session = sessions; |
4913 | 4892 |
pthread_mutex_lock(&sstatus_mutex); |
... | ... |
@@ -4990,6 +4948,13 @@ watchdog(void *a) |
4990 | 4990 |
if(i == max_children) |
4991 | 4991 |
clamdIsDown(); |
4992 | 4992 |
pthread_mutex_unlock(&sstatus_mutex); |
4993 |
+ |
|
4994 |
+ /* Garbage collect IP addresses no longer blacklisted */ |
|
4995 |
+ if(blacklist) { |
|
4996 |
+ pthread_mutex_lock(&blacklist_mutex); |
|
4997 |
+ tableIterate(blacklist, timeoutBlacklist); |
|
4998 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
4999 |
+ } |
|
4993 | 5000 |
} |
4994 | 5001 |
cli_dbgmsg("watchdog quits\n"); |
4995 | 5002 |
return NULL; |
... | ... |
@@ -5006,9 +4971,6 @@ watchdog(void *a) |
5006 | 5006 |
{ |
5007 | 5007 |
static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER; |
5008 | 5008 |
|
5009 |
- if(external) |
|
5010 |
- return NULL; |
|
5011 |
- |
|
5012 | 5009 |
while(!quitting) { |
5013 | 5010 |
struct timespec ts; |
5014 | 5011 |
struct timeval tp; |
... | ... |
@@ -5040,29 +5002,15 @@ watchdog(void *a) |
5040 | 5040 |
* thread-safe, since it's governed by a mutex that we can't |
5041 | 5041 |
* see, and there's no access to it via an approved method |
5042 | 5042 |
*/ |
5043 |
- |
|
5044 |
- /* |
|
5045 |
- * Re-load the database. |
|
5046 |
- */ |
|
5047 |
- switch(cl_statchkdir(&dbstat)) { |
|
5048 |
- case 1: |
|
5049 |
- cli_dbgmsg("Database has changed\n"); |
|
5050 |
- cl_statfree(&dbstat); |
|
5051 |
- if(use_syslog) |
|
5052 |
- syslog(LOG_WARNING, _("Loading new database")); |
|
5053 |
- if(loadDatabase() != 0) { |
|
5054 |
- smfi_stop(); |
|
5055 |
- cli_errmsg("Failed to load updated database\n"); |
|
5056 |
- return NULL; |
|
5057 |
- } |
|
5058 |
- break; |
|
5059 |
- case 0: |
|
5060 |
- cli_dbgmsg("Database has not changed\n"); |
|
5061 |
- break; |
|
5062 |
- default: |
|
5063 |
- smfi_stop(); |
|
5064 |
- cli_errmsg("Database error - %s is stopping\n", progname); |
|
5065 |
- return NULL; |
|
5043 |
+ if(check_and_reload_database() != 0) { |
|
5044 |
+ smfi_stop(); |
|
5045 |
+ return NULL; |
|
5046 |
+ } |
|
5047 |
+ /* Garbage collect IP addresses no longer blacklisted */ |
|
5048 |
+ if(blacklist) { |
|
5049 |
+ pthread_mutex_lock(&blacklist_mutex); |
|
5050 |
+ tableIterate(blacklist, timeoutBlacklist); |
|
5051 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
5066 | 5052 |
} |
5067 | 5053 |
} |
5068 | 5054 |
cli_dbgmsg("watchdog quits\n"); |
... | ... |
@@ -5070,6 +5018,49 @@ watchdog(void *a) |
5070 | 5070 |
} |
5071 | 5071 |
#endif |
5072 | 5072 |
|
5073 |
+/* |
|
5074 |
+ * Check to see if the database needs to be reloaded |
|
5075 |
+ * Return 0 for success |
|
5076 |
+ */ |
|
5077 |
+static int |
|
5078 |
+check_and_reload_database(void) |
|
5079 |
+{ |
|
5080 |
+ int rc; |
|
5081 |
+ |
|
5082 |
+ if(external) |
|
5083 |
+ return 0; |
|
5084 |
+ |
|
5085 |
+ switch(cl_statchkdir(&dbstat)) { |
|
5086 |
+ case 1: |
|
5087 |
+ cli_dbgmsg("Database has changed\n"); |
|
5088 |
+ cl_statfree(&dbstat); |
|
5089 |
+ if(use_syslog) |
|
5090 |
+ syslog(LOG_WARNING, _("Loading new database")); |
|
5091 |
+ rc = loadDatabase(); |
|
5092 |
+ if(rc != 0) { |
|
5093 |
+ cli_errmsg("Failed to load updated database\n"); |
|
5094 |
+ return rc; |
|
5095 |
+ } |
|
5096 |
+ break; |
|
5097 |
+ case 0: |
|
5098 |
+ cli_dbgmsg("Database has not changed\n"); |
|
5099 |
+ break; |
|
5100 |
+ default: |
|
5101 |
+ cli_errmsg("Database error - %s is stopping\n", progname); |
|
5102 |
+ return 1; |
|
5103 |
+ } |
|
5104 |
+ return 0; /* all OK */ |
|
5105 |
+} |
|
5106 |
+ |
|
5107 |
+static void |
|
5108 |
+timeoutBlacklist(char *ip_address, int time_of_blacklist) |
|
5109 |
+{ |
|
5110 |
+ if(time_of_blacklist == 0) /* Must not blacklist this IP address */ |
|
5111 |
+ return; |
|
5112 |
+ if((time((time_t *)0) - time_of_blacklist) > blacklist_time) |
|
5113 |
+ tableRemove(blacklist, ip_address); |
|
5114 |
+} |
|
5115 |
+ |
|
5073 | 5116 |
static const struct { |
5074 | 5117 |
const char *name; |
5075 | 5118 |
int code; |
... | ... |
@@ -5565,13 +5556,11 @@ isBlacklisted(const char *ip_address) |
5565 | 5565 |
if(blacklist == NULL) { |
5566 | 5566 |
blacklist = tableCreate(); |
5567 | 5567 |
|
5568 |
- if(blacklist == NULL) { |
|
5568 |
+ pthread_mutex_unlock(&blacklist_mutex); |
|
5569 |
+ |
|
5570 |
+ if(blacklist == NULL) |
|
5569 | 5571 |
if(use_syslog) |
5570 | 5572 |
syslog(LOG_ERR, _("Can't create blacklist table")); |
5571 |
- pthread_mutex_unlock(&blacklist_mutex); |
|
5572 |
- return 0; |
|
5573 |
- } |
|
5574 |
- pthread_mutex_unlock(&blacklist_mutex); |
|
5575 | 5573 |
return 0; |
5576 | 5574 |
} |
5577 | 5575 |
t = tableFind(blacklist, ip_address); |
... | ... |
@@ -5585,8 +5574,7 @@ isBlacklisted(const char *ip_address) |
5585 | 5585 |
/* IP cannot be blacklisted */ |
5586 | 5586 |
return 0; |
5587 | 5587 |
|
5588 |
- if((now - t) < blacklist_time) |
|
5589 |
- /* FIXME: should be able to renew the certificate */ |
|
5588 |
+ if((now - t) <= blacklist_time) |
|
5590 | 5589 |
return 1; |
5591 | 5590 |
|
5592 | 5591 |
/* FIXME: should be able to remove the certificate */ |
... | ... |
@@ -5770,3 +5758,63 @@ resolve(const char *host) |
5770 | 5770 |
} |
5771 | 5771 |
} |
5772 | 5772 |
} |
5773 |
+ |
|
5774 |
+static sfsistat |
|
5775 |
+black_hole(const struct privdata *privdata) |
|
5776 |
+{ |
|
5777 |
+ int must_scan; |
|
5778 |
+ char **to; |
|
5779 |
+ |
|
5780 |
+ to = privdata->to; |
|
5781 |
+ must_scan = (*to) ? 0 : 1; |
|
5782 |
+ |
|
5783 |
+ for(; *to; to++) { |
|
5784 |
+ char cmd[128]; |
|
5785 |
+ FILE *sendmail; |
|
5786 |
+ |
|
5787 |
+ snprintf(cmd, sizeof(cmd) - 1, "%s -bv \"%s\" < /dev/null 2>&1", |
|
5788 |
+ SENDMAIL_BIN, *to); |
|
5789 |
+ |
|
5790 |
+ cli_dbgmsg("Calling %s\n", cmd); |
|
5791 |
+ sendmail = popen(cmd, "r"); |
|
5792 |
+ |
|
5793 |
+ if(sendmail) { |
|
5794 |
+ char buf[BUFSIZ]; |
|
5795 |
+ |
|
5796 |
+ while(fgets(buf, sizeof(buf), sendmail) != NULL) { |
|
5797 |
+ if(cli_chomp(buf) == 0) |
|
5798 |
+ continue; |
|
5799 |
+ |
|
5800 |
+ cli_dbgmsg("sendmail output: %s\n", buf); |
|
5801 |
+ |
|
5802 |
+ if(strstr(buf, "... deliverable: mailer ")) { |
|
5803 |
+ const char *p = strstr(buf, ", user "); |
|
5804 |
+ |
|
5805 |
+ if(strcmp(&p[7], "/dev/null") != 0) { |
|
5806 |
+ must_scan = 1; |
|
5807 |
+ break; |
|
5808 |
+ } |
|
5809 |
+ } |
|
5810 |
+ } |
|
5811 |
+ pclose(sendmail); |
|
5812 |
+ } else if(use_syslog) { |
|
5813 |
+ syslog(LOG_WARNING, _("Can't execute '%s' to expand '%s'"), |
|
5814 |
+ cmd, *to); |
|
5815 |
+ must_scan = 1; |
|
5816 |
+ } |
|
5817 |
+ if(must_scan) |
|
5818 |
+ break; |
|
5819 |
+ } |
|
5820 |
+ if(!must_scan) { |
|
5821 |
+ /* All recipients map to /dev/null */ |
|
5822 |
+ if(use_syslog) { |
|
5823 |
+ to = privdata->to; |
|
5824 |
+ if(*to) |
|
5825 |
+ syslog(LOG_NOTICE, "discarded, since all recipients (e.g. \"%s\") are /dev/null", *to); |
|
5826 |
+ else |
|
5827 |
+ syslog(LOG_NOTICE, "discarded, since all recipients are /dev/null"); |
|
5828 |
+ } |
|
5829 |
+ return SMFIS_DISCARD; |
|
5830 |
+ } |
|
5831 |
+ return SMFIS_CONTINUE; |
|
5832 |
+} |
... | ... |
@@ -115,6 +115,7 @@ To avoid this, blacklisting does not last for ever. The recommended value is |
115 | 115 |
.TP |
116 | 116 |
Machines on the LAN, the local host, and machines that are our MX peers are |
117 | 117 |
never blacklisted. |
118 |
+.TP |
|
118 | 119 |
\fB-l, \-\-local\fR |
119 | 120 |
Also scan messages sent from LAN. You probably want this especially if |
120 | 121 |
your LAN is populated by machines running Windows or DOS. |
... | ... |
@@ -256,16 +257,30 @@ When neither \-\-force, \-\-local nor \-\-outgoing is given, |
256 | 256 |
this option intercepts incoming mails that incorrectly claim to be from the |
257 | 257 |
local domain. |
258 | 258 |
.TP |
259 |
-\fB\-\-whitelist-file=FILE, \-W file |
|
259 |
+\fB\-\-whitelist-file=FILE, \-W file\fR |
|
260 | 260 |
This option specifies a file which contains a list of e-mail addresses. |
261 | 261 |
E-mails sent to these addresses will NOT be checked. |
262 | 262 |
While this is not an Anti-Virus function, it is quite useful for some systems. |
263 | 263 |
The address given to the \-\-quarantine directive is always white-listed. |
264 | 264 |
.TP |
265 |
-\fB\-\-sendmail-cf=FILE |
|
265 |
+\fB\-\-sendmail-cf=FILE\fR |
|
266 | 266 |
When starting, clamav\-milter runs some sanity checks against the sendmail.cf |
267 | 267 |
file, usually in /etc/sendmail.cf or /etc/mail/sendmail.cf. This directive |
268 | 268 |
tells clamav\-milter where to find the sendmail.cf file. |
269 |
+.TP |
|
270 |
+\fB\-\-black-hole-mode\fR |
|
271 |
+Since \fIsendmail\fR calls its milters before it looks in its alias and virtuser |
|
272 |
+tables, clamav-milter can spend time looking for malware that's going to be |
|
273 |
+thrown away even if the message is clean. |
|
274 |
+.TP. |
|
275 |
+Enable this to not scan these messages (in practice clamav\-milter will discard |
|
276 |
+these messages so the message doesn't go further down the milter call chain). |
|
277 |
+.TP |
|
278 |
+Sadly, because these days sendmail \-bv only works as root, |
|
279 |
+so this option is not compatible with the User directive in clamd.conf, |
|
280 |
+which some may view as a security risk. |
|
281 |
+Only enable this if your site has many addresses aliased to /dev/null. |
|
282 |
+.TP |
|
269 | 283 |
.SH "BUGS" |
270 | 284 |
There is no support for IPv6. |
271 | 285 |
.SH "EXAMPLES" |