git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@132 77e5149b-7576-45b1-b177-96237e5ba77b
Nigel Horne authored on 2003/11/30 15:14:33... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Sun Nov 30 06:13:28 GMT 2003 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * clamav-milter: Added --quarantine-dir |
|
4 |
+ Thanks to Michael Dankov <misha@btrc.ru>. |
|
5 |
+ |
|
1 | 6 |
Sat Nov 29 12:52:21 GMT 2003 (njh) |
2 | 7 |
---------------------------------- |
3 | 8 |
* clamav-milter: Fix problem of possible confused pointers if large number of |
... | ... |
@@ -160,6 +160,8 @@ Changes |
160 | 160 |
0.65e 29/11/03 Fix problem of possible confused pointers if large |
161 | 161 |
number of recipients given. |
162 | 162 |
Fix by Michael Dankov <misha@btrc.ru>. |
163 |
+0.65f 29/11/03 Added --quarantine-dir |
|
164 |
+ Thanks to Michael Dankov <misha@btrc.ru>. |
|
163 | 165 |
|
164 | 166 |
BUG REPORTS |
165 | 167 |
|
... | ... |
@@ -163,9 +163,14 @@ |
163 | 163 |
* 0.65e 29/11/03 Fix problem of possible confused pointers if large |
164 | 164 |
* number of recipients given. |
165 | 165 |
* Fix by Michael Dankov <misha@btrc.ru>. |
166 |
+ * 0.65f 29/11/03 Added --quarantine-dir |
|
167 |
+ * Thanks to Michael Dankov <misha@btrc.ru>. |
|
166 | 168 |
* |
167 | 169 |
* Change History: |
168 | 170 |
* $Log: clamav-milter.c,v $ |
171 |
+ * Revision 1.25 2003/11/30 06:12:06 nigelhorne |
|
172 |
+ * Added --quarantine-dir option |
|
173 |
+ * |
|
169 | 174 |
* Revision 1.24 2003/11/29 11:51:19 nigelhorne |
170 | 175 |
* Fix problem of possible confused pointers if large number of recipients given |
171 | 176 |
* |
... | ... |
@@ -223,9 +228,9 @@ |
223 | 223 |
* Revision 1.6 2003/09/28 16:37:23 nigelhorne |
224 | 224 |
* Added -f flag use MaxThreads if --max-children not set |
225 | 225 |
*/ |
226 |
-static char const rcsid[] = "$Id: clamav-milter.c,v 1.24 2003/11/29 11:51:19 nigelhorne Exp $"; |
|
226 |
+static char const rcsid[] = "$Id: clamav-milter.c,v 1.25 2003/11/30 06:12:06 nigelhorne Exp $"; |
|
227 | 227 |
|
228 |
-#define CM_VERSION "0.65e" |
|
228 |
+#define CM_VERSION "0.65f" |
|
229 | 229 |
|
230 | 230 |
/*#define CONFDIR "/usr/local/etc"*/ |
231 | 231 |
|
... | ... |
@@ -292,6 +297,7 @@ struct privdata { |
292 | 292 |
* dataSocket |
293 | 293 |
*/ |
294 | 294 |
int dataSocket; /* Socket to send data to clamd */ |
295 |
+ char *filename; /* Where to store the message in quarantine */ |
|
295 | 296 |
}; |
296 | 297 |
|
297 | 298 |
static int pingServer(void); |
... | ... |
@@ -328,10 +334,14 @@ static int qflag = 0; /* |
328 | 328 |
* found is the syslog, so it's best to |
329 | 329 |
* enable LogSyslog in clamav.conf |
330 | 330 |
*/ |
331 |
-static char *quarantine; /* |
|
331 |
+static char *quarantine; /* |
|
332 | 332 |
* If a virus is found in an email redirect |
333 | 333 |
* it to this account |
334 | 334 |
*/ |
335 |
+static char *quarantine_dir; /* |
|
336 |
+ * Path to store messages before scanning. |
|
337 |
+ * Infected ones will be left there. |
|
338 |
+ */ |
|
335 | 339 |
static int nflag = 0; /* |
336 | 340 |
* Don't add X-Virus-Scanned to header. Patch |
337 | 341 |
* from Dirk Meyer <dirk.meyer@dinoex.sub.org> |
... | ... |
@@ -389,6 +399,7 @@ help(void) |
389 | 389 |
puts("\t--postmaster-only\t-P\tSend warnings only to the postmaster."); |
390 | 390 |
puts("\t--quiet\t\t\t-q\tDon't send e-mail notifications of interceptions."); |
391 | 391 |
puts("\t--quarantine=USER\t-Q EMAIL\tQuanrantine e-mail account."); |
392 |
+ puts("\t--quarantine-dir=DIR\t-U DIR\tDirectory to store infected emails."); |
|
392 | 393 |
puts("\t--server=ADDRESS\t-s ADDR\tIP address of server running clamd (when using TCPsocket)."); |
393 | 394 |
puts("\t--version\t\t-V\tPrint the version number of this software."); |
394 | 395 |
#ifdef CL_DEBUG |
... | ... |
@@ -403,7 +414,7 @@ main(int argc, char **argv) |
403 | 403 |
char *port = NULL; |
404 | 404 |
const char *cfgfile = CL_DEFAULT_CFG; |
405 | 405 |
struct cfgstruct *cpt; |
406 |
- struct passwd *user; |
|
406 |
+ struct passwd *user; |
|
407 | 407 |
struct smfiDesc smfilter = { |
408 | 408 |
"ClamAv", /* filter name */ |
409 | 409 |
SMFI_VERSION, /* version code -- leave untouched */ |
... | ... |
@@ -431,9 +442,9 @@ main(int argc, char **argv) |
431 | 431 |
for(;;) { |
432 | 432 |
int opt_index = 0; |
433 | 433 |
#ifdef CL_DEBUG |
434 |
- const char *args = "bc:flnopPqQdhs:Vx:"; |
|
434 |
+ const char *args = "bc:flm:nop:PqQ:dhs:U:Vx:"; |
|
435 | 435 |
#else |
436 |
- const char *args = "bc:flnopPqQdhs:V"; |
|
436 |
+ const char *args = "bc:flm:nop:PqQ:dhs:U:V"; |
|
437 | 437 |
#endif |
438 | 438 |
|
439 | 439 |
static struct option long_options[] = { |
... | ... |
@@ -447,7 +458,7 @@ main(int argc, char **argv) |
447 | 447 |
"dont-scan-on-error", 0, NULL, 'd' |
448 | 448 |
}, |
449 | 449 |
{ |
450 |
- "force-scan", 1, NULL, 'f' |
|
450 |
+ "force-scan", 0, NULL, 'f' |
|
451 | 451 |
}, |
452 | 452 |
{ |
453 | 453 |
"help", 0, NULL, 'h' |
... | ... |
@@ -474,6 +485,9 @@ main(int argc, char **argv) |
474 | 474 |
"quarantine", 1, NULL, 'Q', |
475 | 475 |
}, |
476 | 476 |
{ |
477 |
+ "quarantine-dir", 1, NULL, 'U', |
|
478 |
+ }, |
|
479 |
+ { |
|
477 | 480 |
"max-children", 1, NULL, 'm' |
478 | 481 |
}, |
479 | 482 |
{ |
... | ... |
@@ -544,6 +558,9 @@ main(int argc, char **argv) |
544 | 544 |
case 's': /* server running clamd */ |
545 | 545 |
serverIP = optarg; |
546 | 546 |
break; |
547 |
+ case 'U': /* quarantine path */ |
|
548 |
+ quarantine_dir = optarg; |
|
549 |
+ break; |
|
547 | 550 |
case 'V': |
548 | 551 |
puts(clamav_version); |
549 | 552 |
return EX_OK; |
... | ... |
@@ -554,9 +571,9 @@ main(int argc, char **argv) |
554 | 554 |
#endif |
555 | 555 |
default: |
556 | 556 |
#ifdef CL_DEBUG |
557 |
- fprintf(stderr, "Usage: %s [-b] [-c FILE] [--max-children=num] [-l] [-o] [-p address] [-P] [-q] [-Q USER] [-x#] socket-addr\n", argv[0]); |
|
557 |
+ fprintf(stderr, "Usage: %s [-b] [-c FILE] [--max-children=num] [-l] [-o] [-p address] [-P] [-q] [-Q USER] [-x#] [-U PATH] socket-addr\n", argv[0]); |
|
558 | 558 |
#else |
559 |
- fprintf(stderr, "Usage: %s [-b] [-c FILE] [--max-children=num] [-l] [-o] [-p address] [-P] [-q] [-Q USER] socket-addr\n", argv[0]); |
|
559 |
+ fprintf(stderr, "Usage: %s [-b] [-c FILE] [--max-children=num] [-l] [-o] [-p address] [-P] [-q] [-Q USER] [-U PATH] socket-addr\n", argv[0]); |
|
560 | 560 |
#endif |
561 | 561 |
return EX_USAGE; |
562 | 562 |
} |
... | ... |
@@ -597,6 +614,10 @@ main(int argc, char **argv) |
597 | 597 |
} else |
598 | 598 |
fprintf(stderr, "%s: running as root is not recommended\n", argv[0]); |
599 | 599 |
} |
600 |
+ if(quarantine_dir && (access(quarantine_dir, W_OK) < 0)) { |
|
601 |
+ perror(quarantine_dir); |
|
602 |
+ return EX_CONFIG; |
|
603 |
+ } |
|
600 | 604 |
|
601 | 605 |
if(!cfgopt(copt, "StreamSaveToDisk")) { |
602 | 606 |
fprintf(stderr, "%s: StreamSavetoDisk not enabled in %s\n", |
... | ... |
@@ -642,7 +663,13 @@ main(int argc, char **argv) |
642 | 642 |
/* |
643 | 643 |
* TCPSocket is in fact a port number not a full socket |
644 | 644 |
*/ |
645 |
- tcpSocket = (in_port_t)cpt->numarg; |
|
645 |
+ if(quarantine_dir) { |
|
646 |
+ fprintf(stderr, "%s: --quarantine-dir not supported for remote scanning - use --quarantine\n", argv[0]); |
|
647 |
+ return EX_CONFIG; |
|
648 |
+ } |
|
649 |
+ |
|
650 |
+ tcpSocket = cpt->numarg; |
|
651 |
+ |
|
646 | 652 |
if(!pingServer()) { |
647 | 653 |
fprintf(stderr, "Can't talk to clamd server at %s on port %d\n", |
648 | 654 |
serverIP, tcpSocket); |
... | ... |
@@ -976,128 +1003,162 @@ clamfi_envfrom(SMFICTX *ctx, char **argv) |
976 | 976 |
privdata->dataSocket = -1; /* 0.4 */ |
977 | 977 |
privdata->cmdSocket = -1; /* 0.4 */ |
978 | 978 |
|
979 |
- /* |
|
980 |
- * Create socket to talk to clamd. It will tell us the port to use |
|
981 |
- * to send the data. That will require another socket. |
|
982 |
- */ |
|
983 |
- if(localSocket) { |
|
984 |
- struct sockaddr_un server; |
|
979 |
+ if(quarantine_dir) { |
|
980 |
+ /* |
|
981 |
+ * quarantine_dir is specified |
|
982 |
+ * store message in a temporary file |
|
983 |
+ */ |
|
984 |
+ int ntries = 5; |
|
985 | 985 |
|
986 |
- memset((char *)&server, 0, sizeof(struct sockaddr_un)); |
|
987 |
- server.sun_family = AF_UNIX; |
|
988 |
- strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); |
|
986 |
+ privdata->filename = malloc(strlen(quarantine_dir) + 12); |
|
989 | 987 |
|
990 |
- if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
|
991 |
- perror("socket"); |
|
992 |
- return cl_error; |
|
993 |
- } |
|
994 |
- if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) { |
|
995 |
- perror(localSocket); |
|
988 |
+ do { |
|
989 |
+ sprintf(privdata->filename, "%s/msg.XXXXXX", quarantine_dir); |
|
990 |
+#if defined(C_LINUX) || defined(C_BSD) |
|
991 |
+ privdata->dataSocket = mkstemp(privdata->filename); |
|
992 |
+#else |
|
993 |
+ if(mktemp(privdata->filename) == NULL) { |
|
994 |
+ if(use_syslog) |
|
995 |
+ syslog(LOG_ERR, "mktemp %s failed", privdata->filename); |
|
996 |
+ free(privdata->filename); |
|
997 |
+ privdata->filename = NULL; |
|
998 |
+ return cl_error; |
|
999 |
+ } |
|
1000 |
+ privdata->dataSocket = open(privdata->filename, O_CREAT|O_EXCL|O_WRONLY,0600); |
|
1001 |
+#endif |
|
1002 |
+ } while(--ntries > 0 && privdata->dataSocket < 0); |
|
1003 |
+ |
|
1004 |
+ if(privdata->dataSocket < 0) { |
|
1005 |
+ if(use_syslog) |
|
1006 |
+ syslog(LOG_ERR, "tempfile %s creation failed", privdata->filename); |
|
1007 |
+ free(privdata->filename); |
|
1008 |
+ privdata->filename = NULL; |
|
996 | 1009 |
return cl_error; |
997 | 1010 |
} |
998 | 1011 |
} else { |
999 |
- struct sockaddr_in server; |
|
1012 |
+ /* |
|
1013 |
+ * Create socket to talk to clamd. It will tell us the port to use |
|
1014 |
+ * to send the data. That will require another socket. |
|
1015 |
+ */ |
|
1016 |
+ if(localSocket) { |
|
1017 |
+ struct sockaddr_un server; |
|
1000 | 1018 |
|
1001 |
- memset((char *)&server, 0, sizeof(struct sockaddr_in)); |
|
1002 |
- server.sin_family = AF_INET; |
|
1003 |
- server.sin_port = htons(tcpSocket); |
|
1004 |
- server.sin_addr.s_addr = inet_addr(serverIP); |
|
1019 |
+ memset((char *)&server, 0, sizeof(struct sockaddr_un)); |
|
1020 |
+ server.sun_family = AF_UNIX; |
|
1021 |
+ strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); |
|
1005 | 1022 |
|
1006 |
- if((privdata->cmdSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
|
1007 |
- perror("socket"); |
|
1008 |
- return cl_error; |
|
1023 |
+ if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
|
1024 |
+ perror("socket"); |
|
1025 |
+ return cl_error; |
|
1026 |
+ } |
|
1027 |
+ if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) { |
|
1028 |
+ perror(localSocket); |
|
1029 |
+ return cl_error; |
|
1030 |
+ } |
|
1031 |
+ } else { |
|
1032 |
+ struct sockaddr_in server; |
|
1033 |
+ |
|
1034 |
+ memset((char *)&server, 0, sizeof(struct sockaddr_in)); |
|
1035 |
+ server.sin_family = AF_INET; |
|
1036 |
+ server.sin_port = htons(tcpSocket); |
|
1037 |
+ server.sin_addr.s_addr = inet_addr(serverIP); |
|
1038 |
+ |
|
1039 |
+ if((privdata->cmdSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
|
1040 |
+ perror("socket"); |
|
1041 |
+ return cl_error; |
|
1042 |
+ } |
|
1043 |
+ if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { |
|
1044 |
+ perror("connect"); |
|
1045 |
+ return cl_error; |
|
1046 |
+ } |
|
1009 | 1047 |
} |
1010 |
- if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { |
|
1011 |
- perror("connect"); |
|
1048 |
+ |
|
1049 |
+ /* |
|
1050 |
+ * Create socket that we'll use to send the data to clamd |
|
1051 |
+ */ |
|
1052 |
+ if((privdata->dataSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
|
1053 |
+ perror("socket"); |
|
1054 |
+ close(privdata->cmdSocket); |
|
1055 |
+ free(privdata); |
|
1056 |
+ if(use_syslog) |
|
1057 |
+ syslog(LOG_ERR, "failed to create socket"); |
|
1012 | 1058 |
return cl_error; |
1013 | 1059 |
} |
1014 |
- } |
|
1015 |
- |
|
1016 |
- /* |
|
1017 |
- * Create socket that we'll use to send the data to clamd |
|
1018 |
- */ |
|
1019 |
- if((privdata->dataSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
|
1020 |
- perror("socket"); |
|
1021 |
- close(privdata->cmdSocket); |
|
1022 |
- free(privdata); |
|
1023 |
- if(use_syslog) |
|
1024 |
- syslog(LOG_ERR, "failed to create socket"); |
|
1025 |
- return cl_error; |
|
1026 |
- } |
|
1027 | 1060 |
|
1028 |
- shutdown(privdata->dataSocket, SHUT_RD); |
|
1061 |
+ shutdown(privdata->dataSocket, SHUT_RD); |
|
1029 | 1062 |
|
1030 |
- if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) { |
|
1031 |
- perror("send"); |
|
1032 |
- close(privdata->dataSocket); |
|
1033 |
- close(privdata->cmdSocket); |
|
1034 |
- free(privdata); |
|
1035 |
- if(use_syslog) |
|
1036 |
- syslog(LOG_ERR, "send failed to clamd"); |
|
1037 |
- return cl_error; |
|
1038 |
- } |
|
1063 |
+ if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) { |
|
1064 |
+ perror("send"); |
|
1065 |
+ close(privdata->dataSocket); |
|
1066 |
+ close(privdata->cmdSocket); |
|
1067 |
+ free(privdata); |
|
1068 |
+ if(use_syslog) |
|
1069 |
+ syslog(LOG_ERR, "send failed to clamd"); |
|
1070 |
+ return cl_error; |
|
1071 |
+ } |
|
1039 | 1072 |
|
1040 |
- shutdown(privdata->cmdSocket, SHUT_WR); |
|
1073 |
+ shutdown(privdata->cmdSocket, SHUT_WR); |
|
1041 | 1074 |
|
1042 |
- nbytes = recv(privdata->cmdSocket, buf, sizeof(buf), 0); |
|
1043 |
- if(nbytes < 0) { |
|
1044 |
- perror("recv"); |
|
1045 |
- close(privdata->dataSocket); |
|
1046 |
- close(privdata->cmdSocket); |
|
1047 |
- free(privdata); |
|
1048 |
- if(use_syslog) |
|
1049 |
- syslog(LOG_ERR, "recv failed from clamd getting PORT"); |
|
1050 |
- return cl_error; |
|
1051 |
- } |
|
1052 |
- buf[nbytes] = '\0'; |
|
1053 |
-#ifdef CL_DEBUG |
|
1054 |
- if(debug_level >= 4) |
|
1055 |
- printf("Received: %s", buf); |
|
1056 |
-#endif |
|
1057 |
- if(sscanf(buf, "PORT %hu\n", &port) != 1) { |
|
1058 |
- close(privdata->dataSocket); |
|
1059 |
- close(privdata->cmdSocket); |
|
1060 |
- free(privdata); |
|
1061 |
- if(use_syslog) |
|
1062 |
- syslog(LOG_ERR, "Expected port information from clamd, got '%s'", |
|
1063 |
- buf); |
|
1064 |
- else |
|
1065 |
- fprintf(stderr, "Expected port information from clamd, got '%s'\n", |
|
1066 |
- buf); |
|
1067 |
- return cl_error; |
|
1068 |
- } |
|
1075 |
+ nbytes = recv(privdata->cmdSocket, buf, sizeof(buf), 0); |
|
1076 |
+ if(nbytes < 0) { |
|
1077 |
+ perror("recv"); |
|
1078 |
+ close(privdata->dataSocket); |
|
1079 |
+ close(privdata->cmdSocket); |
|
1080 |
+ free(privdata); |
|
1081 |
+ if(use_syslog) |
|
1082 |
+ syslog(LOG_ERR, "recv failed from clamd getting PORT"); |
|
1083 |
+ return cl_error; |
|
1084 |
+ } |
|
1085 |
+ buf[nbytes] = '\0'; |
|
1086 |
+ #ifdef CL_DEBUG |
|
1087 |
+ if(debug_level >= 4) |
|
1088 |
+ printf("Received: %s", buf); |
|
1089 |
+ #endif |
|
1090 |
+ if(sscanf(buf, "PORT %hu\n", &port) != 1) { |
|
1091 |
+ close(privdata->dataSocket); |
|
1092 |
+ close(privdata->cmdSocket); |
|
1093 |
+ free(privdata); |
|
1094 |
+ if(use_syslog) |
|
1095 |
+ syslog(LOG_ERR, "Expected port information from clamd, got '%s'", |
|
1096 |
+ buf); |
|
1097 |
+ else |
|
1098 |
+ fprintf(stderr, "Expected port information from clamd, got '%s'\n", |
|
1099 |
+ buf); |
|
1100 |
+ return cl_error; |
|
1101 |
+ } |
|
1069 | 1102 |
|
1070 |
- memset((char *)&reply, 0, sizeof(struct sockaddr_in)); |
|
1071 |
- reply.sin_family = AF_INET; |
|
1072 |
- reply.sin_port = ntohs(port); |
|
1103 |
+ memset((char *)&reply, 0, sizeof(struct sockaddr_in)); |
|
1104 |
+ reply.sin_family = AF_INET; |
|
1105 |
+ reply.sin_port = ntohs(port); |
|
1073 | 1106 |
|
1074 |
- reply.sin_addr.s_addr = inet_addr(serverIP); |
|
1107 |
+ reply.sin_addr.s_addr = inet_addr(serverIP); |
|
1075 | 1108 |
|
1076 |
-#ifdef CL_DEBUG |
|
1077 |
- if(debug_level >= 4) |
|
1078 |
- printf("Connecting to local port %d\n", port); |
|
1079 |
-#endif |
|
1109 |
+ #ifdef CL_DEBUG |
|
1110 |
+ if(debug_level >= 4) |
|
1111 |
+ printf("Connecting to local port %d\n", port); |
|
1112 |
+ #endif |
|
1080 | 1113 |
|
1081 |
- rc = connect(privdata->dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in)); |
|
1114 |
+ rc = connect(privdata->dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in)); |
|
1082 | 1115 |
|
1083 |
- if(rc < 0) { |
|
1084 |
- perror("connect"); |
|
1116 |
+ if(rc < 0) { |
|
1117 |
+ perror("connect"); |
|
1085 | 1118 |
|
1086 |
- close(privdata->dataSocket); |
|
1087 |
- close(privdata->cmdSocket); |
|
1088 |
- free(privdata); |
|
1119 |
+ close(privdata->dataSocket); |
|
1120 |
+ close(privdata->cmdSocket); |
|
1121 |
+ free(privdata); |
|
1122 |
+ |
|
1123 |
+ /* 0.4 - use better error message */ |
|
1124 |
+ if(use_syslog) { |
|
1125 |
+ #ifdef TARGET_OS_SOLARIS /* no strerror_r */ |
|
1126 |
+ syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, strerror(rc)); |
|
1127 |
+ #else |
|
1128 |
+ strerror_r(rc, buf, sizeof(buf)); |
|
1129 |
+ syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, buf); |
|
1130 |
+ #endif |
|
1131 |
+ } |
|
1089 | 1132 |
|
1090 |
- /* 0.4 - use better error message */ |
|
1091 |
- if(use_syslog) { |
|
1092 |
-#ifdef TARGET_OS_SOLARIS /* no strerror_r */ |
|
1093 |
- syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, strerror(rc)); |
|
1094 |
-#else |
|
1095 |
- strerror_r(rc, buf, sizeof(buf)); |
|
1096 |
- syslog(LOG_ERR, "Failed to connect to port %d given by clamd: %s", port, buf); |
|
1097 |
-#endif |
|
1133 |
+ return cl_error; |
|
1098 | 1134 |
} |
1099 |
- |
|
1100 |
- return cl_error; |
|
1101 | 1135 |
} |
1102 | 1136 |
|
1103 | 1137 |
clamfi_send(privdata, 0, "From %s\n", argv[0]); |
... | ... |
@@ -1249,13 +1310,52 @@ clamfi_eom(SMFICTX *ctx) |
1249 | 1249 |
#ifdef CL_DEBUG |
1250 | 1250 |
puts("clamfi_eom"); |
1251 | 1251 |
assert(privdata != NULL); |
1252 |
- assert(privdata->cmdSocket >= 0); |
|
1252 |
+ assert((privdata->cmdSocket >= 0) || (privdata->filename != NULL)); |
|
1253 |
+ assert(!((privdata->cmdSocket >= 0) && (privdata->filename != NULL))); |
|
1253 | 1254 |
assert(privdata->dataSocket >= 0); |
1254 | 1255 |
#endif |
1255 | 1256 |
|
1256 | 1257 |
close(privdata->dataSocket); |
1257 | 1258 |
privdata->dataSocket = -1; |
1258 | 1259 |
|
1260 |
+ if(quarantine_dir != NULL) { |
|
1261 |
+ char cmdbuf[1024]; |
|
1262 |
+ /* |
|
1263 |
+ * Create socket to talk to clamd. |
|
1264 |
+ */ |
|
1265 |
+ struct sockaddr_un server; |
|
1266 |
+ int nbytes; |
|
1267 |
+ |
|
1268 |
+ assert(localSocket != NULL); |
|
1269 |
+ |
|
1270 |
+ memset((char *)&server, 0, sizeof(struct sockaddr_un)); |
|
1271 |
+ server.sun_family = AF_UNIX; |
|
1272 |
+ strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); |
|
1273 |
+ |
|
1274 |
+ if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
|
1275 |
+ perror("socket"); |
|
1276 |
+ return cl_error; |
|
1277 |
+ } |
|
1278 |
+ if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) { |
|
1279 |
+ perror(localSocket); |
|
1280 |
+ return cl_error; |
|
1281 |
+ } |
|
1282 |
+ |
|
1283 |
+ snprintf(cmdbuf, sizeof(cmdbuf) - 1, "SCAN %s", privdata->filename); |
|
1284 |
+ |
|
1285 |
+ nbytes = (int)strlen(cmdbuf); |
|
1286 |
+ |
|
1287 |
+ if(send(privdata->cmdSocket, cmdbuf, nbytes, 0) < nbytes) { |
|
1288 |
+ perror("send"); |
|
1289 |
+ clamfi_cleanup(ctx); |
|
1290 |
+ if(use_syslog) |
|
1291 |
+ syslog(LOG_ERR, "send failed to clamd"); |
|
1292 |
+ return cl_error; |
|
1293 |
+ } |
|
1294 |
+ |
|
1295 |
+ shutdown(privdata->cmdSocket, SHUT_WR); |
|
1296 |
+ } |
|
1297 |
+ |
|
1259 | 1298 |
if(recv(privdata->cmdSocket, mess, sizeof(mess), 0) > 0) { |
1260 | 1299 |
if((ptr = strchr(mess, '\n')) != NULL) |
1261 | 1300 |
*ptr = '\0'; |
... | ... |
@@ -1366,12 +1466,29 @@ clamfi_eom(SMFICTX *ctx) |
1366 | 1366 |
fputs("contained a virus and has not been delivered.\n\t", sendmail); |
1367 | 1367 |
fputs(mess, sendmail); |
1368 | 1368 |
|
1369 |
+ if(privdata->filename != NULL) |
|
1370 |
+ fprintf(sendmail, "\nThe message in question is quarantined as %s\n", privdata->filename); |
|
1371 |
+ |
|
1369 | 1372 |
pclose(sendmail); |
1370 | 1373 |
} |
1371 | 1374 |
} |
1375 |
+ |
|
1376 |
+ if(privdata->filename) { |
|
1377 |
+ assert(quarantine_dir != NULL); |
|
1378 |
+ |
|
1379 |
+ if(use_syslog) |
|
1380 |
+ syslog(LOG_NOTICE, "Quarantined infected mail as %s", privdata->filename); |
|
1381 |
+ /* |
|
1382 |
+ * Cleanup filename here! Default procedure would delete quarantine file |
|
1383 |
+ */ |
|
1384 |
+ free(privdata->filename); |
|
1385 |
+ privdata->filename = NULL; |
|
1386 |
+ } |
|
1387 |
+ |
|
1372 | 1388 |
if(quarantine) { |
1373 | 1389 |
for(to = privdata->to; *to; to++) { |
1374 | 1390 |
smfi_delrcpt(ctx, *to); |
1391 |
+ smfi_addheader(ctx, "X-Original-To", *to); |
|
1375 | 1392 |
free(*to); |
1376 | 1393 |
} |
1377 | 1394 |
free(privdata->to); |
... | ... |
@@ -1381,12 +1498,11 @@ clamfi_eom(SMFICTX *ctx) |
1381 | 1381 |
syslog(LOG_DEBUG, "Can't set quarantine user %s", quarantine); |
1382 | 1382 |
else |
1383 | 1383 |
fprintf(stderr, "Can't set quarantine user %s\n", quarantine); |
1384 |
- } else { |
|
1384 |
+ } else |
|
1385 | 1385 |
/* |
1386 | 1386 |
* FIXME: doesn't work if there's no subject |
1387 | 1387 |
*/ |
1388 | 1388 |
smfi_chgheader(ctx, "Subject", 1, mess); |
1389 |
- } |
|
1390 | 1389 |
} else |
1391 | 1390 |
rc = SMFIS_REJECT; /* Delete the e-mail */ |
1392 | 1391 |
|
... | ... |
@@ -1446,6 +1562,13 @@ clamfi_cleanup(SMFICTX *ctx) |
1446 | 1446 |
privdata->dataSocket = -1; |
1447 | 1447 |
} |
1448 | 1448 |
|
1449 |
+ if(privdata->filename != NULL) { |
|
1450 |
+ if(unlink(privdata->filename) < 0) |
|
1451 |
+ perror(privdata->filename); |
|
1452 |
+ free(privdata->filename); |
|
1453 |
+ privdata->filename = NULL; |
|
1454 |
+ } |
|
1455 |
+ |
|
1449 | 1456 |
if(privdata->from) { |
1450 | 1457 |
#ifdef CL_DEBUG |
1451 | 1458 |
if(debug_level >= 9) |
... | ... |
@@ -1541,7 +1664,9 @@ clamfi_send(const struct privdata *privdata, size_t len, const char *format, ... |
1541 | 1541 |
#endif |
1542 | 1542 |
|
1543 | 1543 |
while(len > 0) { |
1544 |
- int nbytes = send(privdata->dataSocket, ptr, len, 0); |
|
1544 |
+ int nbytes = (quarantine_dir) ? |
|
1545 |
+ write(privdata->dataSocket, ptr, len) : |
|
1546 |
+ send(privdata->dataSocket, ptr, len, 0); |
|
1545 | 1547 |
|
1546 | 1548 |
if(nbytes == -1) { |
1547 | 1549 |
if(errno == EINTR) |