Browse code

add tempdir, some fixes

git-svn: trunk@4531

aCaB authored on 2008/12/05 01:27:16
Showing 11 changed files
... ...
@@ -16,7 +16,6 @@
16 16
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 17
 #  MA 02110-1301, USA.
18 18
 
19
-# FIXME: check automake for 'and' (&&)
20 19
 if BUILD_CLAMD
21 20
 if HAVE_MILTER
22 21
 
... ...
@@ -51,6 +50,3 @@ LIBS = $(top_builddir)/libclamav/libclamav.la @CLAMAV_MILTER_LIBS@ @THREAD_LIBS@
51 51
 AM_CPPFLAGS = -I$(top_srcdir)/clamd -I$(top_srcdir)/libclamav -I$(top_srcdir)/shared -I$(top_srcdir)
52 52
 EXTRA_DIST = clamav-milter.c INSTALL
53 53
 CLEANFILES=*.gcda *.gcno
54
-CFLAGS=`echo "@CFLAGS@" | sed -e 's/-Werror[^-]//'`
55
-
56
-
... ...
@@ -124,7 +124,7 @@ AWK = @AWK@
124 124
 CC = @CC@
125 125
 CCDEPMODE = @CCDEPMODE@
126 126
 CFGDIR = @CFGDIR@
127
-CFLAGS = `echo "@CFLAGS@" | sed -e 's/-Werror[^-]//'`
127
+CFLAGS = @CFLAGS@
128 128
 CHECK_CPPFLAGS = @CHECK_CPPFLAGS@
129 129
 CHECK_LIBS = @CHECK_LIBS@
130 130
 CLAMAVGROUP = @CLAMAVGROUP@
... ...
@@ -208,6 +208,9 @@ int main(int argc, char **argv) {
208 208
     }
209 209
 #endif
210 210
 
211
+    if((cpt = cfgopt(copt, "TemporaryDirectory"))->enabled)
212
+	tempdir = cpt->strarg;
213
+
211 214
     if(localnets_init(copt) || init_actions(copt)) {
212 215
 	logg_close();
213 216
 	freecfg(copt);
... ...
@@ -223,7 +226,6 @@ int main(int argc, char **argv) {
223 223
 
224 224
     /* FIXME: find a place for these:
225 225
      * maxthreads = cfgopt(copt, "MaxThreads")->numarg;
226
-     * logclean = cfgopt(copt, "LogClean")->numarg;
227 226
      */
228 227
 
229 228
     if(cfgopt(copt, "AddHeader")->enabled) {
... ...
@@ -242,7 +244,7 @@ int main(int argc, char **argv) {
242 242
 	addxvirus = 1;
243 243
     }
244 244
     
245
-    umask(0007);
245
+    umask(0007); /* FIXME */
246 246
     if(!(my_socket = cfgopt(copt, "MilterSocket")->strarg)) {
247 247
 	logg("!Please configure the MilterSocket directive\n");
248 248
 	localnets_free();
... ...
@@ -297,12 +299,27 @@ int main(int argc, char **argv) {
297 297
 	    whitelist_free();
298 298
 	    cpool_free();
299 299
 	    logg_close();
300
+	    freecfg(copt);
300 301
 	    return 1;
301 302
 	}
302 303
 	if(chdir("/") == -1)
303 304
 	    logg("^Can't change current working directory to root\n");
304 305
     }
305 306
 
307
+    if((cpt = cfgopt(copt, "PidFile"))->enabled) {
308
+	FILE *fd;
309
+	mode_t old_umask = umask(0006);
310
+
311
+	if((fd = fopen(cpt->strarg, "w")) == NULL) {
312
+	    logg("!Can't save PID in file %s\n", cpt->strarg);
313
+	} else {
314
+	    if (fprintf(fd, "%u", (unsigned int)getpid())<0) {
315
+	    	logg("!Can't save PID in file %s\n", cpt->strarg);
316
+	    }
317
+	    fclose(fd);
318
+	}
319
+	umask(old_umask);
320
+    }
306 321
 
307 322
     ret = smfi_main();
308 323
 
309 324
deleted file mode 100644
... ...
@@ -1,1122 +0,0 @@
1
-# SOME DESCRIPTIVE TITLE.
2
-# Copyright (C) YEAR njh@bandsman.co.uk
3
-# This file is distributed under the same license as the PACKAGE package.
4
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
-#
6
-#, fuzzy
7
-msgid ""
8
-msgstr ""
9
-"Project-Id-Version: PACKAGE VERSION\n"
10
-"Report-Msgid-Bugs-To: bugs@clamav.net\n"
11
-"POT-Creation-Date: 2007-10-24 09:05+0100\n"
12
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
-"Language-Team: LANGUAGE <LL@li.org>\n"
15
-"MIME-Version: 1.0\n"
16
-"Content-Type: text/plain; charset=CHARSET\n"
17
-"Content-Transfer-Encoding: 8bit\n"
18
-
19
-#: clamav-milter.c:585
20
-msgid "\t--advisory\t\t-A\tFlag viruses rather than deleting them."
21
-msgstr ""
22
-
23
-#: clamav-milter.c:586
24
-msgid "\t--blacklist-time=SECS\t-k\tTime (in seconds) to blacklist an IP."
25
-msgstr ""
26
-
27
-#: clamav-milter.c:587
28
-msgid "\t--black-hole-mode\t\tDon't scan messages aliased to /dev/null."
29
-msgstr ""
30
-
31
-#: clamav-milter.c:589
32
-msgid "\t--bounce\t\t-b\tSend a failure message to the sender."
33
-msgstr ""
34
-
35
-#: clamav-milter.c:591
36
-msgid ""
37
-"\t--broadcast\t\t-B [IFACE]\tBroadcast to a network manager when a virus is "
38
-"found."
39
-msgstr ""
40
-
41
-#: clamav-milter.c:592
42
-msgid "\t--chroot=DIR\t\t-C DIR\tChroot to dir when starting."
43
-msgstr ""
44
-
45
-#: clamav-milter.c:593
46
-msgid "\t--config-file=FILE\t-c FILE\tRead configuration from FILE."
47
-msgstr ""
48
-
49
-#: clamav-milter.c:594
50
-msgid "\t--debug\t\t\t-D\tPrint debug messages."
51
-msgstr ""
52
-
53
-#: clamav-milter.c:595
54
-msgid ""
55
-"\t--detect-forged-local-address\t-L\tReject mails that claim to be from us."
56
-msgstr ""
57
-
58
-#: clamav-milter.c:596
59
-msgid "\t--dont-blacklist\t-K\tDon't blacklist a given IP."
60
-msgstr ""
61
-
62
-#: clamav-milter.c:597
63
-msgid ""
64
-"\t--dont-scan-on-error\t-d\tPass e-mails through unscanned if a system error "
65
-"occurs."
66
-msgstr ""
67
-
68
-#: clamav-milter.c:598
69
-msgid "\t--dont-wait\t\t\tAsk remote end to resend if max-children exceeded."
70
-msgstr ""
71
-
72
-#: clamav-milter.c:599
73
-msgid "\t--external\t\t-e\tUse an external scanner (usually clamd)."
74
-msgstr ""
75
-
76
-#: clamav-milter.c:600
77
-msgid ""
78
-"\t--freshclam-monitor=SECS\t-M SECS\tHow often to check for database update."
79
-msgstr ""
80
-
81
-#: clamav-milter.c:601
82
-msgid "\t--from=EMAIL\t\t-a EMAIL\tError messages come from here."
83
-msgstr ""
84
-
85
-#: clamav-milter.c:602
86
-msgid "\t--force-scan\t\t-f\tForce scan all messages (overrides (-o and -l)."
87
-msgstr ""
88
-
89
-#: clamav-milter.c:603
90
-msgid "\t--help\t\t\t-h\tThis message."
91
-msgstr ""
92
-
93
-#: clamav-milter.c:604
94
-msgid "\t--headers\t\t-H\tInclude original message headers in the report."
95
-msgstr ""
96
-
97
-#: clamav-milter.c:605
98
-msgid ""
99
-"\t--ignore IPaddr\t\t-I IPaddr\tAdd IPaddr to LAN IP list (see --local)."
100
-msgstr ""
101
-
102
-#: clamav-milter.c:606
103
-msgid "\t--local\t\t\t-l\tScan messages sent from machines on our LAN."
104
-msgstr ""
105
-
106
-#: clamav-milter.c:607
107
-msgid "\t--max-childen\t\t-m\tMaximum number of concurrent scans."
108
-msgstr ""
109
-
110
-#: clamav-milter.c:608
111
-msgid "\t--outgoing\t\t-o\tScan outgoing messages from this machine."
112
-msgstr ""
113
-
114
-#: clamav-milter.c:609
115
-msgid "\t--noreject\t\t-N\tDon't reject viruses, silently throw them away."
116
-msgstr ""
117
-
118
-#: clamav-milter.c:610
119
-msgid "\t--noxheader\t\t-n\tSuppress X-Virus-Scanned/X-Virus-Status headers."
120
-msgstr ""
121
-
122
-#: clamav-milter.c:611
123
-msgid "\t--pidfile=FILE\t\t-i FILE\tLocation of pidfile."
124
-msgstr ""
125
-
126
-#: clamav-milter.c:612
127
-msgid "\t--postmaster\t\t-p EMAIL\tPostmaster address [default=postmaster]."
128
-msgstr ""
129
-
130
-#: clamav-milter.c:613
131
-msgid "\t--postmaster-only\t-P\tSend notifications only to the postmaster."
132
-msgstr ""
133
-
134
-#: clamav-milter.c:614
135
-msgid "\t--quiet\t\t\t-q\tDon't send e-mail notifications of interceptions."
136
-msgstr ""
137
-
138
-#: clamav-milter.c:615
139
-msgid "\t--quarantine=USER\t-Q EMAIL\tQuarantine e-mail account."
140
-msgstr ""
141
-
142
-#: clamav-milter.c:616
143
-msgid "\t--report-phish=EMAIL\t-r EMAIL\tReport phish to this email address."
144
-msgstr ""
145
-
146
-#: clamav-milter.c:617
147
-msgid ""
148
-"\t--report-phish-false-positives=EMAIL\t-R EMAIL\tReport phish false "
149
-"positves to this email address."
150
-msgstr ""
151
-
152
-#: clamav-milter.c:618
153
-msgid "\t--quarantine-dir=DIR\t-U DIR\tDirectory to store infected emails."
154
-msgstr ""
155
-
156
-#: clamav-milter.c:619
157
-msgid ""
158
-"\t--server=SERVER\t\t-s SERVER\tHostname/IP address of server(s) running "
159
-"clamd (when using TCPsocket)."
160
-msgstr ""
161
-
162
-#: clamav-milter.c:620
163
-msgid "\t--sendmail-cf=FILE\t\tLocation of the sendmail.cf file to verify"
164
-msgstr ""
165
-
166
-#: clamav-milter.c:621
167
-msgid "\t--sign\t\t\t-S\tAdd a hard-coded signature to each scanned message."
168
-msgstr ""
169
-
170
-#: clamav-milter.c:622
171
-msgid "\t--signature-file=FILE\t-F FILE\tLocation of signature file."
172
-msgstr ""
173
-
174
-#: clamav-milter.c:623
175
-msgid "\t--template-file=FILE\t-t FILE\tLocation of e-mail template file."
176
-msgstr ""
177
-
178
-#: clamav-milter.c:624
179
-msgid ""
180
-"\t--template-headers=FILE\t\tLocation of e-mail headers for template file."
181
-msgstr ""
182
-
183
-#: clamav-milter.c:625
184
-msgid "\t--timeout=SECS\t\t-T SECS\tTimeout waiting to childen to die."
185
-msgstr ""
186
-
187
-#: clamav-milter.c:626
188
-msgid ""
189
-"\t--whitelist-file=FILE\t-W FILE\tLocation of the file of whitelisted "
190
-"addresses"
191
-msgstr ""
192
-
193
-#: clamav-milter.c:627
194
-msgid "\t--version\t\t-V\tPrint the version number of this software."
195
-msgstr ""
196
-
197
-#: clamav-milter.c:629
198
-msgid "\t--debug-level=n\t\t-x n\tSets the debug level to 'n'."
199
-msgstr ""
200
-
201
-#: clamav-milter.c:631
202
-msgid ""
203
-"\n"
204
-"For more information type \"man clamav-milter\"."
205
-msgstr ""
206
-
207
-#: clamav-milter.c:632
208
-msgid "For bug reports, please refer to http://www.clamav.net/bugs"
209
-msgstr ""
210
-
211
-#: clamav-milter.c:931
212
-#, c-format
213
-msgid "%s: %s, -I may only be given %d times\n"
214
-msgstr ""
215
-
216
-#: clamav-milter.c:937
217
-#, c-format
218
-msgid "%s: Cannot convert -I%s to IPaddr\n"
219
-msgstr ""
220
-
221
-#: clamav-milter.c:1051
222
-#, c-format
223
-msgid "%s: SESSIONS mode requires --external\n"
224
-msgstr ""
225
-
226
-#: clamav-milter.c:1059
227
-#, c-format
228
-msgid "%s: No socket-addr given\n"
229
-msgstr ""
230
-
231
-#: clamav-milter.c:1066
232
-#, c-format
233
-msgid "%s: socket-addr (%s) doesn't agree with sendmail.cf\n"
234
-msgstr ""
235
-
236
-#: clamav-milter.c:1082
237
-#, c-format
238
-msgid "%s: when using inet: connexion to sendmail you must enable --local\n"
239
-msgstr ""
240
-
241
-#: clamav-milter.c:1094
242
-#, c-format
243
-msgid "%s: Can't parse the config file %s\n"
244
-msgstr ""
245
-
246
-#: clamav-milter.c:1101
247
-#, c-format
248
-msgid "%s: --detect-forged-local-addresses is not compatible with --outgoing\n"
249
-msgstr ""
250
-
251
-#: clamav-milter.c:1105
252
-#, c-format
253
-msgid "%s: --detect-forged-local-addresses is not compatible with --local\n"
254
-msgstr ""
255
-
256
-#: clamav-milter.c:1109
257
-#, c-format
258
-msgid "%s: --detect-forged-local-addresses is not compatible with --force\n"
259
-msgstr ""
260
-
261
-#: clamav-milter.c:1153
262
-#, c-format
263
-msgid ""
264
-"%s: The iface option to --broadcast is not supported on your operating "
265
-"system\n"
266
-msgstr ""
267
-
268
-#: clamav-milter.c:1162
269
-#, c-format
270
-msgid "%s: Can't get information about user %s\n"
271
-msgstr ""
272
-
273
-#: clamav-milter.c:1173
274
-#, c-format
275
-msgid "%s: AllowSupplementaryGroups: initgroups not supported.\n"
276
-msgstr ""
277
-
278
-#: clamav-milter.c:1191
279
-#, c-format
280
-msgid "Running as user %s (UID %d, GID %d)\n"
281
-msgstr ""
282
-
283
-#: clamav-milter.c:1247
284
-#, c-format
285
-msgid "%s: You cannot use black hole mode unless %s is a TrustedUser\n"
286
-msgstr ""
287
-
288
-#: clamav-milter.c:1253
289
-#, c-format
290
-msgid "^%s: running as root is not recommended (check \"User\" in %s)\n"
291
-msgstr ""
292
-
293
-#: clamav-milter.c:1255
294
-#, c-format
295
-msgid "%s: Only root can set an interface for --broadcast\n"
296
-msgstr ""
297
-
298
-#: clamav-milter.c:1260
299
-#, c-format
300
-msgid "%s: Advisory mode doesn't work with quarantine mode\n"
301
-msgstr ""
302
-
303
-#: clamav-milter.c:1268
304
-#, c-format
305
-msgid "%s: Advisory mode doesn't work with quarantine directories\n"
306
-msgstr ""
307
-
308
-#: clamav-milter.c:1274
309
-#, c-format
310
-msgid "%s: the quarantine directory must not contain the string 'ERROR'\n"
311
-msgstr ""
312
-
313
-#: clamav-milter.c:1280
314
-#, c-format
315
-msgid "%s: the quarantine directory must not contain the string 'FOUND'\n"
316
-msgstr ""
317
-
318
-#: clamav-milter.c:1286
319
-#, c-format
320
-msgid "%s: the quarantine directory must not contain the string 'OK'\n"
321
-msgstr ""
322
-
323
-#: clamav-milter.c:1303
324
-#, c-format
325
-msgid "%s: insecure quarantine directory %s (mode 0%o)\n"
326
-msgstr ""
327
-
328
-#: clamav-milter.c:1344
329
-#, c-format
330
-msgid "%s: ReadTimeout must not be negative in %s\n"
331
-msgstr ""
332
-
333
-#: clamav-milter.c:1353
334
-#, c-format
335
-msgid "%s: StreamMaxLength must not be negative in %s\n"
336
-msgstr ""
337
-
338
-#: clamav-milter.c:1386
339
-#, c-format
340
-msgid ""
341
-"%s: (-q && !LogSyslog): warning - all interception message methods are off\n"
342
-msgstr ""
343
-
344
-#: clamav-milter.c:1402
345
-#, c-format
346
-msgid "%s: --max-children must be given if --external is not given\n"
347
-msgstr ""
348
-
349
-#: clamav-milter.c:1406
350
-#, c-format
351
-msgid "%s: --freshclam_monitor must be at least one second\n"
352
-msgstr ""
353
-
354
-#: clamav-milter.c:1420
355
-#, c-format
356
-msgid "%s: --timeout must not be given if --external is not given\n"
357
-msgstr ""
358
-
359
-#: clamav-milter.c:1433
360
-#, c-format
361
-msgid "%s: No emails will be scanned"
362
-msgstr ""
363
-
364
-#: clamav-milter.c:1444
365
-#, c-format
366
-msgid "%s: You can select one server type only (local/TCP) in %s\n"
367
-msgstr ""
368
-
369
-#: clamav-milter.c:1449
370
-#, c-format
371
-msgid "%s: You cannot use the --server option when using LocalSocket in %s\n"
372
-msgstr ""
373
-
374
-#: clamav-milter.c:1459
375
-#, c-format
376
-msgid "The connexion from sendmail to %s (%s) must not\n"
377
-msgstr ""
378
-
379
-#: clamav-milter.c:1461
380
-#, c-format
381
-msgid "be the same as the connexion to clamd (%s) in %s\n"
382
-msgstr ""
383
-
384
-#: clamav-milter.c:1471 clamav-milter.c:1498
385
-#, c-format
386
-msgid "Can't talk to clamd server via %s\n"
387
-msgstr ""
388
-
389
-#: clamav-milter.c:1473 clamav-milter.c:1500
390
-#, c-format
391
-msgid "Check your entry for LocalSocket in %s\n"
392
-msgstr ""
393
-
394
-#: clamav-milter.c:1510
395
-msgid "!Can't create a clamd session"
396
-msgstr ""
397
-
398
-#: clamav-milter.c:1527
399
-#, c-format
400
-msgid "%s: --quarantine-dir not supported for TCPSocket - use --quarantine\n"
401
-msgstr ""
402
-
403
-#: clamav-milter.c:1542
404
-#, c-format
405
-msgid "%s: hostname %s is longer than %d characters\n"
406
-msgstr ""
407
-
408
-#: clamav-milter.c:1561 clamav-milter.c:1694
409
-#, c-format
410
-msgid "%s: --max-children must be given in sessions mode\n"
411
-msgstr ""
412
-
413
-#: clamav-milter.c:1567
414
-#, c-format
415
-msgid ""
416
-"%1$s: --max-children (%2$d) is lower than the number of servers you have (%3"
417
-"$d)\n"
418
-msgstr ""
419
-
420
-#: clamav-milter.c:1594
421
-#, c-format
422
-msgid "%s: Unknown host %s\n"
423
-msgstr ""
424
-
425
-#: clamav-milter.c:1624
426
-msgid "Waiting for clamd to come up\n"
427
-msgstr ""
428
-
429
-#: clamav-milter.c:1638
430
-#, c-format
431
-msgid "Can't talk to clamd server %s on port %d\n"
432
-msgstr ""
433
-
434
-#: clamav-milter.c:1642
435
-#, c-format
436
-msgid "Check the value for TCPAddr in %s\n"
437
-msgstr ""
438
-
439
-#: clamav-milter.c:1644
440
-#, c-format
441
-msgid "Check the value for TCPAddr in clamd.conf on %s\n"
442
-msgstr ""
443
-
444
-#: clamav-milter.c:1660 clamav-milter.c:1668 clamav-milter.c:4773
445
-msgid "!Can't find any clamd server\n"
446
-msgstr ""
447
-
448
-#: clamav-milter.c:1661 clamav-milter.c:1666
449
-#, c-format
450
-msgid "Check your entry for TCPSocket in %s\n"
451
-msgstr ""
452
-
453
-#: clamav-milter.c:1674
454
-#, c-format
455
-msgid "%s: You must select server type (local/TCP) in %s\n"
456
-msgstr ""
457
-
458
-#: clamav-milter.c:1777
459
-#, c-format
460
-msgid "When debugging it is recommended that you use Foreground mode in %s\n"
461
-msgstr ""
462
-
463
-#: clamav-milter.c:1778
464
-msgid "\tso that you can see all of the messages"
465
-msgstr ""
466
-
467
-#: clamav-milter.c:1886
468
-#, c-format
469
-msgid "%s: ScanMail not defined in %s (needed without --external), enabling\n"
470
-msgstr ""
471
-
472
-#: clamav-milter.c:1946
473
-msgid "Starting clamav-milter"
474
-msgstr ""
475
-
476
-#: clamav-milter.c:1974
477
-#, c-format
478
-msgid "!pidfile: '%s' must be a full pathname"
479
-msgstr ""
480
-
481
-#: clamav-milter.c:1990
482
-#, c-format
483
-msgid "!Can't save PID in file %s\n"
484
-msgstr ""
485
-
486
-#: clamav-milter.c:2058
487
-#, c-format
488
-msgid "Starting %s\n"
489
-msgstr ""
490
-
491
-#: clamav-milter.c:2059
492
-msgid "*Debugging is on\n"
493
-msgstr ""
494
-
495
-#: clamav-milter.c:2159
496
-#, c-format
497
-msgid "Check clamd server %s - it may be down\n"
498
-msgstr ""
499
-
500
-#: clamav-milter.c:2164
501
-msgid "Check clamd server - it may be down"
502
-msgstr ""
503
-
504
-#: clamav-milter.c:2374
505
-msgid "No free clamd sessions\n"
506
-msgstr ""
507
-
508
-#: clamav-milter.c:2495
509
-msgid "^Couldn't establish a connexion to any clamd server\n"
510
-msgstr ""
511
-
512
-#: clamav-milter.c:2519
513
-#, c-format
514
-msgid "^findServer: select failed (maxsock = %d)\n"
515
-msgstr ""
516
-
517
-#: clamav-milter.c:2533
518
-msgid "^findServer: No response from any server\n"
519
-msgstr ""
520
-
521
-#: clamav-milter.c:2602
522
-#, c-format
523
-msgid "^Check clamd server %s - it may be down\n"
524
-msgstr ""
525
-
526
-#: clamav-milter.c:2606
527
-msgid "Check clamd server - it may be down\n"
528
-msgstr ""
529
-
530
-#: clamav-milter.c:2630
531
-msgid "!clamfi_connect: ctx is null"
532
-msgstr ""
533
-
534
-#: clamav-milter.c:2634
535
-msgid "!clamfi_connect: hostname is null"
536
-msgstr ""
537
-
538
-#: clamav-milter.c:2670
539
-#, c-format
540
-msgid "clamfi_connect: Unexpected sa_family %d\n"
541
-msgstr ""
542
-
543
-#: clamav-milter.c:2680
544
-msgid "clamfi_connect: remoteIP is null"
545
-msgstr ""
546
-
547
-#: clamav-milter.c:2688
548
-#, c-format
549
-msgid "clamfi_connect: connexion from %s"
550
-msgstr ""
551
-
552
-#: clamav-milter.c:2690
553
-#, c-format
554
-msgid "clamfi_connect: connexion from %s [%s]"
555
-msgstr ""
556
-
557
-#: clamav-milter.c:2709
558
-msgid "Can't get sendmail hostname"
559
-msgstr ""
560
-
561
-#: clamav-milter.c:2717
562
-#, c-format
563
-msgid "^Access Denied: Host Unknown (%s)"
564
-msgstr ""
565
-
566
-#: clamav-milter.c:2726
567
-#, c-format
568
-msgid "Can't find entry for IP address %s in DNS - check your DNS setting\n"
569
-msgstr ""
570
-
571
-#: clamav-milter.c:2736
572
-#, c-format
573
-msgid "^Access Denied: Can't get IP address for (%s)"
574
-msgstr ""
575
-
576
-#: clamav-milter.c:2752
577
-#, c-format
578
-msgid "^Access Denied for %s[%s]"
579
-msgstr ""
580
-
581
-#: clamav-milter.c:2768
582
-msgid "*clamfi_connect: not scanning outgoing messages"
583
-msgstr ""
584
-
585
-#: clamav-milter.c:2774
586
-msgid "*clamfi_connect: not scanning local messages\n"
587
-msgstr ""
588
-
589
-#: clamav-milter.c:2787
590
-msgid "^clamfi_connect: gethostname failed"
591
-msgstr ""
592
-
593
-#: clamav-milter.c:2792
594
-msgid "Rejected connexion falsely claiming to be from here\n"
595
-msgstr ""
596
-
597
-#: clamav-milter.c:2793
598
-msgid "You have claimed to be me, but you are not"
599
-msgstr ""
600
-
601
-#: clamav-milter.c:2794 clamav-milter.c:3141
602
-msgid "Forged local address detected"
603
-msgstr ""
604
-
605
-#: clamav-milter.c:2810
606
-#, c-format
607
-msgid "%s is blacklisted because your machine is infected with a virus"
608
-msgstr ""
609
-
610
-#: clamav-milter.c:2812 clamav-milter.c:2924
611
-msgid "Blacklisted IP detected"
612
-msgstr ""
613
-
614
-#: clamav-milter.c:2868
615
-msgid "*clamfi_envfrom: ignoring whitelisted message"
616
-msgstr ""
617
-
618
-#: clamav-milter.c:2882
619
-msgid "Rejected email with empty from field"
620
-msgstr ""
621
-
622
-#: clamav-milter.c:2883
623
-msgid "You have not said who the email is from"
624
-msgstr ""
625
-
626
-#: clamav-milter.c:2884
627
-msgid "Reject email with empty from field"
628
-msgstr ""
629
-
630
-#: clamav-milter.c:2902
631
-msgid "AV system temporarily overloaded - please try later"
632
-msgstr ""
633
-
634
-#: clamav-milter.c:2994
635
-msgid "Suspicious recipient address blocked"
636
-msgstr ""
637
-
638
-#: clamav-milter.c:2998
639
-#, c-format
640
-msgid "Will blacklist %s for %d seconds because of cracking attempt\n"
641
-msgstr ""
642
-
643
-#: clamav-milter.c:3108
644
-msgid "*clamfi_eoh\n"
645
-msgstr ""
646
-
647
-#: clamav-milter.c:3133
648
-msgid "clamfi_eoh: gethostname failed"
649
-msgstr ""
650
-
651
-#: clamav-milter.c:3139
652
-#, c-format
653
-msgid "Rejected email falsely claiming to be from %s"
654
-msgstr ""
655
-
656
-#: clamav-milter.c:3140
657
-msgid "You have claimed to be from me, but you are not"
658
-msgstr ""
659
-
660
-#: clamav-milter.c:3187
661
-msgid "*clamfi_enveoh: ignoring whitelisted message"
662
-msgstr ""
663
-
664
-#: clamav-milter.c:3199
665
-#, c-format
666
-msgid "*clamfi_envbody: %lu bytes"
667
-msgstr ""
668
-
669
-#: clamav-milter.c:3256
670
-#, c-format
671
-msgid "%s: Message more than StreamMaxLength (%ld) bytes - not scanned\n"
672
-msgstr ""
673
-
674
-#: clamav-milter.c:3259 clamav-milter.c:3585
675
-msgid "Not Scanned - StreamMaxLength exceeded"
676
-msgstr ""
677
-
678
-#: clamav-milter.c:3322
679
-#, c-format
680
-msgid "^Failed to delete X-Virus-Status header %d\n"
681
-msgstr ""
682
-
683
-#: clamav-milter.c:3377
684
-#, c-format
685
-msgid "failed to send SCAN %s command to clamd\n"
686
-msgstr ""
687
-
688
-#: clamav-milter.c:3398
689
-msgid "failed to send SCAN command to clamd\n"
690
-msgstr ""
691
-
692
-#: clamav-milter.c:3415
693
-#, c-format
694
-msgid "Waiting to read status from fd %d\n"
695
-msgstr ""
696
-
697
-#: clamav-milter.c:3427
698
-#, c-format
699
-msgid "*clamfi_eom: read %s\n"
700
-msgstr ""
701
-
702
-#: clamav-milter.c:3445
703
-#, c-format
704
-msgid "clamfi_eom: read nothing from clamd on %s\n"
705
-msgstr ""
706
-
707
-#: clamav-milter.c:3490 clamav-milter.c:3537
708
-msgid "Error determining host"
709
-msgstr ""
710
-
711
-#: clamav-milter.c:3551
712
-#, c-format
713
-msgid "%s: Ignoring %s false positive from %s received from %s\n"
714
-msgstr ""
715
-
716
-#: clamav-milter.c:3567
717
-#, c-format
718
-msgid "#Reported phishing false positive to %s"
719
-msgstr ""
720
-
721
-#: clamav-milter.c:3569
722
-#, c-format
723
-msgid "^Couldn't report false positive to %s\n"
724
-msgstr ""
725
-
726
-#: clamav-milter.c:3571
727
-msgid "^Can't set phish FP header\n"
728
-msgstr ""
729
-
730
-#: clamav-milter.c:3582
731
-#, c-format
732
-msgid "%s: Message more than StreamMaxLength (%ld) bytes - not scanned"
733
-msgstr ""
734
-
735
-#: clamav-milter.c:3590
736
-msgid "Not Scanned"
737
-msgstr ""
738
-
739
-#: clamav-milter.c:3618
740
-msgid "Infected with"
741
-msgstr ""
742
-
743
-#: clamav-milter.c:3640
744
-#, c-format
745
-msgid "Intercepted virus from %s to"
746
-msgstr ""
747
-
748
-#: clamav-milter.c:3732
749
-msgid "Subject: Virus intercepted\n"
750
-msgstr ""
751
-
752
-#: clamav-milter.c:3747
753
-#, c-format
754
-msgid "!Can't open e-mail template header file %s"
755
-msgstr ""
756
-
757
-#: clamav-milter.c:3762 clamav-milter.c:3766
758
-msgid "\n"
759
-msgstr ""
760
-
761
-#: clamav-milter.c:3775
762
-msgid "A message you sent to\n"
763
-msgstr ""
764
-
765
-#: clamav-milter.c:3785
766
-#, c-format
767
-msgid "The message %1$s sent from %2$s to\n"
768
-msgstr ""
769
-
770
-#: clamav-milter.c:3788
771
-#, c-format
772
-msgid "A message sent from %s to\n"
773
-msgstr ""
774
-
775
-#: clamav-milter.c:3793
776
-#, c-format
777
-msgid "contained %s and has not been accepted for delivery.\n"
778
-msgstr ""
779
-
780
-#: clamav-milter.c:3796
781
-#, c-format
782
-msgid ""
783
-"\n"
784
-"The message in question has been quarantined as %s\n"
785
-msgstr ""
786
-
787
-#: clamav-milter.c:3799
788
-#, c-format
789
-msgid ""
790
-"\n"
791
-"The message was received by %1$s from %2$s via %3$s\n"
792
-"\n"
793
-msgstr ""
794
-
795
-#: clamav-milter.c:3802
796
-msgid ""
797
-"For your information, the original message headers were:\n"
798
-"\n"
799
-msgstr ""
800
-
801
-#: clamav-milter.c:3815
802
-#, c-format
803
-msgid ""
804
-"\n"
805
-"The infected machine is likely to be here:\n"
806
-"%s\t\n"
807
-msgstr ""
808
-
809
-#: clamav-milter.c:3822
810
-#, c-format
811
-msgid "%s: Failed to notify clamAV interception - see dead.letter\n"
812
-msgstr ""
813
-
814
-#: clamav-milter.c:3824
815
-#, c-format
816
-msgid "^Can't execute '%s' to send virus notice"
817
-msgstr ""
818
-
819
-#: clamav-milter.c:3846
820
-#, c-format
821
-msgid "#Reported phishing to %s"
822
-msgstr ""
823
-
824
-#: clamav-milter.c:3848
825
-#, c-format
826
-msgid "^Couldn't report to %s\n"
827
-msgstr ""
828
-
829
-#: clamav-milter.c:3854
830
-msgid "^Can't set anti-phish header\n"
831
-msgstr ""
832
-
833
-#: clamav-milter.c:3872
834
-#, c-format
835
-msgid "^Can't set quarantine user %s"
836
-msgstr ""
837
-
838
-#: clamav-milter.c:3906
839
-#, c-format
840
-msgid "virus %s detected by ClamAV - http://www.clamav.net"
841
-msgstr ""
842
-
843
-#: clamav-milter.c:3911
844
-#, c-format
845
-msgid "Will blacklist %s for %d seconds because of %s\n"
846
-msgstr ""
847
-
848
-#: clamav-milter.c:3920
849
-msgid "Unknown"
850
-msgstr ""
851
-
852
-#: clamav-milter.c:3921
853
-#, c-format
854
-msgid "!%s: incorrect message \"%s\" from clamd"
855
-msgstr ""
856
-
857
-#: clamav-milter.c:3926
858
-msgid "Clean"
859
-msgstr ""
860
-
861
-#: clamav-milter.c:3930
862
-#, c-format
863
-msgid "%s: clean message from %s\n"
864
-msgstr ""
865
-
866
-#: clamav-milter.c:3932
867
-msgid "an unknown sender"
868
-msgstr ""
869
-
870
-#: clamav-milter.c:4020
871
-#, c-format
872
-msgid "!Can't remove clean file %s"
873
-msgstr ""
874
-
875
-#: clamav-milter.c:4193 clamav-milter.c:4197
876
-#, c-format
877
-msgid "!write failure (%lu bytes) to %s: %s\n"
878
-msgstr ""
879
-
880
-#: clamav-milter.c:4209 clamav-milter.c:4213
881
-#, c-format
882
-msgid "!write failure (%lu bytes) to clamd: %s\n"
883
-msgstr ""
884
-
885
-#: clamav-milter.c:4290
886
-#, c-format
887
-msgid "!No data received from clamd in %d seconds\n"
888
-msgstr ""
889
-
890
-#: clamav-milter.c:4318
891
-#, c-format
892
-msgid "Can't stat %s"
893
-msgstr ""
894
-
895
-#: clamav-milter.c:4328
896
-#, c-format
897
-msgid "Can't open %s"
898
-msgstr ""
899
-
900
-#: clamav-milter.c:4447
901
-#, c-format
902
-msgid "mkdir %s failed"
903
-msgstr ""
904
-
905
-#: clamav-milter.c:4461
906
-#, c-format
907
-msgid "mktemp %s failed"
908
-msgstr ""
909
-
910
-#: clamav-milter.c:4470
911
-#, c-format
912
-msgid "Temporary quarantine file %s creation failed"
913
-msgstr ""
914
-
915
-#: clamav-milter.c:4581
916
-#, c-format
917
-msgid "!failed to send STREAM command clamd server %d"
918
-msgstr ""
919
-
920
-#: clamav-milter.c:4589
921
-msgid "!failed to send STREAM command clamd"
922
-msgstr ""
923
-
924
-#: clamav-milter.c:4600
925
-msgid "!failed to create TCPSocket to talk to clamd"
926
-msgstr ""
927
-
928
-#: clamav-milter.c:4611 clamav-milter.c:4624
929
-msgid "!recv failed from clamd getting PORT"
930
-msgstr ""
931
-
932
-#: clamav-milter.c:4613 clamav-milter.c:4626
933
-msgid "!EOF from clamd getting PORT"
934
-msgstr ""
935
-
936
-#: clamav-milter.c:4637
937
-#, c-format
938
-msgid "!Expected port information from clamd, got '%s'"
939
-msgstr ""
940
-
941
-#: clamav-milter.c:4657 clamav-milter.c:4660
942
-#, c-format
943
-msgid "Connecting to local port %d - data %d cmd %d\n"
944
-msgstr ""
945
-
946
-#: clamav-milter.c:4673 clamav-milter.c:4676
947
-#, c-format
948
-msgid "!Failed to connect to port %d given by clamd: %s"
949
-msgstr ""
950
-
951
-#: clamav-milter.c:4785
952
-#, c-format
953
-msgid "!Can't open %s\n"
954
-msgstr ""
955
-
956
-#: clamav-milter.c:4799
957
-#, c-format
958
-msgid "!Clamd (pid %d) seems to have died\n"
959
-msgstr ""
960
-
961
-#: clamav-milter.c:4825
962
-#, c-format
963
-msgid "!Can't open e-mail template file %s"
964
-msgstr ""
965
-
966
-#: clamav-milter.c:4832
967
-#, c-format
968
-msgid "!Can't stat e-mail template file %s"
969
-msgstr ""
970
-
971
-#: clamav-milter.c:4839
972
-msgid "!Out of memory"
973
-msgstr ""
974
-
975
-#: clamav-milter.c:4844
976
-#, c-format
977
-msgid "!Error reading e-mail template file %s"
978
-msgstr ""
979
-
980
-#: clamav-milter.c:4872
981
-#, c-format
982
-msgid "!%s: Unknown clamAV variable \"%c\"\n"
983
-msgstr ""
984
-
985
-#: clamav-milter.c:4882
986
-#, c-format
987
-msgid "!%s: Unterminated sendmail variable \"%s\"\n"
988
-msgstr ""
989
-
990
-#: clamav-milter.c:4891
991
-#, c-format
992
-msgid "!%s: Unknown sendmail variable \"%s\"\n"
993
-msgstr ""
994
-
995
-#: clamav-milter.c:4957
996
-#, c-format
997
-msgid "!mkdir %s failed\n"
998
-msgstr ""
999
-
1000
-#: clamav-milter.c:4982
1001
-#, c-format
1002
-msgid "^Can't rename %1$s to %2$s\n"
1003
-msgstr ""
1004
-
1005
-#: clamav-milter.c:4990
1006
-#, c-format
1007
-msgid "Email quarantined as %s\n"
1008
-msgstr ""
1009
-
1010
-#: clamav-milter.c:5098
1011
-#, c-format
1012
-msgid "[Virus] %s"
1013
-msgstr ""
1014
-
1015
-#: clamav-milter.c:5307
1016
-msgid ""
1017
-"!No response from any clamd server - your AV system is not scanning emails\n"
1018
-msgstr ""
1019
-
1020
-#: clamav-milter.c:5325
1021
-msgid "Subject: ClamAV Down\n"
1022
-msgstr ""
1023
-
1024
-#: clamav-milter.c:5328
1025
-msgid ""
1026
-"This is an automatic message\n"
1027
-"\n"
1028
-msgstr ""
1029
-
1030
-#: clamav-milter.c:5331
1031
-msgid "The clamd program cannot be contacted.\n"
1032
-msgstr ""
1033
-
1034
-#: clamav-milter.c:5333
1035
-msgid "No clamd server can be contacted.\n"
1036
-msgstr ""
1037
-
1038
-#: clamav-milter.c:5335
1039
-msgid "Emails may not be being scanned, please check your servers.\n"
1040
-msgstr ""
1041
-
1042
-#: clamav-milter.c:5396 clamav-milter.c:5542
1043
-msgid "!No emails will be scanned"
1044
-msgstr ""
1045
-
1046
-#: clamav-milter.c:5606
1047
-#, c-format
1048
-msgid "Stopping %s\n"
1049
-msgstr ""
1050
-
1051
-#: clamav-milter.c:5654
1052
-msgid "Stopping clamav-milter"
1053
-msgstr ""
1054
-
1055
-#: clamav-milter.c:5802
1056
-#, c-format
1057
-msgid "Loaded %s\n"
1058
-msgstr ""
1059
-
1060
-#: clamav-milter.c:5806
1061
-#, c-format
1062
-msgid "ClamAV: Protecting against %u viruses\n"
1063
-msgstr ""
1064
-
1065
-#: clamav-milter.c:5954
1066
-#, c-format
1067
-msgid "!Can't open whitelist file %s"
1068
-msgstr ""
1069
-
1070
-#: clamav-milter.c:5961
1071
-msgid "!Can't create whitelist table"
1072
-msgstr ""
1073
-
1074
-#: clamav-milter.c:6049
1075
-msgid "!Can't create blacklist table"
1076
-msgstr ""
1077
-
1078
-#: clamav-milter.c:6472
1079
-msgid "^MX peers will not be immune from being blacklisted"
1080
-msgstr ""
1081
-
1082
-#: clamav-milter.c:6498
1083
-msgid "!Can't create pipe\n"
1084
-msgstr ""
1085
-
1086
-#: clamav-milter.c:6519
1087
-msgid "!Can't fork\n"
1088
-msgstr ""
1089
-
1090
-#: clamav-milter.c:6567
1091
-#, c-format
1092
-msgid "^Can't execute '%s' to expand '%s' (error %d)\n"
1093
-msgstr ""
1094
-
1095
-#: clamav-milter.c:6625
1096
-#, c-format
1097
-msgid "hit max-children limit (%u >= %u)\n"
1098
-msgstr ""
1099
-
1100
-#: clamav-milter.c:6626
1101
-#, c-format
1102
-msgid "hit max-children limit (%u >= %u): waiting for some to exit\n"
1103
-msgstr ""
1104
-
1105
-#: clamav-milter.c:6648
1106
-#, c-format
1107
-msgid "n_children %d: waiting %d seconds for some to exit\n"
1108
-msgstr ""
1109
-
1110
-#: clamav-milter.c:6661
1111
-#, c-format
1112
-msgid "Finished waiting, n_children = %d\n"
1113
-msgstr ""
1114
-
1115
-#: clamav-milter.c:6669
1116
-msgid "*Timeout waiting for a child to die\n"
1117
-msgstr ""
1118
-
1119
-#: clamav-milter.c:6703
1120
-#, c-format
1121
-msgid "Won't blacklist %s\n"
1122
-msgstr ""
1123 1
deleted file mode 100644
... ...
@@ -1,6951 +0,0 @@
1
-/*
2
- * clamav-milter.c
3
- *	.../clamav-milter/clamav-milter.c
4
- *
5
- *  Copyright (C) 2003-2007 Nigel Horne <njh@bandsman.co.uk>
6
- *
7
- *  This program is free software; you can redistribute it and/or modify
8
- *  it under the terms of the GNU General Public License as published by
9
- *  the Free Software Foundation; either version 2 of the License, or
10
- *  (at your option) any later version.
11
- *
12
- *  This program is distributed in the hope that it will be useful,
13
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
- *  GNU General Public License for more details.
16
- *
17
- *  You should have received a copy of the GNU General Public License
18
- *  along with this program; if not, write to the Free Software
19
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
- *  MA 02110-1301, USA.
21
- *
22
- * Install into /usr/local/sbin/clamav-milter
23
- * See http://www.elandsys.com/resources/sendmail/libmilter/overview.html
24
- *
25
- * For installation instructions see the file INSTALL that came with this file
26
- *
27
- * NOTE: first character of strings to logg():
28
- *	! Error
29
- *	^ Warning
30
- *	* Verbose
31
- *	# Info, but not logged in foreground
32
- *	Default Info
33
- */
34
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.312 2007/02/12 22:24:21 njh Exp $";
35
-
36
-#if HAVE_CONFIG_H
37
-#include "clamav-config.h"
38
-#endif
39
-
40
-#include "cfgparser.h"
41
-#include "target.h"
42
-#include "str.h"
43
-#include "../libclamav/others.h"
44
-#include "output.h"
45
-#include "clamav.h"
46
-#include "table.h"
47
-#include "network.h"
48
-#include "misc.h"
49
-
50
-#include <stdio.h>
51
-#include <sysexits.h>
52
-#ifdef	HAVE_SYS_STAT_H
53
-#include <sys/stat.h>
54
-#endif
55
-#if	HAVE_STDLIB_H
56
-#include <stdlib.h>
57
-#endif
58
-#if	HAVE_MEMORY_H
59
-#include <memory.h>
60
-#endif
61
-#if	HAVE_STRING_H
62
-#include <string.h>
63
-#endif
64
-#ifdef HAVE_STRINGS_H
65
-#include <strings.h>
66
-#endif
67
-#include <sys/wait.h>
68
-#include <assert.h>
69
-#include <sys/socket.h>
70
-#include <netinet/in.h>
71
-#include <net/if.h>
72
-#include <arpa/inet.h>
73
-#include <sys/un.h>
74
-#include <stdarg.h>
75
-#include <errno.h>
76
-#if	HAVE_LIBMILTER_MFAPI_H
77
-#include <libmilter/mfapi.h>
78
-#endif
79
-#include <pthread.h>
80
-#include <sys/time.h>
81
-#include <sys/resource.h>
82
-#include <signal.h>
83
-#include <fcntl.h>
84
-#include <pwd.h>
85
-#include <grp.h>
86
-#if	HAVE_SYS_PARAM_H
87
-#include <sys/param.h>
88
-#endif
89
-#if	HAVE_RESOLV_H
90
-#include <arpa/nameser.h>	/* for HEADER */
91
-#include <resolv.h>
92
-#endif
93
-#ifdef	HAVE_UNISTD_H
94
-#include <unistd.h>
95
-#endif
96
-#include <ctype.h>
97
-
98
-#if HAVE_MMAP
99
-#if HAVE_SYS_MMAN_H
100
-#include <sys/mman.h>
101
-#else /* HAVE_SYS_MMAN_H */
102
-#undef HAVE_MMAP
103
-#endif
104
-#endif
105
-
106
-#define NONBLOCK_SELECT_MAX_FAILURES	3
107
-#define NONBLOCK_MAX_ATTEMPTS	10
108
-#define	CONNECT_TIMEOUT	5	/* Allow 5 seconds to connect */
109
-
110
-#ifdef	C_LINUX
111
-#include <sys/sendfile.h>	/* FIXME: use sendfile on BSD not Linux */
112
-#include <libintl.h>
113
-#include <locale.h>
114
-
115
-#define	gettext_noop(s)	s
116
-#define	_(s)	gettext(s)
117
-#define	N_(s)	gettext_noop(s)
118
-
119
-#else
120
-
121
-#define	_(s)	s
122
-#define	N_(s)	s
123
-
124
-#endif
125
-
126
-#ifdef	USE_SYSLOG
127
-#include <syslog.h>
128
-#endif
129
-
130
-#ifdef	WITH_TCPWRAP
131
-#if	HAVE_TCPD_H
132
-#include <tcpd.h>
133
-#endif
134
-
135
-int	allow_severity = LOG_DEBUG;
136
-int	deny_severity = LOG_NOTICE;
137
-#endif
138
-
139
-#ifdef	CL_DEBUG
140
-static	char	console[] = "/dev/console";
141
-#endif
142
-
143
-#if defined(CL_DEBUG) && defined(C_LINUX)
144
-#include <sys/resource.h>
145
-#endif
146
-
147
-#define _GNU_SOURCE
148
-#include <getopt.h>
149
-
150
-#ifndef	SENDMAIL_BIN
151
-#define	SENDMAIL_BIN	"/usr/lib/sendmail"
152
-#endif
153
-
154
-#ifndef HAVE_IN_PORT_T
155
-typedef	unsigned short	in_port_t;
156
-#endif
157
-
158
-#ifndef	HAVE_IN_ADDR_T
159
-typedef	unsigned int	in_addr_t;
160
-#endif
161
-
162
-#ifndef	INET6_ADDRSTRLEN
163
-#ifdef	AF_INET6
164
-#define	INET6_ADDRSTRLEN	40
165
-#else
166
-#define	INET6_ADDRSTRLEN	16
167
-#endif
168
-#endif
169
-
170
-#ifndef	EX_CONFIG	/* HP-UX */
171
-#define	EX_CONFIG	78
172
-#endif
173
-
174
-#define	VERSION_LENGTH	128
175
-#define	DEFAULT_TIMEOUT	120
176
-
177
-#define	NTRIES	5	/* How many times we try to connect to a clamd */
178
-
179
-/*#define	SESSION*/
180
-		/* Keep one command connexion open to clamd, otherwise a new
181
-		 * command connexion is created for each new email
182
-		 *
183
-		 * FIXME: When SESSIONS are open, freshclam can hang when
184
-		 *	notfying clamd of an update. This is most likely to be a
185
-		 *	problem with the implementation of SESSIONS on clamd.
186
-		 *	The problem seems worst on BSD.
187
-		 *
188
-		 * Note that clamd is buggy and can hang or even crash if you
189
-		 *	send SESSION command so be aware
190
-		 */
191
-
192
-/*
193
- * TODO: optional: xmessage on console when virus stopped (SNMP would be real nice!)
194
- *	Having said that, with LogSysLog you can (on Linux) configure the system
195
- *	to get messages on the system console, see syslog.conf(5), also you
196
- *	can use wall(1) in the VirusEvent entry in clamd.conf
197
- * TODO: Decide action (bounce, discard, reject etc.) based on the virus
198
- *	found. Those with faked addresses, such as SCO.A want discarding,
199
- *	others could be bounced properly.
200
- * TODO: Encrypt mails sent to clamd to stop sniffers. Sending by UNIX domain
201
- *	sockets is better
202
- * TODO: Load balancing, allow local machine to talk via UNIX domain socket.
203
- * TODO: allow each To: line in the whitelist file to specify a quarantine email
204
- *	address
205
- * TODO: optionally use zlib to compress data sent to remote hosts
206
- * TODO: Finish IPv6 support (serverIPs array and SPF are IPv4 only)
207
- * TODO: Check domainkeys as well as SPF for phish false positives
208
- */
209
-
210
-struct header_node_t {
211
-	char	*header;
212
-	struct	header_node_t *next;
213
-};
214
-
215
-struct header_list_struct {
216
-	struct	header_node_t *first;
217
-	struct	header_node_t *last;
218
-};
219
-
220
-typedef struct header_list_struct *header_list_t;
221
-
222
-/*
223
- * Local addresses are those not scanned if --local is not set
224
- * 127.0.0.0 is not in this table since that's goverend by --outgoing
225
- * Andy Fiddaman <clam@fiddaman.net> added 169.254.0.0/16
226
- *	(Microsoft default DHCP)
227
- * TODO: compare this with RFC1918/RFC3330
228
- */
229
-#define PACKADDR(a, b, c, d) (((uint32_t)(a) << 24) | ((b) << 16) | ((c) << 8) | (d))
230
-#define MAKEMASK(bits)	((uint32_t)(0xffffffff << (32 - bits)))
231
-
232
-static struct cidr_net {	/* don't make this const because of -I flag */
233
-	uint32_t	base;
234
-	uint32_t	mask;
235
-} localNets[] = {
236
-	/*{ PACKADDR(127,   0,   0,   0), MAKEMASK(8) },	*   127.0.0.0/8 */
237
-	{ PACKADDR(192, 168,   0,   0), MAKEMASK(16) },	/* 192.168.0.0/16 - RFC3330 */
238
-	/*{ PACKADDR(192, 18,   0,   0), MAKEMASK(15) },	* 192.18.0.0/15 - RFC2544 */
239
-	/*{ PACKADDR(192, 0,   2,   0), MAKEMASK(24) },	* 192.0.2.0/24 - RFC3330 */
240
-	{ PACKADDR( 10,   0,   0,   0), MAKEMASK(8) },	/*    10.0.0.0/8 */
241
-	{ PACKADDR(172,  16,   0,   0), MAKEMASK(12) },	/*  172.16.0.0/12 */
242
-	{ PACKADDR(169, 254,   0,   0), MAKEMASK(16) },	/* 169.254.0.0/16 */
243
-	{ 0, 0 },	/* space to put eight more via -I addr */
244
-	{ 0, 0 },
245
-	{ 0, 0 },
246
-	{ 0, 0 },
247
-	{ 0, 0 },
248
-	{ 0, 0 },
249
-	{ 0, 0 },
250
-	{ 0, 0 },
251
-	{ 0, 0 }
252
-};
253
-#define IFLAG_MAX 8
254
-
255
-#ifdef	AF_INET6
256
-typedef struct cidr_net6 {
257
-	struct in6_addr	base;
258
-	int preflen;
259
-} cidr_net6;
260
-static	cidr_net6	localNets6[IFLAG_MAX];
261
-static	int	localNets6_cnt;
262
-#endif
263
-
264
-/*
265
- * Each libmilter thread has one of these
266
- */
267
-struct	privdata {
268
-	char	*from;	/* Who sent the message */
269
-	char	*subject;	/* Original subject */
270
-	char	*sender;	/* Secretary - often used in mailing lists */
271
-	char	**to;	/* Who is the message going to */
272
-	char	ip[INET6_ADDRSTRLEN];	/* IP address of the other end */
273
-	int	numTo;	/* Number of people the message is going to */
274
-#ifndef	SESSION
275
-	int	cmdSocket;	/*
276
-				 * Socket to send/get commands e.g. PORT for
277
-				 * dataSocket
278
-				 */
279
-#endif
280
-	int	dataSocket;	/* Socket to send data to clamd */
281
-	char	*filename;	/* Where to store the message in quarantine */
282
-	u_char	*body;		/* body of the message if Sflag is set */
283
-	size_t	bodyLen;	/* number of bytes in body */
284
-	header_list_t headers;	/* Message headers */
285
-	long	numBytes;	/* Number of bytes sent so far */
286
-	char	*received;	/* keep track of received from */
287
-	const	char	*rejectCode;	/* 550 or 554? */
288
-	unsigned	int	discard:1;	/*
289
-				 * looks like the remote end is playing ping
290
-				 * pong with us
291
-				 */
292
-#ifdef	HAVE_RESOLV_H
293
-	unsigned	int	spf_ok:1;
294
-#endif
295
-	int	statusCount;	/* number of X-Virus-Status headers */
296
-	int	serverNumber;	/* Index into serverIPs */
297
-};
298
-
299
-#ifdef	SESSION
300
-static	int		createSession(unsigned int s);
301
-#else
302
-static	int		pingServer(int serverNumber);
303
-static	void		*try_server(void *var);
304
-static	int		active_servers(int *active);
305
-struct	try_server_struct {
306
-	int	sock;
307
-	int	rc;
308
-	struct	sockaddr_in *server;
309
-	int	server_index;
310
-};
311
-#endif
312
-static	int		findServer(void);
313
-static	sfsistat	clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr);
314
-#ifdef	CL_DEBUG
315
-static	sfsistat	clamfi_helo(SMFICTX *ctx, char *helostring);
316
-#endif
317
-static	sfsistat	clamfi_envfrom(SMFICTX *ctx, char **argv);
318
-static	sfsistat	clamfi_envrcpt(SMFICTX *ctx, char **argv);
319
-static	sfsistat	clamfi_header(SMFICTX *ctx, char *headerf, char *headerv);
320
-static	sfsistat	clamfi_eoh(SMFICTX *ctx);
321
-static	sfsistat	clamfi_body(SMFICTX *ctx, u_char *bodyp, size_t len);
322
-static	sfsistat	clamfi_eom(SMFICTX *ctx);
323
-static	sfsistat	clamfi_abort(SMFICTX *ctx);
324
-static	sfsistat	clamfi_close(SMFICTX *ctx);
325
-static	void		clamfi_cleanup(SMFICTX *ctx);
326
-static	void		clamfi_free(struct privdata *privdata, int keep);
327
-#ifdef __GNUC__
328
-static	int		clamfi_send(struct privdata *privdata, size_t len, const char *format, ...) __attribute__((format(printf, 3,4)));
329
-#else
330
-static	int		clamfi_send(struct privdata *privdata, size_t len, const char *format, ...);
331
-#endif
332
-static	long		clamd_recv(int sock, char *buf, size_t len);
333
-static	off_t		updateSigFile(void);
334
-static	header_list_t	header_list_new(void);
335
-static	void	header_list_free(header_list_t list);
336
-static	void	header_list_add(header_list_t list, const char *headerf, const char *headerv);
337
-static	void	header_list_print(header_list_t list, FILE *fp);
338
-static	int	connect2clamd(struct privdata *privdata);
339
-static	int	sendToFrom(struct privdata *privdata);
340
-static	int	checkClamd(int log_result);
341
-static	int	sendtemplate(SMFICTX *ctx, const char *filename, FILE *sendmail, const char *virusname);
342
-static	int	qfile(struct privdata *privdata, const char *sendmailId, const char *virusname);
343
-static	int	move(const char *oldfile, const char *newfile);
344
-static	void	setsubject(SMFICTX *ctx, const char *virusname);
345
-/*static	int	clamfi_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len);*/
346
-static	int	add_local_ip(char *address);
347
-static	int	isLocalAddr(in_addr_t addr);
348
-static	int	isLocal(const char *addr);
349
-static	void	clamdIsDown(void);
350
-static	void	*watchdog(void *a);
351
-static	int	check_and_reload_database(void);
352
-static	void	timeoutBlacklist(char *ip_address, int time_of_blacklist, void *v);
353
-static	void	quit(void);
354
-static	void	broadcast(const char *mess);
355
-static	int	loadDatabase(void);
356
-static	int	increment_connexions(void);
357
-static	void	decrement_connexions(void);
358
-static	void	dump_blacklist(char *key, int value, void *v);
359
-static	int	nonblock_connect(int sock, const struct sockaddr_in *sin, const char *hostname);
360
-static	int	connect_error(int sock, const char *hostname);
361
-
362
-#ifdef	SESSION
363
-static	pthread_mutex_t	version_mutex = PTHREAD_MUTEX_INITIALIZER;
364
-static	char	**clamav_versions;	/* max_children elements in the array */
365
-#define	clamav_version	(clamav_versions[0])
366
-#else
367
-static	char	clamav_version[VERSION_LENGTH + 1];
368
-#endif
369
-static	int	fflag = 0;	/* force a scan, whatever */
370
-static	int	oflag = 0;	/* scan messages from our machine? */
371
-static	int	lflag = 0;	/* scan messages from our site? */
372
-static	int	Iflag = 0;	/* Added an IP addr to localNets? */
373
-static	const	char	*progname;	/* our name - usually clamav-milter */
374
-
375
-/* Variables for --external */
376
-static	int	external = 0;	/* scan messages ourself or use clamd? */
377
-static	pthread_mutex_t	engine_mutex = PTHREAD_MUTEX_INITIALIZER;
378
-struct  cl_engine *engine = NULL;
379
-uint64_t maxscansize;
380
-uint64_t maxfilesize;
381
-uint32_t maxreclevel;
382
-uint32_t maxfiles;
383
-
384
-static	struct	cl_stat	dbstat;
385
-static	int	options = CL_SCAN_STDOPT;
386
-
387
-#ifdef	BOUNCE
388
-static	int	bflag = 0;	/*
389
-				 * send a failure (bounce) message to the
390
-				 * sender. This probably isn't a good idea
391
-				 * since most reply addresses will be fake
392
-				 *
393
-				 * TODO: Perhaps we can have an option to
394
-				 * bounce outgoing mail, but not incoming?
395
-				 */
396
-#endif
397
-static	const	char	*iface;	/*
398
-				 * Broadcast a message when a virus is found,
399
-				 * this allows remote network management
400
-				 */
401
-static	int	broadcastSock = -1;
402
-static	int	pflag = 0;	/*
403
-				 * Send a warning to the postmaster only,
404
-				 * this means user's won't be told when someone
405
-				 * sent them a virus
406
-				 */
407
-static	int	qflag = 0;	/*
408
-				 * Send no warnings when a virus is found,
409
-				 * this means that the only log of viruses
410
-				 * found is the syslog, so it's best to
411
-				 * enable LogSyslog in clamd.conf
412
-				 */
413
-static	int	Sflag = 0;	/*
414
-				 * Add a signature to each message that
415
-				 * has been scanned
416
-				 */
417
-static	const	char	*sigFilename;	/*
418
-				 * File where the scanned message signature
419
-				 * can be found
420
-				 */
421
-static	char	*quarantine;	/*
422
-				 * If a virus is found in an email redirect
423
-				 * it to this account
424
-				 */
425
-static	char	*quarantine_dir; /*
426
-				 * Path to store messages before scanning.
427
-				 * Infected ones will be left there.
428
-				 */
429
-static	int	nflag = 0;	/*
430
-				 * Don't add X-Virus-Scanned to header. Patch
431
-				 * from Dirk Meyer <dirk.meyer@dinoex.sub.org>
432
-				 */
433
-static	int	rejectmail = 1;	/*
434
-				 * Send a 550 rejection when a virus is
435
-				 * found
436
-				 */
437
-static	int	hflag = 0;	/*
438
-				 * Include original message headers in
439
-				 * report
440
-				 */
441
-static	int	cl_error = SMFIS_TEMPFAIL; /*
442
-				 * If an error occurs, return
443
-				 * this status. Allows messages
444
-				 * to be passed through
445
-				 * unscanned in the event of
446
-				 * an error. Patch from
447
-				 * Joe Talbott <josepht@cstone.net>
448
-				 */
449
-static	int	readTimeout = DEFAULT_TIMEOUT; /*
450
-				 * number of seconds to wait for clamd to
451
-				 * respond, see ReadTimeout in clamd.conf
452
-				 */
453
-static	long	streamMaxLength = 10*1024*1024;	/* StreamMaxLength from clamd.conf */
454
-static	int	logok = 0;	/*
455
-				 * Add clean items to the log file
456
-				 */
457
-static	const char	*signature = N_("-- \nScanned by ClamAv - http://www.clamav.net\n");
458
-static	time_t	signatureStamp;
459
-static	char	*templateFile;	/* e-mail to be sent when virus detected */
460
-static	char	*templateHeaders;	/* headers to be added to the above */
461
-static	const char	*tmpdir;
462
-
463
-#ifdef	CL_DEBUG
464
-static	int	debug_level = 0;
465
-#endif
466
-
467
-static	pthread_mutex_t	n_children_mutex = PTHREAD_MUTEX_INITIALIZER;
468
-static	pthread_cond_t	n_children_cond = PTHREAD_COND_INITIALIZER;
469
-static	int	n_children = 0;
470
-static	int	max_children = 0;
471
-static	unsigned	int	freshclam_monitor = 10;	/*
472
-							 * how often, in
473
-							 * seconds, to scan for
474
-							 * database updates
475
-							 */
476
-static	int	child_timeout = 300;	/* number of seconds to wait for
477
-					 * a child to die. Set to 0 to
478
-					 * wait forever
479
-					 */
480
-static	int	dont_wait = 0;	/*
481
-				 * If 1 send retry later to the remote end
482
-				 * if max_chilren is exceeded, otherwise we
483
-				 * wait for the number to go down
484
-				 */
485
-static	int	dont_sanitise = 0; /*
486
-				 * Don't check for ";" and "|" chars in 
487
-				 * email addresses.
488
-				 */
489
-static	int	advisory = 0;	/*
490
-				 * Run clamav-milter in advisory mode - viruses
491
-				 * are flagged rather than deleted. Incompatible
492
-				 * with quarantine options
493
-				 */
494
-static	int	detect_forged_local_address;	/*
495
-				 * for incoming only mail servers, drop emails
496
-				 * claiming to be from us that must be false
497
-				 * Requires that -o, -l or -f are NOT given
498
-				 */
499
-static	struct	cfgstruct	*copt;
500
-static	const	char	*localSocket;	/* milter->clamd comms */
501
-static	in_port_t	tcpSocket;	/* milter->clamd comms */
502
-static	char	*port = NULL;	/* sendmail->milter comms */
503
-
504
-static	const	char	*serverHostNames = "127.0.0.1";
505
-#if	HAVE_IN_ADDR_T
506
-static	in_addr_t	*serverIPs;	/* IPv4 only, in network byte order */
507
-#else
508
-static	long	*serverIPs;	/* IPv4 only, in network byte order */
509
-#endif
510
-static	int	numServers;	/* number of elements in serverIPs array */
511
-#ifndef	SESSION
512
-#define	RETRY_SECS	300	/* How often to retry a server that's down */
513
-static	time_t	*last_failed_pings;	/* For servers that are down. NB: not mutexed */
514
-#endif
515
-static	char	*rootdir;	/* for chroot */
516
-
517
-#ifdef	SESSION
518
-static	struct	session {
519
-	int	sock;	/* fd */
520
-	enum	{ CMDSOCKET_FREE, CMDSOCKET_INUSE, CMDSOCKET_DOWN }	status;
521
-} *sessions;	/* max_children elements in the array */
522
-static	pthread_mutex_t sstatus_mutex = PTHREAD_MUTEX_INITIALIZER;
523
-#endif	/*SESSION*/
524
-
525
-static	pthread_cond_t	watchdog_cond = PTHREAD_COND_INITIALIZER;
526
-
527
-#ifndef	SHUT_RD
528
-#define	SHUT_RD		0
529
-#endif
530
-#ifndef	SHUT_WR
531
-#define	SHUT_WR		1
532
-#endif
533
-
534
-static	const	char	*postmaster = "postmaster";
535
-static	const	char	*from = "MAILER-DAEMON";
536
-static	int	quitting;
537
-static	int	reload;	/* reload database when SIGUSR2 is received */
538
-static	const	char	*report;	/* Report Phishing to this address */
539
-static	const	char	*report_fps;	/* Report Phish FPs to this address */
540
-
541
-static	const	char	*whitelistFile;	/*
542
-					 * file containing destination email
543
-					 * addresses that we don't scan
544
-					 */
545
-static	const	char	*sendmailCF;	/* location of sendmail.cf to verify */
546
-static		int	checkCF = 1;
547
-static	const	char	*pidfile;
548
-static	int	black_hole_mode; /*
549
-				 * Since sendmail calls its milters before it
550
-				 * looks in /etc/aliases we can spend time
551
-				 * looking for malware that's going to be
552
-				 * thrown away even if the message is clean.
553
-				 * Enable this to not scan these messages.
554
-				 * Sadly, because these days sendmail -bv
555
-				 * only works as root, you can't use this with
556
-				 * the User directive, which some won't like
557
-				 * which also may contain the real target name
558
-				 *
559
-				 * smfi_getsymval(ctx, "{rcpt_addr}") only
560
-				 * handles virtuser, it doesn't also deref
561
-				 * the alias table, so it isn't any help
562
-				 */
563
-
564
-static	table_t	*blacklist;	/* never freed */
565
-static	int	blacklist_time;	/* How long to blacklist an IP */
566
-static	pthread_mutex_t	blacklist_mutex = PTHREAD_MUTEX_INITIALIZER;
567
-
568
-#ifdef	CL_DEBUG
569
-#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
570
-#define HAVE_BACKTRACE
571
-#endif
572
-#endif
573
-
574
-static	void	sigsegv(int sig);
575
-static	void	sigusr1(int sig);
576
-static	void	sigusr2(int sig);
577
-
578
-#ifdef HAVE_BACKTRACE
579
-#include <execinfo.h>
580
-
581
-static	void	print_trace(void);
582
-
583
-#define	BACKTRACE_SIZE	200
584
-
585
-#endif
586
-
587
-static	int	verifyIncomingSocketName(const char *sockName);
588
-static	int	isWhitelisted(const char *emailaddress, int to);
589
-static	int	isBlacklisted(const char *ip_address);
590
-static	table_t	*mx(const char *host, table_t *t);
591
-static	sfsistat	black_hole(const struct privdata *privdata);
592
-static	int	useful_header(const char *cmd);
593
-
594
-extern	short	logg_foreground;
595
-
596
-#ifdef HAVE_RESOLV_H
597
-static	table_t	*resolve(const char *host, table_t *t);
598
-static	int	spf(struct privdata *privdata, table_t *prevhosts);
599
-static	void	spf_ip(char *ip, int zero, void *v);
600
-
601
-pthread_mutex_t	res_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
602
-
603
-#ifdef HAVE_LRESOLV_R
604
-res_state res_pool;
605
-uint8_t *res_pool_state;
606
-pthread_cond_t res_pool_cond = PTHREAD_COND_INITIALIZER;
607
-
608
-static int safe_res_query(const char *d, int c, int t, u_char *a, int l) {
609
-	int i = -1, ret;
610
-
611
-	pthread_mutex_lock(&res_pool_mutex);
612
-	while(i==-1) {
613
-		int j;
614
-		for(j=0; j<max_children+1; j++) {
615
-			if(!res_pool_state[j]) continue;
616
-			i = j;
617
-			break;
618
-		}
619
-		if(i!=-1) break;
620
-		pthread_cond_wait(&res_pool_cond, &res_pool_mutex);
621
-	}
622
-	res_pool_state[i]=0;
623
-	pthread_mutex_unlock(&res_pool_mutex);
624
-
625
-	ret = res_nquery(&res_pool[i], d, c, t, a, l);
626
-  
627
-	pthread_mutex_lock(&res_pool_mutex);
628
-	res_pool_state[i]=1;
629
-	pthread_cond_signal(&res_pool_cond);
630
-	pthread_mutex_unlock(&res_pool_mutex);
631
-	return ret;
632
-}
633
-
634
-#else /* !HAVE_LRESOLV_R - non thread safe resolver (old bsd's) */
635
-
636
-static int safe_res_query(const char *d, int c, int t, u_char *a, int l) {
637
-	int ret;
638
-	pthread_mutex_lock(&res_pool_mutex);
639
-	ret = res_query(d, c, t, a, l);
640
-	pthread_mutex_unlock(&res_pool_mutex);
641
-	return ret;
642
-}
643
-
644
-#endif /* HAVE_LRESOLV_R */
645
-
646
-#endif /* HAVE_RESOLV_H */
647
-
648
-static void
649
-help(void)
650
-{
651
-	printf("\n\tclamav-milter version %s\n", get_version());
652
-	puts("\tCopyright (C) 2007 Nigel Horne <njh@clamav.net>\n");
653
-
654
-	puts(_("\t--advisory\t\t-A\tFlag viruses rather than deleting them."));
655
-	puts(_("\t--blacklist-time=SECS\t-k\tTime (in seconds) to blacklist an IP."));
656
-	puts(_("\t--black-hole-mode\t\tDon't scan messages aliased to /dev/null."));
657
-#ifdef	BOUNCE
658
-	puts(_("\t--bounce\t\t-b\tSend a failure message to the sender."));
659
-#endif
660
-	puts(_("\t--broadcast\t\t-B [IFACE]\tBroadcast to a network manager when a virus is found."));
661
-	puts(_("\t--chroot=DIR\t\t-C DIR\tChroot to dir when starting."));
662
-	puts(_("\t--config-file=FILE\t-c FILE\tRead configuration from FILE."));
663
-	puts(_("\t--debug\t\t\t-D\tPrint debug messages."));
664
-	puts(_("\t--detect-forged-local-address\t-L\tReject mails that claim to be from us."));
665
-	puts(_("\t--dont-blacklist\t-K\tDon't blacklist a given IP."));
666
-	puts(_("\t--dont-scan-on-error\t-d\tPass e-mails through unscanned if a system error occurs."));
667
-	puts(_("\t--dont-wait\t\t\tAsk remote end to resend if max-children exceeded."));
668
-	puts(_("\t--dont-sanitise\t\t\tAllow semicolon and pipe characters in email addresses."));
669
-	puts(_("\t--external\t\t-e\tUse an external scanner (usually clamd)."));
670
-	puts(_("\t--freshclam-monitor=SECS\t-M SECS\tHow often to check for database update."));
671
-	puts(_("\t--from=EMAIL\t\t-a EMAIL\tError messages come from here."));
672
-	puts(_("\t--force-scan\t\t-f\tForce scan all messages (overrides (-o and -l)."));
673
-	puts(_("\t--help\t\t\t-h\tThis message."));
674
-	puts(_("\t--headers\t\t-H\tInclude original message headers in the report."));
675
-	puts(_("\t--ignore IPaddr\t\t-I IPaddr\tAdd IPaddr to LAN IP list (see --local)."));
676
-	puts(_("\t--local\t\t\t-l\tScan messages sent from machines on our LAN."));
677
-	puts(_("\t--max-childen\t\t-m\tMaximum number of concurrent scans."));
678
-	puts(_("\t--outgoing\t\t-o\tScan outgoing messages from this machine."));
679
-	puts(_("\t--noreject\t\t-N\tDon't reject viruses, silently throw them away."));
680
-	puts(_("\t--noxheader\t\t-n\tSuppress X-Virus-Scanned/X-Virus-Status headers."));
681
-	puts(_("\t--pidfile=FILE\t\t-i FILE\tLocation of pidfile."));
682
-	puts(_("\t--postmaster\t\t-p EMAIL\tPostmaster address [default=postmaster]."));
683
-	puts(_("\t--postmaster-only\t-P\tSend notifications only to the postmaster."));
684
-	puts(_("\t--quiet\t\t\t-q\tDon't send e-mail notifications of interceptions."));
685
-	puts(_("\t--quarantine=USER\t-Q EMAIL\tQuarantine e-mail account."));
686
-	puts(_("\t--report-phish=EMAIL\t-r EMAIL\tReport phish to this email address."));
687
-	puts(_("\t--report-phish-false-positives=EMAIL\t-R EMAIL\tReport phish false positves to this email address."));
688
-	puts(_("\t--quarantine-dir=DIR\t-U DIR\tDirectory to store infected emails."));
689
-	puts(_("\t--server=SERVER\t\t-s SERVER\tHostname/IP address of server(s) running clamd (when using TCPsocket)."));
690
-	puts(_("\t--sendmail-cf=FILE\t\tLocation of the sendmail.cf file to verify"));
691
-	puts(_("\t--no-check-cf\t\tSkip verification of sendmail.cf"));
692
-	puts(_("\t--sign\t\t\t-S\tAdd a hard-coded signature to each scanned message."));
693
-	puts(_("\t--signature-file=FILE\t-F FILE\tLocation of signature file."));
694
-	puts(_("\t--template-file=FILE\t-t FILE\tLocation of e-mail template file."));
695
-	puts(_("\t--template-headers=FILE\t\tLocation of e-mail headers for template file."));
696
-	puts(_("\t--timeout=SECS\t\t-T SECS\tTimeout waiting to childen to die."));
697
-	puts(_("\t--whitelist-file=FILE\t-W FILE\tLocation of the file of whitelisted addresses"));
698
-	puts(_("\t--version\t\t-V\tPrint the version number of this software."));
699
-#ifdef	CL_DEBUG
700
-	puts(_("\t--debug-level=n\t\t-x n\tSets the debug level to 'n'."));
701
-#endif
702
-	puts(_("\nFor more information type \"man clamav-milter\"."));
703
-	puts(_("For bug reports, please refer to http://www.clamav.net/bugs"));
704
-}
705
-
706
-extern char *optarg;
707
-int
708
-main(int argc, char **argv)
709
-{
710
-	int i, Bflag = 0, server = 0;
711
-	char *cfgfile = NULL;
712
-	const char *wont_blacklist = NULL;
713
-	const struct cfgstruct *cpt;
714
-	char version[VERSION_LENGTH + 1];
715
-	pthread_t tid;
716
-	struct rlimit rlim;
717
-#ifdef	CL_DEBUG
718
-	int consolefd;
719
-#endif
720
-
721
-	/*
722
-	 * The SMFI_VERSION checks are for Sendmail 8.14, which I don't have
723
-	 * yet, so I can't verify them
724
-	 * Patch from Andy Fiddaman <clam@fiddaman.net>
725
-	 */
726
-	struct smfiDesc smfilter = {
727
-		"ClamAv", /* filter name */
728
-		SMFI_VERSION,	/* version code -- leave untouched */
729
-		SMFIF_ADDHDRS|SMFIF_CHGHDRS,	/* flags - we add and delete headers */
730
-		clamfi_connect, /* connexion callback */
731
-#ifdef	CL_DEBUG
732
-		clamfi_helo,	/* HELO filter callback */
733
-#else
734
-		NULL,
735
-#endif
736
-		clamfi_envfrom, /* envelope sender filter callback */
737
-		clamfi_envrcpt, /* envelope recipient filter callback */
738
-		clamfi_header,	/* header filter callback */
739
-		clamfi_eoh,	/* end of header callback */
740
-		clamfi_body,	/* body filter callback */
741
-		clamfi_eom,	/* end of message callback */
742
-		clamfi_abort,	/* message aborted callback */
743
-		clamfi_close,	/* connexion cleanup callback */
744
-#if	SMFI_VERSION > 2
745
-		NULL,		/* Unrecognised command */
746
-#endif
747
-#if	SMFI_VERSION > 3
748
-		NULL,		/* DATA command callback */
749
-#endif
750
-#if	SMFI_VERSION >= 0x01000000
751
-		NULL,		/* Negotiation callback */
752
-#endif
753
-	};
754
-
755
-#if defined(CL_DEBUG) && defined(C_LINUX)
756
-	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
757
-	if(setrlimit(RLIMIT_CORE, &rlim) < 0)
758
-		perror("setrlimit");
759
-#endif
760
-
761
-	/*
762
-	 * Temporarily enter guessed value into version, will
763
-	 * be overwritten later by the value returned by clamd
764
-	 */
765
-	snprintf(version, sizeof(version) - 1,
766
-		"ClamAV version %s, clamav-milter version %s",
767
-		cl_retver(), get_version());
768
-
769
-	progname = strrchr(argv[0], '/');
770
-	if(progname)
771
-		progname++;
772
-	else
773
-		progname = "clamav-milter";
774
-
775
-#ifdef	C_LINUX
776
-	setlocale(LC_ALL, "");
777
-	bindtextdomain(progname, DATADIR"/clamav-milter/locale");
778
-	textdomain(progname);
779
-#endif
780
-
781
-	for(;;) {
782
-		int opt_index = 0;
783
-#ifdef	BOUNCE
784
-#ifdef	CL_DEBUG
785
-		const char *args = "a:AbB:c:C:dDefF:I:i:k:K:lLm:M:nNop:PqQ:r:R:hHs:St:T:U:VwW:x:z0:1:2";
786
-#else
787
-		const char *args = "a:AbB:c:C:dDefF:I:i:k:K:lLm:M:nNop:PqQ:r:R:hHs:St:T:U:VwW:z0:1:2";
788
-#endif
789
-#else	/*!BOUNCE*/
790
-#ifdef	CL_DEBUG
791
-		const char *args = "a:AB:c:C:dDefF:I:i:k:K:lLm:M:nNop:PqQ:r:R:hHs:St:T:U:VwW:x:z0:1:2";
792
-#else
793
-		const char *args = "a:AB:c:C:dDefF:I:i:k:K:lLm:M:nNop:PqQ:r:R:hHs:St:T:U:VwW:z0:1:2";
794
-#endif
795
-#endif	/*BOUNCE*/
796
-
797
-		static struct option long_options[] = {
798
-			{
799
-				"from", 2, NULL, 'a'
800
-			},
801
-			{
802
-				"advisory", 0, NULL, 'A'
803
-			},
804
-#ifdef	BOUNCE
805
-			{
806
-				"bounce", 0, NULL, 'b'
807
-			},
808
-#endif
809
-			{
810
-				"broadcast", 2, NULL, 'B'
811
-			},
812
-			{
813
-				"config-file", 1, NULL, 'c'
814
-			},
815
-			{
816
-				"chroot", 1, NULL, 'C'
817
-			},
818
-			{
819
-				"detect-forged-local-address", 0, NULL, 'L'
820
-			},
821
-			{
822
-				"dont-blacklist", 1, NULL, 'K'
823
-			},
824
-			{
825
-				"dont-scan-on-error", 0, NULL, 'd'
826
-			},
827
-			{
828
-				"dont-wait", 0, NULL, 'w'
829
-			},
830
-			{
831
-				"dont-sanitise", 0, NULL, 'z'
832
-			},
833
-			{
834
-				"debug", 0, NULL, 'D'
835
-			},
836
-			{
837
-				"external", 0, NULL, 'e'
838
-			},
839
-			{
840
-				"force-scan", 0, NULL, 'f'
841
-			},
842
-			{
843
-				"headers", 0, NULL, 'H'
844
-			},
845
-			{
846
-				"help", 0, NULL, 'h'
847
-			},
848
-			{
849
-				"ignore", 1, NULL, 'I'
850
-			},
851
-			{
852
-				"pidfile", 1, NULL, 'i'
853
-			},
854
-			{
855
-				"blacklist-time", 1, NULL, 'k'
856
-			},
857
-			{
858
-				"local", 0, NULL, 'l'
859
-			},
860
-			{
861
-				"noreject", 0, NULL, 'N'
862
-			},
863
-			{
864
-				"noxheader", 0, NULL, 'n'
865
-			},
866
-			{
867
-				"outgoing", 0, NULL, 'o'
868
-			},
869
-			{
870
-				"postmaster", 1, NULL, 'p'
871
-			},
872
-			{
873
-				"postmaster-only", 0, NULL, 'P',
874
-			},
875
-			{
876
-				"quiet", 0, NULL, 'q'
877
-			},
878
-			{
879
-				"quarantine", 1, NULL, 'Q',
880
-			},
881
-			{
882
-				"report-phish", 1, NULL, 'r'
883
-			},
884
-			{
885
-				"report-phish-false-positives", 1, NULL, 'R'
886
-			},
887
-			{
888
-				"quarantine-dir", 1, NULL, 'U',
889
-			},
890
-			{
891
-				"max-children", 1, NULL, 'm'
892
-			},
893
-			{
894
-				"freshclam-monitor", 1, NULL, 'M'
895
-			},
896
-			{
897
-				"sendmail-cf", 1, NULL, '0'
898
-			},
899
-			{
900
-				"no-check-cf", 0, &checkCF, 0
901
-			},
902
-			{
903
-				"server", 1, NULL, 's'
904
-			},
905
-			{
906
-				"sign", 0, NULL, 'S'
907
-			},
908
-			{
909
-				"signature-file", 1, NULL, 'F'
910
-			},
911
-			{
912
-				"template-file", 1, NULL, 't'
913
-			},
914
-			{
915
-				"template-headers", 1, NULL, '1'
916
-			},
917
-			{
918
-				"timeout", 1, NULL, 'T'
919
-			},
920
-			{
921
-				"whitelist-file", 1, NULL, 'W'
922
-			},
923
-			{
924
-				"version", 0, NULL, 'V'
925
-			},
926
-			{
927
-				"black-hole-mode", 0, NULL, '2'
928
-			},
929
-#ifdef	CL_DEBUG
930
-			{
931
-				"debug-level", 1, NULL, 'x'
932
-			},
933
-#endif
934
-			{
935
-				NULL, 0, NULL, '\0'
936
-			}
937
-		};
938
-
939
-		int ret = getopt_long(argc, argv, args, long_options, &opt_index);
940
-
941
-		if(ret == -1)
942
-			break;
943
-  		else if(ret == 0)
944
-  			continue;
945
-
946
-		switch(ret) {
947
-			case 'a':	/* e-mail errors from here */
948
-				/*
949
-				 * optarg is optional - if you give --from
950
-				 * then the --from is set to the orginal,
951
-				 * probably forged, email address
952
-				 */
953
-				from = optarg;
954
-				break;
955
-			case 'A':
956
-				advisory++;
957
-				break;
958
-#ifdef	BOUNCE
959
-			case 'b':	/* bounce worms/viruses */
960
-				bflag++;
961
-				break;
962
-#endif
963
-			case 'B':	/* broadcast */
964
-				Bflag++;
965
-				if(optarg)
966
-					iface = optarg;
967
-				break;
968
-			case 'c':	/* where is clamd.conf? */
969
-				cfgfile = optarg;
970
-				break;
971
-			case 'C':	/* chroot */
972
-				rootdir = optarg;
973
-				break;
974
-			case 'd':	/* don't scan on error */
975
-				cl_error = SMFIS_ACCEPT;
976
-				break;
977
-			case 'D':	/* enable debug messages */
978
-				cl_debug();
979
-				break;
980
-			case 'e':	/* use clamd */
981
-				external++;
982
-				break;
983
-			case 'f':	/* force the scan */
984
-				fflag++;
985
-				break;
986
-			case 'h':
987
-				help();
988
-				return EX_OK;
989
-			case 'H':
990
-				hflag++;
991
-				break;
992
-			case 'i':	/* pidfile */
993
-				pidfile = optarg;
994
-				break;
995
-			case 'k':	/* blacklist time */
996
-				blacklist_time = atoi(optarg);
997
-				break;
998
-			case 'K':	/* don't black list given IP */
999
-				wont_blacklist = optarg;
1000
-				break;
1001
-			case 'I':	/* --ignore, -I hostname */
1002
-				/*
1003
-				 * Based on patch by jpd@louisiana.edu
1004
-				 */
1005
-				if(Iflag == IFLAG_MAX) {
1006
-					fprintf(stderr,
1007
-						_("%s: %s, -I may only be given %d times\n"),
1008
-							argv[0], optarg, IFLAG_MAX);
1009
-					return EX_USAGE;
1010
-				}
1011
-				if(!add_local_ip(optarg)) {
1012
-					fprintf(stderr,
1013
-						_("%s: Cannot convert -I%s to IPaddr\n"),
1014
-							argv[0], optarg);
1015
-					return EX_USAGE;
1016
-				}
1017
-				Iflag++;
1018
-				break;
1019
-			case 'l':	/* scan mail from the lan */
1020
-				lflag++;
1021
-				break;
1022
-			case 'L':	/* detect forged local addresses */
1023
-				detect_forged_local_address++;
1024
-				break;
1025
-			case 'm':	/* maximum number of children */
1026
-				max_children = atoi(optarg);
1027
-				break;
1028
-			case 'M':	/* how often to monitor for freshclam */
1029
-				freshclam_monitor = atoi(optarg);
1030
-				break;
1031
-			case 'n':	/* don't add X-Virus-Scanned */
1032
-				nflag++;
1033
-				smfilter.xxfi_flags &= ~(SMFIF_ADDHDRS|SMFIF_CHGHDRS);
1034
-				break;
1035
-			case 'N':	/* Do we reject mail or silently drop it */
1036
-				rejectmail = 0;
1037
-				break;
1038
-			case 'o':	/* scan outgoing mail */
1039
-				oflag++;
1040
-				break;
1041
-			case 'p':	/* postmaster e-mail address */
1042
-				postmaster = optarg;
1043
-				break;
1044
-			case 'P':	/* postmaster only */
1045
-				pflag++;
1046
-				break;
1047
-			case 'q':	/* send NO notification email */
1048
-				qflag++;
1049
-				break;
1050
-			case 'Q':	/* quarantine e-mail address */
1051
-				quarantine = optarg;
1052
-				smfilter.xxfi_flags |= SMFIF_CHGHDRS|SMFIF_ADDRCPT|SMFIF_DELRCPT;
1053
-				break;
1054
-			case 'r':	/* report phishing here */
1055
-				/* e.g. reportphishing@antiphishing.org */
1056
-				report = optarg;
1057
-				break;
1058
-			case 'R':	/* report phishing false positives here */
1059
-				report_fps = optarg;
1060
-				break;
1061
-			case 's':	/* server running clamd */
1062
-				server++;
1063
-				serverHostNames = optarg;
1064
-				break;
1065
-			case 'F':	/* signature file */
1066
-				sigFilename = optarg;
1067
-				signature = NULL;
1068
-				/* fall through */
1069
-			case 'S':	/* sign */
1070
-				smfilter.xxfi_flags |= SMFIF_CHGBODY;
1071
-				Sflag++;
1072
-				break;
1073
-			case 't':	/* e-mail template file */
1074
-				templateFile = optarg;
1075
-				break;
1076
-			case '1':	/* headers for the template file */
1077
-				templateHeaders = optarg;
1078
-				break;
1079
-			case '2':
1080
-				black_hole_mode++;
1081
-				break;
1082
-			case 'T':	/* time to wait for child to die */
1083
-				child_timeout = atoi(optarg);
1084
-				break;
1085
-			case 'U':	/* quarantine path */
1086
-				quarantine_dir = optarg;
1087
-				break;
1088
-			case 'V':
1089
-				puts(version);
1090
-				return EX_OK;
1091
-			case 'w':
1092
-				dont_wait++;
1093
-				break;
1094
-			case 'W':
1095
-				whitelistFile = optarg;
1096
-				break;
1097
-			case 'z':
1098
-				dont_sanitise=1;
1099
-				break;
1100
-			case '0':
1101
-				sendmailCF = optarg;
1102
-				break;
1103
-#ifdef	CL_DEBUG
1104
-			case 'x':
1105
-				debug_level = atoi(optarg);
1106
-				break;
1107
-#endif
1108
-			default:
1109
-#ifdef	CL_DEBUG
1110
-				fprintf(stderr, "Usage: %s [-b] [-c FILE] [-F FILE] [--max-children=num] [-e] [-l] [-o] [-p address] [-P] [-q] [-Q USER] [-s SERVER] [-S] [-x#] [-U PATH] [-M#] socket-addr\n", argv[0]);
1111
-#else
1112
-				fprintf(stderr, "Usage: %s [-b] [-c FILE] [-F FILE] [--max-children=num] [-e] [-l] [-o] [-p address] [-P] [-q] [-Q USER] [-s SERVER] [-S] [-U PATH] [-M#] socket-addr\n", argv[0]);
1113
-#endif
1114
-				return EX_USAGE;
1115
-		}
1116
-	}
1117
-
1118
-	/*
1119
-	 * Check sanity of --external and --server arguments
1120
-	 */
1121
-	if(server && !external) {
1122
-		fprintf(stderr,
1123
-			"%s: --server can only be used with --external\n",
1124
-			argv[0]);
1125
-		return EX_USAGE;
1126
-	}
1127
-#ifdef	SESSION
1128
-	if(!external) {
1129
-		fprintf(stderr,
1130
-			_("%s: SESSIONS mode requires --external\n"), argv[0]);
1131
-		return EX_USAGE;
1132
-	}
1133
-#endif
1134
-
1135
-	/* TODO: support freshclam's daemon notify if --external is not given */
1136
-
1137
-	if(optind == argc) {
1138
-		fprintf(stderr, _("%s: No socket-addr given\n"), argv[0]);
1139
-		return EX_USAGE;
1140
-	}
1141
-	port = argv[optind];
1142
-
1143
-	if(rootdir == NULL)	/* FIXME: Handle CHROOT */
1144
-		if(checkCF && verifyIncomingSocketName(port) < 0) {
1145
-			fprintf(stderr, _("%s: socket-addr (%s) doesn't agree with sendmail.cf\n"), argv[0], port);
1146
-			return EX_CONFIG;
1147
-		}
1148
-
1149
-	if(strncasecmp(port, "inet:", 5) == 0)
1150
-		if(!lflag) {
1151
-			/*
1152
-			 * Barmy but true. It seems that clamfi_connect will,
1153
-			 * in this case, get the IP address of the machine
1154
-			 * running sendmail, not of the machine sending the
1155
-			 * mail, so the remote end will be a local address so
1156
-			 * we must scan by enabling --local
1157
-			 *
1158
-			 * TODO: this is probably not needed if the remote
1159
-			 * machine is localhost, need to check though
1160
-			 */
1161
-			fprintf(stderr, _("%s: when using inet: connexion to sendmail you must enable --local\n"), argv[0]);
1162
-			return EX_USAGE;
1163
-		}
1164
-
1165
-	/*
1166
-	 * Sanity checks on the clamav configuration file
1167
-	 */
1168
-	if(cfgfile == NULL) {
1169
-		cfgfile = cli_malloc(strlen(CONFDIR) + 12);	/* leak */
1170
-		sprintf(cfgfile, "%s/clamd.conf", CONFDIR);
1171
-	}
1172
-	if((copt = getcfg(cfgfile, 1)) == NULL) {
1173
-		fprintf(stderr, _("%s: Can't parse the config file %s\n"),
1174
-			argv[0], cfgfile);
1175
-		return EX_CONFIG;
1176
-	}
1177
-
1178
-	if(detect_forged_local_address) {
1179
-		if(oflag) {
1180
-			fprintf(stderr, _("%s: --detect-forged-local-addresses is not compatible with --outgoing\n"), argv[0]);
1181
-			return EX_CONFIG;
1182
-		}
1183
-		if(lflag) {
1184
-			fprintf(stderr, _("%s: --detect-forged-local-addresses is not compatible with --local\n"), argv[0]);
1185
-			return EX_CONFIG;
1186
-		}
1187
-		if(fflag) {
1188
-			fprintf(stderr, _("%s: --detect-forged-local-addresses is not compatible with --force\n"), argv[0]);
1189
-			return EX_CONFIG;
1190
-		}
1191
-	}
1192
-
1193
-	if(Bflag) {
1194
-		int on;
1195
-
1196
-		broadcastSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1197
-		/*
1198
-		 * SO_BROADCAST doesn't sent to all NICs on Linux, it only
1199
-		 * broadcasts on eth0, which is why there's an optional argument
1200
-		 * to --broadcast to say which NIC to broadcast on. You can use
1201
-		 * SO_BINDTODEVICE to get around that, but you need to have
1202
-		 * uid == 0 for that
1203
-		 */
1204
-		on = 1;
1205
-		if(setsockopt(broadcastSock, SOL_SOCKET, SO_BROADCAST, (int *)&on, sizeof(on)) < 0) {
1206
-			perror("setsockopt");
1207
-			return EX_UNAVAILABLE;
1208
-		}
1209
-		shutdown(broadcastSock, SHUT_RD);
1210
-	}
1211
-
1212
-	/*
1213
-	 * Drop privileges
1214
-	 */
1215
-#ifdef	CL_DEBUG
1216
-	/* Save the fd for later, open while we can */
1217
-	consolefd = open(console, O_WRONLY);
1218
-#endif
1219
-
1220
-	if(getuid() == 0) {
1221
-		if(iface) {
1222
-#ifdef	SO_BINDTODEVICE
1223
-			struct ifreq ifr;
1224
-
1225
-			memset(&ifr, '\0', sizeof(struct ifreq));
1226
-			strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
1227
-			ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';
1228
-			if(setsockopt(broadcastSock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
1229
-				perror(iface);
1230
-				return EX_CONFIG;
1231
-			}
1232
-#else
1233
-			fprintf(stderr, _("%s: The iface option to --broadcast is not supported on your operating system\n"), argv[0]);
1234
-			return EX_CONFIG;
1235
-#endif
1236
-		}
1237
-
1238
-		if(((cpt = cfgopt(copt, "User")) != NULL) && cpt->enabled) {
1239
-			const struct passwd *user;
1240
-
1241
-			if((user = getpwnam(cpt->strarg)) == NULL) {
1242
-				fprintf(stderr, _("%s: Can't get information about user %s\n"), argv[0], cpt->strarg);
1243
-				return EX_CONFIG;
1244
-			}
1245
-
1246
-			if(cfgopt(copt, "AllowSupplementaryGroups")->enabled) {
1247
-#ifdef HAVE_INITGROUPS
1248
-				if(initgroups(cpt->strarg, user->pw_gid) < 0) {
1249
-					perror(cpt->strarg);
1250
-					return EX_CONFIG;
1251
-				}
1252
-#else
1253
-				fprintf(stderr, _("%s: AllowSupplementaryGroups: initgroups not supported.\n"),
1254
-					argv[0]);
1255
-				return EX_CONFIG;
1256
-#endif
1257
-			} else {
1258
-#ifdef	HAVE_SETGROUPS
1259
-				if(setgroups(1, &user->pw_gid) < 0) {
1260
-					perror(cpt->strarg);
1261
-					return EX_CONFIG;
1262
-				}
1263
-#endif
1264
-			}
1265
-
1266
-			setgid(user->pw_gid);
1267
-
1268
-			if(setuid(user->pw_uid) < 0)
1269
-				perror(cpt->strarg);
1270
-#ifdef	CL_DEBUG
1271
-			else
1272
-				printf(_("Running as user %s (UID %d, GID %d)\n"),
1273
-					cpt->strarg, (int)user->pw_uid,
1274
-					(int)user->pw_gid);
1275
-#endif
1276
-
1277
-			/*
1278
-			 * Note, some O/Ss (e.g. OpenBSD/Fedora Linux) FORCE
1279
-			 * you to run as root in black-hole-mode because
1280
-			 * /var/spool/mqueue is mode 700 owned by root!
1281
-			 * Flames to them, not to me, please.
1282
-			 */
1283
-			if(black_hole_mode && (user->pw_uid != 0)) {
1284
-				int are_trusted;
1285
-				FILE *sendmail;
1286
-				char cmd[128];
1287
-
1288
-				/*
1289
-				 * Determine if we're a "trusted user"
1290
-				 */
1291
-				snprintf(cmd, sizeof(cmd) - 1, "%s -bv root</dev/null 2>&1",
1292
-					SENDMAIL_BIN);
1293
-
1294
-				sendmail = popen(cmd, "r");
1295
-
1296
-				if(sendmail == NULL) {
1297
-					perror(SENDMAIL_BIN);
1298
-					are_trusted = 0;
1299
-				} else {
1300
-					int status;
1301
-					char buf[BUFSIZ];
1302
-
1303
-					while(fgets(buf, sizeof(buf), sendmail) != NULL)
1304
-						;
1305
-					/*
1306
-					 * Can't do
1307
-					 * switch(WEXITSTATUS(pclose(sendmail)))
1308
-					 * because that fails to compile on
1309
-					 * NetBSD2.0
1310
-					 */
1311
-					status = pclose(sendmail);
1312
-					switch(WEXITSTATUS(status)) {
1313
-						case EX_NOUSER:
1314
-							/*
1315
-							 * No root? But at least
1316
-							 * we're trusted enough
1317
-							 * to find out!
1318
-							 */
1319
-							are_trusted = 1;
1320
-							break;
1321
-						default:
1322
-							are_trusted = 0;
1323
-							break;
1324
-						case EX_OK:
1325
-							are_trusted = 1;
1326
-					}
1327
-				}
1328
-				if(!are_trusted) {
1329
-					fprintf(stderr, _("%s: You cannot use black hole mode unless %s is a TrustedUser\n"),
1330
-						argv[0], cpt->strarg);
1331
-					return EX_CONFIG;
1332
-				}
1333
-			}
1334
-		} else
1335
-			printf(_("^%s: running as root is not recommended (check \"User\" in %s)\n"), argv[0], cfgfile);
1336
-	} else if(iface) {
1337
-		fprintf(stderr, _("%s: Only root can set an interface for --broadcast\n"), argv[0]);
1338
-		return EX_USAGE;
1339
-	}
1340
-
1341
-	if(advisory && quarantine) {
1342
-		fprintf(stderr, _("%s: Advisory mode doesn't work with quarantine mode\n"), argv[0]);
1343
-		return EX_USAGE;
1344
-	}
1345
-	if(quarantine_dir) {
1346
-		struct stat statb;
1347
-
1348
-		if(advisory) {
1349
-			fprintf(stderr,
1350
-				_("%s: Advisory mode doesn't work with quarantine directories\n"),
1351
-				argv[0]);
1352
-			return EX_USAGE;
1353
-		}
1354
-		if(strstr(quarantine_dir, "ERROR") != NULL) {
1355
-			fprintf(stderr,
1356
-				_("%s: the quarantine directory must not contain the string 'ERROR'\n"),
1357
-				argv[0]);
1358
-			return EX_USAGE;
1359
-		}
1360
-		if(strstr(quarantine_dir, "FOUND") != NULL) {
1361
-			fprintf(stderr,
1362
-				_("%s: the quarantine directory must not contain the string 'FOUND'\n"),
1363
-				argv[0]);
1364
-			return EX_USAGE;
1365
-		}
1366
-		if(strstr(quarantine_dir, "OK") != NULL) {
1367
-			fprintf(stderr,
1368
-				_("%s: the quarantine directory must not contain the string 'OK'\n"),
1369
-				argv[0]);
1370
-			return EX_USAGE;
1371
-		}
1372
-		if(access(quarantine_dir, W_OK) < 0) {
1373
-			perror(quarantine_dir);
1374
-			return EX_USAGE;
1375
-		}
1376
-		if(stat(quarantine_dir, &statb) < 0) {
1377
-			perror(quarantine_dir);
1378
-			return EX_USAGE;
1379
-		}
1380
-		/*
1381
-		 * Quit if the quarantine directory is publically readable
1382
-		 * or writeable
1383
-		 */
1384
-		if(statb.st_mode & 077) {
1385
-			fprintf(stderr, _("%s: insecure quarantine directory %s (mode 0%o)\n"),
1386
-				argv[0], quarantine_dir, (int)statb.st_mode & 0777);
1387
-			return EX_CONFIG;
1388
-		}
1389
-	}
1390
-
1391
-	if(sigFilename && !updateSigFile())
1392
-		return EX_USAGE;
1393
-
1394
-	if(templateFile && (access(templateFile, R_OK) < 0)) {
1395
-		perror(templateFile);
1396
-		return EX_CONFIG;
1397
-	}
1398
-	if(templateHeaders) {
1399
-		if(templateFile == NULL) {
1400
-			fputs(("%s: --template-headers requires --template-file\n"),
1401
-				stderr);
1402
-			return EX_CONFIG;
1403
-		}
1404
-		if(access(templateHeaders, R_OK) < 0) {
1405
-			perror(templateHeaders);
1406
-			return EX_CONFIG;
1407
-		}
1408
-	}
1409
-	if(whitelistFile && (access(whitelistFile, R_OK) < 0)) {
1410
-		perror(whitelistFile);
1411
-		return EX_CONFIG;
1412
-	}
1413
-
1414
-	/*
1415
-	 * If the --max-children flag isn't set, see if MaxThreads
1416
-	 * is set in the config file. Based on an idea by "Richard G. Roberto"
1417
-	 * <rgr@dedlegend.com>
1418
-	 */
1419
-	if((max_children == 0) && ((cpt = cfgopt(copt, "MaxThreads")) != NULL))
1420
-		max_children = cfgopt(copt, "MaxThreads")->numarg;
1421
-
1422
-#ifdef HAVE_LRESOLV_R
1423
-	/* allocate a pool of resolvers */
1424
-	if(!(res_pool=cli_calloc(max_children+1, sizeof(*res_pool))))
1425
-		return EX_OSERR;
1426
-	if(!(res_pool_state=cli_malloc(max_children+1)))
1427
-		return EX_OSERR;
1428
-	memset(res_pool_state, 1, max_children+1);
1429
-	for(i = 0; i < max_children+1; i++)
1430
-		res_ninit(&res_pool[i]);
1431
-#endif
1432
-
1433
-	if((cpt = cfgopt(copt, "ReadTimeout")) != NULL) {
1434
-		readTimeout = cpt->numarg;
1435
-
1436
-		if(readTimeout < 0) {
1437
-			fprintf(stderr, _("%s: ReadTimeout must not be negative in %s\n"),
1438
-				argv[0], cfgfile);
1439
-			return EX_CONFIG;
1440
-		}
1441
-	}
1442
-
1443
-	if((cpt = cfgopt(copt, "StreamMaxLength")) != NULL) {
1444
-		streamMaxLength = (long)cpt->numarg;
1445
-		if(streamMaxLength < 0L) {
1446
-			fprintf(stderr, _("%s: StreamMaxLength must not be negative in %s\n"),
1447
-			argv[0], cfgfile);
1448
-			return EX_CONFIG;
1449
-		}
1450
-	}
1451
-
1452
-	if(((cpt = cfgopt(copt, "LogSyslog")) != NULL) && cpt->enabled) {
1453
-#if defined(USE_SYSLOG) && !defined(C_AIX)
1454
-		int fac = LOG_LOCAL6;
1455
-#endif
1456
-
1457
-		if(cfgopt(copt, "LogVerbose")->enabled) {
1458
-			logg_verbose = 1;
1459
-#ifdef	CL_DEBUG
1460
-#if	((SENDMAIL_VERSION_A > 8) || ((SENDMAIL_VERSION_A == 8) && (SENDMAIL_VERSION_B >= 13)))
1461
-			if(debug_level >= 15)
1462
-				smfi_setdbg(6);
1463
-#endif
1464
-#endif
1465
-		}
1466
-#if defined(USE_SYSLOG) && !defined(C_AIX)
1467
-		logg_syslog = 1;
1468
-
1469
-		if(((cpt = cfgopt(copt, "LogFacility")) != NULL) && cpt->enabled)
1470
-			if((fac = logg_facility(cpt->strarg)) == -1) {
1471
-				fprintf(stderr, "%s: LogFacility: %s: No such facility\n",
1472
-					argv[0], cpt->strarg);
1473
-				return EX_CONFIG;
1474
-			}
1475
-		openlog(progname, LOG_CONS|LOG_PID, fac);
1476
-#endif
1477
-	} else {
1478
-		if(qflag)
1479
-			fprintf(stderr, _("%s: (-q && !LogSyslog): warning - all interception message methods are off\n"),
1480
-				argv[0]);
1481
-#if defined(USE_SYSLOG) && !defined(C_AIX)
1482
-		logg_syslog = 0;
1483
-#endif
1484
-	}
1485
-	/*
1486
-	 * Get the outgoing socket details - the way to talk to clamd, unless
1487
-	 * we're doing the scanning internally
1488
-	 */
1489
-	if(!external) {
1490
-#ifdef	C_LINUX
1491
-		const char *lang;
1492
-#endif
1493
-
1494
-		if(max_children == 0) {
1495
-			fprintf(stderr, _("%s: --max-children must be given if --external is not given\n"), argv[0]);
1496
-			return EX_CONFIG;
1497
-		}
1498
-		if(freshclam_monitor <= 0) {
1499
-			fprintf(stderr, _("%s: --freshclam_monitor must be at least one second\n"), argv[0]);
1500
-			return EX_CONFIG;
1501
-		}
1502
-#ifdef	C_LINUX
1503
-		lang = getenv("LANG");
1504
-
1505
-		if(lang && (strstr(lang, "UTF-8") != NULL)) {
1506
-			fprintf(stderr, "Your LANG environment variable is set to '%s'\n", lang);
1507
-			fprintf(stderr, "This is known to cause problems for some %s installations.\n", argv[0]);
1508
-			fputs("If you get failures with temporary files, please try again with LANG unset.\n", stderr);
1509
-		}
1510
-#endif
1511
-#if	0
1512
-		if(child_timeout) {
1513
-			fprintf(stderr, _("%s: --timeout must not be given if --external is not given\n"), argv[0]);
1514
-			return EX_CONFIG;
1515
-		}
1516
-#endif
1517
-		if (cl_init(CL_INIT_DEFAULT)!=CL_SUCCESS) {
1518
-			fprintf(stderr, "%s: Failed to initialize libclamav, bailing out.\n", argv[0]);
1519
-			return EX_UNAVAILABLE;
1520
-		}
1521
-		if(loadDatabase() != 0) {
1522
-			/*
1523
-			 * Handle the dont-scan-on-error option, which says
1524
-			 * that we pass on emails, unscanned, if an error has
1525
-			 * occurred
1526
-			 */
1527
-			if(cl_error != SMFIS_ACCEPT)
1528
-				return EX_CONFIG;
1529
-
1530
-			fprintf(stderr, _("%s: No emails will be scanned"),
1531
-				argv[0]);
1532
-		}
1533
-		numServers = 1;
1534
-	} else if(((cpt = cfgopt(copt, "LocalSocket")) != NULL) && cpt->enabled) {
1535
-#ifdef	SESSION
1536
-		struct sockaddr_un sockun;
1537
-#endif
1538
-		char *sockname = NULL;
1539
-
1540
-		if(cfgopt(copt, "TCPSocket")->enabled) {
1541
-			fprintf(stderr, _("%s: You can select one server type only (local/TCP) in %s\n"),
1542
-				argv[0], cfgfile);
1543
-			return EX_CONFIG;
1544
-		}
1545
-		if(server) {
1546
-			fprintf(stderr, _("%s: You cannot use the --server option when using LocalSocket in %s\n"),
1547
-				argv[0], cfgfile);
1548
-			return EX_USAGE;
1549
-		}
1550
-		if(strncasecmp(port, "unix:", 5) == 0)
1551
-			sockname = &port[5];
1552
-		else if(strncasecmp(port, "local:", 6) == 0)
1553
-			sockname = &port[6];
1554
-
1555
-		if(sockname && (strcmp(sockname, cpt->strarg) == 0)) {
1556
-			fprintf(stderr, _("The connexion from sendmail to %s (%s) must not\n"),
1557
-				argv[0], sockname);
1558
-			fprintf(stderr, _("be the same as the connexion to clamd (%s) in %s\n"),
1559
-				cpt->strarg, cfgfile);
1560
-			return EX_CONFIG;
1561
-		}
1562
-		/*
1563
-		 * TODO: check --server hasn't been set
1564
-		 */
1565
-		localSocket = cpt->strarg;
1566
-#ifndef	SESSION
1567
-		if(!pingServer(-1)) {
1568
-			fprintf(stderr, _("Can't talk to clamd server via %s\n"),
1569
-				localSocket);
1570
-			fprintf(stderr, _("Check your entry for LocalSocket in %s\n"),
1571
-				cfgfile);
1572
-			return EX_CONFIG;
1573
-		}
1574
-#endif
1575
-		/*if(quarantine_dir == NULL)
1576
-			fprintf(stderr, _("When using Localsocket in %s\nyou may improve performance if you use the --quarantine-dir option\n"), cfgfile);*/
1577
-
1578
-		umask(077);
1579
-
1580
-		serverIPs = (in_addr_t *)cli_malloc(sizeof(in_addr_t));
1581
-#ifdef	INADDR_LOOPBACK
1582
-		serverIPs[0] = htonl(INADDR_LOOPBACK);
1583
-#else
1584
-		serverIPs[0] = inet_addr("127.0.0.1");
1585
-#endif
1586
-
1587
-#ifdef	SESSION
1588
-		memset((char *)&sockun, 0, sizeof(struct sockaddr_un));
1589
-		sockun.sun_family = AF_UNIX;
1590
-		strncpy(sockun.sun_path, localSocket, sizeof(sockun.sun_path));
1591
-		sockun.sun_path[sizeof(sockun.sun_path)-1]='\0';
1592
-
1593
-		sessions = (struct session *)cli_malloc(sizeof(struct session));
1594
-		if((sessions[0].sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
1595
-			perror(localSocket);
1596
-			fprintf(stderr, _("Can't talk to clamd server via %s\n"),
1597
-				localSocket);
1598
-			fprintf(stderr, _("Check your entry for LocalSocket in %s\n"),
1599
-				cfgfile);
1600
-			return EX_CONFIG;
1601
-		}
1602
-		if(connect(sessions[0].sock, (struct sockaddr *)&sockun, sizeof(struct sockaddr_un)) < 0) {
1603
-			perror(localSocket);
1604
-			return EX_UNAVAILABLE;
1605
-		}
1606
-		if(send(sessions[0].sock, "SESSION\n", 8, 0) < 8) {
1607
-			perror("send");
1608
-			fputs(_("!Can't create a clamd session"), stderr);
1609
-			return EX_UNAVAILABLE;
1610
-		}
1611
-		sessions[0].status = CMDSOCKET_FREE;
1612
-#endif
1613
-		/*
1614
-		 * FIXME: Allow connexion to remote servers by TCP/IP whilst
1615
-		 * connecting to the localserver via a UNIX domain socket
1616
-		 */
1617
-		numServers = 1;
1618
-	} else if(((cpt = cfgopt(copt, "TCPSocket")) != NULL) && cpt->enabled) {
1619
-		int activeServers;
1620
-
1621
-		/*
1622
-		 * TCPSocket is in fact a port number not a full socket
1623
-		 */
1624
-		if(quarantine_dir) {
1625
-			fprintf(stderr, _("%s: --quarantine-dir not supported for TCPSocket - use --quarantine\n"), argv[0]);
1626
-			return EX_CONFIG;
1627
-		}
1628
-
1629
-		tcpSocket = (in_port_t)cpt->numarg;
1630
-
1631
-		/*
1632
-		 * cli_strtok's fieldno counts from 0
1633
-		 */
1634
-		for(;;) {
1635
-			char *hostname = cli_strtok(serverHostNames, numServers, ":");
1636
-			if(hostname == NULL)
1637
-				break;
1638
-#ifdef	MAXHOSTNAMELEN
1639
-			if(strlen(hostname) > MAXHOSTNAMELEN) {
1640
-				fprintf(stderr, _("%s: hostname %s is longer than %d characters\n"),
1641
-					argv[0], hostname, MAXHOSTNAMELEN);
1642
-				return EX_CONFIG;
1643
-			}
1644
-#endif
1645
-			numServers++;
1646
-			free(hostname);
1647
-		}
1648
-
1649
-#ifdef	CL_DEBUG
1650
-		printf("numServers: %d\n", numServers);
1651
-#endif
1652
-
1653
-		serverIPs = (in_addr_t *)cli_malloc(numServers * sizeof(in_addr_t));
1654
-		if(serverIPs == NULL)
1655
-			return EX_OSERR;
1656
-		activeServers = 0;
1657
-
1658
-#ifdef	SESSION
1659
-		/*
1660
-		 * We need to know how many connexion to establish to clamd
1661
-		 */
1662
-		if(max_children == 0) {
1663
-			fprintf(stderr, _("%s: --max-children must be given in sessions mode\n"), argv[0]);
1664
-			return EX_CONFIG;
1665
-		}
1666
-#endif
1667
-
1668
-		if(numServers > max_children) {
1669
-			fprintf(stderr, _("%1$s: --max-children (%2$d) is lower than the number of servers you have (%3$d)\n"),
1670
-				argv[0], max_children, numServers);
1671
-			return EX_CONFIG;
1672
-		}
1673
-
1674
-		for(i = 0; i < numServers; i++) {
1675
-#ifdef	MAXHOSTNAMELEN
1676
-			char hostname[MAXHOSTNAMELEN + 1];
1677
-
1678
-			if(cli_strtokbuf(serverHostNames, i, ":", hostname) == NULL)
1679
-				break;
1680
-#else
1681
-			char *hostname = cli_strtok(serverHostNames, i, ":");
1682
-#endif
1683
-
1684
-			/*
1685
-			 * Translate server's name to IP address
1686
-			 */
1687
-			serverIPs[i] = inet_addr(hostname);
1688
-#ifdef	INADDR_NONE
1689
-			if(serverIPs[i] == INADDR_NONE) {
1690
-#else
1691
-			if(serverIPs[i] == (in_addr_t)-1) {
1692
-#endif
1693
-				const struct hostent *h = gethostbyname(hostname);
1694
-
1695
-				if(h == NULL) {
1696
-					fprintf(stderr, _("%s: Unknown host %s\n"),
1697
-						argv[0], hostname);
1698
-					return EX_USAGE;
1699
-				}
1700
-
1701
-				memcpy((char *)&serverIPs[i], h->h_addr, sizeof(serverIPs[i]));
1702
-			}
1703
-
1704
-#if	defined(NTRIES) && ((NTRIES > 1))
1705
-#ifndef	SESSION
1706
-#ifdef	INADDR_LOOPBACK
1707
-			if(serverIPs[i] == htonl(INADDR_LOOPBACK)) {
1708
-#else
1709
-#if	HAVE_IN_ADDR_T
1710
-			if(serverIPs[i] == (in_addr_t)inet_addr("127.0.0.1")) {
1711
-#else
1712
-			if(serverIPs[i] == (long)inet_addr("127.0.0.1")) {
1713
-#endif
1714
-#endif
1715
-				int tries;
1716
-
1717
-				/*
1718
-				 * Fudge to allow clamd to come up on
1719
-				 * our local machine
1720
-				 */
1721
-				for(tries = 0; tries < NTRIES - 1; tries++) {
1722
-					if(pingServer(i))
1723
-						break;
1724
-					if(checkClamd(1))	/* will try all servers */
1725
-						break;
1726
-					puts(_("Waiting for clamd to come up"));
1727
-					/*
1728
-					 * something to do as the system starts
1729
-					 */
1730
-					sync();
1731
-					sleep(1);
1732
-				}
1733
-				/* Will try one more time */
1734
-			}
1735
-#endif	/* NTRIES > 1 */
1736
-
1737
-			if(pingServer(i))
1738
-				activeServers++;
1739
-			else {
1740
-				printf(_("Can't talk to clamd server %s on port %d\n"),
1741
-					hostname, tcpSocket);
1742
-				if(serverIPs[i] == htonl(INADDR_LOOPBACK)) {
1743
-					if(cfgopt(copt, "TCPAddr")->enabled)
1744
-						printf(_("Check the value for TCPAddr in %s\n"), cfgfile);
1745
-				} else
1746
-					printf(_("Check the value for TCPAddr in clamd.conf on %s\n"), hostname);
1747
-			}
1748
-#endif
1749
-
1750
-#ifndef	MAXHOSTNAMELEN
1751
-			free(hostname);
1752
-#endif
1753
-		}
1754
-#ifdef	SESSION
1755
-		activeServers = numServers;
1756
-
1757
-		sessions = (struct session *)cli_calloc(max_children, sizeof(struct session));
1758
-		for(i = 0; i < (int)max_children; i++)
1759
-			if(createSession(i) < 0)
1760
-				return EX_UNAVAILABLE;
1761
-		if(activeServers == 0) {
1762
-			fprintf(stderr, _("Check your entry for TCPSocket in %s\n"),
1763
-				cfgfile);
1764
-		}
1765
-#else
1766
-		if(activeServers == 0) {
1767
-			fprintf(stderr, _("Check your entry for TCPSocket in %s\n"),
1768
-				cfgfile);
1769
-			fputs(_("Can't find any clamd server\n"), stderr);
1770
-			return EX_CONFIG;
1771
-		}
1772
-		last_failed_pings = (time_t *)cli_calloc(numServers, sizeof(time_t));
1773
-#endif
1774
-	} else {
1775
-		fprintf(stderr, _("%s: You must select server type (local/TCP) in %s\n"),
1776
-			argv[0], cfgfile);
1777
-		return EX_CONFIG;
1778
-	}
1779
-
1780
-#ifdef	SESSION
1781
-	if(!external) {
1782
-		if(clamav_versions == NULL) {
1783
-			clamav_versions = (char **)cli_malloc(sizeof(char *));
1784
-			if(clamav_versions == NULL)
1785
-				return EX_TEMPFAIL;
1786
-			clamav_version = cli_strdup(version);
1787
-		}
1788
-	} else {
1789
-		unsigned int session;
1790
-
1791
-		/*
1792
-		 * We need to know how many connexions to establish to clamd
1793
-		 */
1794
-		if(max_children == 0) {
1795
-			fprintf(stderr, _("%s: --max-children must be given in sessions mode\n"), argv[0]);
1796
-			return EX_CONFIG;
1797
-		}
1798
-
1799
-		clamav_versions = (char **)cli_malloc(max_children * sizeof(char *));
1800
-		if(clamav_versions == NULL)
1801
-			return EX_TEMPFAIL;
1802
-
1803
-		for(session = 0; session < max_children; session++) {
1804
-			clamav_versions[session] = cli_strdup(version);
1805
-			if(clamav_versions[session] == NULL)
1806
-				return EX_TEMPFAIL;
1807
-		}
1808
-	}
1809
-#else
1810
-	strcpy(clamav_version, version);
1811
-#endif
1812
-
1813
-	if(((quarantine_dir == NULL) && localSocket) || !external) {
1814
-		/* set the temporary dir */
1815
-		if((cpt = cfgopt(copt, "TemporaryDirectory")) && cpt->enabled)
1816
-			tmpdir = cpt->strarg;
1817
-		else 
1818
-			tmpdir = cli_gentemp(NULL);
1819
-
1820
-		logg("#Making %s\n", tmpdir);
1821
-
1822
-		if(mkdir(tmpdir, 0700)) {
1823
-			perror(tmpdir);
1824
-			return EX_CANTCREAT;
1825
-		}
1826
-	} else
1827
-		tmpdir = NULL;
1828
-
1829
-	if(report) {
1830
-		if(!cfgopt(copt, "PhishingSignatures")->enabled) {
1831
-			fprintf(stderr, "%s: You have chosen --report-phish, but PhishingSignatures is off in %s\n",
1832
-				argv[0], cfgfile);
1833
-			return EX_USAGE;
1834
-		}
1835
-		if((quarantine_dir == NULL) && (tmpdir == NULL)) {
1836
-			/*
1837
-			 * Limitation: doesn't store message in a temporary
1838
-			 * file, so we won't be able to use mail < file
1839
-			 */
1840
-			fprintf(stderr, "%s: when using --external, --report-phish cannot be used without either LocalSocket or --quarantine-dir\n",
1841
-				argv[0]);
1842
-			return EX_USAGE;
1843
-		}
1844
-		if(lflag) {
1845
-			/*
1846
-			 * Naturally, if you attempt to scan the phish you've
1847
-			 * just reported, it'll be blocked!
1848
-			 */
1849
-			fprintf(stderr, "%s: --report-phish cannot be used with --local\n",
1850
-				argv[0]);
1851
-			return EX_USAGE;
1852
-		}
1853
-	}
1854
-	if(report_fps)
1855
-		if(!cfgopt(copt, "PhishingSignatures")->enabled) {
1856
-			fprintf(stderr, "%s: You have chosen --report-phish-false-positives, but PhishingSignatures is off in %s\n",
1857
-				argv[0], cfgfile);
1858
-			return EX_USAGE;
1859
-		}
1860
-
1861
-	if(cfgopt(copt, "Foreground")->enabled)
1862
-		logg_foreground = 1;
1863
-	else {
1864
-		logg_foreground = 0;
1865
-#ifdef	CL_DEBUG
1866
-		printf(_("When debugging it is recommended that you use Foreground mode in %s\n"), cfgfile);
1867
-		puts(_("\tso that you can see all of the messages"));
1868
-#endif
1869
-
1870
-		switch(fork()) {
1871
-			case -1:
1872
-				perror("fork");
1873
-				return EX_OSERR;
1874
-			case 0:	/* child */
1875
-				break;
1876
-			default:	/* parent */
1877
-				return EX_OK;
1878
-		}
1879
-		close(0);
1880
-		open("/dev/null", O_RDONLY);
1881
-
1882
-		/* initialize logger */
1883
-		logg_time = cfgopt(copt, "LogTime")->enabled;
1884
-		logok = cfgopt(copt, "LogClean")->enabled;
1885
-		logg_size = cfgopt(copt, "LogFileMaxSize")->numarg;
1886
-		logg_verbose = mprintf_verbose = cfgopt(copt, "LogVerbose")->enabled;
1887
-
1888
-		if(cfgopt(copt, "Debug")->enabled) /* enable debug messages in libclamav */
1889
-			cl_debug();
1890
-
1891
-		if((cpt = cfgopt(copt, "LogFile"))->enabled) {
1892
-			time_t currtime;
1893
-
1894
-			logg_file = cpt->strarg;
1895
-			if((strlen(logg_file) < 2) ||
1896
-			   ((logg_file[0] != '/') && (logg_file[0] != '\\') && (logg_file[1] != ':'))) {
1897
-				fprintf(stderr, "ERROR: LogFile requires full path.\n");
1898
-				logg_close();
1899
-				freecfg(copt);
1900
-				return 1;
1901
-			}
1902
-			time(&currtime);
1903
-			close(1);
1904
-			if(logg("#ClamAV-milter started at %s", ctime(&currtime))) {
1905
-				fprintf(stderr, "ERROR: Problem with internal logger. Please check the permissions on the %s file.\n", logg_file);
1906
-				logg_close();
1907
-				freecfg(copt);
1908
-				return 1;
1909
-			}
1910
-		} else {
1911
-#ifdef	CL_DEBUG
1912
-			close(1);
1913
-			logg_file = console;
1914
-			if(consolefd < 0) {
1915
-				perror(console);
1916
-				return EX_OSFILE;
1917
-			}
1918
-			dup(consolefd);
1919
-#else
1920
-			int fds[3];
1921
-			logg_file = NULL;
1922
-			if(chdir("/") < 0)
1923
-				perror("/");
1924
-			fds[0] = open("/dev/null", O_RDONLY);
1925
-			fds[1] = open("/dev/null", O_WRONLY);
1926
-			fds[2] = open("/dev/null", O_WRONLY);
1927
-			for(i = 0; i <= 2; i++) {
1928
-				if(fds[i] == -1 || dup2(fds[i], i) == -1) {
1929
-					fprintf(stderr, "ERROR: failed to daemonize.\n");
1930
-					logg_close();
1931
-					freecfg(copt);
1932
-					return 1;
1933
-				}
1934
-			}
1935
-#endif
1936
-		}
1937
-
1938
-		dup2(1, 2);
1939
-
1940
-#ifdef	CL_DEBUG
1941
-		if(consolefd >= 0)
1942
-			close(consolefd);
1943
-#endif
1944
-
1945
-#ifdef HAVE_SETPGRP
1946
-#ifdef SETPGRP_VOID
1947
-		setpgrp();
1948
-#else
1949
-		setpgrp(0,0);
1950
-#endif
1951
-#else
1952
-#ifdef HAVE_SETSID
1953
-		setsid();
1954
-#endif
1955
-#endif
1956
-	}
1957
-
1958
-	if(cfgopt(copt, "Debug")->enabled)
1959
-		/*
1960
-		 * enable debug messages in libclamav, --debug also does this
1961
-		 */
1962
-		cl_debug();
1963
-
1964
-	atexit(quit);
1965
-
1966
-	if(!external) {
1967
-		if(!cfgopt(copt, "ScanMail")->enabled)
1968
-			printf(_("%s: ScanMail not defined in %s (needed without --external), enabling\n"),
1969
-				argv[0], cfgfile);
1970
-
1971
-		options |= CL_SCAN_MAIL;	/* no choice */
1972
-		/*if(!cfgopt(copt, "ScanRAR")->enabled)
1973
-			options |= CL_SCAN_DISABLERAR;*/
1974
-		if(cfgopt(copt, "ArchiveBlockEncrypted")->enabled)
1975
-			options |= CL_SCAN_BLOCKENCRYPTED;
1976
-		if(cfgopt(copt, "ScanPE")->enabled)
1977
-			options |= CL_SCAN_PE;
1978
-		if(cfgopt(copt, "DetectBrokenExecutables")->enabled)
1979
-			options |= CL_SCAN_BLOCKBROKEN;
1980
-		if(cfgopt(copt, "MailFollowURLs")->enabled)
1981
-			options |= CL_SCAN_MAILURL;
1982
-		if(cfgopt(copt, "ScanOLE2")->enabled)
1983
-			options |= CL_SCAN_OLE2;
1984
-		if(cfgopt(copt, "ScanHTML")->enabled)
1985
-			options |= CL_SCAN_HTML;
1986
-
1987
-		if(((cpt = cfgopt(copt, "MaxScanSize")) != NULL) && cpt->enabled)
1988
-			maxscansize = cpt->numarg;
1989
-		else
1990
-			maxscansize = 104857600;
1991
-		if(((cpt = cfgopt(copt, "MaxFileSize")) != NULL) && cpt->enabled)
1992
-			maxfilesize = cpt->numarg;
1993
-		else
1994
-			maxfilesize = 10485760;
1995
-
1996
-		if(getrlimit(RLIMIT_FSIZE, &rlim) == 0) {
1997
-			if((rlim.rlim_max < maxfilesize) || (rlim.rlim_max < maxscansize))
1998
-				logg("^System limit for file size is lower than maxfilesize or maxscansize\n");
1999
-		} else {
2000
-			logg("^Cannot obtain resource limits for file size\n");
2001
-		}
2002
-
2003
-		if(((cpt = cfgopt(copt, "MaxRecursion")) != NULL) && cpt->enabled)
2004
-			maxreclevel = cpt->numarg;
2005
-		else
2006
-			maxreclevel = 8;
2007
-
2008
-		if(((cpt = cfgopt(copt, "MaxFiles")) != NULL) && cpt->enabled)
2009
-			maxfiles = cpt->numarg;
2010
-		else
2011
-			maxfiles = 1000;
2012
-
2013
-		if(cfgopt(copt, "ScanArchive")->enabled)
2014
-			options |= CL_SCAN_ARCHIVE;
2015
-	}
2016
-
2017
-	pthread_create(&tid, NULL, watchdog, NULL);
2018
-
2019
-	broadcast(_("Starting clamav-milter"));
2020
-
2021
-	if(rootdir) {
2022
-		if(getuid() == 0) {
2023
-			if(chdir(rootdir) < 0) {
2024
-				perror(rootdir);
2025
-				logg("!chdir %s failed\n", rootdir);
2026
-				return EX_CONFIG;
2027
-			}
2028
-			if(chroot(rootdir) < 0) {
2029
-				perror(rootdir);
2030
-				logg("!chroot %s failed\n", rootdir);
2031
-				return EX_CONFIG;
2032
-			}
2033
-			logg("Chrooted to %s\n", rootdir);
2034
-		} else {
2035
-			logg("!chroot option needs root\n");
2036
-			return EX_CONFIG;
2037
-		}
2038
-	}
2039
-
2040
-	if(pidfile) {
2041
-		/* save the PID */
2042
-		char *p, *q;
2043
-		FILE *fd;
2044
-		const mode_t old_umask = umask(0006);
2045
-
2046
-		if(pidfile[0] != '/') {
2047
-			logg(_("!pidfile: '%s' must be a full pathname"),
2048
-				pidfile);
2049
-
2050
-			return EX_CONFIG;
2051
-		}
2052
-		p = cli_strdup(pidfile);
2053
-		q = strrchr(p, '/');
2054
-		*q = '\0';
2055
-
2056
-		if(rootdir == NULL)
2057
-			if(chdir(p) < 0)	/* safety */
2058
-				perror(p);
2059
-
2060
-		free(p);
2061
-
2062
-		if((fd = fopen(pidfile, "w")) == NULL) {
2063
-			logg(_("!Can't save PID in file %s\n"), pidfile);
2064
-			return EX_CONFIG;
2065
-		}
2066
-#ifdef	C_LINUX
2067
-		/* Ensure that all threads are kill()ed */
2068
-		fprintf(fd, "-%d\n", (int)getpgrp());
2069
-#else
2070
-		fprintf(fd, "%d\n", (int)getpid());
2071
-#endif
2072
-		fclose(fd);
2073
-		umask(old_umask);
2074
-	} else if(tmpdir) {
2075
-		if(rootdir == NULL)
2076
-			if(chdir(tmpdir) < 0) {	/* safety */
2077
-				perror(tmpdir);
2078
-				logg("!chdir %s failed\n", tmpdir);
2079
-			}
2080
-	} else
2081
-		if(rootdir == NULL)
2082
-#ifdef	P_tmpdir
2083
-			if(chdir(P_tmpdir) < 0) {
2084
-				perror(P_tmpdir);
2085
-				logg("!chdir %s failed\n", P_tmpdir);
2086
-			}
2087
-#else
2088
-			if(chdir("/tmp") < 0) {
2089
-				perror("/tmp");
2090
-				logg("!chdir /tmp failed\n", P_tmpdir);
2091
-			}
2092
-#endif
2093
-
2094
-	if(smfi_setconn(port) == MI_FAILURE) {
2095
-		logg("!smfi_setconn failure\n");
2096
-		return EX_SOFTWARE;
2097
-	}
2098
-
2099
-	if(smfi_register(smfilter) == MI_FAILURE) {
2100
-		fprintf(stderr, "smfi_register failure, ensure that you have linked against the correct version of sendmail\n");
2101
-		return EX_UNAVAILABLE;
2102
-	}
2103
-
2104
-#if	((SENDMAIL_VERSION_A > 8) || ((SENDMAIL_VERSION_A == 8) && (SENDMAIL_VERSION_B >= 13)))
2105
-	if(smfi_opensocket(1) == MI_FAILURE) {
2106
-		perror(port);
2107
-		fprintf(stderr, "Can't open/create %s\n", port);
2108
-		return EX_CONFIG;
2109
-	}
2110
-#endif
2111
-
2112
-	signal(SIGPIPE, SIG_IGN);	/* libmilter probably does this as well */
2113
-	signal(SIGXFSZ, SIG_IGN); /* TODO: check if it's safe to call signal() here */
2114
-
2115
-#ifdef	SESSION
2116
-	pthread_mutex_lock(&version_mutex);
2117
-#endif
2118
-	logg(_("Starting %s\n"), clamav_version);
2119
-	logg(_("*Debugging is on\n"));
2120
-
2121
-#ifdef HAVE_RESOLV_H
2122
-#if ! defined(HAVE_LRESOLV_R)
2123
-	if(!(_res.options&RES_INIT))
2124
-		if(res_init() < 0) {
2125
-			fprintf(stderr, "%s: Can't initialise the resolver\n",
2126
-				argv[0]);
2127
-			return EX_UNAVAILABLE;
2128
-		}
2129
-#endif
2130
-	if(blacklist_time) {
2131
-		char name[MAXHOSTNAMELEN + 1];
2132
-
2133
-		if(gethostname(name, sizeof(name)) < 0) {
2134
-			perror("gethostname");
2135
-			return EX_UNAVAILABLE;
2136
-		}
2137
-
2138
-		blacklist = mx(name, NULL);
2139
-		if(blacklist)
2140
-			/* We must never blacklist ourself */
2141
-			tableInsert(blacklist, "127.0.0.1", 0);
2142
-
2143
-		if(wont_blacklist) {
2144
-			char *w;
2145
-
2146
-			i = 0;
2147
-			while((w = cli_strtok(wont_blacklist, i++, ",")) != NULL) {
2148
-				(void)tableInsert(blacklist, w, 0);
2149
-				free(w);
2150
-			}
2151
-		}
2152
-		tableIterate(blacklist, dump_blacklist, NULL);
2153
-	}
2154
-#endif /* HAVE_RESOLV_H */
2155
-
2156
-#ifdef	SESSION
2157
-	pthread_mutex_unlock(&version_mutex);
2158
-#endif
2159
-
2160
-	(void)signal(SIGSEGV, sigsegv);
2161
-	if(!logg_foreground)
2162
-		(void)signal(SIGUSR1, sigusr1);
2163
-	if(!external)
2164
-		(void)signal(SIGUSR2, sigusr2);
2165
-
2166
-	return smfi_main();
2167
-}
2168
-
2169
-#ifdef	SESSION
2170
-/*
2171
- * Use the SESSION command of clamd.
2172
- * Returns -1 for terminal failure, 0 for OK, 1 for nonterminal failure
2173
- * The caller must take care of locking the sessions array
2174
- */
2175
-static int
2176
-createSession(unsigned int s)
2177
-{
2178
-	int ret = 0, fd;
2179
-	const int serverNumber = s % numServers;
2180
-	struct session *session = &sessions[s];
2181
-	const struct protoent *proto;
2182
-	struct sockaddr_in server;
2183
-
2184
-	logg("#createSession session %d, server %d\n", s, serverNumber);
2185
-	assert(s < max_children);
2186
-
2187
-	memset((char *)&server, 0, sizeof(struct sockaddr_in));
2188
-	server.sin_family = AF_INET;
2189
-	server.sin_port = (in_port_t)htons(tcpSocket);
2190
-
2191
-	server.sin_addr.s_addr = serverIPs[serverNumber];
2192
-
2193
-	session->sock = -1;
2194
-	proto = getprotobyname("tcp");
2195
-	if(proto == NULL) {
2196
-		fputs("Unknown prototol tcp, check /etc/protocols\n", stderr);
2197
-		fd = ret = -1;
2198
-	} else if((fd = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
2199
-		perror("socket");
2200
-		ret = -1;
2201
-	} else if(connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
2202
-		perror("connect");
2203
-		ret = 1;
2204
-	} else if(send(fd, "SESSION\n", 8, 0) < 8) {
2205
-		perror("send");
2206
-		ret = 1;
2207
-	}
2208
-
2209
-	if(ret != 0) {
2210
-#ifdef	MAXHOSTNAMELEN
2211
-		char hostname[MAXHOSTNAMELEN + 1];
2212
-
2213
-		cli_strtokbuf(serverHostNames, serverNumber, ":", hostname);
2214
-		if(strcmp(hostname, "127.0.0.1") == 0)
2215
-			gethostname(hostname, sizeof(hostname));
2216
-#else
2217
-		char *hostname = cli_strtok(serverHostNames, serverNumber, ":");
2218
-#endif
2219
-
2220
-		session->status = CMDSOCKET_DOWN;
2221
-
2222
-		if(fd >= 0)
2223
-			close(fd);
2224
-
2225
-		logg(_("^Check clamd server %s - it may be down\n"), hostname);
2226
-#ifndef	MAXHOSTNAMELEN
2227
-		free(hostname);
2228
-#endif
2229
-
2230
-		broadcast(_("Check clamd server - it may be down"));
2231
-	} else
2232
-		session->sock = fd;
2233
-
2234
-	return ret;
2235
-}
2236
-
2237
-#else
2238
-
2239
-/*
2240
- * Verify that the server is where we think it is
2241
- * Returns true or false
2242
- *
2243
- * serverNumber counts from 0, but is only used for TCPSocket
2244
- */
2245
-static int
2246
-pingServer(int serverNumber)
2247
-{
2248
-	char *ptr;
2249
-	int sock;
2250
-	long nbytes;
2251
-	char buf[128];
2252
-
2253
-	if(localSocket) {
2254
-		struct sockaddr_un server;
2255
-
2256
-		memset((char *)&server, 0, sizeof(struct sockaddr_un));
2257
-		server.sun_family = AF_UNIX;
2258
-		strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
2259
-		server.sun_path[sizeof(server.sun_path)-1]='\0';
2260
-
2261
-		if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
2262
-			perror(localSocket);
2263
-			return 0;
2264
-		}
2265
-		checkClamd(1);
2266
-		if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
2267
-			perror(localSocket);
2268
-			close(sock);
2269
-			return 0;
2270
-		}
2271
-	} else {
2272
-		struct sockaddr_in server;
2273
-		char *hostname;
2274
-
2275
-		memset((char *)&server, 0, sizeof(struct sockaddr_in));
2276
-		server.sin_family = AF_INET;
2277
-		server.sin_port = (in_port_t)htons(tcpSocket);
2278
-
2279
-		assert(serverIPs != NULL);
2280
-#ifdef	INADDR_NONE
2281
-		assert(serverIPs[0] != INADDR_NONE);
2282
-#else
2283
-		assert(serverIPs[0] != (in_addr_t)-1);
2284
-#endif
2285
-
2286
-		server.sin_addr.s_addr = serverIPs[serverNumber];
2287
-
2288
-		if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2289
-			perror("socket");
2290
-			return 0;
2291
-		}
2292
-		hostname = cli_strtok(serverHostNames, serverNumber, ":");
2293
-		/*
2294
-		 * FIXME: use non-blocking connect, once the code is
2295
-		 * amalgomated
2296
-		 */
2297
-		if(nonblock_connect(sock, &server, hostname) < 0) {
2298
-			int is_connected = 0;
2299
-
2300
-#if	(!defined(NTRIES)) || ((NTRIES <= 1))
2301
-			if(errno == ECONNREFUSED) {
2302
-				/*
2303
-				 * During startup there is a race condition:
2304
-				 * clamd can start and fork, then rc will start
2305
-				 * clamav-milter before clamd has run accept(2),
2306
-				 * so we fail to connect.
2307
-				 * In case this is the situation here, we wait
2308
-				 * for a couple of seconds and try again. The
2309
-				 * sync() is because during startup the machine
2310
-				 * won't be doing much for most of the time, so
2311
-				 * we may as well do something constructive!
2312
-				 */
2313
-				sync();
2314
-				sleep(2);
2315
-				if(nonblock_connect(sock, &server, hostname) >= 0)
2316
-					is_connected = 1;
2317
-			}
2318
-#endif
2319
-			if(!is_connected) {
2320
-				if(errno != EINPROGRESS)
2321
-					perror(hostname ? hostname : "connect");
2322
-				close(sock);
2323
-				if(hostname)
2324
-					free(hostname);
2325
-				return 0;
2326
-			}
2327
-		}
2328
-		if(hostname)
2329
-			free(hostname);
2330
-	}
2331
-
2332
-	/*
2333
-	 * It would be better to use PING, check for PONG then issue the
2334
-	 * VERSION command, since that would better validate that we're
2335
-	 * talking to clamd, however clamd closes the session after
2336
-	 * sending PONG :-(
2337
-	 * So this code does not really validate that we're talking to clamd
2338
-	 * Needs a fix to clamd
2339
-	 * Also version command is verbose: says "clamd / ClamAV version"
2340
-	 * instead of "clamAV version"
2341
-	 */
2342
-	logg("#pingServer%d: sending VERSION\n", serverNumber);
2343
-	if(send(sock, "VERSION\n", 8, 0) < 8) {
2344
-		perror("send");
2345
-		return close(sock);
2346
-	}
2347
-
2348
-	shutdown(sock, SHUT_WR);
2349
-
2350
-	nbytes = clamd_recv(sock, buf, sizeof(buf) - 1);
2351
-
2352
-	close(sock);
2353
-
2354
-	if(nbytes < 0) {
2355
-		perror("recv");
2356
-		return 0;
2357
-	}
2358
-	if(nbytes == 0)
2359
-		return 0;
2360
-
2361
-	buf[nbytes] = '\0';
2362
-
2363
-	/* Remove the trailing new line from the reply */
2364
-	if((ptr = strchr(buf, '\n')) != NULL)
2365
-		*ptr = '\0';
2366
-
2367
-	/*
2368
-	 * No real validation is done here
2369
-	 *
2370
-	 * TODO: When connecting to more than one server, give a warning
2371
-	 *	if they're running different versions, or if the virus DBs
2372
-	 *	are out of date (say more than a month old)
2373
-	 */
2374
-	snprintf(clamav_version, sizeof(clamav_version) - 1,
2375
-		"%s\n\tclamav-milter version %s",
2376
-		buf, get_version());
2377
-
2378
-	return 1;
2379
-}
2380
-#endif
2381
-
2382
-/*
2383
- * Find the best server to connect to. No intelligence to this.
2384
- * It is best to weight the order of the servers from most wanted to least
2385
- * wanted
2386
- *
2387
- * Return value is from 0 - index into sessions array
2388
- *
2389
- * If the load balancing fails return the first server in the list, not
2390
- * an error, to be on the safe side
2391
- */
2392
-#ifdef	SESSION
2393
-static int
2394
-findServer(void)
2395
-{
2396
-	unsigned int i, j;
2397
-	struct session *session;
2398
-
2399
-	/*
2400
-	 * FIXME: Sessions code isn't flexible at handling servers
2401
-	 *	appearing and disappearing, e.g. sessions[n_children].sock == -1
2402
-	 */
2403
-	i = 0;
2404
-	pthread_mutex_lock(&n_children_mutex);
2405
-	assert(n_children > 0);
2406
-	assert(n_children <= max_children);
2407
-	j = n_children - 1;
2408
-	pthread_mutex_unlock(&n_children_mutex);
2409
-
2410
-	pthread_mutex_lock(&sstatus_mutex);
2411
-	for(; i < max_children; i++) {
2412
-		const int sess = (j + i) % max_children;
2413
-
2414
-		session = &sessions[sess];
2415
-		logg("#findServer: try server %d\n", sess);
2416
-		if(session->status == CMDSOCKET_FREE) {
2417
-			session->status = CMDSOCKET_INUSE;
2418
-			pthread_mutex_unlock(&sstatus_mutex);
2419
-			return sess;
2420
-		}
2421
-	}
2422
-	pthread_mutex_unlock(&sstatus_mutex);
2423
-
2424
-	/*
2425
-	 * No session free - wait until one comes available. Only
2426
-	 * retries once.
2427
-	 */
2428
-	if(pthread_cond_broadcast(&watchdog_cond) < 0)
2429
-		perror("pthread_cond_broadcast");
2430
-
2431
-	i = 0;
2432
-	session = sessions;
2433
-	pthread_mutex_lock(&sstatus_mutex);
2434
-	for(; i < max_children; i++, session++) {
2435
-		logg("#findServer: try server %d\n", i);
2436
-		if(session->status == CMDSOCKET_FREE) {
2437
-			session->status = CMDSOCKET_INUSE;
2438
-			pthread_mutex_unlock(&sstatus_mutex);
2439
-			return i;
2440
-		}
2441
-	}
2442
-	pthread_mutex_unlock(&sstatus_mutex);
2443
-
2444
-	logg(_("^No free clamd sessions\n"));
2445
-
2446
-	return -1;	/* none available - must fail */
2447
-}
2448
-#else
2449
-/*
2450
- * Return value is from 0 - index into serverIPs
2451
- */
2452
-static int
2453
-findServer(void)
2454
-{
2455
-	struct sockaddr_in *servers, *server;
2456
-	int maxsock, i, j, active;
2457
-	int retval;
2458
-	pthread_t *tids;
2459
-	struct try_server_struct *socks;
2460
-	fd_set rfds;
2461
-
2462
-	assert(tcpSocket != 0);
2463
-	assert(numServers > 0);
2464
-
2465
-	if(numServers == 1)
2466
-		return 0;
2467
-
2468
-	if(active_servers(&active) <= 1)
2469
-		return active;
2470
-
2471
-	servers = (struct sockaddr_in *)cli_calloc(numServers, sizeof(struct sockaddr_in));
2472
-	if(servers == NULL)
2473
-		return 0;
2474
-	socks = (struct try_server_struct *)cli_malloc(numServers * sizeof(struct try_server_struct));
2475
-
2476
-	if(max_children > 0) {
2477
-		assert(n_children > 0);
2478
-		assert(n_children <= max_children);
2479
-
2480
-		/*
2481
-		 * Don't worry about no lock - it's doesn't matter if it's
2482
-		 * not really accurate
2483
-		 */
2484
-		j = n_children - 1;	/* look at the next free one */
2485
-		if(j < 0)
2486
-			j = 0;
2487
-	} else
2488
-		/*
2489
-		 * cli_rndnum returns 0..max
2490
-		 */
2491
-		j = cli_rndnum(numServers - 1);
2492
-
2493
-	for(i = 0; i < numServers; i++)
2494
-		socks[i].sock = -1;
2495
-
2496
-	tids = cli_malloc(numServers * sizeof(pthread_t));
2497
-
2498
-	for(i = 0, server = servers; i < numServers; i++, server++) {
2499
-		int sock;
2500
-		int server_index = (i + j) % numServers;
2501
-
2502
-		server->sin_family = AF_INET;
2503
-		server->sin_port = (in_port_t)htons(tcpSocket);
2504
-		server->sin_addr.s_addr = serverIPs[server_index];
2505
-
2506
-		logg("*findServer: try server %d\n", server_index);
2507
-
2508
-		sock = socks[i].sock = socket(AF_INET, SOCK_STREAM, 0);
2509
-
2510
-		if(sock < 0) {
2511
-			perror("socket");
2512
-			while(i--) {
2513
-				pthread_join(tids[i], NULL);
2514
-				if(socks[i].sock >= 0)
2515
-					close(socks[i].sock);
2516
-			}
2517
-			free(socks);
2518
-			free(servers);
2519
-			free(tids);
2520
-			return 0;	/* Use the first server on failure */
2521
-		}
2522
-
2523
-		socks[i].server = server;
2524
-		socks[i].server_index = server_index;
2525
-
2526
-		if(pthread_create(&tids[i], NULL, try_server, &socks[i]) != 0) {
2527
-			perror("pthread_create");
2528
-			j = i;
2529
-			do {
2530
-				if (j!=i) pthread_join(tids[i], NULL);
2531
-				if(socks[i].sock >= 0)
2532
-					close(socks[i].sock);
2533
-			} while(--i >= 0);
2534
-			free(socks);
2535
-			free(servers);
2536
-			free(tids);
2537
-			return 0;	/* Use the first server on failure */
2538
-		}
2539
-	}
2540
-
2541
-	maxsock = -1;
2542
-	FD_ZERO(&rfds);
2543
-
2544
-	for(i = 0; i < numServers; i++) {
2545
-		struct try_server_struct *rc;
2546
-
2547
-		pthread_join(tids[i], (void **)&rc);
2548
-		assert(rc->sock == socks[i].sock);
2549
-		if(rc->rc == 0) {
2550
-			close(rc->sock);
2551
-			socks[i].sock = -1;
2552
-		} else {
2553
-			shutdown(rc->sock, SHUT_WR);
2554
-			FD_SET(rc->sock, &rfds);
2555
-			if(rc->sock > maxsock)
2556
-				maxsock = rc->sock;
2557
-		}
2558
-	}
2559
-
2560
-	free(servers);
2561
-	free(tids);
2562
-
2563
-	if(maxsock == -1) {
2564
-		logg(_("^Couldn't establish a connexion to any clamd server\n"));
2565
-		retval = 0;
2566
-	} else {
2567
-		struct timeval tv;
2568
-
2569
-		tv.tv_sec = readTimeout ? readTimeout : DEFAULT_TIMEOUT;
2570
-		tv.tv_usec = 0;
2571
-
2572
-		retval = select(maxsock + 1, &rfds, NULL, NULL, &tv);
2573
-	}
2574
-
2575
-	if(retval < 0)
2576
-		perror("select");
2577
-
2578
-	for(i = 0; i < numServers; i++)
2579
-		if(socks[i].sock >= 0)
2580
-			close(socks[i].sock);
2581
-
2582
-	if(retval == 0) {
2583
-		free(socks);
2584
-		clamdIsDown();
2585
-		return 0;
2586
-	} else if(retval < 0) {
2587
-		free(socks);
2588
-		logg(_("^findServer: select failed (maxsock = %d)\n"), maxsock);
2589
-		return 0;
2590
-	}
2591
-
2592
-	for(i = 0; i < numServers; i++)
2593
-		if((socks[i].sock >= 0) && (FD_ISSET(socks[i].sock, &rfds))) {
2594
-			const int s = (i + j) % numServers;
2595
-
2596
-			free(socks);
2597
-			logg("*findServer: use server %d\n", s);
2598
-			return s;
2599
-		}
2600
-
2601
-	free(socks);
2602
-	logg(_("^findServer: No response from any server\n"));
2603
-	return 0;
2604
-}
2605
-
2606
-/*
2607
- * How many servers are up at the moment? If a server is marked as down,
2608
- *	don't keep on flooding it with requests to see if it's now back up
2609
- * If only one server is active, let the caller know, which server is the
2610
- *	active one
2611
- */
2612
-static int
2613
-active_servers(int *active)
2614
-{
2615
-	int server, count;
2616
-	time_t now = (time_t)0;
2617
-
2618
-	for(count = server = 0; server < numServers; server++)
2619
-		if(last_failed_pings[server] == (time_t)0) {
2620
-			*active = server;
2621
-			count++;
2622
-		} else {
2623
-			if(now == (time_t)0)
2624
-				time(&now);
2625
-			if(now - last_failed_pings[server] >= RETRY_SECS)
2626
-				/* Try this server again next time */
2627
-				last_failed_pings[server] = (time_t)0;
2628
-		}
2629
-
2630
-	if(count != 1)
2631
-		*active = 0;
2632
-	return count;
2633
-}
2634
-
2635
-/*
2636
- * Connecting to remote servers can take some time, so let's connect to
2637
- *	them in parallel. This routine is started as a thread
2638
- */
2639
-static void *
2640
-try_server(void *var)
2641
-{
2642
-	struct try_server_struct *s = (struct try_server_struct *)var;
2643
-	int sock = s->sock;
2644
-	struct sockaddr *server = (struct sockaddr *)s->server;
2645
-	int server_index = s->server_index;
2646
-
2647
-	if(last_failed_pings[server_index]) {
2648
-		s->rc = 0;
2649
-		return var;
2650
-	}
2651
-
2652
-	logg("*try_server: sock %d\n", sock);
2653
-
2654
-	if((connect(sock, server, sizeof(struct sockaddr)) < 0) ||
2655
-	   (send(sock, "PING\n", 5, 0) < 5)) {
2656
-		time(&last_failed_pings[server_index]);
2657
-		s->rc = 0;
2658
-	} else
2659
-		s->rc = 1;
2660
-
2661
-	if(s->rc == 0) {
2662
-#ifdef	MAXHOSTNAMELEN
2663
-		char hostname[MAXHOSTNAMELEN + 1];
2664
-
2665
-		cli_strtokbuf(serverHostNames, server_index, ":", hostname);
2666
-		if(strcmp(hostname, "127.0.0.1") == 0)
2667
-			gethostname(hostname, sizeof(hostname));
2668
-#else
2669
-		char *hostname = cli_strtok(serverHostNames, server_index, ":");
2670
-#endif
2671
-		perror(hostname);
2672
-		logg(_("^Check clamd server %s - it may be down\n"), hostname);
2673
-#ifndef	MAXHOSTNAMELEN
2674
-		free(hostname);
2675
-#endif
2676
-		broadcast(_("Check clamd server - it may be down\n"));
2677
-	}
2678
-
2679
-	return var;
2680
-}
2681
-#endif
2682
-
2683
-/*
2684
- * Sendmail wants to establish a connexion to us
2685
- * TODO: is it possible (desirable?) to determine if the remote machine has been
2686
- *	compromised?
2687
- */
2688
-static sfsistat
2689
-clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
2690
-{
2691
-#if	defined(HAVE_INET_NTOP) || defined(WITH_TCPWRAP)
2692
-	char ip[INET6_ADDRSTRLEN];
2693
-#endif
2694
-	int t;
2695
-	const char *remoteIP;
2696
-	struct privdata *privdata;
2697
-
2698
-	if(quitting)
2699
-		return cl_error;
2700
-
2701
-	if(ctx == NULL) {
2702
-		logg(_("!clamfi_connect: ctx is null"));
2703
-		return cl_error;
2704
-	}
2705
-	if(hostname == NULL) {
2706
-		logg(_("!clamfi_connect: hostname is null"));
2707
-		return cl_error;
2708
-	}
2709
-	if(smfi_getpriv(ctx) != NULL) {
2710
-		/* More than one connexion command, "can't happen" */
2711
-		logg("^clamfi_connect: called more than once\n");
2712
-		clamfi_cleanup(ctx);
2713
-		return cl_error;
2714
-	}
2715
-#ifdef AF_INET6
2716
-	if((hostaddr == NULL) ||
2717
-	   ((hostaddr->sa_family == AF_INET) && (&(((struct sockaddr_in *)(hostaddr))->sin_addr) == NULL)) ||
2718
-	   ((hostaddr->sa_family == AF_INET6) && (&(((struct sockaddr_in6 *)(hostaddr))->sin6_addr) == NULL)))
2719
-#else
2720
-	if((hostaddr == NULL) || (&(((struct sockaddr_in *)(hostaddr))->sin_addr) == NULL))
2721
-#endif
2722
-		/*
2723
-		 * According to the sendmail API hostaddr is NULL if
2724
-		 * "the type is not supported in the current version". What
2725
-		 * the documentation doesn't say is the type of what.
2726
-		 *
2727
-		 * Possibly the input is not a TCP/IP socket e.g. stdin?
2728
-		 */
2729
-		remoteIP = "127.0.0.1";
2730
-	else {
2731
-#ifdef HAVE_INET_NTOP
2732
-		switch(hostaddr->sa_family) {
2733
-			case AF_INET:
2734
-				remoteIP = (const char *)inet_ntop(AF_INET, &((struct sockaddr_in *)(hostaddr))->sin_addr, ip, sizeof(ip));
2735
-				break;
2736
-#ifdef AF_INET6
2737
-			case AF_INET6:
2738
-				remoteIP = (const char *)inet_ntop(AF_INET6, &((struct sockaddr_in6 *)(hostaddr))->sin6_addr, ip, sizeof(ip));
2739
-				break;
2740
-#endif
2741
-			default:
2742
-				logg(_("clamfi_connect: Unexpected sa_family %d\n"),
2743
-					hostaddr->sa_family);
2744
-				return cl_error;
2745
-		}
2746
-
2747
-#else
2748
-		remoteIP = inet_ntoa(((struct sockaddr_in *)(hostaddr))->sin_addr);
2749
-#endif
2750
-
2751
-		if(remoteIP == NULL) {
2752
-			logg(_("clamfi_connect: remoteIP is null"));
2753
-			return cl_error;
2754
-		}
2755
-	}
2756
-
2757
-#ifdef	CL_DEBUG
2758
-	if(debug_level >= 4) {
2759
-		if(hostname[0] == '[')
2760
-			logg(_("clamfi_connect: connexion from %s"), remoteIP);
2761
-		else
2762
-			logg(_("clamfi_connect: connexion from %s [%s]"), hostname, remoteIP);
2763
-	}
2764
-#endif
2765
-
2766
-#ifdef	WITH_TCPWRAP
2767
-	/*
2768
-	 * Support /etc/hosts.allow and /etc/hosts.deny
2769
-	 */
2770
-	if(strncasecmp(port, "inet:", 5) == 0) {
2771
-		const char *hostmail;
2772
-		struct hostent hostent;
2773
-		char buf[BUFSIZ];
2774
-		static pthread_mutex_t wrap_mutex = PTHREAD_MUTEX_INITIALIZER;
2775
-
2776
-		/*
2777
-		 * Using TCP/IP for the sendmail->clamav-milter connexion
2778
-		 */
2779
-		if(((hostmail = smfi_getsymval(ctx, "{if_name}")) == NULL) &&
2780
-		   ((hostmail = smfi_getsymval(ctx, "j")) == NULL)) {
2781
-			logg(_("Can't get sendmail hostname"));
2782
-			return cl_error;
2783
-		}
2784
-		/*
2785
-		 * Use hostmail for error statements, not hostname, suggestion
2786
-		 * by Yar Tikhiy <yar@comp.chem.msu.su>
2787
-		 */
2788
-		if(r_gethostbyname(hostmail, &hostent, buf, sizeof(buf)) != 0) {
2789
-			logg(_("^Access Denied: Host Unknown (%s)"), hostmail);
2790
-			if(hostmail[0] == '[')
2791
-				/*
2792
-				 * A case could be made that it's not clamAV's
2793
-				 * job to check a system's DNS configuration
2794
-				 * and let this message through. However I am
2795
-				 * just too worried about any knock on effects
2796
-				 * to do that...
2797
-				 */
2798
-				logg(_("^Can't find entry for IP address %s in DNS - check your DNS setting\n"),
2799
-					hostmail);
2800
-			return cl_error;
2801
-		}
2802
-
2803
-#ifdef HAVE_INET_NTOP
2804
-		if(hostent.h_addr &&
2805
-		   (inet_ntop(AF_INET, (struct in_addr *)hostent.h_addr, ip, sizeof(ip)) == NULL)) {
2806
-			perror(hostent.h_name);
2807
-			/*strcpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr));*/
2808
-			logg(_("^Access Denied: Can't get IP address for (%s)"), hostent.h_name);
2809
-			return cl_error;
2810
-		}
2811
-#else
2812
-		strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip));
2813
-		ip[sizeof(ip)-1]='\0';
2814
-#endif
2815
-
2816
-		/*
2817
-		 * Ask is this is a allowed name or IP number
2818
-		 *
2819
-		 * hosts_ctl uses strtok so it is not thread safe, see
2820
-		 * hosts_access(3)
2821
-		 */
2822
-		pthread_mutex_lock(&wrap_mutex);
2823
-		if(!hosts_ctl(progname, hostent.h_name, ip, STRING_UNKNOWN)) {
2824
-			pthread_mutex_unlock(&wrap_mutex);
2825
-			logg(_("^Access Denied for %s[%s]"), hostent.h_name, ip);
2826
-			return SMFIS_TEMPFAIL;
2827
-		}
2828
-		pthread_mutex_unlock(&wrap_mutex);
2829
-	}
2830
-#endif	/*WITH_TCPWRAP*/
2831
-
2832
-	if(fflag)
2833
-		/*
2834
-		 * Patch from "Richard G. Roberto" <rgr@dedlegend.com>
2835
-		 * Always scan whereever the message is from
2836
-		 */
2837
-		return SMFIS_CONTINUE;
2838
-
2839
-	if(!oflag)
2840
-		if(strcmp(remoteIP, "127.0.0.1") == 0) {
2841
-			logg(_("*clamfi_connect: not scanning outgoing messages"));
2842
-			return SMFIS_ACCEPT;
2843
-		}
2844
-
2845
-	if((!lflag) && isLocal(remoteIP)) {
2846
-#ifdef	CL_DEBUG
2847
-		logg(_("*clamfi_connect: not scanning local messages\n"));
2848
-#endif
2849
-		return SMFIS_ACCEPT;
2850
-	}
2851
-
2852
-#if	defined(HAVE_INET_NTOP) || defined(WITH_TCPWRAP)
2853
-	if(detect_forged_local_address && !isLocal(ip)) {
2854
-#else
2855
-	if(detect_forged_local_address && !isLocal(remoteIP)) {
2856
-#endif
2857
-		char me[MAXHOSTNAMELEN + 1];
2858
-
2859
-		if(gethostname(me, sizeof(me) - 1) < 0) {
2860
-			logg(_("^clamfi_connect: gethostname failed"));
2861
-			return SMFIS_CONTINUE;
2862
-		}
2863
-		logg("*me '%s' hostname '%s'\n", me, hostname);
2864
-		if(strcasecmp(hostname, me) == 0) {
2865
-			logg(_("Rejected connexion falsely claiming to be from here\n"));
2866
-			smfi_setreply(ctx, "550", "5.7.1", _("You have claimed to be me, but you are not"));
2867
-			broadcast(_("Forged local address detected"));
2868
-			return SMFIS_REJECT;
2869
-		}
2870
-	}
2871
-	if(isBlacklisted(remoteIP)) {
2872
-		char mess[128];
2873
-
2874
-		/*
2875
-		 * TODO: Option to greylist rather than blacklist, by sending
2876
-		 *	a try again code
2877
-		 * TODO: state *which* virus
2878
-		 * TODO: add optional list of IP addresses that won't be
2879
-		 *	blacklisted
2880
-		 */
2881
-		logg("Rejected connexion from blacklisted IP %s\n", remoteIP);
2882
-
2883
-		snprintf(mess, sizeof(mess), _("%s is blacklisted because your machine is infected with a virus"), remoteIP);
2884
-		smfi_setreply(ctx, "550", "5.7.1", mess);
2885
-		broadcast(_("Blacklisted IP detected"));
2886
-
2887
-		/*
2888
-		 * Keep them blacklisted
2889
-		 */
2890
-		pthread_mutex_lock(&blacklist_mutex);
2891
-		(void)tableUpdate(blacklist, remoteIP, (int)time((time_t *)0));
2892
-		pthread_mutex_unlock(&blacklist_mutex);
2893
-
2894
-		return SMFIS_REJECT;
2895
-	}
2896
-
2897
-	if(blacklist_time == 0)
2898
-		return SMFIS_CONTINUE;	/* allocate privdata per message */
2899
-
2900
-	pthread_mutex_lock(&blacklist_mutex);
2901
-	t = tableFind(blacklist, remoteIP);
2902
-	pthread_mutex_unlock(&blacklist_mutex);
2903
-
2904
-	if(t == 0)
2905
-		return SMFIS_CONTINUE;	/* this IP will never be blacklisted */
2906
-
2907
-	privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata));
2908
-	if(privdata == NULL)
2909
-		return cl_error;
2910
-
2911
-#ifdef	SESSION
2912
-	privdata->dataSocket = -1;
2913
-#else
2914
-	privdata->dataSocket = privdata->cmdSocket = -1;
2915
-#endif
2916
-
2917
-	if(smfi_setpriv(ctx, privdata) == MI_SUCCESS) {
2918
-		strcpy(privdata->ip, remoteIP);
2919
-		return SMFIS_CONTINUE;
2920
-	}
2921
-
2922
-	free(privdata);
2923
-
2924
-	return cl_error;
2925
-}
2926
-
2927
-/*
2928
- * Since sendmail requires that MAIL FROM is called before RCPT TO, it is
2929
- *	safe to assume that this routine is called first, so the n_children
2930
- *	handler is put here
2931
- */
2932
-static sfsistat
2933
-clamfi_envfrom(SMFICTX *ctx, char **argv)
2934
-{
2935
-	struct privdata *privdata;
2936
-	const char *mailaddr = argv[0];
2937
-
2938
-	logg("*clamfi_envfrom: %s\n", argv[0]);
2939
-
2940
-	if(isWhitelisted(argv[0], 0)) {
2941
-		logg(_("*clamfi_envfrom: ignoring whitelisted message"));
2942
-		return SMFIS_ACCEPT;
2943
-	}
2944
-
2945
-	if(strcmp(argv[0], "<>") == 0) {
2946
-		mailaddr = smfi_getsymval(ctx, "{mail_addr}");
2947
-		if(mailaddr == NULL)
2948
-			mailaddr = smfi_getsymval(ctx, "_");
2949
-
2950
-		if(mailaddr && *mailaddr)
2951
-			logg("#Message from \"%s\" has no from field\n", mailaddr);
2952
-		else {
2953
-#if	0
2954
-			if(use_syslog)
2955
-				syslog(LOG_NOTICE, _("Rejected email with empty from field"));
2956
-			smfi_setreply(ctx, "554", "5.7.1", _("You have not said who the email is from"));
2957
-			broadcast(_("Reject email with empty from field"));
2958
-			clamfi_cleanup(ctx);
2959
-			return SMFIS_REJECT;
2960
-#endif
2961
-			mailaddr = "<>";
2962
-		}
2963
-	}
2964
-	privdata = smfi_getpriv(ctx);
2965
-
2966
-	if(privdata == NULL) {
2967
-		privdata = (struct privdata *)cli_calloc(1, sizeof(struct privdata));
2968
-		if(privdata == NULL)
2969
-			return cl_error;
2970
-		if(smfi_setpriv(ctx, privdata) != MI_SUCCESS) {
2971
-			free(privdata);
2972
-			return cl_error;
2973
-		}
2974
-		if(!increment_connexions()) {
2975
-			smfi_setreply(ctx, "451", "4.3.2", _("AV system temporarily overloaded - please try later"));
2976
-			free(privdata);
2977
-			smfi_setpriv(ctx, NULL);
2978
-			return SMFIS_TEMPFAIL;
2979
-		}
2980
-	} else {
2981
-		/* More than one message on this connexion */
2982
-		char ip[INET6_ADDRSTRLEN];
2983
-
2984
-		strcpy(ip, privdata->ip);
2985
-		if(isBlacklisted(ip)) {
2986
-			char mess[80 + INET6_ADDRSTRLEN];
2987
-
2988
-			logg("Rejected email from blacklisted IP %s\n", ip);
2989
-
2990
-			/*
2991
-			 * TODO: Option to greylist rather than blacklist, by
2992
-			 *	sending	a try again code
2993
-			 * TODO: state *which* virus
2994
-			 */
2995
-			sprintf(mess, "Your IP (%s) is blacklisted because your machine is infected with a virus", ip);
2996
-			smfi_setreply(ctx, "550", "5.7.1", mess);
2997
-			broadcast(_("Blacklisted IP detected"));
2998
-
2999
-			/*
3000
-			 * Keep them blacklisted
3001
-			 */
3002
-			pthread_mutex_lock(&blacklist_mutex);
3003
-			(void)tableUpdate(blacklist, ip, (int)time((time_t *)0));
3004
-			pthread_mutex_unlock(&blacklist_mutex);
3005
-
3006
-			return SMFIS_REJECT;
3007
-		}
3008
-		clamfi_free(privdata, 1);
3009
-		strcpy(privdata->ip, ip);
3010
-	}
3011
-
3012
-#ifdef	SESSION
3013
-	privdata->dataSocket = -1;
3014
-#else
3015
-	privdata->dataSocket = privdata->cmdSocket = -1;
3016
-#endif
3017
-
3018
-	/*
3019
-	 * Rejection is via 550 until DATA is received. We know that
3020
-	 * DATA has been sent when either we get a header or the end of
3021
-	 * header statement
3022
-	 */
3023
-	privdata->rejectCode = "550";
3024
-
3025
-	privdata->from = cli_strdup(mailaddr);
3026
-
3027
-	if(hflag) {
3028
-		privdata->headers = header_list_new();
3029
-
3030
-		if(privdata->headers == NULL) {
3031
-			clamfi_free(privdata, 1);
3032
-			return cl_error;
3033
-		}
3034
-	}
3035
-
3036
-	return SMFIS_CONTINUE;
3037
-}
3038
-
3039
-#ifdef	CL_DEBUG
3040
-static sfsistat
3041
-clamfi_helo(SMFICTX *ctx, char *helostring)
3042
-{
3043
-	logg("HELO '%s'\n", helostring);
3044
-
3045
-	return SMFIS_CONTINUE;
3046
-}
3047
-#endif
3048
-
3049
-static sfsistat
3050
-clamfi_envrcpt(SMFICTX *ctx, char **argv)
3051
-{
3052
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
3053
-	const char *to, *ptr;
3054
-
3055
-	logg("*clamfi_envrcpt: %s\n", argv[0]);
3056
-
3057
-	if(privdata == NULL)	/* sanity check */
3058
-		return cl_error;
3059
-
3060
-	if(privdata->to == NULL) {
3061
-		privdata->to = cli_malloc(sizeof(char *) * 2);
3062
-
3063
-		assert(privdata->numTo == 0);
3064
-	} else
3065
-		privdata->to = cli_realloc(privdata->to, sizeof(char *) * (privdata->numTo + 2));
3066
-
3067
-	if(privdata->to == NULL)
3068
-		return cl_error;
3069
-
3070
-	to = smfi_getsymval(ctx, "{rcpt_addr}");
3071
-	if(to == NULL)
3072
-		to = argv[0];
3073
-
3074
-	for(ptr = to; !dont_sanitise && *ptr; ptr++)
3075
-		if(strchr("|;", *ptr) != NULL) {
3076
-			smfi_setreply(ctx, "554", "5.7.1", _("Suspicious recipient address blocked"));
3077
-			logg("^Suspicious recipient address blocked: '%s'\n", to);
3078
-			privdata->to[privdata->numTo] = NULL;
3079
-			if(blacklist_time && privdata->ip[0]) {
3080
-				logg(_("Will blacklist %s for %d seconds because of cracking attempt\n"),
3081
-					privdata->ip, blacklist_time);
3082
-				pthread_mutex_lock(&blacklist_mutex);
3083
-				(void)tableUpdate(blacklist, privdata->ip,
3084
-					(int)time((time_t *)0));
3085
-				pthread_mutex_unlock(&blacklist_mutex);
3086
-			}
3087
-			/*
3088
-			 * REJECT rejects this recipient, not the entire email
3089
-			 */
3090
-			return SMFIS_REJECT;
3091
-		}
3092
-
3093
-	privdata->to[privdata->numTo] = cli_strdup(to);
3094
-	privdata->to[++privdata->numTo] = NULL;
3095
-
3096
-	return SMFIS_CONTINUE;
3097
-}
3098
-
3099
-static sfsistat
3100
-clamfi_header(SMFICTX *ctx, char *headerf, char *headerv)
3101
-{
3102
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
3103
-
3104
-#ifdef	CL_DEBUG
3105
-	if(debug_level >= 9)
3106
-		logg("*clamfi_header: %s: %s\n", headerf, headerv);
3107
-	else
3108
-		logg("*clamfi_header: %s\n", headerf);
3109
-#else
3110
-	logg("*clamfi_header: %s\n", headerf);
3111
-#endif
3112
-
3113
-	/*
3114
-	 * The DATA instruction from SMTP (RFC2821) must have been sent
3115
-	 */
3116
-	privdata->rejectCode = "554";
3117
-
3118
-	if(hflag)
3119
-		header_list_add(privdata->headers, headerf, headerv);
3120
-	else if((strcasecmp(headerf, "Received") == 0) &&
3121
-		(strncasecmp(headerv, "from ", 5) == 0) &&
3122
-		(strstr(headerv, "localhost") != 0)) {
3123
-		if(privdata->received)
3124
-			free(privdata->received);
3125
-		privdata->received = cli_strdup(headerv);
3126
-	}
3127
-
3128
-	if((strcasecmp(headerf, "Message-ID") == 0) &&
3129
-	   (strncasecmp(headerv, "<MDAEMON", 8) == 0))
3130
-		privdata->discard = 1;
3131
-	else if((strcasecmp(headerf, "Subject") == 0) && headerv) {
3132
-		if(privdata->subject)
3133
-			free(privdata->subject);
3134
-		if(headerv)
3135
-			privdata->subject = cli_strdup(headerv);
3136
-	} else if(strcasecmp(headerf, "X-Virus-Status") == 0)
3137
-		privdata->statusCount++;
3138
-	else if((strcasecmp(headerf, "Sender") == 0) && headerv) {
3139
-		if(privdata->sender)
3140
-			free(privdata->sender);
3141
-		privdata->sender = cli_strdup(headerv);
3142
-	}
3143
-#ifdef	HAVE_RESOLV_H
3144
-	else if((strcasecmp(headerf, "From") == 0) && headerv) {
3145
-		/*
3146
-		 * SPF check against the from header, since the SMTP header
3147
-		 * may be valid. This is not what the SPF spec says, but I
3148
-		 * have seen SPF matches on what are clearly phishes, so by
3149
-		 * checking against the from: header we're less likely to
3150
-		 * FP a real phish
3151
-		 */
3152
-		if(privdata->from)
3153
-			free(privdata->from);
3154
-		privdata->from = cli_strdup(headerv);
3155
-	}
3156
-#endif
3157
-
3158
-	if(!useful_header(headerf)) {
3159
-		logg("*Discarded the header\n");
3160
-		return SMFIS_CONTINUE;
3161
-	}
3162
-
3163
-	if(privdata->dataSocket == -1)
3164
-		/*
3165
-		 * First header - make connexion with clamd
3166
-		 */
3167
-		if(!connect2clamd(privdata)) {
3168
-			clamfi_cleanup(ctx);
3169
-			return cl_error;
3170
-		}
3171
-
3172
-	if(clamfi_send(privdata, 0, "%s: %s\n", headerf, headerv) <= 0) {
3173
-		clamfi_cleanup(ctx);
3174
-		return cl_error;
3175
-	}
3176
-
3177
-	return SMFIS_CONTINUE;
3178
-}
3179
-
3180
-/*
3181
- * At this point DATA will have been received, so we really ought to
3182
- * send 554 back not 550
3183
- */
3184
-static sfsistat
3185
-clamfi_eoh(SMFICTX *ctx)
3186
-{
3187
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
3188
-	char **to;
3189
-
3190
-	logg(_("*clamfi_eoh\n"));
3191
-
3192
-	/*
3193
-	 * The DATA instruction from SMTP (RFC2821) must have been sent
3194
-	 */
3195
-	privdata->rejectCode = "554";
3196
-
3197
-	if(privdata->dataSocket == -1)
3198
-		/*
3199
-		 * No headers - make connexion with clamd
3200
-		 */
3201
-		if(!connect2clamd(privdata)) {
3202
-			clamfi_cleanup(ctx);
3203
-			return cl_error;
3204
-		}
3205
-
3206
-#if	0
3207
-	/* Mailing lists often say our own posts are from us */
3208
-	if(detect_forged_local_address && privdata->from &&
3209
-	   (!privdata->sender) && !isWhitelisted(privdata->from, 1)) {
3210
-		char me[MAXHOSTNAMELEN + 1];
3211
-		const char *ptr;
3212
-
3213
-		if(gethostname(me, sizeof(me) - 1) < 0) {
3214
-			if(use_syslog)
3215
-				syslog(LOG_WARNING, _("clamfi_eoh: gethostname failed"));
3216
-			return SMFIS_CONTINUE;
3217
-		}
3218
-		ptr = strstr(privdata->from, me);
3219
-		if(ptr && (ptr != privdata->from) && (*--ptr == '@')) {
3220
-			if(use_syslog)
3221
-				syslog(LOG_NOTICE, _("Rejected email falsely claiming to be from %s"), privdata->from);
3222
-			smfi_setreply(ctx, "554", "5.7.1", _("You have claimed to be from me, but you are not"));
3223
-			broadcast(_("Forged local address detected"));
3224
-			clamfi_cleanup(ctx);
3225
-			return SMFIS_REJECT;
3226
-		}
3227
-	}
3228
-#endif
3229
-
3230
-	if(clamfi_send(privdata, 1, "\n") != 1) {
3231
-		clamfi_cleanup(ctx);
3232
-		return cl_error;
3233
-	}
3234
-
3235
-	if(black_hole_mode) {
3236
-		sfsistat rc = black_hole(privdata);
3237
-
3238
-		if(rc != SMFIS_CONTINUE) {
3239
-			clamfi_cleanup(ctx);
3240
-			return rc;
3241
-		}
3242
-	}
3243
-
3244
-	/*
3245
-	 * See if the e-mail is only going to members of the list
3246
-	 * of users we don't scan for. If it is, don't scan, otherwise
3247
-	 * scan
3248
-	 *
3249
-	 * scan = false
3250
-	 * FORALL recipients
3251
-	 *	IF receipient NOT MEMBER OF white address list
3252
-	 *	THEN
3253
-	 *		scan = true
3254
-	 *	FI
3255
-	 * ENDFOR
3256
-	 */
3257
-	for(to = privdata->to; *to; to++)
3258
-		if(!isWhitelisted(*to, 1))
3259
-			/*
3260
-			 * This recipient is not on the whitelist,
3261
-			 * no need to check any further
3262
-			 */
3263
-			return SMFIS_CONTINUE;
3264
-
3265
-	/*
3266
-	 * Didn't find a recipient who is not on the white list, so all
3267
-	 * must be on the white list, so just accept the e-mail
3268
-	 */
3269
-	logg(_("*clamfi_enveoh: ignoring whitelisted message"));
3270
-	clamfi_cleanup(ctx);
3271
-
3272
-	return SMFIS_ACCEPT;
3273
-}
3274
-
3275
-static sfsistat
3276
-clamfi_body(SMFICTX *ctx, u_char *bodyp, size_t len)
3277
-{
3278
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
3279
-	int nbytes;
3280
-
3281
-	logg(_("*clamfi_envbody: %lu bytes"), (unsigned long)len);
3282
-
3283
-	if(len == 0)	/* unlikely */
3284
-		return SMFIS_CONTINUE;
3285
-
3286
-	if(privdata == NULL)	/* sanity check */
3287
-		return cl_error;
3288
-
3289
-	/*
3290
-	 * TODO:
3291
-	 *	If not in external mode, call cli_scanbuff here, at least for
3292
-	 * the first block
3293
-	 */
3294
-	/*
3295
-	 * Lines starting with From are changed to >From, to
3296
-	 *	avoid FP matches in the scanning code, which will speed it up
3297
-	 */
3298
-	if((len >= 6) && cli_memstr((char *)bodyp, len, "\nFrom ", 6)) {
3299
-		const char *ptr = (const char *)bodyp;
3300
-		int left = len;
3301
-
3302
-		nbytes = 0;
3303
-
3304
-		/*
3305
-		 * FIXME: sending one byte at a time down a socket is
3306
-		 *	inefficient
3307
-		 */
3308
-		do {
3309
-			if(*ptr == '\n') {
3310
-				/*
3311
-				 * FIXME: doesn't work if the \nFrom straddles
3312
-				 * multiple calls to clamfi_body
3313
-				 */
3314
-				if(strncmp(ptr, "\nFrom ", 6) == 0) {
3315
-					nbytes += clamfi_send(privdata, 7, "\n>From ");
3316
-					ptr += 6;
3317
-					left -= 6;
3318
-				} else {
3319
-					nbytes += clamfi_send(privdata, 1, "\n");
3320
-					ptr++;
3321
-					left--;
3322
-				}
3323
-			} else {
3324
-				nbytes += clamfi_send(privdata, 1, ptr++);
3325
-				left--;
3326
-			}
3327
-			if(left < 6 && left > 0) {
3328
-				nbytes += clamfi_send(privdata, left, ptr);
3329
-				break;
3330
-			}
3331
-		} while(left > 0);
3332
-	} else
3333
-		nbytes = clamfi_send(privdata, len, (char *)bodyp);
3334
-
3335
-	if(streamMaxLength > 0L) {
3336
-		if(privdata->numBytes > streamMaxLength) {
3337
-			const char *sendmailId = smfi_getsymval(ctx, "i");
3338
-
3339
-			if(sendmailId == NULL)
3340
-				sendmailId = "Unknown";
3341
-			logg(_("%s: Message more than StreamMaxLength (%ld) bytes - not scanned\n"),
3342
-				sendmailId, streamMaxLength);
3343
-			if(!nflag)
3344
-				smfi_addheader(ctx, "X-Virus-Status", _("Not Scanned - StreamMaxLength exceeded"));
3345
-
3346
-			return SMFIS_ACCEPT;	/* clamfi_close will be called */
3347
-		}
3348
-	}
3349
-	if(nbytes < (int)len) {
3350
-		clamfi_cleanup(ctx);	/* not needed, but just to be safe */
3351
-		return cl_error;
3352
-	}
3353
-	if(Sflag) {
3354
-		if(privdata->body) {
3355
-			assert(privdata->bodyLen > 0);
3356
-			privdata->body = cli_realloc(privdata->body, privdata->bodyLen + len);
3357
-			memcpy(&privdata->body[privdata->bodyLen], bodyp, len);
3358
-			privdata->bodyLen += len;
3359
-		} else {
3360
-			assert(privdata->bodyLen == 0);
3361
-			privdata->body = cli_malloc(len);
3362
-			memcpy(privdata->body, bodyp, len);
3363
-			privdata->bodyLen = len;
3364
-		}
3365
-	}
3366
-	return SMFIS_CONTINUE;
3367
-}
3368
-
3369
-static sfsistat
3370
-clamfi_eom(SMFICTX *ctx)
3371
-{
3372
-	int rc = SMFIS_CONTINUE;
3373
-	char *ptr;
3374
-	const char *sendmailId;
3375
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
3376
-	char mess[128];
3377
-#ifdef	SESSION
3378
-	struct session *session;
3379
-#endif
3380
-
3381
-	logg("*clamfi_eom\n");
3382
-
3383
-#ifdef	CL_DEBUG
3384
-	assert(privdata != NULL);
3385
-#ifndef	SESSION
3386
-	assert((privdata->cmdSocket >= 0) || (privdata->filename != NULL));
3387
-	assert(!((privdata->cmdSocket >= 0) && (privdata->filename != NULL)));
3388
-#endif
3389
-#endif
3390
-
3391
-	if(external) {
3392
-		shutdown(privdata->dataSocket, SHUT_WR);	/* bug 487 */
3393
-		close(privdata->dataSocket);
3394
-		privdata->dataSocket = -1;
3395
-	}
3396
-
3397
-	if(!nflag) {
3398
-		/*
3399
-		 * remove any existing claims that it's virus free so that
3400
-		 * downstream checkers aren't fooled by a carefully crafted
3401
-		 * virus.
3402
-		 */
3403
-		int i;
3404
-
3405
-		for(i = privdata->statusCount; i > 0; --i)
3406
-			if(smfi_chgheader(ctx, "X-Virus-Status", i, NULL) == MI_FAILURE)
3407
-				logg(_("^Failed to delete X-Virus-Status header %d\n"), i);
3408
-	}
3409
-
3410
-	if(!external) {
3411
-		const char *virname;
3412
-		int ret;
3413
-		struct  cl_engine *cur_engine;
3414
-
3415
-		pthread_mutex_lock(&engine_mutex);
3416
-		ret = cl_engine_addref(engine);
3417
-		cur_engine = engine; /* avoid races */
3418
-		pthread_mutex_unlock(&engine_mutex);
3419
-		if(ret != CL_SUCCESS) {
3420
-			logg("!cl_engine_addref failed\n");
3421
-			clamfi_cleanup(ctx);
3422
-			return cl_error;
3423
-		}
3424
-		switch(cl_scanfile(privdata->filename, &virname, NULL, cur_engine, options)) {
3425
-			case CL_CLEAN:
3426
-				if(logok)
3427
-					logg("#%s: OK\n", privdata->filename);
3428
-				strcpy(mess, "OK");
3429
-				break;
3430
-			case CL_VIRUS:
3431
-				snprintf(mess, sizeof(mess), "%s: %s FOUND", privdata->filename, virname);
3432
-				logg("#%s\n", mess);
3433
-				break;
3434
-			default:
3435
-				snprintf(mess, sizeof(mess), "%s: ERROR", privdata->filename);
3436
-				logg("!%s\n", mess);
3437
-				break;
3438
-		}
3439
-		cl_engine_free(cur_engine); /* drop reference or free */
3440
-
3441
-#ifdef	SESSION
3442
-		session = NULL;
3443
-#endif
3444
-	} else if(privdata->filename) {
3445
-		char cmdbuf[1024];
3446
-		/*
3447
-		 * Create socket to talk to clamd.
3448
-		 */
3449
-#ifndef	SESSION
3450
-		struct sockaddr_un server;
3451
-#endif
3452
-		long nbytes;
3453
-
3454
-		snprintf(cmdbuf, sizeof(cmdbuf) - 1, "SCAN %s", privdata->filename);
3455
-		logg("#clamfi_eom: SCAN %s\n", privdata->filename);
3456
-
3457
-		nbytes = (int)strlen(cmdbuf);
3458
-
3459
-#ifdef	SESSION
3460
-		session = sessions;
3461
-		if(send(session->sock, cmdbuf, nbytes, 0) < nbytes) {
3462
-			perror("send");
3463
-			clamfi_cleanup(ctx);
3464
-			logg(_("failed to send SCAN %s command to clamd\n"), privdata->filename);
3465
-			return cl_error;
3466
-		}
3467
-#else
3468
-		if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
3469
-			perror("socket");
3470
-			clamfi_cleanup(ctx);
3471
-			return cl_error;
3472
-		}
3473
-		memset((char *)&server, 0, sizeof(struct sockaddr_un));
3474
-		server.sun_family = AF_UNIX;
3475
-		strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
3476
-		server.sun_path[sizeof(server.sun_path)-1]='\0';
3477
-
3478
-		if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
3479
-			perror(localSocket);
3480
-			clamfi_cleanup(ctx);
3481
-			return cl_error;
3482
-		}
3483
-		if(send(privdata->cmdSocket, cmdbuf, nbytes, 0) < nbytes) {
3484
-			perror("send");
3485
-			clamfi_cleanup(ctx);
3486
-			logg(_("failed to send SCAN command to clamd\n"));
3487
-			return cl_error;
3488
-		}
3489
-
3490
-		shutdown(privdata->cmdSocket, SHUT_WR);
3491
-#endif
3492
-	}
3493
-#ifdef	SESSION
3494
-	else
3495
-		session = &sessions[privdata->serverNumber];
3496
-#endif
3497
-
3498
-	sendmailId = smfi_getsymval(ctx, "i");
3499
-	if(sendmailId == NULL)
3500
-		sendmailId = "Unknown";
3501
-
3502
-	if(external) {
3503
-		int nbytes;
3504
-#ifdef	SESSION
3505
-#ifdef	CL_DEBUG
3506
-		if(debug_level >= 4)
3507
-			logg(_("#Waiting to read status from fd %d\n"),
3508
-				session->sock);
3509
-#endif
3510
-		nbytes = clamd_recv(session->sock, mess, sizeof(mess) - 1);
3511
-#else
3512
-		nbytes = clamd_recv(privdata->cmdSocket, mess, sizeof(mess) - 1);
3513
-#endif
3514
-		if(nbytes > 0) {
3515
-			mess[nbytes] = '\0';
3516
-			if((ptr = strchr(mess, '\n')) != NULL)
3517
-				*ptr = '\0';
3518
-
3519
-			logg(_("*clamfi_eom: read %s\n"), mess);
3520
-		} else {
3521
-#ifdef	MAXHOSTNAMELEN
3522
-			char hostname[MAXHOSTNAMELEN + 1];
3523
-
3524
-			cli_strtokbuf(serverHostNames, privdata->serverNumber, ":", hostname);
3525
-			if(strcmp(hostname, "127.0.0.1") == 0)
3526
-				gethostname(hostname, sizeof(hostname));
3527
-#else
3528
-			char *hostname = cli_strtok(serverHostNames, privdata->serverNumber, ":");
3529
-#endif
3530
-			if(privdata->subject)
3531
-				logg(_("^%s: clamfi_eom: read nothing from clamd on %s, from %s (%s)\n"),
3532
-					sendmailId, hostname, privdata->from,
3533
-					privdata->subject);
3534
-			else
3535
-				logg(_("^%s: clamfi_eom: read nothing from clamd on %s, from %s\n"),
3536
-					sendmailId, hostname, privdata->from);
3537
-
3538
-			if((!nflag) && (cl_error == SMFIS_ACCEPT))
3539
-				smfi_addheader(ctx, "X-Virus-Status", _("Not Scanned - Read timeout exceeded"));
3540
-#ifndef	MAXHOSTNAMELEN
3541
-			free(hostname);
3542
-#endif
3543
-
3544
-#ifdef	CL_DEBUG
3545
-			/*
3546
-			 * Save the file which caused the timeout, for
3547
-			 * debugging
3548
-			 */
3549
-			if(quarantine_dir) {
3550
-				logg(_("Quarantining failed email\n"));
3551
-				qfile(privdata, sendmailId, "scanning-timeout");
3552
-			}
3553
-#endif
3554
-
3555
-			/*
3556
-			 * TODO: if more than one host has been specified, try
3557
-			 * another one - setting cl_error to SMFIS_TEMPFAIL
3558
-			 * helps by forcing a retry
3559
-			 */
3560
-			clamfi_cleanup(ctx);
3561
-
3562
-#ifdef	SESSION
3563
-			pthread_mutex_lock(&sstatus_mutex);
3564
-			session->status = CMDSOCKET_DOWN;
3565
-			pthread_mutex_unlock(&sstatus_mutex);
3566
-#endif
3567
-			return cl_error;
3568
-		}
3569
-
3570
-#ifdef	SESSION
3571
-		pthread_mutex_lock(&sstatus_mutex);
3572
-		if(session->status == CMDSOCKET_INUSE)
3573
-			session->status = CMDSOCKET_FREE;
3574
-		pthread_mutex_unlock(&sstatus_mutex);
3575
-#else
3576
-		close(privdata->cmdSocket);
3577
-		privdata->cmdSocket = -1;
3578
-#endif
3579
-	}
3580
-
3581
-	if(!nflag) {
3582
-		char buf[1024];
3583
-
3584
-		/*
3585
-		 * Include the hostname where the scan took place
3586
-		 */
3587
-		if(localSocket || !external) {
3588
-#ifdef	MAXHOSTNAMELEN
3589
-			char hostname[MAXHOSTNAMELEN + 1];
3590
-#else
3591
-			char hostname[65];
3592
-#endif
3593
-
3594
-			if(gethostname(hostname, sizeof(hostname)) < 0) {
3595
-				const char *j = smfi_getsymval(ctx, "{j}");
3596
-
3597
-				if(j)
3598
-					strncpy(hostname, j, sizeof(hostname) - 1);
3599
-				else
3600
-					strcpy(hostname, _("Error determining host"));
3601
-				hostname[sizeof(hostname)-1]='\0';
3602
-			} else if(strchr(hostname, '.') == NULL) {
3603
-				/*
3604
-				 * Determine fully qualified name
3605
-				 */
3606
-				struct hostent hostent;
3607
-
3608
-				if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) && hostent.h_name) {
3609
-					strncpy(hostname, hostent.h_name, sizeof(hostname));
3610
-					hostname[sizeof(hostname)-1]='\0';
3611
-				}
3612
-			}
3613
-
3614
-#ifdef	SESSION
3615
-			pthread_mutex_lock(&version_mutex);
3616
-			snprintf(buf, sizeof(buf) - 1, "%s on %s",
3617
-				clamav_versions[privdata->serverNumber], hostname);
3618
-			pthread_mutex_unlock(&version_mutex);
3619
-#else
3620
-			snprintf(buf, sizeof(buf) - 1, "%s on %s",
3621
-				clamav_version, hostname);
3622
-#endif
3623
-		} else {
3624
-#ifdef	MAXHOSTNAMELEN
3625
-			char hostname[MAXHOSTNAMELEN + 1];
3626
-
3627
-			if(cli_strtokbuf(serverHostNames, privdata->serverNumber, ":", hostname)) {
3628
-				if(strcmp(hostname, "127.0.0.1") == 0)
3629
-					gethostname(hostname, sizeof(hostname));
3630
-#else
3631
-			char *hostname = cli_strtok(serverHostNames, privdata->serverNumber, ":");
3632
-			if(hostname) {
3633
-#endif
3634
-
3635
-#ifdef	SESSION
3636
-				pthread_mutex_lock(&version_mutex);
3637
-				snprintf(buf, sizeof(buf) - 1, "%s on %s",
3638
-					clamav_versions[privdata->serverNumber], hostname);
3639
-				pthread_mutex_unlock(&version_mutex);
3640
-#else
3641
-				snprintf(buf, sizeof(buf) - 1, "%s on %s",
3642
-					clamav_version, hostname);
3643
-#endif
3644
-#ifndef	MAXHOSTNAMELEN
3645
-				free(hostname);
3646
-#endif
3647
-			} else
3648
-				/* sanity check failed - should issue warning */
3649
-				strcpy(buf, _("Error determining host"));
3650
-		}
3651
-		smfi_addheader(ctx, "X-Virus-Scanned", buf);
3652
-	}
3653
-
3654
-	/*
3655
-	 * TODO: it would be useful to add a header if mbox.c/FOLLOWURLS was
3656
-	 * exceeded
3657
-	 */
3658
-#ifdef	HAVE_RESOLV_H
3659
-	if((strstr(mess, "FOUND") != NULL) && (strstr(mess, "Phishing") != NULL)) {
3660
-		table_t *prevhosts = tableCreate();
3661
-
3662
-		if(spf(privdata, prevhosts)) {
3663
-			logg(_("%s: Ignoring %s false positive from %s received from %s\n"),
3664
-				sendmailId, mess, privdata->from, privdata->ip);
3665
-			strcpy(mess, "OK");
3666
-			/*
3667
-			 * Report false positive to ClamAV, works best when
3668
-			 * clamav-milter has had to create a local copy of
3669
-			 * the email, e.g. when --quarantine-dir is on
3670
-			 */
3671
-			if(report_fps &&
3672
-			   (smfi_addrcpt(ctx, report_fps) == MI_FAILURE)) {
3673
-				if(privdata->filename) {
3674
-					char cmd[1024];
3675
-
3676
-					snprintf(cmd, sizeof(cmd) - 1,
3677
-						"mail -s \"False Positive: %s\" %s < %s",
3678
-						mess, report_fps,
3679
-						privdata->filename);
3680
-					if(system(cmd) == 0)
3681
-						logg(_("#Reported phishing false positive to %s"), report_fps);
3682
-					else
3683
-						logg(_("^Couldn't report false positive to %s\n"), report_fps);
3684
-				} else
3685
-					/*
3686
-					 * Most likely this is because we're
3687
-					 * attempting to add a recipient on
3688
-					 * another host
3689
-					 */
3690
-					logg(_("^Can't set phish FP header\n"));
3691
-			}
3692
-		}
3693
-		tableDestroy(prevhosts);
3694
-	}
3695
-#endif
3696
-	if(strstr(mess, "ERROR") != NULL) {
3697
-		if(strstr(mess, "Size limit reached") != NULL) {
3698
-			/*
3699
-			 * Clamd has stopped on StreamMaxLength before us
3700
-			 */
3701
-			logg(_("%s: Message more than StreamMaxLength (%ld) bytes - not scanned"),
3702
-				sendmailId, streamMaxLength);
3703
-			if(!nflag)
3704
-				smfi_addheader(ctx, "X-Virus-Status", _("Not Scanned - StreamMaxLength exceeded"));
3705
-			clamfi_cleanup(ctx);	/* not needed, but just to be safe */
3706
-			return SMFIS_ACCEPT;
3707
-		}
3708
-		if(!nflag)
3709
-			smfi_addheader(ctx, "X-Virus-Status", _("Not Scanned"));
3710
-
3711
-		logg("!%s: %s\n", sendmailId, mess);
3712
-		rc = cl_error;
3713
-	} else if((ptr = strstr(mess, "FOUND")) != NULL) {
3714
-		/*
3715
-		 * FIXME: This will give false positives if the
3716
-		 *	word "FOUND" is in the email, e.g. the
3717
-		 *	quarantine directory is /tmp/VIRUSES-FOUND
3718
-		 */
3719
-		int i;
3720
-		char **to, *virusname, *err;
3721
-		char reject[1024];
3722
-
3723
-		/*
3724
-		 * Remove the "FOUND" word, and the space before it
3725
-		 */
3726
-		*--ptr = '\0';
3727
-
3728
-		/* skip over 'stream/filename: ' at the start */
3729
-		if((virusname = strchr(mess, ':')) != NULL)
3730
-			virusname = &virusname[2];
3731
-		else
3732
-			virusname = mess;
3733
-
3734
-		if(!nflag) {
3735
-			char buf[129];
3736
-
3737
-			snprintf(buf, sizeof(buf) - 1, "%s %s", _("Infected with"), virusname);
3738
-			smfi_addheader(ctx, "X-Virus-Status", buf);
3739
-		}
3740
-
3741
-		if(quarantine_dir)
3742
-			qfile(privdata, sendmailId, virusname);
3743
-
3744
-		/*
3745
-		 * Setup err as a list of recipients
3746
-		 */
3747
-		err = (char *)cli_malloc(1024);
3748
-
3749
-		if(err == NULL) {
3750
-			clamfi_cleanup(ctx);
3751
-			return cl_error;
3752
-		}
3753
-
3754
-		/*
3755
-		 * Use snprintf rather than printf since we don't know
3756
-		 * the length of privdata->from and may get a buffer
3757
-		 * overrun
3758
-		 */
3759
-		snprintf(err, 1023, _("Intercepted virus from %s to"),
3760
-			privdata->from);
3761
-
3762
-		ptr = strchr(err, '\0');
3763
-
3764
-		i = 1024;
3765
-
3766
-		for(to = privdata->to; *to; to++) {
3767
-			/*
3768
-			 * Re-alloc if we are about run out of buffer
3769
-			 * space
3770
-			 *
3771
-			 * TODO: Only append *to if it's a valid, local
3772
-			 *	email address
3773
-			 */
3774
-			if(&ptr[strlen(*to) + 2] >= &err[i]) {
3775
-				i += 1024;
3776
-				err = cli_realloc(err, i);
3777
-				if(err == NULL) {
3778
-					clamfi_cleanup(ctx);
3779
-					return cl_error;
3780
-				}
3781
-				ptr = strchr(err, '\0');
3782
-			}
3783
-			ptr = cli_strrcpy(ptr, " ");
3784
-			ptr = cli_strrcpy(ptr, *to);
3785
-		}
3786
-		(void)strcpy(ptr, "\n");
3787
-
3788
-		/* Include the sendmail queue ID in the log */
3789
-		logg("%s: %s %s", sendmailId, mess, err);
3790
-		free(err);
3791
-
3792
-		if(!qflag) {
3793
-			char cmd[128];
3794
-			FILE *sendmail;
3795
-
3796
-			/*
3797
-			 * If the oflag is given this sendmail command
3798
-			 * will cause the mail being generated here to be
3799
-			 * scanned. So if oflag is given we just put the
3800
-			 * item in the queue so there's no scanning of two
3801
-			 * messages at once. It'll still be scanned, but
3802
-			 * not at the same time as the incoming message
3803
-			 *
3804
-			 * FIXME: there is a race condition here when sendmail
3805
-			 * and clamav-milter run on the same machine. If the
3806
-			 * system is very overloaded this sendmail can
3807
-			 * take a long time to start - and may even fail
3808
-			 * is the LA is > REFUSE_LA. In all the time we're
3809
-			 * taking to start this sendmail, the sendmail that's
3810
-			 * started us may timeout waiting for a response and
3811
-			 * let the virus through (albeit tagged with
3812
-			 * X-Virus-Status: Infected) because we haven't
3813
-			 * sent SMFIS_DISCARD or SMFIS_REJECT
3814
-			 *
3815
-			 * -i flag, suggested by Michal Jaegermann
3816
-			 *	<michal@harddata.com>
3817
-			 */
3818
-			snprintf(cmd, sizeof(cmd) - 1,
3819
-				(oflag || fflag) ? "%s -t -i -odq" : "%s -t -i",
3820
-				SENDMAIL_BIN);
3821
-
3822
-			logg("#Calling %s\n", cmd);
3823
-			sendmail = popen(cmd, "w");
3824
-
3825
-			if(sendmail) {
3826
-				if(from && from[0])
3827
-					fprintf(sendmail, "From: %s\n", from);
3828
-				else
3829
-					fprintf(sendmail, "From: %s\n", privdata->from);
3830
-#ifdef	BOUNCE
3831
-				if(bflag && privdata->from) {
3832
-					fprintf(sendmail, "To: %s\n", privdata->from);
3833
-					fprintf(sendmail, "Cc: %s\n", postmaster);
3834
-				} else
3835
-#endif
3836
-					fprintf(sendmail, "To: %s\n", postmaster);
3837
-
3838
-				if((!pflag) && privdata->to)
3839
-					for(to = privdata->to; *to; to++)
3840
-						fprintf(sendmail, "Cc: %s\n", *to);
3841
-				/*
3842
-				 * Auto-submitted is still a draft, keep an
3843
-				 * eye on its format
3844
-				 */
3845
-				fputs("Auto-Submitted: auto-submitted (antivirus notify)\n", sendmail);
3846
-				/* "Sergey Y. Afonin" <asy@kraft-s.ru> */
3847
-				if((ptr = smfi_getsymval(ctx, "{_}")) != NULL)
3848
-					fprintf(sendmail,
3849
-						"X-Infected-Received-From: %s\n",
3850
-						ptr);
3851
-				fputs(_("Subject: Virus intercepted\n"), sendmail);
3852
-
3853
-				if(templateHeaders) {
3854
-					/*
3855
-					 * For example, to state the character
3856
-					 * set of the message:
3857
-					 *	Content-Type: text/plain; charset=koi8-r
3858
-					 *
3859
-					 * Based on a suggestion by Denis
3860
-					 *	Eremenko <moonshade@mail.kz>
3861
-					 */
3862
-					FILE *fin = fopen(templateHeaders, "r");
3863
-
3864
-					if(fin == NULL) {
3865
-						perror(templateHeaders);
3866
-						logg(_("!Can't open e-mail template header file %s"),
3867
-								templateHeaders);
3868
-					} else {
3869
-						int c;
3870
-						int lastc = EOF;
3871
-
3872
-						while((c = getc(fin)) != EOF) {
3873
-							putc(c, sendmail);
3874
-							lastc = c;
3875
-						}
3876
-						fclose(fin);
3877
-						/*
3878
-						 * File not new line terminated
3879
-						 */
3880
-						if(lastc != '\n')
3881
-							fputs(_("\n"), sendmail);
3882
-					}
3883
-				}
3884
-
3885
-				fputs(_("\n"), sendmail);
3886
-
3887
-				if((templateFile == NULL) ||
3888
-				   (sendtemplate(ctx, templateFile, sendmail, virusname) < 0)) {
3889
-					/*
3890
-					 * Use our own hardcoded template
3891
-					 */
3892
-#ifdef	BOUNCE
3893
-					if(bflag)
3894
-						fputs(_("A message you sent to\n"), sendmail);
3895
-					else if(pflag)
3896
-#else
3897
-					if(pflag)
3898
-#endif
3899
-						/*
3900
-						 * The message is only going to
3901
-						 * the postmaster, so include
3902
-						 * some useful information
3903
-						 */
3904
-						fprintf(sendmail, _("The message %1$s sent from %2$s to\n"),
3905
-							sendmailId, privdata->from);
3906
-					else
3907
-						fprintf(sendmail, _("A message sent from %s to\n"),
3908
-							privdata->from);
3909
-
3910
-					for(to = privdata->to; *to; to++)
3911
-						fprintf(sendmail, "\t%s\n", *to);
3912
-					fprintf(sendmail, _("contained %s and has not been accepted for delivery.\n"), virusname);
3913
-
3914
-					if(quarantine_dir != NULL)
3915
-						fprintf(sendmail, _("\nThe message in question has been quarantined as %s\n"), privdata->filename);
3916
-
3917
-					if(hflag) {
3918
-						fprintf(sendmail, _("\nThe message was received by %1$s from %2$s via %3$s\n\n"),
3919
-							smfi_getsymval(ctx, "j"), privdata->from,
3920
-							smfi_getsymval(ctx, "_"));
3921
-						fputs(_("For your information, the original message headers were:\n\n"), sendmail);
3922
-						header_list_print(privdata->headers, sendmail);
3923
-					} else if(privdata->received)
3924
-						/*
3925
-						 * TODO: parse this to find
3926
-						 * real infected machine.
3927
-						 * Need to decide how to find
3928
-						 * if it's a dynamic IP from a
3929
-						 * dial up account in which
3930
-						 * case there may not be much
3931
-						 * we can do if that DHCP has
3932
-						 * set the hostname...
3933
-						 */
3934
-						fprintf(sendmail, _("\nThe infected machine is likely to be here:\n%s\t\n"),
3935
-							privdata->received);
3936
-
3937
-				}
3938
-
3939
-				logg("#Waiting for %s to finish\n", cmd);
3940
-				if(pclose(sendmail) != 0)
3941
-					logg(_("%s: Failed to notify clamAV interception - see dead.letter\n"), sendmailId);
3942
-			} else
3943
-				logg(_("^Can't execute '%s' to send virus notice"), cmd);
3944
-		}
3945
-
3946
-		if(report && (quarantine == NULL) && (!advisory) &&
3947
-		   (strstr(virusname, "Phishing") != NULL)) {
3948
-			/*
3949
-			 * Report phishing to an agency
3950
-			 */
3951
-			for(to = privdata->to; *to; to++) {
3952
-				smfi_delrcpt(ctx, *to);
3953
-				smfi_addheader(ctx, "X-Original-To", *to);
3954
-			}
3955
-			if(smfi_addrcpt(ctx, report) == MI_FAILURE) {
3956
-				/* It's a remote site */
3957
-				if(privdata->filename) {
3958
-					char cmd[1024];
3959
-
3960
-					snprintf(cmd, sizeof(cmd) - 1,
3961
-						"mail -s \"%s\" %s < %s",
3962
-						virusname, report,
3963
-						privdata->filename);
3964
-					if(system(cmd) == 0)
3965
-						logg(_("#Reported phishing to %s"), report);
3966
-					else
3967
-						logg(_("^Couldn't report to %s\n"), report);
3968
-					if((!rejectmail) || privdata->discard)
3969
-						rc = SMFIS_DISCARD;
3970
-					else
3971
-						rc = SMFIS_REJECT;
3972
-				} else {
3973
-					logg(_("^Can't set anti-phish header\n"));
3974
-					rc = (privdata->discard) ? SMFIS_DISCARD : SMFIS_REJECT;
3975
-				}
3976
-			} else {
3977
-				setsubject(ctx, "Phishing attempt trapped by ClamAV and redirected");
3978
-
3979
-				logg("Redirected phish to %s\n", report);
3980
-			}
3981
-		} else if(quarantine) {
3982
-			for(to = privdata->to; *to; to++) {
3983
-				smfi_delrcpt(ctx, *to);
3984
-				smfi_addheader(ctx, "X-Original-To", *to);
3985
-			}
3986
-			/*
3987
-			 * NOTE: on a closed relay this will not work
3988
-			 * if the recipient is a remote address
3989
-			 */
3990
-			if(smfi_addrcpt(ctx, quarantine) == MI_FAILURE) {
3991
-				logg(_("^Can't set quarantine user %s"), quarantine);
3992
-				rc = (privdata->discard) ? SMFIS_DISCARD : SMFIS_REJECT;
3993
-			} else {
3994
-				if(report &&
3995
-				   strstr(virusname, "Phishing") != NULL)
3996
-					(void)smfi_addrcpt(ctx, report);
3997
-				setsubject(ctx, virusname);
3998
-
3999
-				logg("Redirected virus to %s", quarantine);
4000
-			}
4001
-		} else if(advisory)
4002
-			setsubject(ctx, virusname);
4003
-		else if(rejectmail) {
4004
-			if(privdata->discard)
4005
-				rc = SMFIS_DISCARD;
4006
-			else
4007
-				rc = SMFIS_REJECT;	/* Delete the e-mail */
4008
-		} else
4009
-			rc = SMFIS_DISCARD;
4010
-
4011
-		if(quarantine_dir) {
4012
-			/*
4013
-			 * Cleanup filename here otherwise clamfi_free() will
4014
-			 * delete the file that we wish to keep because it
4015
-			 * is infected
4016
-			 */
4017
-			free(privdata->filename);
4018
-			privdata->filename = NULL;
4019
-		}
4020
-
4021
-		/*
4022
-		 * Don't drop the message if it's been forwarded to a
4023
-		 * quarantine email
4024
-		 */
4025
-		snprintf(reject, sizeof(reject) - 1, _("virus %s detected by ClamAV - http://www.clamav.net"), virusname);
4026
-		smfi_setreply(ctx, (const char *)privdata->rejectCode, "5.7.1", reject);
4027
-		broadcast(mess);
4028
-
4029
-		if(blacklist_time && privdata->ip[0]) {
4030
-			logg(_("Will blacklist %s for %d seconds because of %s\n"),
4031
-				privdata->ip, blacklist_time, virusname);
4032
-			pthread_mutex_lock(&blacklist_mutex);
4033
-			(void)tableUpdate(blacklist, privdata->ip,
4034
-				(int)time((time_t *)0));
4035
-			pthread_mutex_unlock(&blacklist_mutex);
4036
-		}
4037
-	} else if((strstr(mess, "OK") == NULL) && (strstr(mess, "Empty file") == NULL)) {
4038
-		if(!nflag)
4039
-			smfi_addheader(ctx, "X-Virus-Status", _("Unknown"));
4040
-		logg(_("!%s: incorrect message \"%s\" from clamd"),
4041
-				sendmailId, mess);
4042
-		rc = cl_error;
4043
-	} else {
4044
-		if(!nflag)
4045
-			smfi_addheader(ctx, "X-Virus-Status", _("Clean"));
4046
-
4047
-		/* Include the sendmail queue ID in the log */
4048
-		if(logok)
4049
-			logg(_("%s: clean message from %s\n"),
4050
-				sendmailId,
4051
-				(privdata->from) ? privdata->from : _("an unknown sender"));
4052
-
4053
-		if(privdata->body) {
4054
-			/*
4055
-			 * Add a signature that all has been scanned OK
4056
-			 *
4057
-			 * Note that this is simple minded and isn't aware of
4058
-			 *	any MIME segments in the message. In practice
4059
-			 *	this means that the message will only display
4060
-			 *	on users' terminals if the message is
4061
-			 *	plain/text
4062
-			 */
4063
-			off_t len = updateSigFile();
4064
-
4065
-			if(len) {
4066
-				assert(Sflag != 0);
4067
-
4068
-				privdata->body = cli_realloc(privdata->body, privdata->bodyLen + len);
4069
-				if(privdata->body) {
4070
-					memcpy(&privdata->body[privdata->bodyLen], signature, len);
4071
-					smfi_replacebody(ctx, privdata->body, privdata->bodyLen + len);
4072
-				}
4073
-			}
4074
-		}
4075
-	}
4076
-
4077
-	return rc;
4078
-}
4079
-
4080
-static sfsistat
4081
-clamfi_abort(SMFICTX *ctx)
4082
-{
4083
-	logg("*clamfi_abort\n");
4084
-
4085
-	clamfi_cleanup(ctx);
4086
-	decrement_connexions();
4087
-
4088
-	logg("*clamfi_abort returns\n");
4089
-
4090
-	return cl_error;
4091
-}
4092
-
4093
-static sfsistat
4094
-clamfi_close(SMFICTX *ctx)
4095
-{
4096
-	logg("*clamfi_close\n");
4097
-
4098
-	clamfi_cleanup(ctx);
4099
-	decrement_connexions();
4100
-
4101
-	return SMFIS_CONTINUE;
4102
-}
4103
-
4104
-static void
4105
-clamfi_cleanup(SMFICTX *ctx)
4106
-{
4107
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
4108
-
4109
-	logg("#clamfi_cleanup\n");
4110
-
4111
-	if(privdata) {
4112
-		clamfi_free(privdata, 0);
4113
-		smfi_setpriv(ctx, NULL);
4114
-	}
4115
-}
4116
-
4117
-static void
4118
-clamfi_free(struct privdata *privdata, int keep)
4119
-{
4120
-	logg("#clamfi_free\n");
4121
-
4122
-	if(privdata) {
4123
-#ifdef	SESSION
4124
-		struct session *session;
4125
-#endif
4126
-		if(privdata->body)
4127
-			free(privdata->body);
4128
-
4129
-		if(privdata->dataSocket >= 0)
4130
-			close(privdata->dataSocket);
4131
-
4132
-		if(privdata->filename != NULL) {
4133
-			/*
4134
-			 * Don't print an error if the file hasn't been
4135
-			 * created yet
4136
-			 */
4137
-			if((unlink(privdata->filename) < 0) && (errno != ENOENT)) {
4138
-				perror(privdata->filename);
4139
-				logg(_("!Can't remove clean file %s"),
4140
-					privdata->filename);
4141
-			}
4142
-			free(privdata->filename);
4143
-		}
4144
-
4145
-		if(privdata->from) {
4146
-#ifdef	CL_DEBUG
4147
-			if(debug_level >= 9)
4148
-				logg("#Free privdata->from\n");
4149
-#endif
4150
-			free(privdata->from);
4151
-		}
4152
-
4153
-		if(privdata->subject)
4154
-			free(privdata->subject);
4155
-		if(privdata->sender)
4156
-			free(privdata->sender);
4157
-
4158
-		if(privdata->to) {
4159
-			char **to;
4160
-
4161
-			for(to = privdata->to; *to; to++) {
4162
-#ifdef	CL_DEBUG
4163
-				if(debug_level >= 9)
4164
-					logg("#Free *privdata->to\n");
4165
-#endif
4166
-				free(*to);
4167
-			}
4168
-#ifdef	CL_DEBUG
4169
-			if(debug_level >= 9)
4170
-				logg("#Free privdata->to\n");
4171
-#endif
4172
-			free(privdata->to);
4173
-		}
4174
-
4175
-		if(external) {
4176
-#ifdef	SESSION
4177
-			session = &sessions[privdata->serverNumber];
4178
-			pthread_mutex_lock(&sstatus_mutex);
4179
-			if(session->status == CMDSOCKET_INUSE) {
4180
-				/*
4181
-				 * Probably we've got here because
4182
-				 * StreamMaxLength has been reached
4183
-				 */
4184
-#if	0
4185
-				pthread_mutex_unlock(&sstatus_mutex);
4186
-				if(readTimeout) {
4187
-					char buf[64];
4188
-					const int fd = session->sock;
4189
-
4190
-					logg("#clamfi_free: flush server %d fd %d\n",
4191
-						privdata->serverNumber, fd);
4192
-
4193
-					/*
4194
-					 * FIXME: whenever this code gets
4195
-					 *	executed, all of the PINGs fail
4196
-					 *	in the next watchdog cycle
4197
-					 */
4198
-					while(clamd_recv(fd, buf, sizeof(buf)) > 0)
4199
-						;
4200
-				}
4201
-				pthread_mutex_lock(&sstatus_mutex);
4202
-#endif
4203
-				/* Force a reset */
4204
-				session->status = CMDSOCKET_DOWN;
4205
-			}
4206
-			pthread_mutex_unlock(&sstatus_mutex);
4207
-#else
4208
-			if(privdata->cmdSocket >= 0) {
4209
-#if	0
4210
-				char buf[64];
4211
-
4212
-				/*
4213
-				 * Flush the remote end so that clamd doesn't
4214
-				 * get a SIGPIPE
4215
-				 */
4216
-				if(readTimeout)
4217
-					while(clamd_recv(privdata->cmdSocket, buf, sizeof(buf)) > 0)
4218
-						;
4219
-#endif
4220
-				close(privdata->cmdSocket);
4221
-			}
4222
-#endif
4223
-		}
4224
-
4225
-		if(privdata->headers)
4226
-			header_list_free(privdata->headers);
4227
-
4228
-#ifdef	CL_DEBUG
4229
-		if(debug_level >= 9)
4230
-			logg("#Free privdata\n");
4231
-#endif
4232
-		if(privdata->received)
4233
-			free(privdata->received);
4234
-
4235
-		if(keep) {
4236
-			memset(privdata, '\0', sizeof(struct privdata));
4237
-#ifdef	SESSION
4238
-			privdata->dataSocket = -1;
4239
-#else
4240
-			privdata->dataSocket = privdata->cmdSocket = -1;
4241
-#endif
4242
-		} else
4243
-			free(privdata);
4244
-	}
4245
-
4246
-	logg("#clamfi_free returns\n");
4247
-}
4248
-
4249
-/*
4250
- * Returns < 0 for failure, otherwise the number of bytes sent
4251
- */
4252
-static int
4253
-clamfi_send(struct privdata *privdata, size_t len, const char *format, ...)
4254
-{
4255
-	char output[BUFSIZ];
4256
-	const char *ptr;
4257
-	int ret = 0;
4258
-	assert(format != NULL);
4259
-
4260
-	if(len > 0)
4261
-		/*
4262
-		 * It isn't a NUL terminated string. We have a set number of
4263
-		 * bytes to output.
4264
-		 */
4265
-		ptr = format;
4266
-	else {
4267
-		va_list argp;
4268
-
4269
-		va_start(argp, format);
4270
-		vsnprintf(output, sizeof(output) - 1, format, argp);
4271
-		va_end(argp);
4272
-
4273
-		len = strlen(output);
4274
-		ptr = output;
4275
-	}
4276
-#ifdef	CL_DEBUG
4277
-	if(debug_level >= 9) {
4278
-		time_t t;
4279
-		const struct tm *tm;
4280
-
4281
-		time(&t);
4282
-		tm = localtime(&t);
4283
-
4284
-		logg("#%d:%d:%d clamfi_send: len=%u bufsiz=%u, fd=%d\n",
4285
-			tm->tm_hour, tm->tm_min, tm->tm_sec, len,
4286
-			sizeof(output), privdata->dataSocket);
4287
-	}
4288
-#endif
4289
-
4290
-	while(len > 0) {
4291
-		const int nbytes = (privdata->filename) ?
4292
-			write(privdata->dataSocket, ptr, len) :
4293
-			send(privdata->dataSocket, ptr, len, 0);
4294
-
4295
-		assert(privdata->dataSocket >= 0);
4296
-
4297
-		if(nbytes == -1) {
4298
-			if(privdata->filename) {
4299
-#ifdef HAVE_STRERROR_R
4300
-				char buf[32];
4301
-
4302
-				perror(privdata->filename);
4303
-				strerror_r(errno, buf, sizeof(buf));
4304
-				logg(_("!write failure (%lu bytes) to %s: %s\n"),
4305
-					(unsigned long)len, privdata->filename, buf);
4306
-#else
4307
-				perror(privdata->filename);
4308
-				logg(_("!write failure (%lu bytes) to %s: %s\n"),
4309
-					(unsigned long)len, privdata->filename,
4310
-					strerror(errno));
4311
-#endif
4312
-			} else {
4313
-				if(errno == EINTR)
4314
-					continue;
4315
-				perror("send");
4316
-#ifdef HAVE_STRERROR_R
4317
-				{
4318
-					char buf[32];
4319
-					strerror_r(errno, buf, sizeof(buf));
4320
-					logg(_("!write failure (%lu bytes) to clamd: %s\n"),
4321
-						(unsigned long)len, buf);
4322
-				}
4323
-#else
4324
-				logg(_("!write failure (%lu bytes) to clamd: %s\n"),
4325
-					(unsigned long)len, strerror(errno));
4326
-#endif
4327
-				checkClamd(1);
4328
-			}
4329
-
4330
-			return -1;
4331
-		}
4332
-		ret += nbytes;
4333
-		len -= nbytes;
4334
-		ptr = &ptr[nbytes];
4335
-
4336
-		if(streamMaxLength > 0L) {
4337
-			privdata->numBytes += nbytes;
4338
-			if(privdata->numBytes >= streamMaxLength)
4339
-				break;
4340
-		}
4341
-	}
4342
-	return ret;
4343
-}
4344
-
4345
-/*
4346
- * Like strcpy, but return the END of the destination, allowing a quicker
4347
- * means of adding to the end of a string than strcat
4348
- */
4349
-#if	0
4350
-static char *
4351
-strrcpy(char *dest, const char *source)
4352
-{
4353
-	/* Pre assertions */
4354
-	assert(dest != NULL);
4355
-	assert(source != NULL);
4356
-	assert(dest != source);
4357
-
4358
-	while((*dest++ = *source++) != '\0')
4359
-		;
4360
-	return(--dest);
4361
-}
4362
-#endif
4363
-
4364
-/*
4365
- * Read from clamav - timeout if necessary
4366
- */
4367
-static long
4368
-clamd_recv(int sock, char *buf, size_t len)
4369
-{
4370
-	struct timeval tv;
4371
-	long ret;
4372
-
4373
-	assert(sock >= 0);
4374
-
4375
-	if(readTimeout == 0) {
4376
-		do
4377
-			/* TODO: Needs a test for ssize_t in configure */
4378
-			ret = (long)recv(sock, buf, len, 0);
4379
-		while((ret < 0) && (errno == EINTR));
4380
-
4381
-		return ret;
4382
-	}
4383
-
4384
-	tv.tv_sec = readTimeout;
4385
-	tv.tv_usec = 0;
4386
-
4387
-	for(;;) {
4388
-		fd_set rfds;
4389
-
4390
-		FD_ZERO(&rfds);
4391
-		FD_SET(sock, &rfds);
4392
-
4393
-		switch(select(sock + 1, &rfds, NULL, NULL, &tv)) {
4394
-			case -1:
4395
-				if(errno == EINTR)
4396
-					/* FIXME: work out time left */
4397
-					continue;
4398
-				perror("select");
4399
-				return -1;
4400
-			case 0:
4401
-				logg(_("!No data received from clamd in %d seconds\n"), readTimeout);
4402
-				return 0;
4403
-		}
4404
-		break;
4405
-	}
4406
-
4407
-	do
4408
-		ret = recv(sock, buf, len, 0);
4409
-	while((ret < 0) && (errno == EINTR));
4410
-
4411
-	return ret;
4412
-}
4413
-
4414
-/*
4415
- * Read in the signature file
4416
- */
4417
-static off_t
4418
-updateSigFile(void)
4419
-{
4420
-	struct stat statb;
4421
-	int fd;
4422
-
4423
-	if(sigFilename == NULL)
4424
-		/* nothing to read */
4425
-		return 0;
4426
-
4427
-	if(stat(sigFilename, &statb) < 0) {
4428
-		perror(sigFilename);
4429
-		logg(_("Can't stat %s"), sigFilename);
4430
-		return 0;
4431
-	}
4432
-
4433
-	if(statb.st_mtime <= signatureStamp)
4434
-		return statb.st_size;	/* not changed */
4435
-
4436
-	fd = open(sigFilename, O_RDONLY);
4437
-	if(fd < 0) {
4438
-		perror(sigFilename);
4439
-		logg(_("Can't open %s"), sigFilename);
4440
-		return 0;
4441
-	}
4442
-
4443
-	signatureStamp = statb.st_mtime;
4444
-
4445
-	signature = cli_realloc((void *)signature, statb.st_size);
4446
-	if(signature)
4447
-		cli_readn(fd, (void *)signature, statb.st_size);
4448
-	close(fd);
4449
-
4450
-	return statb.st_size;
4451
-}
4452
-
4453
-static header_list_t
4454
-header_list_new(void)
4455
-{
4456
-	header_list_t ret;
4457
-
4458
-	ret = (header_list_t)cli_malloc(sizeof(struct header_list_struct));
4459
-	if(ret) {
4460
-		ret->first = NULL;
4461
-		ret->last = NULL;
4462
-	}
4463
-	return ret;
4464
-}
4465
-
4466
-static void
4467
-header_list_free(header_list_t list)
4468
-{
4469
-	struct header_node_t *iter;
4470
-
4471
-	if(list == NULL)
4472
-		return;
4473
-
4474
-	iter = list->first;
4475
-	while(iter) {
4476
-		struct header_node_t *iter2 = iter->next;
4477
-		free(iter->header);
4478
-		free(iter);
4479
-		iter = iter2;
4480
-	}
4481
-	free(list);
4482
-}
4483
-
4484
-static void
4485
-header_list_add(header_list_t list, const char *headerf, const char *headerv)
4486
-{
4487
-	char *header;
4488
-	size_t len;
4489
-	struct header_node_t *new_node;
4490
-
4491
-	if(list == NULL)
4492
-		return;
4493
-
4494
-	len = (size_t)(strlen(headerf) + strlen(headerv) + 3);
4495
-
4496
-	header = (char *)cli_malloc(len);
4497
-	if(header == NULL)
4498
-		return;
4499
-
4500
-	sprintf(header, "%s: %s", headerf, headerv);
4501
-	new_node = (struct header_node_t *)cli_malloc(sizeof(struct header_node_t));
4502
-	if(new_node == NULL) {
4503
-		free(header);
4504
-		return;
4505
-	}
4506
-	new_node->header = header;
4507
-	new_node->next = NULL;
4508
-	if(list->first == NULL)
4509
-		list->first = new_node;
4510
-	if(list->last)
4511
-		list->last->next = new_node;
4512
-
4513
-	list->last = new_node;
4514
-}
4515
-
4516
-static void
4517
-header_list_print(const header_list_t list, FILE *fp)
4518
-{
4519
-	const struct header_node_t *iter;
4520
-
4521
-	if(list == NULL)
4522
-		return;
4523
-
4524
-	for(iter = list->first; iter; iter = iter->next) {
4525
-		if(strncmp(iter->header, "From ", 5) == 0)
4526
-			putc('>', fp);
4527
-		fprintf(fp, "%s\n", iter->header);
4528
-	}
4529
-}
4530
-
4531
-/*
4532
- * Establish a connexion to clamd
4533
- *	Returns success (1) or failure (0)
4534
- */
4535
-static int
4536
-connect2clamd(struct privdata *privdata)
4537
-{
4538
-	assert(privdata != NULL);
4539
-	assert(privdata->dataSocket == -1);
4540
-	assert(privdata->from != NULL);
4541
-	assert(privdata->to != NULL);
4542
-
4543
-	logg("*connect2clamd\n");
4544
-
4545
-	if(quarantine_dir || tmpdir) {	/* store message in a temporary file */
4546
-		int ntries = 5;
4547
-		const char *dir = (tmpdir) ? tmpdir : quarantine_dir;
4548
-
4549
-		/*
4550
-		 * TODO: investigate mkdtemp on LINUX and possibly others
4551
-		 */
4552
-#ifdef	C_AIX
4553
-		/*
4554
-		 * Patch by Andy Feldt <feldt@nhn.ou.edu>, AIX 5.2 sets errno
4555
-		 * to ENOENT often and sometimes sets errno to 0 (after a
4556
-		 * database reload) for the mkdir call
4557
-		 */
4558
-		if((mkdir(dir, 0700) < 0) && (errno != EEXIST) && (errno > 0) &&
4559
-		    (errno != ENOENT)) {
4560
-#else
4561
-		if((mkdir(dir, 0700) < 0) && (errno != EEXIST)) {
4562
-#endif
4563
-			perror(dir);
4564
-			logg(_("mkdir %s failed"), dir);
4565
-			return 0;
4566
-		}
4567
-		privdata->filename = (char *)cli_malloc(strlen(dir) + 12);
4568
-
4569
-		if(privdata->filename == NULL)
4570
-			return 0;
4571
-
4572
-		do {
4573
-			sprintf(privdata->filename, "%s/msg.XXXXXX", dir);
4574
-#if	defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS)
4575
-			privdata->dataSocket = mkstemp(privdata->filename);
4576
-#else
4577
-			if(mktemp(privdata->filename) == NULL) {
4578
-				logg(_("mktemp %s failed"), privdata->filename);
4579
-				return 0;
4580
-			}
4581
-			privdata->dataSocket = open(privdata->filename, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0600);
4582
-#endif
4583
-		} while((--ntries > 0) && (privdata->dataSocket < 0));
4584
-
4585
-		if(privdata->dataSocket < 0) {
4586
-			perror(privdata->filename);
4587
-			logg(_("Temporary quarantine file %s creation failed"),
4588
-				privdata->filename);
4589
-			free(privdata->filename);
4590
-			privdata->filename = NULL;
4591
-			return 0;
4592
-		}
4593
-		privdata->serverNumber = 0;
4594
-		logg("#Saving message to %s to scan later\n", privdata->filename);
4595
-	} else {	/* communicate to clamd */
4596
-		int freeServer, nbytes;
4597
-		in_port_t p;
4598
-		struct sockaddr_in reply;
4599
-		char buf[64];
4600
-
4601
-#ifdef	SESSION
4602
-		struct session *session;
4603
-#else
4604
-		assert(privdata->cmdSocket == -1);
4605
-#endif
4606
-
4607
-		/*
4608
-		 * Create socket to talk to clamd. It will tell us the port to
4609
-		 * use to send the data. That will require another socket.
4610
-		 */
4611
-		if(localSocket) {
4612
-#ifndef	SESSION
4613
-			struct sockaddr_un server;
4614
-
4615
-			memset((char *)&server, 0, sizeof(struct sockaddr_un));
4616
-			server.sun_family = AF_UNIX;
4617
-			strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
4618
-			server.sun_path[sizeof(server.sun_path)-1]='\0';
4619
-
4620
-			if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
4621
-				perror("socket");
4622
-				return 0;
4623
-			}
4624
-			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
4625
-				perror(localSocket);
4626
-				return 0;
4627
-			}
4628
-			privdata->serverNumber = 0;
4629
-#endif
4630
-			freeServer = 0;
4631
-		} else {	/* TCP/IP */
4632
-#ifdef	SESSION
4633
-			freeServer = findServer();
4634
-			if(freeServer < 0)
4635
-				return 0;
4636
-			assert(freeServer < (int)max_children);
4637
-#else
4638
-			struct sockaddr_in server;
4639
-
4640
-			memset((char *)&server, 0, sizeof(struct sockaddr_in));
4641
-			server.sin_family = AF_INET;
4642
-			server.sin_port = (in_port_t)htons(tcpSocket);
4643
-
4644
-			assert(serverIPs != NULL);
4645
-
4646
-			freeServer = findServer();
4647
-			if(freeServer < 0)
4648
-				return 0;
4649
-			assert(freeServer < (int)numServers);
4650
-
4651
-			server.sin_addr.s_addr = serverIPs[freeServer];
4652
-
4653
-			if((privdata->cmdSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4654
-				perror("socket");
4655
-				return 0;
4656
-			}
4657
-			if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
4658
-				char *hostname = cli_strtok(serverHostNames, freeServer, ":");
4659
-
4660
-				perror(hostname ? hostname : "connect");
4661
-				close(privdata->cmdSocket);
4662
-				privdata->cmdSocket = -1;
4663
-				if(hostname)
4664
-					free(hostname);
4665
-				time(&last_failed_pings[freeServer]);
4666
-				return 0;
4667
-			}
4668
-			last_failed_pings[freeServer] = (time_t)0;
4669
-#endif
4670
-			privdata->serverNumber = freeServer;
4671
-		}
4672
-
4673
-#ifdef	SESSION
4674
-		if(serverIPs[freeServer] == (int)inet_addr("127.0.0.1")) {
4675
-			privdata->filename = cli_gentemp(NULL);
4676
-			if(privdata->filename) {
4677
-				logg("#connect2clamd(%d): creating %s\n", freeServer, privdata->filename);
4678
-#ifdef	O_TEXT
4679
-				privdata->dataSocket = open(privdata->filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_TEXT, 0600);
4680
-#else
4681
-				privdata->dataSocket = open(privdata->filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
4682
-#endif
4683
-				if(privdata->dataSocket < 0) {
4684
-					perror(privdata->filename);
4685
-					free(privdata->filename);
4686
-					privdata->filename = NULL;
4687
-				} else
4688
-					return sendToFrom(privdata);
4689
-			}
4690
-		}
4691
-		logg("#connect2clamd(%d): STREAM\n", freeServer);
4692
-
4693
-		session = &sessions[freeServer];
4694
-		if((session->sock < 0) || (send(session->sock, "STREAM\n", 7, 0) < 7)) {
4695
-			perror("send");
4696
-			pthread_mutex_lock(&sstatus_mutex);
4697
-			session->status = CMDSOCKET_DOWN;
4698
-			pthread_mutex_unlock(&sstatus_mutex);
4699
-			logg(_("!failed to send STREAM command clamd server %d"),
4700
-				freeServer);
4701
-
4702
-			return 0;
4703
-		}
4704
-#else
4705
-		if(send(privdata->cmdSocket, "STREAM\n", 7, 0) < 7) {
4706
-			perror("send");
4707
-			logg(_("!failed to send STREAM command clamd"));
4708
-			return 0;
4709
-		}
4710
-		shutdown(privdata->cmdSocket, SHUT_WR);
4711
-#endif
4712
-
4713
-		/*
4714
-		 * Create socket that we'll use to send the data to clamd
4715
-		 */
4716
-		if((privdata->dataSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4717
-			perror("socket");
4718
-			logg(_("!failed to create TCPSocket to talk to clamd\n"));
4719
-			return 0;
4720
-		}
4721
-
4722
-		shutdown(privdata->dataSocket, SHUT_RD);
4723
-
4724
-#ifdef	SESSION
4725
-		nbytes = clamd_recv(session->sock, buf, sizeof(buf));
4726
-		if(nbytes <= 0) {
4727
-			if(nbytes < 0) {
4728
-				perror("recv");
4729
-				logg(_("!recv failed from clamd getting PORT\n"));
4730
-			} else
4731
-				logg(_("!EOF from clamd getting PORT\n"));
4732
-
4733
-			pthread_mutex_lock(&sstatus_mutex);
4734
-			session->status = CMDSOCKET_DOWN;
4735
-			return pthread_mutex_unlock(&sstatus_mutex);
4736
-		}
4737
-#else
4738
-		nbytes = clamd_recv(privdata->cmdSocket, buf, sizeof(buf));
4739
-		if(nbytes <= 0) {
4740
-			if(nbytes < 0) {
4741
-				perror("recv");
4742
-				logg(_("!recv failed from clamd getting PORT\n"));
4743
-			} else
4744
-				logg(_("!EOF from clamd getting PORT\n"));
4745
-
4746
-			return 0;
4747
-		}
4748
-#endif
4749
-		buf[nbytes] = '\0';
4750
-#ifdef	CL_DEBUG
4751
-		if(debug_level >= 4)
4752
-			logg("#Received: %s\n", buf);
4753
-#endif
4754
-		if(sscanf(buf, "PORT %hu\n", &p) != 1) {
4755
-			logg(_("!Expected port information from clamd, got '%s'\n"),
4756
-				buf);
4757
-#ifdef	SESSION
4758
-			session->status = CMDSOCKET_DOWN;
4759
-			pthread_mutex_unlock(&sstatus_mutex);
4760
-#endif
4761
-			return 0;
4762
-		}
4763
-
4764
-		memset((char *)&reply, 0, sizeof(struct sockaddr_in));
4765
-		reply.sin_family = AF_INET;
4766
-		reply.sin_port = (in_port_t)htons(p);
4767
-
4768
-		assert(serverIPs != NULL);
4769
-
4770
-		reply.sin_addr.s_addr = serverIPs[freeServer];
4771
-
4772
-#ifdef	CL_DEBUG
4773
-		if(debug_level >= 4)
4774
-#ifdef	SESSION
4775
-			logg(_("#Connecting to local port %d - data %d cmd %d\n"),
4776
-				p, privdata->dataSocket, session->sock);
4777
-#else
4778
-			logg(_("#Connecting to local port %d - data %d cmd %d\n"),
4779
-				p, privdata->dataSocket, privdata->cmdSocket);
4780
-#endif
4781
-#endif
4782
-
4783
-		if(connect(privdata->dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in)) < 0) {
4784
-			perror("connect");
4785
-
4786
-			logg("#Failed to connect to port %d given by clamd\n",
4787
-				p);
4788
-			/* 0.4 - use better error message */
4789
-#ifdef HAVE_STRERROR_R
4790
-			strerror_r(errno, buf, sizeof(buf));
4791
-			logg(_("!Failed to connect to port %d given by clamd: %s"),
4792
-					p, buf);
4793
-#else
4794
-			logg(_("!Failed to connect to port %d given by clamd: %s"), p, strerror(errno));
4795
-#endif
4796
-#ifdef	SESSION
4797
-			pthread_mutex_lock(&sstatus_mutex);
4798
-			session->status = CMDSOCKET_DOWN;
4799
-			pthread_mutex_unlock(&sstatus_mutex);
4800
-#endif
4801
-			return 0;
4802
-		}
4803
-	}
4804
-
4805
-	if(!sendToFrom(privdata))
4806
-		return 0;
4807
-
4808
-	logg("#connect2clamd: serverNumber = %d\n", privdata->serverNumber);
4809
-
4810
-	return 1;
4811
-}
4812
-
4813
-/*
4814
- * Combine the To and From into one clamfi_send to save bandwidth
4815
- * when sending using TCP/IP to connect to a remote clamd, by band
4816
- * width here I mean number of packets
4817
- */
4818
-static int
4819
-sendToFrom(struct privdata *privdata)
4820
-{
4821
-	char **to;
4822
-	char *msg;
4823
-	int length;
4824
-
4825
-	length = strlen(privdata->from) + 34;
4826
-	for(to = privdata->to; *to; to++)
4827
-		length += strlen(*to) + 5;
4828
-
4829
-	msg = cli_malloc(length + 1);
4830
-
4831
-	if(msg) {
4832
-		sprintf(msg, "Received: by clamav-milter\nFrom: %s\n",
4833
-			privdata->from);
4834
-
4835
-		for(to = privdata->to; *to; to++) {
4836
-			char *eom = strchr(msg, '\0');
4837
-
4838
-			sprintf(eom, "To: %s\n", *to);
4839
-		}
4840
-		if(clamfi_send(privdata, length, msg) != length) {
4841
-			free(msg);
4842
-			return 0;
4843
-		}
4844
-		free(msg);
4845
-	} else {
4846
-		if(clamfi_send(privdata, 0,
4847
-		    "Received: by clamav-milter\nFrom: %s\n",
4848
-		    privdata->from) <= 0)
4849
-			return 0;
4850
-
4851
-		for(to = privdata->to; *to; to++)
4852
-			if(clamfi_send(privdata, 0, "To: %s\n", *to) <= 0)
4853
-				return 0;
4854
-	}
4855
-
4856
-	return 1;
4857
-}
4858
-
4859
-/*
4860
- * If possible, check if clamd has died, and, if requested, report if it has
4861
- * Returns true if OK or unknown, otherwise false
4862
- */
4863
-static int
4864
-checkClamd(int log_result)
4865
-{
4866
-	pid_t pid;
4867
-	int fd, nbytes;
4868
-	char buf[9];
4869
-
4870
-	int i, onlocal;
4871
-
4872
-	for(i = 0; i < numServers; i++) {
4873
-		if(serverIPs[i] && pingServer(i))
4874
-			return 1;
4875
-	}
4876
-
4877
-	if(log_result)
4878
-		logg(_("!Can't find any clamd server\n"));
4879
-	return 0;
4880
-}
4881
-
4882
-/*
4883
- * Send a templated message about an intercepted message. Very basic for
4884
- * now, just to prove it works, will enhance the flexability later, only
4885
- * supports %v and $sendmail_variables$ at present.
4886
- *
4887
- * TODO: more template features
4888
- * TODO: allow filename to start with a '|' taken to mean the output of
4889
- *	a program
4890
- */
4891
-static int
4892
-sendtemplate(SMFICTX *ctx, const char *filename, FILE *sendmail, const char *virusname)
4893
-{
4894
-	FILE *fin = fopen(filename, "r");
4895
-	struct stat statb;
4896
-	char *buf, *ptr /* , *ptr2 */;
4897
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
4898
-
4899
-	if(fin == NULL) {
4900
-		perror(filename);
4901
-		logg(_("!Can't open e-mail template file %s"), filename);
4902
-		return -1;
4903
-	}
4904
-
4905
-	if(fstat(fileno(fin), &statb) < 0) {
4906
-		/* File disappeared in race condition? */
4907
-		perror(filename);
4908
-		logg(_("!Can't stat e-mail template file %s"), filename);
4909
-		fclose(fin);
4910
-		return -1;
4911
-	}
4912
-	buf = cli_malloc(statb.st_size + 1);
4913
-	if(buf == NULL) {
4914
-		fclose(fin);
4915
-		logg(_("!Out of memory"));
4916
-		return -1;
4917
-	}
4918
-	if(fread(buf, sizeof(char), statb.st_size, fin) != (size_t)statb.st_size) {
4919
-		perror(filename);
4920
-		logg(_("!Error reading e-mail template file %s"),
4921
-			filename);
4922
-		fclose(fin);
4923
-		free(buf);
4924
-		return -1;
4925
-	}
4926
-	fclose(fin);
4927
-	buf[statb.st_size] = '\0';
4928
-
4929
-	for(ptr = buf; *ptr; ptr++)
4930
-		switch(*ptr) {
4931
-			case '%': /* clamAV variable */
4932
-				switch(*++ptr) {
4933
-					case 'v':	/* virus name */
4934
-						fputs(virusname, sendmail);
4935
-						break;
4936
-					case '%':
4937
-						putc('%', sendmail);
4938
-						break;
4939
-					case 'h':	/* headers */
4940
-						if(privdata)
4941
-							header_list_print(privdata->headers, sendmail);
4942
-						break;
4943
-					case '\0':
4944
-						putc('%', sendmail);
4945
-						--ptr;
4946
-						continue;
4947
-					default:
4948
-						logg(_("!%s: Unknown clamAV variable \"%c\"\n"),
4949
-							filename, *ptr);
4950
-						break;
4951
-				}
4952
-				break;
4953
-			case '$': /* sendmail string */ {
4954
-				const char *val;
4955
-				char *end = strchr(++ptr, '$');
4956
-
4957
-				if(end == NULL) {
4958
-					logg(_("!%s: Unterminated sendmail variable \"%s\"\n"),
4959
-						filename, ptr);
4960
-					continue;
4961
-				}
4962
-				*end = '\0';
4963
-
4964
-				val = smfi_getsymval(ctx, ptr);
4965
-				if(val == NULL) {
4966
-					fputs(ptr, sendmail);
4967
-						logg(_("!%s: Unknown sendmail variable \"%s\"\n"),
4968
-							filename, ptr);
4969
-				} else
4970
-					fputs(val, sendmail);
4971
-				ptr = end;
4972
-				break;
4973
-			}
4974
-			case '\\':
4975
-				if(*++ptr == '\0') {
4976
-					--ptr;
4977
-					continue;
4978
-				}
4979
-				putc(*ptr, sendmail);
4980
-				break;
4981
-			default:
4982
-				putc(*ptr, sendmail);
4983
-		}
4984
-
4985
-	free(buf);
4986
-
4987
-	return 0;
4988
-}
4989
-
4990
-/*
4991
- * Keep the infected file in quarantine, return success (0) or failure
4992
- *
4993
- * It's quicker if the quarantine directory is on the same filesystem
4994
- *	as the temporary directory
4995
- */
4996
-static int
4997
-qfile(struct privdata *privdata, const char *sendmailId, const char *virusname)
4998
-{
4999
-	int MM, YY, DD;
5000
-	time_t t;
5001
-	size_t len;
5002
-	char *newname, *ptr;
5003
-	const struct tm *tm;
5004
-
5005
-	assert(privdata != NULL);
5006
-
5007
-	if((privdata->filename == NULL) || (virusname == NULL))
5008
-		return -1;
5009
-
5010
-	logg("#qfile filename '%s' sendmailId '%s' virusname '%s'\n", privdata->filename, sendmailId, virusname);
5011
-
5012
-	len = strlen(quarantine_dir);
5013
-
5014
-	newname = cli_malloc(len + strlen(sendmailId) + strlen(virusname) + 10);
5015
-
5016
-	if(newname == NULL)
5017
-		return -1;
5018
-
5019
-	t = time((time_t *)0);
5020
-	tm = localtime(&t);
5021
-	MM = tm->tm_mon + 1;
5022
-	YY = tm->tm_year - 100;
5023
-	DD = tm->tm_mday;
5024
-
5025
-	sprintf(newname, "%s/%02d%02d%02d", quarantine_dir, YY, MM, DD);
5026
-#ifdef	C_AIX
5027
-	if((mkdir(newname, 0700) < 0) && (errno != EEXIST) && (errno > 0) &&
5028
-	    (errno != ENOENT)) {
5029
-#else
5030
-	if((mkdir(newname, 0700) < 0) && (errno != EEXIST)) {
5031
-#endif
5032
-		perror(newname);
5033
-		logg(_("!mkdir %s failed\n"), newname);
5034
-		return -1;
5035
-	}
5036
-	sprintf(newname, "%s/%02d%02d%02d/%s.%s",
5037
-		quarantine_dir, YY, MM, DD, sendmailId, virusname);
5038
-
5039
-	/*
5040
-	 * Strip out funnies that may be in the name of the virus, such as '/'
5041
-	 * that would cause the quarantine to fail to save since the name
5042
-	 * of the virus is included in the filename
5043
-	 */
5044
-	for(ptr = &newname[len + 8]; *ptr; ptr++) {
5045
-#ifdef	C_DARWIN
5046
-		*ptr &= '\177';
5047
-#endif
5048
-#if	defined(MSDOS) || defined(C_WINDOWS) || defined(C_OS2)
5049
-		if(strchr("/*?<>|\\\"+=,;:\t ", *ptr))
5050
-#else
5051
-		if(*ptr == '/')
5052
-#endif
5053
-			*ptr = '_';
5054
-	}
5055
-	logg("#qfile move '%s' to '%s'\n", privdata->filename, newname);
5056
-
5057
-	if(move(privdata->filename, newname) < 0) {
5058
-		logg(_("^Can't rename %1$s to %2$s\n"),
5059
-			privdata->filename, newname);
5060
-		free(newname);
5061
-		return -1;
5062
-	}
5063
-	free(privdata->filename);
5064
-	privdata->filename = newname;
5065
-
5066
-	logg(_("Email quarantined as %s\n"), newname);
5067
-
5068
-	return 0;
5069
-}
5070
-
5071
-/*
5072
- * Move oldfile to newfile using the fastest possible method
5073
- */
5074
-static int
5075
-move(const char *oldfile, const char *newfile)
5076
-{
5077
-	int ret, c;
5078
-	FILE *fin, *fout;
5079
-#ifdef	C_LINUX
5080
-	struct stat statb;
5081
-	int in, out;
5082
-	off_t offset;
5083
-#endif
5084
-
5085
-	ret = rename(oldfile, newfile);
5086
-	if(ret >= 0)
5087
-		return 0;
5088
-
5089
-	if((ret < 0) && (errno != EXDEV)) {
5090
-		perror(newfile);
5091
-		return -1;
5092
-	}
5093
-
5094
-#ifdef	C_LINUX	/* >= 2.2 */
5095
-	in = open(oldfile, O_RDONLY);
5096
-	if(in < 0) {
5097
-		perror(oldfile);
5098
-		return -1;
5099
-	}
5100
-
5101
-	if(fstat(in, &statb) < 0) {
5102
-		perror(oldfile);
5103
-		close(in);
5104
-		return -1;
5105
-	}
5106
-	out = open(newfile, O_WRONLY|O_CREAT, 0600);
5107
-	if(out < 0) {
5108
-		perror(newfile);
5109
-		close(in);
5110
-		return -1;
5111
-	}
5112
-	offset = (off_t)0;
5113
-	ret = sendfile(out, in, &offset, statb.st_size);
5114
-	close(in);
5115
-	if(ret < 0) {
5116
-		/*
5117
-		 * Fall back if sendfile fails, which will happen on Linux
5118
-		 * 2.6 :-(. FreeBSD works correctly, so the ifdef should be
5119
-		 * fixed
5120
-		 */
5121
-		close(out);
5122
-		unlink(newfile);
5123
-
5124
-		fin = fopen(oldfile, "r");
5125
-		if(fin == NULL)
5126
-			return -1;
5127
-
5128
-		fout = fopen(newfile, "w");
5129
-		if(fout == NULL) {
5130
-			fclose(fin);
5131
-			return -1;
5132
-		}
5133
-		while((c = getc(fin)) != EOF)
5134
-			putc(c, fout);
5135
-
5136
-		fclose(fin);
5137
-		fclose(fout);
5138
-	} else
5139
-		close(out);
5140
-#else
5141
-	fin = fopen(oldfile, "r");
5142
-	if(fin == NULL)
5143
-		return -1;
5144
-
5145
-	fout = fopen(newfile, "w");
5146
-	if(fout == NULL) {
5147
-		fclose(fin);
5148
-		return -1;
5149
-	}
5150
-	while((c = getc(fin)) != EOF)
5151
-		putc(c, fout);
5152
-
5153
-	fclose(fin);
5154
-	fclose(fout);
5155
-#endif
5156
-
5157
-	logg("#removing %s\n", oldfile);
5158
-
5159
-	return unlink(oldfile);
5160
-}
5161
-
5162
-/*
5163
- * Store the name of the virus in the subject of the e-mail
5164
- */
5165
-static void
5166
-setsubject(SMFICTX *ctx, const char *virusname)
5167
-{
5168
-	struct privdata *privdata = (struct privdata *)smfi_getpriv(ctx);
5169
-	char subject[128];
5170
-
5171
-	if(privdata->subject)
5172
-		smfi_addheader(ctx, "X-Original-Subject", privdata->subject);
5173
-
5174
-	snprintf(subject, sizeof(subject) - 1, _("[Virus] %s"), virusname);
5175
-	if(privdata->subject)
5176
-		smfi_chgheader(ctx, "Subject", 1, subject);
5177
-	else
5178
-		smfi_addheader(ctx, "Subject", subject);
5179
-}
5180
-
5181
-#if	0
5182
-/*
5183
- * TODO: gethostbyname_r is non-standard so different operating
5184
- * systems do it in different ways. Need more examples
5185
- * Perhaps we could use res_search()?
5186
- * Perhaps we could use http://www.chiark.greenend.org.uk/~ian/adns/
5187
- *
5188
- * Returns 0 for success
5189
- */
5190
-static int
5191
-clamfi_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len)
5192
-{
5193
-#if	defined(HAVE_GETHOSTBYNAME_R_6)
5194
-	/* e.g. Linux */
5195
-	struct hostent *hp2;
5196
-	int ret = -1;
5197
-
5198
-	if((hostname == NULL) || (hp == NULL))
5199
-		return -1;
5200
-	if(gethostbyname_r(hostname, hp, buf, len, &hp2, &ret) < 0)
5201
-		return ret;
5202
-#elif	defined(HAVE_GETHOSTBYNAME_R_5)
5203
-	/* e.g. BSD, Solaris, Cygwin */
5204
-	int ret = -1;
5205
-
5206
-	if((hostname == NULL) || (hp == NULL))
5207
-		return -1;
5208
-	if(gethostbyname_r(hostname, hp, buf, len, &ret) == NULL)
5209
-		return ret;
5210
-#elif	defined(HAVE_GETHOSTBYNAME_R_3)
5211
-	/* e.g. HP/UX, AIX */
5212
-	if((hostname == NULL) || (hp == NULL))
5213
-		return -1;
5214
-	if(gethostbyname_r(hostname, &hp, (struct hostent_data *)buf) < 0)
5215
-		return h_errno;
5216
-#else
5217
-	/* Single thread the code */
5218
-	struct hostent *hp2;
5219
-	static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
5220
-
5221
-	if((hostname == NULL) || (hp == NULL))
5222
-		return -1;
5223
-
5224
-	pthread_mutex_lock(&hostent_mutex);
5225
-	if((hp2 = gethostbyname(hostname)) == NULL) {
5226
-		pthread_mutex_unlock(&hostent_mutex);
5227
-		return h_errno;
5228
-	}
5229
-	memcpy(hp, hp2, sizeof(struct hostent));
5230
-	pthread_mutex_unlock(&hostent_mutex);
5231
-#endif
5232
-
5233
-	return 0;
5234
-}
5235
-#endif
5236
-
5237
-/*
5238
- * Handle the -I flag
5239
- */
5240
-static int
5241
-add_local_ip(char *address)
5242
-{
5243
-	char *opt, *pref;
5244
-	int preflen;
5245
-	int retval;
5246
-	struct in_addr ignoreIP;
5247
-#ifdef	AF_INET6
5248
-	struct in6_addr ignoreIP6;
5249
-#endif
5250
-
5251
-	opt = cli_strdup(address);
5252
-	if(opt == NULL)
5253
-		return 0;
5254
-
5255
-	pref = strchr(opt, '/'); /* search for "/prefix" */
5256
-	if(pref)
5257
-		*pref = '\0';
5258
-#ifdef HAVE_INET_NTOP
5259
-	/* IPv4 address ? */
5260
-	if(inet_pton(AF_INET, opt, &ignoreIP) > 0) {
5261
-#else
5262
-	if(inet_aton(address, &ignoreIP)) {
5263
-#endif
5264
-		struct cidr_net *net;
5265
-
5266
-		for(net = (struct cidr_net *)localNets; net->base; net++)
5267
-			;
5268
-		if(pref && *(pref+1))
5269
-			preflen = atoi(pref+1);
5270
-		else
5271
-			preflen = 32;
5272
-
5273
-		net->base = ntohl(ignoreIP.s_addr);
5274
-		net->mask = MAKEMASK(preflen);
5275
-
5276
-		retval = 1;
5277
-	}
5278
-
5279
-#ifdef HAVE_INET_NTOP
5280
-#ifdef AF_INET6
5281
-	else if(inet_pton(AF_INET6, opt, &ignoreIP6) > 0) {
5282
-		/* IPv6 address ? */
5283
-		localNets6[localNets6_cnt].base = ignoreIP6;
5284
-
5285
-		if(pref && *(pref+1))
5286
-			preflen = atoi (pref+1);
5287
-		else
5288
-			preflen = 128;
5289
-		localNets6[localNets6_cnt].preflen = preflen;
5290
-		localNets6_cnt++;
5291
-
5292
-		retval = 1;
5293
-	}
5294
-#endif
5295
-#endif
5296
-	else
5297
-		retval = 0;
5298
-
5299
-	free(opt);
5300
-	return retval;
5301
-}
5302
-
5303
-/*
5304
- * Determine if an IPv6 email address is "local". The address is the
5305
- *	human readable version. Calls isLocalAddr if the given address is
5306
- *	IPv4
5307
- */
5308
-static int
5309
-isLocal(const char *addr)
5310
-{
5311
-	struct in_addr ip;
5312
-#ifdef	AF_INET6
5313
-	struct in6_addr ip6;
5314
-#endif
5315
-
5316
-#ifdef HAVE_INET_NTOP
5317
-	if(inet_pton(AF_INET, addr, &ip) > 0)
5318
-		return isLocalAddr(ip.s_addr);
5319
-#ifdef AF_INET6
5320
-	else if(inet_pton (AF_INET6, addr, &ip6) > 0) {
5321
-		int i;
5322
-		const cidr_net6 *pnet6 = localNets6;
5323
-
5324
-		for (i = 0; i < localNets6_cnt; i++) {
5325
-			int match = 1;
5326
-			int j;
5327
-
5328
-			for(j = 0; match && j < (pnet6->preflen >> 3); j++)
5329
-				if(pnet6->base.s6_addr[j] != ip6.s6_addr[j])
5330
-					match = 0;
5331
-			if(match && (j < 16)) {
5332
-				uint8_t mask = (uint8_t)(0xff << (8 - (pnet6->preflen & 7)) & 0xFF);
5333
-
5334
-				if((pnet6->base.s6_addr[j] & mask) != (ip6.s6_addr[j] & mask))
5335
-					match = 0;
5336
-			}
5337
-			if(match)
5338
-				return 1;	/* isLocal */
5339
-			pnet6++;
5340
-		 }
5341
-	}
5342
-#endif	/* AF_INET6 */
5343
-#endif	/* HAVE_INET_NTOP */
5344
-	return isLocalAddr(inet_addr(addr));
5345
-}
5346
-
5347
-/*
5348
- * David Champion <dgc@uchicago.edu>
5349
- *
5350
- * Check whether addr is on network by applying netmasks.
5351
- * addr must be a 32-bit integer-packed IPv4 address in network order.
5352
- * For example:
5353
- *	struct in_addr IPAddress;
5354
- *	isLocal = isLocalAddr(IPAddress.s_addr);
5355
- */
5356
-static int
5357
-isLocalAddr(in_addr_t addr)
5358
-{
5359
-	const struct cidr_net *net;
5360
-
5361
-	for(net = localNets; net->base; net++)
5362
-		if((net->base & net->mask) == (ntohl(addr) & net->mask))
5363
-			return 1;
5364
-
5365
-	return 0;	/* is non-local */
5366
-}
5367
-
5368
-/*
5369
- * Can't connect to any clamd server. This is serious, we need to inform
5370
- * someone. In the absence of SNMP the best way is by e-mail. We
5371
- * don't want to flood so there's a need to restrict to
5372
- * no more than say one message every 15 minutes
5373
- */
5374
-static void
5375
-clamdIsDown(void)
5376
-{
5377
-	static time_t lasttime;
5378
-	time_t thistime, diff;
5379
-	static pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER;
5380
-
5381
-	logg(_("!No response from any clamd server - your AV system is not scanning emails\n"));
5382
-
5383
-	time(&thistime);
5384
-	pthread_mutex_lock(&time_mutex);
5385
-	diff = thistime - lasttime;
5386
-	pthread_mutex_unlock(&time_mutex);
5387
-
5388
-	if(diff >= (time_t)(15 * 60)) {
5389
-		char cmd[128];
5390
-		FILE *sendmail;
5391
-
5392
-		snprintf(cmd, sizeof(cmd) - 1, "%s -t -i", SENDMAIL_BIN);
5393
-
5394
-		sendmail = popen(cmd, "w");
5395
-
5396
-		if(sendmail) {
5397
-			fprintf(sendmail, "To: %s\n", postmaster);
5398
-			fprintf(sendmail, "From: %s\n", postmaster);
5399
-			fputs(_("Subject: ClamAV Down\n"), sendmail);
5400
-			fputs("Priority: High\n\n", sendmail);
5401
-
5402
-			fputs(_("This is an automatic message\n\n"), sendmail);
5403
-
5404
-			if(numServers == 1)
5405
-				fputs(_("The clamd program cannot be contacted.\n"), sendmail);
5406
-			else
5407
-				fputs(_("No clamd server can be contacted.\n"), sendmail);
5408
-
5409
-			fputs(_("Emails may not be being scanned, please check your servers.\n"), sendmail);
5410
-
5411
-			if(pclose(sendmail) == 0) {
5412
-				pthread_mutex_lock(&time_mutex);
5413
-				time(&lasttime);
5414
-				pthread_mutex_unlock(&time_mutex);
5415
-			}
5416
-		}
5417
-	}
5418
-}
5419
-
5420
-#ifdef	SESSION
5421
-/*
5422
- * Thread to monitor the links to clamd sessions. Any marked as being in
5423
- * an error state because of previous I/O errors are restarted, and a heartbeat
5424
- * is sent the others
5425
- *
5426
- * It is woken up when the milter goes idle, when there are no free servers
5427
- * available and once every readTimeout-1 seconds
5428
- *
5429
- * TODO: reload the whiteList file if it's been changed
5430
- *
5431
- * TODO: localSocket support
5432
- */
5433
-static void *
5434
-watchdog(void *a)
5435
-{
5436
-	static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER;
5437
-
5438
-	while(!quitting) {
5439
-		unsigned int i;
5440
-		struct timespec ts;
5441
-		struct timeval tp;
5442
-		struct session *session;
5443
-
5444
-		gettimeofday(&tp, NULL);
5445
-
5446
-		ts.tv_sec = tp.tv_sec + freshclam_monitor;
5447
-		ts.tv_nsec = tp.tv_usec * 1000;
5448
-		logg("#watchdog sleeps\n");
5449
-		pthread_mutex_lock(&watchdog_mutex);
5450
-		/*
5451
-		 * Sometimes this returns EPIPE which isn't listed as a
5452
-		 * return value in the Linux man page for pthread_cond_timedwait
5453
-		 * so I'm not sure why it happens
5454
-		 */
5455
-		switch(pthread_cond_timedwait(&watchdog_cond, &watchdog_mutex, &ts)) {
5456
-			case ETIMEDOUT:
5457
-			case 0:
5458
-				break;
5459
-			default:
5460
-				perror("pthread_cond_timedwait");
5461
-		}
5462
-		pthread_mutex_unlock(&watchdog_mutex);
5463
-
5464
-		logg("#watchdog wakes\n");
5465
-
5466
-		if(check_and_reload_database() != 0) {
5467
-			if(cl_error != SMFIS_ACCEPT) {
5468
-				smfi_stop();
5469
-				return NULL;
5470
-			}
5471
-			logg(_("!No emails will be scanned"));
5472
-		}
5473
-
5474
-		i = 0;
5475
-		session = sessions;
5476
-		pthread_mutex_lock(&sstatus_mutex);
5477
-		for(; i < max_children; i++, session++) {
5478
-			const int sock = session->sock;
5479
-
5480
-			/*
5481
-			 * Check all free sessions are still usable
5482
-			 * This could take some time with many free
5483
-			 * sessions to slow remote servers, so only do this
5484
-			 * when the system is quiet (not 100% accurate when
5485
-			 * determining this since n_children isn't locked but
5486
-			 * that doesn't really matter)
5487
-			 */
5488
-			logg("#watchdog: check server %d\n", i);
5489
-			if((n_children == 0) &&
5490
-			   (session->status == CMDSOCKET_FREE) &&
5491
-			   (clamav_versions != NULL)) {
5492
-				if(send(sock, "VERSION\n", 8, 0) == 8) {
5493
-					char buf[81];
5494
-					const int nbytes = clamd_recv(sock, buf, sizeof(buf) - 1);
5495
-
5496
-					if(nbytes <= 0)
5497
-						session->status = CMDSOCKET_DOWN;
5498
-					else {
5499
-						buf[nbytes] = '\0';
5500
-						if(strncmp(buf, "ClamAV ", 7) == 0) {
5501
-							/* Remove the trailing new line from the reply */
5502
-							char *ptr;
5503
-
5504
-							if((ptr = strchr(buf, '\n')) != NULL)
5505
-								*ptr = '\0';
5506
-							pthread_mutex_lock(&version_mutex);
5507
-							if(clamav_versions[i] == NULL)
5508
-								clamav_versions[i] = cli_strdup(buf);
5509
-							else if(strcmp(buf, clamav_versions[i]) != 0) {
5510
-								logg("New version received for server %d: '%s'\n", i, buf);
5511
-								free(clamav_versions[i]);
5512
-								clamav_versions[i] = cli_strdup(buf);
5513
-							}
5514
-							pthread_mutex_unlock(&version_mutex);
5515
-						} else {
5516
-							logg("^watchdog: expected \"ClamAV\", got \"%s\"\n", buf);
5517
-							session->status = CMDSOCKET_DOWN;
5518
-						}
5519
-					}
5520
-				} else {
5521
-					perror("send");
5522
-					session->status = CMDSOCKET_DOWN;
5523
-				}
5524
-
5525
-				if(session->status == CMDSOCKET_DOWN)
5526
-					logg("^Session %d has gone down\n", i);
5527
-			}
5528
-			/*
5529
-			 * Reset all all dead sessions
5530
-			 */
5531
-			if(session->status == CMDSOCKET_DOWN) {
5532
-				/*
5533
-				 * The END command probably won't get through,
5534
-				 * but let's give it a go anyway
5535
-				 */
5536
-				if(sock >= 0) {
5537
-					send(sock, "END\n", 4, 0);
5538
-					close(sock);
5539
-				}
5540
-
5541
-				logg("#Trying to restart session %d\n", i);
5542
-				if(createSession(i) == 0) {
5543
-					session->status = CMDSOCKET_FREE;
5544
-					logg("^Session %d restarted OK\n", i);
5545
-				}
5546
-			}
5547
-		}
5548
-		for(i = 0; i < max_children; i++)
5549
-			if(sessions[i].status != CMDSOCKET_DOWN)
5550
-				break;
5551
-
5552
-		if(i == max_children)
5553
-			clamdIsDown();
5554
-		pthread_mutex_unlock(&sstatus_mutex);
5555
-
5556
-		/* Garbage collect IP addresses no longer blacklisted */
5557
-		if(blacklist) {
5558
-			pthread_mutex_lock(&blacklist_mutex);
5559
-			tableIterate(blacklist, timeoutBlacklist, NULL);
5560
-			pthread_mutex_unlock(&blacklist_mutex);
5561
-		}
5562
-	}
5563
-	logg("#watchdog quits\n");
5564
-	return NULL;
5565
-}
5566
-#else	/*!SESSION*/
5567
-/*
5568
- * Reload the database from time to time, when using the internal scanner
5569
- *
5570
- * TODO: reload the whiteList file if it's been changed
5571
- */
5572
-/*ARGSUSED*/
5573
-static void *
5574
-watchdog(void *a)
5575
-{
5576
-	static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER;
5577
-
5578
-	if((!blacklist_time) && external)
5579
-		return NULL;	/* no need for this thread */
5580
-
5581
-	while(!quitting) {
5582
-		struct timespec ts;
5583
-		struct timeval tp;
5584
-
5585
-		gettimeofday(&tp, NULL);
5586
-
5587
-		ts.tv_sec = tp.tv_sec + freshclam_monitor;
5588
-		ts.tv_nsec = tp.tv_usec * 1000;
5589
-		logg("#watchdog sleeps\n");
5590
-
5591
-		pthread_mutex_lock(&watchdog_mutex);
5592
-		/*
5593
-		 * Sometimes this returns EPIPE which isn't listed as a
5594
-		 * return value in the Linux man page for pthread_cond_timedwait
5595
-		 * so I'm not sure why it happens
5596
-		 */
5597
-		switch(pthread_cond_timedwait(&watchdog_cond, &watchdog_mutex, &ts)) {
5598
-			case ETIMEDOUT:
5599
-			case 0:
5600
-				break;
5601
-			default:
5602
-				perror("pthread_cond_timedwait");
5603
-		}
5604
-		pthread_mutex_unlock(&watchdog_mutex);
5605
-		logg("#watchdog wakes\n");
5606
-
5607
-		/*
5608
-		 * TODO: sanity check that if n_children == 0, that
5609
-		 * root->refcount == 0. Unfortunatly root->refcount isn't
5610
-		 * thread-safe, since it's governed by a mutex that we can't
5611
-		 * see, and there's no access to it via an approved method
5612
-		 */
5613
-		if(check_and_reload_database() != 0) {
5614
-			if(cl_error != SMFIS_ACCEPT) {
5615
-				smfi_stop();
5616
-				return NULL;
5617
-			}
5618
-			logg(_("!No emails will be scanned"));
5619
-		}
5620
-		/* Garbage collect IP addresses no longer blacklisted */
5621
-		if(blacklist) {
5622
-			pthread_mutex_lock(&blacklist_mutex);
5623
-			tableIterate(blacklist, timeoutBlacklist, NULL);
5624
-			pthread_mutex_unlock(&blacklist_mutex);
5625
-		}
5626
-	}
5627
-	logg("#watchdog quits\n");
5628
-	return NULL;
5629
-}
5630
-#endif
5631
-
5632
-/*
5633
- * Check to see if the database needs to be reloaded
5634
- *	Return 0 for success
5635
- */
5636
-static int
5637
-check_and_reload_database(void)
5638
-{
5639
-	int rc;
5640
-
5641
-	if(external)
5642
-		return 0;
5643
-
5644
-	if(reload) {
5645
-		rc = 1;
5646
-		reload = 0;
5647
-	} else
5648
-		rc = cl_statchkdir(&dbstat);
5649
-
5650
-	switch(rc) {
5651
-		case 1:
5652
-			logg("^Database has changed, loading updated database\n");
5653
-			cl_statfree(&dbstat);
5654
-			rc = loadDatabase();
5655
-			if(rc != 0) {
5656
-				logg("!Failed to load updated database\n");
5657
-				return rc;
5658
-			}
5659
-			break;
5660
-		case 0:
5661
-			logg("*Database has not changed\n");
5662
-			break;
5663
-		default:
5664
-			logg("Database error %d - %s is stopping\n",
5665
-				rc, progname);
5666
-			return 1;
5667
-	}
5668
-	return 0;	/* all OK */
5669
-}
5670
-
5671
-static void
5672
-timeoutBlacklist(char *ip_address, int time_of_blacklist, void *v)
5673
-{
5674
-	if(time_of_blacklist == 0)	/* Must not blacklist this IP address */
5675
-		return;
5676
-	if((time((time_t *)0) - time_of_blacklist) > blacklist_time)
5677
-		tableRemove(blacklist, ip_address);
5678
-}
5679
-
5680
-static void
5681
-quit(void)
5682
-{
5683
-	quitting++;
5684
-
5685
-#ifdef	SESSION
5686
-	pthread_mutex_lock(&version_mutex);
5687
-#endif
5688
-	logg(_("Stopping %s\n"), clamav_version);
5689
-#ifdef	SESSION
5690
-	pthread_mutex_unlock(&version_mutex);
5691
-#endif
5692
-
5693
-	if(!external) {
5694
-		pthread_mutex_lock(&engine_mutex);
5695
-		if(engine)
5696
-			cl_engine_free(engine);
5697
-		pthread_mutex_unlock(&engine_mutex);
5698
-	} else {
5699
-#ifdef	SESSION
5700
-		int i = 0;
5701
-		struct session *session = sessions;
5702
-
5703
-		pthread_mutex_lock(&sstatus_mutex);
5704
-		for(; i < ((localSocket != NULL) ? 1 : (int)max_children); i++) {
5705
-			/*
5706
-			 * Check all free sessions are still usable
5707
-			 * This could take some time with many free
5708
-			 * sessions to slow remote servers, so only do this
5709
-			 * when the system is quiet (not 100% accurate when
5710
-			 * determining this since n_children isn't locked but
5711
-			 * that doesn't really matter)
5712
-			 */
5713
-			logg("#quit: close server %d\n", i);
5714
-			if(session->status == CMDSOCKET_FREE) {
5715
-				const int sock = session->sock;
5716
-
5717
-				send(sock, "END\n", 4, 0);
5718
-				shutdown(sock, SHUT_WR);
5719
-				session->status = CMDSOCKET_DOWN;
5720
-				pthread_mutex_unlock(&sstatus_mutex);
5721
-				close(sock);
5722
-				pthread_mutex_lock(&sstatus_mutex);
5723
-			}
5724
-			session++;
5725
-		}
5726
-		pthread_mutex_unlock(&sstatus_mutex);
5727
-#endif
5728
-	}
5729
-
5730
-	if(tmpdir)
5731
-		if(rmdir(tmpdir) < 0)
5732
-			perror(tmpdir);
5733
-
5734
-	broadcast(_("Stopping clamav-milter"));
5735
-
5736
-	if(pidfile)
5737
-		if(unlink(pidfile) < 0)
5738
-			perror(pidfile);
5739
-
5740
-	logg_close();
5741
-}
5742
-
5743
-static void
5744
-broadcast(const char *mess)
5745
-{
5746
-	struct sockaddr_in s;
5747
-
5748
-	if(broadcastSock < 0)
5749
-		return;
5750
-
5751
-	memset(&s, '\0', sizeof(struct sockaddr_in));
5752
-	s.sin_family = AF_INET;
5753
-	s.sin_port = (in_port_t)htons(tcpSocket ? tcpSocket : 3310);
5754
-	s.sin_addr.s_addr = htonl(INADDR_BROADCAST);
5755
-
5756
-	logg("#broadcast %s to %d\n", mess, broadcastSock);
5757
-	if(sendto(broadcastSock, mess, strlen(mess), 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0)
5758
-		perror("sendto");
5759
-}
5760
-
5761
-/*
5762
- * Load a new database into the internal scanner
5763
- */
5764
-static int
5765
-loadDatabase(void)
5766
-{
5767
-	int ret;
5768
-	unsigned int signatures, dboptions;
5769
-	char *daily;
5770
-	struct cl_cvd *d;
5771
-	const struct cfgstruct *cpt;
5772
-	static const char *dbdir;
5773
-
5774
-	assert(!external);
5775
-
5776
-	if(dbdir == NULL) {
5777
-		/*
5778
-		 * First time through, find out in which directory the signature
5779
-		 * databases are
5780
-		 */
5781
-		if((cpt = cfgopt(copt, "DatabaseDirectory")) && cpt->enabled)
5782
-			dbdir = cpt->strarg;
5783
-		else
5784
-			dbdir = cl_retdbdir();
5785
-	}
5786
-
5787
-	daily = cli_malloc(strlen(dbdir) + 11);
5788
-	sprintf(daily, "%s/daily.cvd", dbdir);
5789
-	if(access(daily, R_OK) < 0)
5790
-		sprintf(daily, "%s/daily.cld", dbdir);
5791
-
5792
-
5793
-	logg("#loadDatabase: check %s for updates\n", daily);
5794
-
5795
-	d = cl_cvdhead(daily);
5796
-
5797
-	if(d) {
5798
-		char *ptr;
5799
-		time_t t = d->stime;
5800
-		char buf[26];
5801
-
5802
-		snprintf(clamav_version, VERSION_LENGTH,
5803
-			"ClamAV %s/%u/%s", get_version(), d->version,
5804
-			cli_ctime(&t, buf, sizeof(buf)));
5805
-
5806
-		/* Remove ctime's trailing \n */
5807
-		if((ptr = strchr(clamav_version, '\n')) != NULL)
5808
-			*ptr = '\0';
5809
-
5810
-		cl_cvdfree(d);
5811
-	} else
5812
-		snprintf(clamav_version, VERSION_LENGTH,
5813
-			"ClamAV version %s, clamav-milter version %s",
5814
-			cl_retver(), get_version());
5815
-
5816
-	free(daily);
5817
-
5818
-#ifdef	SESSION
5819
-	pthread_mutex_lock(&version_mutex);
5820
-	if(clamav_versions == NULL) {
5821
-		clamav_versions = (char **)cli_malloc(sizeof(char *));
5822
-		if(clamav_versions == NULL) {
5823
-			pthread_mutex_unlock(&version_mutex);
5824
-			return -1;
5825
-		}
5826
-		clamav_version = cli_malloc(VERSION_LENGTH + 1);
5827
-		if(clamav_version == NULL) {
5828
-			free(clamav_versions);
5829
-			clamav_versions = NULL;
5830
-			pthread_mutex_unlock(&version_mutex);
5831
-			return -1;
5832
-		}
5833
-	}
5834
-	pthread_mutex_unlock(&version_mutex);
5835
-#endif
5836
-	signatures = 0;
5837
-	pthread_mutex_lock(&engine_mutex);
5838
-	if(engine) cl_engine_free(engine);
5839
-	engine = cl_engine_new();
5840
-	if (!engine) {
5841
-		logg("!Can't initialize antivirus engine\n");
5842
-		pthread_mutex_unlock(&engine_mutex);
5843
-		return -1;
5844
-	}
5845
-	if(!cfgopt(copt, "PhishingSignatures")->enabled) {
5846
-		logg("Not loading phishing signatures.\n");
5847
-		dboptions = 0;
5848
-	} else
5849
-		dboptions = CL_DB_PHISHING;
5850
-	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_SCANSIZE, &maxscansize))) {
5851
-		logg("!cli_engine_set(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret));
5852
-		cl_engine_free(engine);
5853
-		pthread_mutex_unlock(&engine_mutex);
5854
-		return -1;
5855
-	}
5856
-	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_FILESIZE, &maxfilesize))) {
5857
-		logg("!cli_engine_set(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret));
5858
-		cl_engine_free(engine);
5859
-		pthread_mutex_unlock(&engine_mutex);
5860
-		return -1;
5861
-	}
5862
-	ret = cl_load(dbdir, engine, &signatures, dboptions);
5863
-	if(ret != CL_SUCCESS) {
5864
-		logg("!%s\n", cl_strerror(ret));
5865
-		cl_engine_free(engine);
5866
-		pthread_mutex_unlock(&engine_mutex);
5867
-		return -1;
5868
-	}
5869
-	ret = cl_engine_compile(engine);
5870
-	if(ret != CL_SUCCESS) {
5871
-		logg("!Database initialization error: %s\n", cl_strerror(ret));
5872
-		cl_engine_free(engine);
5873
-		pthread_mutex_unlock(&engine_mutex);
5874
-		return -1;
5875
-	}
5876
-	pthread_mutex_unlock(&engine_mutex);
5877
-#ifdef	SESSION
5878
-	pthread_mutex_lock(&version_mutex);
5879
-#endif
5880
-	logg( _("Loaded %s\n"), clamav_version);
5881
-#ifdef	SESSION
5882
-	pthread_mutex_unlock(&version_mutex);
5883
-#endif
5884
-	logg(_("ClamAV: Protecting against %u viruses\n"), signatures);
5885
-	logg("#Database correctly (re)loaded (%u viruses)\n");
5886
-	return cl_statinidir(dbdir, &dbstat);
5887
-}
5888
-
5889
-static void
5890
-sigsegv(int sig)
5891
-{
5892
-	signal(SIGSEGV, SIG_DFL);
5893
-
5894
-#ifdef HAVE_BACKTRACE
5895
-	print_trace();
5896
-#endif
5897
-
5898
-	logg("!Segmentation fault :-( Bye.., notify bugs@clamav.net\n");
5899
-
5900
-	quitting++;
5901
-	smfi_stop();
5902
-}
5903
-
5904
-extern FILE *logg_fd;
5905
-static void
5906
-sigusr1(int sig)
5907
-{
5908
-
5909
-	signal(SIGUSR1, sigusr1);
5910
-
5911
-	if(!(cfgopt(copt, "LogFile"))->enabled)
5912
-		return;
5913
-
5914
-	logg("SIGUSR1 caught: re-opening log file\n");
5915
-	logg_close();
5916
-	logg("*Log file re-opened\n");
5917
-	dup2(fileno(logg_fd), 2);
5918
-}
5919
-
5920
-static void
5921
-sigusr2(int sig)
5922
-{
5923
-	signal(SIGUSR2, sigusr2);
5924
-
5925
-	logg("^SIGUSR2 caught: scheduling database reload\n");
5926
-	reload++;
5927
-}
5928
-
5929
-#ifdef HAVE_BACKTRACE
5930
-static void
5931
-print_trace(void)
5932
-{
5933
-	void *array[BACKTRACE_SIZE];
5934
-	size_t size, i;
5935
-	char **strings;
5936
-	pid_t pid = getpid();
5937
-
5938
-	size = backtrace(array, BACKTRACE_SIZE);
5939
-	strings = backtrace_symbols(array, size);
5940
-
5941
-	logg("*Backtrace of pid %d:\n", pid);
5942
-
5943
-	for(i = 0; i < size; i++)
5944
-		logg("bt[%u]: %s", i, strings[i]);
5945
-
5946
-	/* TODO: dump the current email */
5947
-
5948
-	free(strings);
5949
-}
5950
-#endif
5951
-
5952
-/*
5953
- * Check that the correct port name has been given, i.e. that the
5954
- * input socket to clamav-milter from sendmail, is the same that
5955
- * sendmail has been configured to use as it's output socket
5956
- * Return:	<0 invalid
5957
- *		=0 valid
5958
- *		>0 unknown
5959
- *
5960
- * You wouldn't believe the amount of time I used to waste chasing bug reports
5961
- *	from people who's sendmail.cf didn't tally with the arguments given to
5962
- *	clamav-milter before I put this check in, which is why bug 726 must
5963
- *	never be acted upon.
5964
- *
5965
- * FIXME: return different codes for "the value is wrong" and "sendmail.cf"
5966
- *	hasn't been set up, though that's not so easy to work out.
5967
- */
5968
-static int
5969
-verifyIncomingSocketName(const char *sockName)
5970
-{
5971
-#if HAVE_MMAP
5972
-	int fd, ret;
5973
-	char *ptr;
5974
-	size_t size;
5975
-	struct stat statb;
5976
-
5977
-	if(strncmp(sockName, "inet:", 5) == 0)
5978
-		/*
5979
-		 * clamav-milter is running on a different machine from sendmail
5980
-		 */
5981
-		return 1;
5982
-
5983
-	if(sendmailCF)
5984
-		fd = open(sendmailCF, O_RDONLY);
5985
-	else {
5986
-		fd = open("/etc/mail/sendmail.cf", O_RDONLY);
5987
-		if(fd < 0)
5988
-			fd = open("/etc/sendmail.cf", O_RDONLY);
5989
-	}
5990
-
5991
-	if(fd < 0)
5992
-		return 1;
5993
-
5994
-	if(fstat(fd, &statb) < 0) {
5995
-		close(fd);
5996
-		return 1;
5997
-	}
5998
-
5999
-	size = statb.st_size;
6000
-
6001
-	if(size == 0) {
6002
-		close(fd);
6003
-		return -1;
6004
-	}
6005
-
6006
-	ptr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
6007
-	if(ptr == MAP_FAILED) {
6008
-		perror("mmap");
6009
-		close(fd);
6010
-		return -1;
6011
-	}
6012
-
6013
-	ret = (cli_memstr(ptr, size, sockName, strlen(sockName)) != NULL) ? 1 : -1;
6014
-
6015
-	munmap(ptr, size);
6016
-	close(fd);
6017
-
6018
-	return ret;
6019
-#else	/*!HAVE_MMAP*/
6020
-	return 1;
6021
-#endif
6022
-}
6023
-
6024
-/*
6025
- * If the given email address is whitelisted don't scan emails to them,
6026
- *	the addresses are in angle brackets e.g. <foo@bar.com>.
6027
- *
6028
- * TODO: Allow regular expressions in the addresses
6029
- * TODO: Syntax check the contents of the files
6030
- * TODO: Allow emails of the form "name <address>"
6031
- * TODO: Allow emails not of the form "<address>", i.e. no angle brackets
6032
- * TODO: Assume that if a '@' is missing from the address, that all emails
6033
- *	to that domain are to be whitelisted
6034
- */
6035
-static int
6036
-isWhitelisted(const char *emailaddress, int to)
6037
-{
6038
-	static table_t *to_whitelist, *from_whitelist;	/* never freed */
6039
-	table_t *table;
6040
-
6041
-	logg("*isWhitelisted %s\n", emailaddress);
6042
-
6043
-	/*
6044
-	 * Don't scan messages to the quarantine email address
6045
-	 */
6046
-	if(quarantine && (strcasecmp(quarantine, emailaddress) == 0))
6047
-		return 1;
6048
-
6049
-	if((to_whitelist == NULL) && whitelistFile) {
6050
-		FILE *fin;
6051
-		char buf[BUFSIZ + 1];
6052
-
6053
-		fin = fopen(whitelistFile, "r");
6054
-
6055
-		if(fin == NULL) {
6056
-			perror(whitelistFile);
6057
-			logg(_("!Can't open whitelist file %s"), whitelistFile);
6058
-			return 0;
6059
-		}
6060
-		to_whitelist = tableCreate();
6061
-		from_whitelist = tableCreate();
6062
-
6063
-		if((to_whitelist == NULL) || (from_whitelist == NULL)) {
6064
-			logg(_("!Can't create whitelist table"));
6065
-			if(to_whitelist) {
6066
-				tableDestroy(to_whitelist);
6067
-				to_whitelist = NULL;
6068
-			} else {
6069
-				tableDestroy(from_whitelist);
6070
-				from_whitelist = NULL;
6071
-			}
6072
-			fclose(fin);
6073
-			return 0;
6074
-		}
6075
-
6076
-		while(fgets(buf, sizeof(buf), fin) != NULL) {
6077
-			const char *ptr;
6078
-
6079
-			/* comment line? */
6080
-			switch(buf[0]) {
6081
-				case '#':
6082
-				case '/':
6083
-				case ':':
6084
-					continue;
6085
-			}
6086
-			if(cli_chomp(buf) > 0) {
6087
-				if((ptr = strchr(buf, ':')) != NULL) {
6088
-					do
6089
-						ptr++;
6090
-					while(*ptr && isspace(*ptr));
6091
-
6092
-					if(*ptr == '\0') {
6093
-						logg("*Ignoring bad line '%s'\n",
6094
-							buf);
6095
-						continue;
6096
-					}
6097
-				} else
6098
-					ptr = buf;
6099
-
6100
-				if(strncasecmp(buf, "From:", 5) == 0)
6101
-					table = from_whitelist;
6102
-				else
6103
-					table = to_whitelist;
6104
-
6105
-				(void)tableInsert(table, ptr, 1);
6106
-			}
6107
-		}
6108
-		fclose(fin);
6109
-	}
6110
-	table = (to) ? to_whitelist : from_whitelist;
6111
-
6112
-	if(table && (tableFind(table, emailaddress) == 1))
6113
-		/*
6114
-		 * This recipient is on the whitelist
6115
-		 */
6116
-		return 1;
6117
-
6118
-	return 0;
6119
-}
6120
-
6121
-/*
6122
- * Blacklist IP addresses that send malware. Often in the phishing world, one
6123
- * phish is quickly followed by another. IP addresses are blacklisted for one
6124
- * minute. We can't blacklist for longer since DHCP means we could hit innocent
6125
- * parties, and in theory malware could go through a smart host and affect
6126
- * innocent parties
6127
- *
6128
- * Note that sites which can't be blacklisted will have their timestamp set
6129
- * to 0, since that can never be less than blacklist_time seconds from now
6130
- */
6131
-static int
6132
-isBlacklisted(const char *ip_address)
6133
-{
6134
-	time_t t;
6135
-
6136
-	if(blacklist_time == 0)
6137
-		/* Blacklisting not being used */
6138
-		return 0;
6139
-
6140
-	logg("*isBlacklisted %s\n", ip_address);
6141
-
6142
-	if(isLocal(ip_address))
6143
-		return 0;
6144
-
6145
-	pthread_mutex_lock(&blacklist_mutex);
6146
-	if(blacklist == NULL) {
6147
-		blacklist = tableCreate();
6148
-
6149
-		pthread_mutex_unlock(&blacklist_mutex);
6150
-
6151
-		if(blacklist == NULL)
6152
-			logg(_("!Can't create blacklist table"));
6153
-		return 0;
6154
-	}
6155
-	t = tableFind(blacklist, ip_address);
6156
-	pthread_mutex_unlock(&blacklist_mutex);
6157
-
6158
-	if(t == (time_t)-1)
6159
-		/* IP address is not blacklisted */
6160
-		return 0;
6161
-
6162
-	if(t == (time_t)0)
6163
-		/* IP cannot be blacklisted */
6164
-		return 0;
6165
-
6166
-	if((time((time_t *)0) - t) <= blacklist_time)
6167
-		return 1;
6168
-
6169
-	/* timedout: remove the IP from the blacklist */
6170
-	pthread_mutex_lock(&blacklist_mutex);
6171
-	tableRemove(blacklist, ip_address);
6172
-	pthread_mutex_unlock(&blacklist_mutex);
6173
-
6174
-	return 0;
6175
-}
6176
-
6177
-#ifdef	HAVE_RESOLV_H
6178
-/*
6179
- * Determine our MX peers, they must never be blacklisted
6180
- * See RFC1034 for the definition of the record formats
6181
- *
6182
- * This is only ever called once, which is wrong, but the overheard of calling
6183
- * this from the watchdog isn't worth it
6184
- */
6185
-static table_t *
6186
-mx(const char *host, table_t *t)
6187
-{
6188
-	u_char *p, *end;
6189
-	const HEADER *hp;
6190
-	int len, i;
6191
-	union {
6192
-		HEADER h;
6193
-		u_char u[PACKETSZ];
6194
-	} q;
6195
-	char buf[BUFSIZ];
6196
-
6197
-	if(t == NULL) {
6198
-		t = tableCreate();
6199
-
6200
-		if(t == NULL)
6201
-			return NULL;
6202
-	}
6203
-
6204
-	len = safe_res_query(host, C_IN, T_MX, (u_char *)&q, sizeof(q));
6205
-	if(len < 0)
6206
-		return t;	/* Host has no MX records */
6207
-
6208
-	if((unsigned int)len > sizeof(q))
6209
-		return t;
6210
-
6211
-	hp = &(q.h);
6212
-	p = q.u + HFIXEDSZ;
6213
-	end = q.u + len;
6214
-
6215
-	for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ)
6216
-		if((len = dn_skipname(p, end)) < 0)
6217
-			return t;
6218
-
6219
-	i = ntohs(hp->ancount);
6220
-
6221
-	while((--i >= 0) && (p < end)) {
6222
-		in_addr_t addr;
6223
-		u_short type, pref;
6224
-		u_long ttl;	/* unused */
6225
-
6226
-		if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0)
6227
-			break;
6228
-		p += len;
6229
-		GETSHORT(type, p);
6230
-		p += INT16SZ;
6231
-		GETLONG(ttl, p);
6232
-		GETSHORT(len, p);
6233
-		if(type != T_MX) {
6234
-			p += len;
6235
-			continue;
6236
-		}
6237
-		GETSHORT(pref, p);
6238
-		if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0)
6239
-			break;
6240
-		p += len;
6241
-		addr = inet_addr(buf);
6242
-#ifdef	INADDR_NONE
6243
-		if(addr != INADDR_NONE) {
6244
-#else
6245
-		if(addr != (in_addr_t)-1) {
6246
-#endif
6247
-			(void)tableInsert(t, buf, 0);
6248
-		} else
6249
-			t = resolve(buf, t);
6250
-	}
6251
-	return t;
6252
-}
6253
-
6254
-/*
6255
- * If the MX record points to a name, we need to resolve that name. This routine
6256
- * does that
6257
- */
6258
-static table_t *
6259
-resolve(const char *host, table_t *t)
6260
-{
6261
-	u_char *p, *end;
6262
-	const HEADER *hp;
6263
-	int len, i;
6264
-	union {
6265
-		HEADER h;
6266
-		u_char u[PACKETSZ];
6267
-	} q;
6268
-	char buf[BUFSIZ];
6269
-
6270
-	if((host == NULL) || (*host == '\0'))
6271
-		return t;
6272
-
6273
-	len = safe_res_query(host, C_IN, T_A, (u_char *)&q, sizeof(q));
6274
-	if(len < 0)
6275
-		return t;	/* Host has no A records */
6276
-
6277
-	if((unsigned int)len > sizeof(q))
6278
-		return t;
6279
-
6280
-	hp = &(q.h);
6281
-	p = q.u + HFIXEDSZ;
6282
-	end = q.u + len;
6283
-
6284
-	for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ)
6285
-		if((len = dn_skipname(p, end)) < 0)
6286
-			return t;
6287
-
6288
-	i = ntohs(hp->ancount);
6289
-
6290
-	while((--i >= 0) && (p < end)) {
6291
-		u_short type;
6292
-		u_long ttl;
6293
-		const char *ip;
6294
-		struct in_addr addr;
6295
-
6296
-		if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0)
6297
-			return t;
6298
-		p += len;
6299
-		GETSHORT(type, p);
6300
-		p += INT16SZ;
6301
-		GETLONG(ttl, p);	/* unused */
6302
-		GETSHORT(len, p);
6303
-		if(type != T_A) {
6304
-			p += len;
6305
-			continue;
6306
-		}
6307
-		memcpy(&addr, p, sizeof(struct in_addr));
6308
-		p += 4;	/* Should check len == 4 */
6309
-		ip = inet_ntoa(addr);
6310
-		if(ip) {
6311
-			if(t == NULL) {
6312
-				t = tableCreate();
6313
-
6314
-				if(t == NULL)
6315
-					return NULL;
6316
-			}
6317
-			(void)tableInsert(t, ip, 0);
6318
-		}
6319
-	}
6320
-	return t;
6321
-}
6322
-
6323
-/*
6324
- * Validate SPF records to help to stop Phish false positives
6325
- * http://www.openspf.org/SPF_Record_Syntax
6326
- *
6327
- * Currently only handles ip4, a and mx fields in the DNS record
6328
- * Having said that, this is NOT a replacement for spf-milter, it is NOT
6329
- *	an SPF system, we ONLY use SPF records to reduce phish false positives
6330
- * TODO: IPv6?
6331
- * TODO: cache queries?
6332
- *
6333
- * INPUT: prevhosts, a list of hosts already searched: stops include loops
6334
- *	e.g. mercado.com includes medrcadosw.com which includes mercado.com,
6335
- *	causing a loop
6336
- * Return 1 if SPF says this email is from a legitimate source
6337
- *	0 for fail or unknown
6338
- */
6339
-static int
6340
-spf(struct privdata *privdata, table_t *prevhosts)
6341
-{
6342
-	char *host, *ptr;
6343
-	u_char *p, *end;
6344
-	const HEADER *hp;
6345
-	int len, i;
6346
-	union {
6347
-		HEADER h;
6348
-		u_char u[PACKETSZ];
6349
-	} q;
6350
-	char buf[BUFSIZ];
6351
-
6352
-	if(privdata->spf_ok)
6353
-		return 1;
6354
-	if(privdata->ip[0] == '\0')
6355
-		return 0;
6356
-	if(strcmp(privdata->ip, "127.0.0.1") == 0) {
6357
-		/* Loopback always pass SPF */
6358
-		privdata->spf_ok = 1;
6359
-		return 1;
6360
-	}
6361
-	if(isLocal(privdata->ip)) {
6362
-		/* Local addresses always pass SPF */
6363
-		privdata->spf_ok = 1;
6364
-		return 1;
6365
-	}
6366
-
6367
-	if(privdata->from == NULL)
6368
-		return 0;
6369
-	if((host = strrchr(privdata->from, '@')) == NULL)
6370
-		return 0;
6371
-
6372
-	host = cli_strdup(++host);
6373
-
6374
-	if(host == NULL)
6375
-		return 0;
6376
-
6377
-	ptr = strchr(host, '>');
6378
-
6379
-	if(ptr)
6380
-		*ptr = '\0';
6381
-
6382
-	logg("*SPF query '%s'\n", host);
6383
-	len = safe_res_query(host, C_IN, T_TXT, (u_char *)&q, sizeof(q));
6384
-	if(len < 0) {
6385
-		free(host);
6386
-		return 0;	/* Host has no TXT records */
6387
-	}
6388
-
6389
-	if((unsigned int)len > sizeof(q)) {
6390
-		free(host);
6391
-		return 0;
6392
-	}
6393
-
6394
-	hp = &(q.h);
6395
-	p = q.u + HFIXEDSZ;
6396
-	end = q.u + len;
6397
-
6398
-	for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ)
6399
-		if((len = dn_skipname(p, end)) < 0) {
6400
-			free(host);
6401
-			return 0;
6402
-		}
6403
-
6404
-	i = ntohs(hp->ancount);
6405
-
6406
-	while((--i >= 0) && (p < end) && !privdata->spf_ok) {
6407
-		u_short type;
6408
-		u_long ttl;
6409
-		char txt[BUFSIZ];
6410
-
6411
-		if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) {
6412
-			free(host);
6413
-			return 0;
6414
-		}
6415
-		p += len;
6416
-		GETSHORT(type, p);
6417
-		p += INT16SZ;
6418
-		GETLONG(ttl, p);	/* unused */
6419
-		GETSHORT(len, p);
6420
-		if(type != T_TXT) {
6421
-			p += len;
6422
-			continue;
6423
-		}
6424
-		strncpy(txt, (const char *)&p[1], sizeof(txt) - 1);
6425
-		txt[sizeof(txt)-1]='\0';
6426
-		txt[len - 1] = '\0';
6427
-		if((strncmp(txt, "v=spf1 ", 7) == 0) || (strncmp(txt, "spf2.0/pra ", 11) == 0)) {
6428
-			int j;
6429
-			char *record;
6430
-			struct in_addr remote_ip;	/* IP connecting to us */
6431
-
6432
-			logg("*%s(%s): SPF record %s\n",
6433
-				host, privdata->ip, txt);
6434
-#ifdef HAVE_INET_NTOP
6435
-			/* IPv4 address ? */
6436
-			if(inet_pton(AF_INET, privdata->ip, &remote_ip) <= 0) {
6437
-				p += len;
6438
-				continue;
6439
-			}
6440
-#else
6441
-			if(inet_aton(privdata->ip, &remote_ip) == 0) {
6442
-				p += len;
6443
-				continue;
6444
-			}
6445
-#endif
6446
-
6447
-			j = 1;	/* strtok 0 would give the v= part */
6448
-			while((record = cli_strtok(txt, j++, " ")) != NULL) {
6449
-				if(strncmp(record, "ip4:", 4) == 0) {
6450
-					int preflen;
6451
-					char *ip, *pref;
6452
-					uint32_t mask;
6453
-					struct in_addr spf_range;	/* acceptable range of IPs */
6454
-
6455
-					ip = &record[4];
6456
-
6457
-					pref = strchr(ip, '/');
6458
-					preflen = 32;
6459
-					if(pref) {
6460
-						*pref++ = '\0';
6461
-						if(*pref)
6462
-							preflen = atoi(pref);
6463
-					}
6464
-
6465
-#ifdef HAVE_INET_NTOP
6466
-					/* IPv4 address ? */
6467
-					if(inet_pton(AF_INET, ip, &spf_range) <= 0) {
6468
-						free(record);
6469
-						continue;
6470
-					}
6471
-#else
6472
-					if(inet_aton(ip, &spf_range) == 0) {
6473
-						free(record);
6474
-						continue;
6475
-					}
6476
-#endif
6477
-					mask = MAKEMASK(preflen);
6478
-					if((ntohl(remote_ip.s_addr) & mask) == (ntohl(spf_range.s_addr) & mask)) {
6479
-						if(privdata->subject)
6480
-							logg("#SPF ip4 pass (%s) %s is valid for %s\n",
6481
-								privdata->subject, ip, host);
6482
-						else
6483
-							logg("#SPF ip4 pass %s is valid for %s\n", ip, host);
6484
-						privdata->spf_ok = 1;
6485
-					}
6486
-				} else if(strcmp(record, "mx") == 0) {
6487
-					table_t *t = mx(host, NULL);
6488
-
6489
-					if(t) {
6490
-						tableIterate(t, spf_ip,
6491
-							(void *)privdata);
6492
-						tableDestroy(t);
6493
-					}
6494
-				} else if(strcmp(record, "a") == 0) {
6495
-					table_t *t = resolve(host, NULL);
6496
-
6497
-					if(t) {
6498
-						tableIterate(t, spf_ip,
6499
-							(void *)privdata);
6500
-						tableDestroy(t);
6501
-					}
6502
-				} else if(strncmp(record, "a:", 2) == 0) {
6503
-					const char *ahost = &record[2];
6504
-
6505
-					if(*ahost && (strcmp(ahost, host) != 0)) {
6506
-						table_t *t = resolve(ahost, NULL);
6507
-
6508
-						if(t) {
6509
-							tableIterate(t, spf_ip,
6510
-								(void *)privdata);
6511
-							tableDestroy(t);
6512
-						}
6513
-					}
6514
-				} else if(strncmp(record, "mx:", 3) == 0) {
6515
-					const char *mxhost = &record[3];
6516
-
6517
-					if(*mxhost && (strcmp(mxhost, host) != 0)) {
6518
-						table_t *t = mx(mxhost, NULL);
6519
-
6520
-						if(t) {
6521
-							tableIterate(t, spf_ip,
6522
-								(void *)privdata);
6523
-							tableDestroy(t);
6524
-						}
6525
-					}
6526
-				} else if(strncmp(record, "include:", 8) == 0) {
6527
-					const char *inchost = &record[8];
6528
-
6529
-					/*
6530
-					 * Ensure we haven't already looked at
6531
-					 *	the host that's to be included
6532
-					 */
6533
-					if(*inchost &&
6534
-					   (strcmp(inchost, host) != 0) &&
6535
-					   (tableFind(prevhosts, inchost) == -1)) {
6536
-						char *real_from = privdata->from;
6537
-						privdata->from = cli_malloc(strlen(inchost) + 3);
6538
-						sprintf(privdata->from, "n@%s", inchost);
6539
-						tableInsert(prevhosts, host, 0);
6540
-						spf(privdata, prevhosts);
6541
-						free(privdata->from);
6542
-						privdata->from = real_from;
6543
-					}
6544
-				}
6545
-				free(record);
6546
-				if(privdata->spf_ok)
6547
-					break;
6548
-			}
6549
-		}
6550
-		p += len;
6551
-	}
6552
-	free(host);
6553
-
6554
-	return privdata->spf_ok;
6555
-}
6556
-
6557
-static void
6558
-spf_ip(char *ip, int zero, void *v)
6559
-{
6560
-	struct privdata *privdata = (struct privdata *)v;
6561
-
6562
-	if(strcmp(ip, privdata->ip) == 0) {
6563
-		if(privdata->subject)
6564
-			logg("#SPF mx/a pass (%s) %s\n", privdata->subject, ip);
6565
-		else
6566
-			logg("#SPF mx/a pass %s\n", ip);
6567
-		privdata->spf_ok = 1;
6568
-	}
6569
-}
6570
-
6571
-#else	/*!HAVE_RESOLV_H */
6572
-static table_t *
6573
-mx(const char *host, table_t *t)
6574
-{
6575
-	logg(_("^MX peers will not be immune from being blacklisted"));
6576
-
6577
-	if(blacklist == NULL)
6578
-		blacklist = tableCreate();
6579
-	return NULL;
6580
-}
6581
-#endif	/* HAVE_RESOLV_H */
6582
-
6583
-static sfsistat
6584
-black_hole(const struct privdata *privdata)
6585
-{
6586
-	int must_scan;
6587
-	char **to;
6588
-
6589
-	to = privdata->to;
6590
-	must_scan = (*to) ? 0 : 1;
6591
-
6592
-	for(; *to; to++) {
6593
-		pid_t pid, w;
6594
-		int pv[2], status;
6595
-		FILE *sendmail;
6596
-		char buf[BUFSIZ];
6597
-
6598
-		logg("*Calling \"%s -bv %s\"\n", SENDMAIL_BIN, *to);
6599
-
6600
-		if(pipe(pv) < 0) {
6601
-			perror("pipe");
6602
-			logg(_("!Can't create pipe\n"));
6603
-			must_scan = 1;
6604
-			break;
6605
-		}
6606
-		pid = fork();
6607
-		if(pid == 0) {
6608
-			close(1);
6609
-			close(pv[0]);
6610
-			dup2(pv[1], 1);
6611
-			close(pv[1]);
6612
-
6613
-			/*
6614
-			 * Avoid calling popen() since *to isn't trusted
6615
-			 */
6616
-			execl(SENDMAIL_BIN, "sendmail", "-bv", *to, NULL);
6617
-			perror(SENDMAIL_BIN);
6618
-			logg("Can't execl %s\n", SENDMAIL_BIN);
6619
-			_exit(errno ? errno : 1);
6620
-		}
6621
-		if(pid == -1) {
6622
-			perror("fork");
6623
-			logg(_("!Can't fork\n"));
6624
-			close(pv[0]);
6625
-			close(pv[1]);
6626
-			must_scan = 1;
6627
-			break;
6628
-		}
6629
-		close(pv[1]);
6630
-		sendmail = fdopen(pv[0], "r");
6631
-
6632
-		if(sendmail == NULL) {
6633
-			logg("fdopen failed\n");
6634
-			close(pv[0]);
6635
-			must_scan = 1;
6636
-			break;
6637
-		}
6638
-
6639
-		while(fgets(buf, sizeof(buf), sendmail) != NULL) {
6640
-			if(cli_chomp(buf) == 0)
6641
-				continue;
6642
-
6643
-			logg("*sendmail output: %s\n", buf);
6644
-
6645
-			if(strstr(buf, "... deliverable: mailer ")) {
6646
-				const char *p = strstr(buf, ", user ");
6647
-
6648
-				if(strcmp(&p[7], "/dev/null") != 0) {
6649
-					must_scan = 1;
6650
-					break;
6651
-				}
6652
-			}
6653
-		}
6654
-		fclose(sendmail);
6655
-
6656
-		status = -1;
6657
-		do
6658
-			w = wait(&status);
6659
-		while((w != pid) && (w != -1));
6660
-
6661
-		if(w == -1)
6662
-			status = -1;
6663
-		else
6664
-			status = WEXITSTATUS(status);
6665
-
6666
-		switch(status) {
6667
-			case EX_NOUSER:
6668
-			case EX_OK:
6669
-				break;
6670
-			default:
6671
-				logg(_("^Can't execute '%s' to expand '%s' (error %d)\n"),
6672
-					SENDMAIL_BIN, *to, WEXITSTATUS(status));
6673
-				must_scan = 1;
6674
-		}
6675
-		if(must_scan)
6676
-			break;
6677
-	}
6678
-	if(!must_scan) {
6679
-		/* All recipients map to /dev/null */
6680
-		to = privdata->to;
6681
-		if(*to)
6682
-			logg("Discarded, since all recipients (e.g. \"%s\") are /dev/null\n", *to);
6683
-		else
6684
-			logg("Discarded, since all recipients are /dev/null\n");
6685
-		return SMFIS_DISCARD;
6686
-	}
6687
-	return SMFIS_CONTINUE;
6688
-}
6689
-
6690
-/* See also libclamav/mbox.c */
6691
-static int
6692
-useful_header(const char *cmd)
6693
-{
6694
-	if(strcasecmp(cmd, "From") == 0)
6695
-		return 1;
6696
-	if(strcasecmp(cmd, "Received") == 0)
6697
-		return 1;
6698
-	if(strcasecmp(cmd, "Content-Type") == 0)
6699
-		return 1;
6700
-	if(strcasecmp(cmd, "Content-Transfer-Encoding") == 0)
6701
-		return 1;
6702
-	if(strcasecmp(cmd, "Content-Disposition") == 0)
6703
-		return 1;
6704
-	if(strcasecmp(cmd, "De") == 0)
6705
-		return 1;
6706
-
6707
-	return 0;
6708
-}
6709
-
6710
-static int
6711
-increment_connexions(void)
6712
-{
6713
-	if(max_children > 0) {
6714
-		int rc = 0;
6715
-
6716
-		pthread_mutex_lock(&n_children_mutex);
6717
-
6718
-		/*
6719
-		 * Wait a while since sendmail doesn't like it if we
6720
-		 * take too long replying. Effectively this means that
6721
-		 * max_children is more of a hint than a rule
6722
-		 */
6723
-		if(n_children >= max_children) {
6724
-			struct timespec timeout;
6725
-			struct timeval now;
6726
-			struct timezone tz;
6727
-
6728
-			logg((dont_wait) ?
6729
-					_("hit max-children limit (%u >= %u)\n") :
6730
-					_("hit max-children limit (%u >= %u): waiting for some to exit\n"),
6731
-				n_children, max_children);
6732
-
6733
-			if(dont_wait) {
6734
-				pthread_mutex_unlock(&n_children_mutex);
6735
-				return 0;
6736
-			}
6737
-			/*
6738
-			 * Wait for an amount of time for a child to go
6739
-			 *
6740
-			 * Use pthread_cond_timedwait rather than
6741
-			 * pthread_cond_wait since the sendmail which
6742
-			 * calls us will have a timeout that we don't
6743
-			 * want to exceed, stops sendmail getting
6744
-			 * fidgety.
6745
-			 *
6746
-			 * Patch from Damian Menscher
6747
-			 * <menscher@uiuc.edu> to ensure it wakes up
6748
-			 * when a child goes away
6749
-			 */
6750
-			gettimeofday(&now, &tz);
6751
-			do {
6752
-				logg(_("n_children %d: waiting %d seconds for some to exit\n"),
6753
-					n_children, child_timeout);
6754
-
6755
-				if(child_timeout == 0) {
6756
-					pthread_cond_wait(&n_children_cond, &n_children_mutex);
6757
-					rc = 0;
6758
-				} else {
6759
-					timeout.tv_sec = now.tv_sec + child_timeout;
6760
-					timeout.tv_nsec = 0;
6761
-
6762
-					rc = pthread_cond_timedwait(&n_children_cond, &n_children_mutex, &timeout);
6763
-				}
6764
-			} while((n_children >= max_children) && (rc != ETIMEDOUT));
6765
-			logg(_("Finished waiting, n_children = %d\n"), n_children);
6766
-		}
6767
-		n_children++;
6768
-
6769
-		logg("*>n_children = %d\n", n_children);
6770
-		pthread_mutex_unlock(&n_children_mutex);
6771
-
6772
-		if(child_timeout && (rc == ETIMEDOUT))
6773
-			logg(_("Timeout waiting for a child to die\n"));
6774
-	}
6775
-
6776
-	return 1;
6777
-}
6778
-
6779
-static void
6780
-decrement_connexions(void)
6781
-{
6782
-	if(max_children > 0) {
6783
-		pthread_mutex_lock(&n_children_mutex);
6784
-		logg("*decrement_connexions: n_children = %d\n", n_children);
6785
-		/*
6786
-		 * Deliberately errs on the side of broadcasting too many times
6787
-		 */
6788
-		if(n_children > 0)
6789
-			if(--n_children == 0) {
6790
-				logg("*%s is idle\n", progname);
6791
-				if(pthread_cond_broadcast(&watchdog_cond) < 0)
6792
-					perror("pthread_cond_broadcast");
6793
-			}
6794
-#ifdef	CL_DEBUG
6795
-		logg("*pthread_cond_broadcast\n");
6796
-#endif
6797
-		if(pthread_cond_broadcast(&n_children_cond) < 0)
6798
-			perror("pthread_cond_broadcast");
6799
-		logg("*<n_children = %d\n", n_children);
6800
-		pthread_mutex_unlock(&n_children_mutex);
6801
-	}
6802
-}
6803
-
6804
-static void
6805
-dump_blacklist(char *key, int value, void *v)
6806
-{
6807
-	logg(_("Won't blacklist %s\n"), key);
6808
-}
6809
-
6810
-/*
6811
- * Non-blocking connect, based on an idea by Everton da Silva Marques
6812
- *	 <everton.marques@gmail.com>
6813
- * FIXME: There are lots of copies of this code :-(
6814
- */
6815
-static int
6816
-nonblock_connect(int sock, const struct sockaddr_in *sin, const char *hostname)
6817
-{
6818
-	int select_failures;	/* Max. of unexpected select() failures */
6819
-	int attempts;
6820
-	struct timeval timeout;	/* When we should time out */
6821
-	int numfd;		/* Highest fdset fd plus 1 */
6822
-	long flags;
6823
-
6824
-	gettimeofday(&timeout, 0);	/* store when we started to connect */
6825
-
6826
-	if(hostname == NULL)
6827
-		hostname = "clamav-milter";	/* It's only used in debug messages */
6828
-
6829
-#ifdef	F_GETFL
6830
-	flags = fcntl(sock, F_GETFL, 0);
6831
-
6832
-	if(flags == -1L)
6833
-		logg("^getfl: %s\n", strerror(errno));
6834
-	else if(fcntl(sock, F_SETFL, (long)(flags | O_NONBLOCK)) < 0)
6835
-		logg("^setfl: %s\n", strerror(errno));
6836
-#else
6837
-	flags = -1L;
6838
-#endif
6839
-	if(connect(sock, (const struct sockaddr *)sin, sizeof(struct sockaddr_in)) != 0)
6840
-		switch(errno) {
6841
-			case EALREADY:
6842
-			case EINPROGRESS:
6843
-				logg("*%s: connect: %s\n", hostname,
6844
-					strerror(errno));
6845
-				break; /* wait for connection */
6846
-			case EISCONN:
6847
-				return 0; /* connected */
6848
-			default:
6849
-				logg("^%s: connect: %s\n", hostname,
6850
-					strerror(errno));
6851
-#ifdef	F_SETFL
6852
-				if(flags != -1L)
6853
-					if(fcntl(sock, F_SETFL, flags))
6854
-						logg("^f_setfl: %s\n", strerror(errno));
6855
-#endif
6856
-				return -1; /* failed */
6857
-		}
6858
-	else {
6859
-#ifdef	F_SETFL
6860
-		if(flags != -1L)
6861
-			if(fcntl(sock, F_SETFL, flags))
6862
-				logg("^f_setfl: %s\n", strerror(errno));
6863
-#endif
6864
-		return connect_error(sock, hostname);
6865
-	}
6866
-
6867
-	numfd = (int)sock + 1;
6868
-	select_failures = NONBLOCK_SELECT_MAX_FAILURES;
6869
-	attempts = 1;
6870
-	timeout.tv_sec += CONNECT_TIMEOUT;
6871
-
6872
-	for (;;) {
6873
-		int n, t;
6874
-		fd_set fds;
6875
-		struct timeval now, waittime;
6876
-
6877
-		/* Force timeout if we ran out of time */
6878
-		gettimeofday(&now, 0);
6879
-		t = (now.tv_sec == timeout.tv_sec) ?
6880
-			(now.tv_usec > timeout.tv_usec) :
6881
-			(now.tv_sec > timeout.tv_sec);
6882
-
6883
-		if(t) {
6884
-			logg("^%s: connect timeout (%d secs)\n",
6885
-				hostname, CONNECT_TIMEOUT);
6886
-			break;
6887
-		}
6888
-
6889
-		/* Calculate how long to wait */
6890
-		waittime.tv_sec = timeout.tv_sec - now.tv_sec;
6891
-		waittime.tv_usec = timeout.tv_usec - now.tv_usec;
6892
-		if(waittime.tv_usec < 0) {
6893
-			waittime.tv_sec--;
6894
-			waittime.tv_usec += 1000000;
6895
-		}
6896
-
6897
-		/* Init fds with 'sock' as the only fd */
6898
-		FD_ZERO(&fds);
6899
-		FD_SET(sock, &fds);
6900
-
6901
-		n = select(numfd, 0, &fds, 0, &waittime);
6902
-		if(n < 0) {
6903
-			logg("^%s: select attempt %d %s\n",
6904
-				hostname, select_failures, strerror(errno));
6905
-			if(--select_failures >= 0)
6906
-				continue; /* not timed-out, try again */
6907
-			break; /* failed */
6908
-		}
6909
-
6910
-		logg("*%s: select = %d\n", hostname, n);
6911
-
6912
-		if(n) {
6913
-#ifdef	F_SETFL
6914
-			if(flags != -1L)
6915
-				if(fcntl(sock, F_SETFL, flags))
6916
-					logg("^f_setfl: %s\n", strerror(errno));
6917
-#endif
6918
-			return connect_error(sock, hostname);
6919
-		}
6920
-
6921
-		/* timeout */
6922
-		if(attempts++ == NONBLOCK_MAX_ATTEMPTS) {
6923
-			logg("^timeout connecting to %s\n", hostname);
6924
-			break;
6925
-		}
6926
-	}
6927
-
6928
-#ifdef	F_SETFL
6929
-	if(flags != -1L)
6930
-		if(fcntl(sock, F_SETFL, flags))
6931
-			logg("^f_setfl: %s\n", strerror(errno));
6932
-#endif
6933
-	return -1; /* failed */
6934
-}
6935
-
6936
-static int
6937
-connect_error(int sock, const char *hostname)
6938
-{
6939
-#ifdef	SO_ERROR
6940
-	int optval;
6941
-	socklen_t optlen = sizeof(optval);
6942
-
6943
-	getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen);
6944
-
6945
-	if(optval) {
6946
-		logg("^%s: %s\n", hostname, strerror(optval));
6947
-		return -1;
6948
-	}
6949
-#endif
6950
-	return 0;
6951
-}
... ...
@@ -40,13 +40,8 @@
40 40
 #include "connpool.h"
41 41
 #include "netcode.h"
42 42
 
43
-#ifdef HAVE_GETADDRINFO
44 43
 #define SETGAI(k, v) {(k)->gai = (void *)(v);} while(0)
45 44
 #define FREESRV(k) { if((k).gai) freeaddrinfo((k).gai); else if((k).server) free((k).server); } while(0)
46
-#else
47
-#define SETGAI
48
-#define FREESRV(k) { if ((k).server) free((k).server); } while(0)
49
-#endif
50 45
 
51 46
 struct CPOOL *cp = NULL;
52 47
 
... ...
@@ -90,17 +85,12 @@ static int islocal(struct sockaddr *sa, socklen_t addrlen) {
90 90
 }
91 91
 
92 92
 
93
-#ifdef HAVE_GETADDRINFO
94 93
 static int cpool_addtcp(char *addr, char *port) {
95 94
     struct addrinfo hints, *res, *res2;;
96 95
     struct CP_ENTRY *cpe = (struct CP_ENTRY *)&cp->pool[cp->entries-1];
97 96
 
98 97
     memset(&hints, 0, sizeof(hints));
99
-#ifdef SUPPORT_IPv6
100 98
     hints.ai_family = AF_UNSPEC;
101
-#else
102
-    hints.ai_family = AF_INET;
103
-#endif
104 99
     hints.ai_socktype = SOCK_STREAM;
105 100
 
106 101
     if(getaddrinfo(addr, port ? port : "3310", &hints, &res)) {
... ...
@@ -113,11 +103,7 @@ static int cpool_addtcp(char *addr, char *port) {
113 113
     memset(&hints, 0, sizeof(hints));
114 114
     hints.ai_flags = AI_PASSIVE;
115 115
     hints.ai_socktype = SOCK_STREAM;
116
-#ifdef SUPPORT_IPv6
117 116
     hints.ai_family = AF_UNSPEC;
118
-#else
119
-    hints.ai_family = AF_INET;
120
-#endif
121 117
     if(!getaddrinfo(addr, NULL, &hints, &res2)) {
122 118
 	cpe->local = islocal(res2->ai_addr, res2->ai_addrlen);
123 119
 	freeaddrinfo(res2);
... ...
@@ -129,49 +115,6 @@ static int cpool_addtcp(char *addr, char *port) {
129 129
     logg("*%s socket tcp:%s:%s added to the pool (slot %d)\n", cpe->local ? "Local" : "Remote", addr ? addr : "localhost", port ? port : "3310", cp->entries);
130 130
     return 0;
131 131
 }
132
-#else
133
-static int cpool_addtcp(char *addr, char *port) {
134
-    struct sockaddr_in *srv;
135
-    struct CP_ENTRY *cpe = (struct CP_ENTRY *)&cp->pool[cp->entries-1];
136
-    int nport = 3310;
137
-
138
-    if(port) {
139
-	nport = atoi(port);
140
-	if (nport<=0 || nport>65535) {
141
-	    logg("!Bad port for clamd socket (%d)\n", nport);
142
-	    return 1;
143
-	}
144
-    }
145
-    if(!(srv = malloc(sizeof(*srv)))) {
146
-	logg("!Out of memory allocating unix socket space\n");
147
-	return 1;
148
-    }
149
-
150
-    srv->sin_family = AF_INET;
151
-
152
-    if (addr) {
153
-	struct hostent *h;
154
-	if(!(h=gethostbyname(addr))) {
155
-	    logg("^Can't resolve tcp socket hostname %s\n", addr);
156
-	    free(srv);
157
-	    return 1;
158
-	}
159
-	memcpy(&srv->sin_addr.s_addr, h->h_addr_list[0], 4);
160
-    } else {
161
-	srv->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
162
-    }
163
-    cpe->type = 1;
164
-    cpe->dead = 1;
165
-    srv->sin_port = htons(INADDR_ANY);
166
-    cpe->local = islocal(srv, sizeof(srv));
167
-    srv->sin_port = htons(nport);
168
-    cpe->last_poll = 0;
169
-    cpe->server = (struct sockaddr *)srv;
170
-    cpe->socklen = sizeof(*srv);
171
-    logg("*%s socket tcp:%s:%u added to the pool (slot %d)\n", cpe->local ? "Local" : "Remote", addr ? addr : "localhost", nport, cp->entries);
172
-    return 0;
173
-}    
174
-#endif
175 132
 
176 133
 
177 134
 int addslot(void) {
... ...
@@ -248,31 +191,6 @@ void cpool_init(struct cfgstruct *copt) {
248 248
 	}
249 249
     }
250 250
 
251
-#ifdef MILTER_LEGACY
252
-    if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
253
-	if(addslot()) return;
254
-	if(cpool_addunix(cpt->strarg)) {
255
-	    cpool_free();
256
-	    return;
257
-	}
258
-    }
259
-
260
-    if((cpt = cfgopt(copt, "TCPSocket"))->enabled) {
261
-	char *addr = NULL;
262
-	char port[5];
263
-
264
-	if(addslot()) return;
265
-	snprintf(port, 5, "%d", cpt->numarg);
266
-	port[5] = 0;
267
-	if((cpt = cfgopt(copt, "TCPAddr"))->enabled)
268
-	    addr = cpt->strarg;
269
-	if(cpool_addtcp(addr, port)) {
270
-	    cpool_free();
271
-	    return;
272
-	}
273
-    }
274
-#endif
275
-
276 251
     if(!cp->entries) {
277 252
 	logg("!No ClamdSocket specified\n");
278 253
 	cpool_free();
... ...
@@ -8,6 +8,7 @@
8 8
 #include <sys/socket.h>
9 9
 #include <netinet/in.h>
10 10
 #include <netinet/ip.h>
11
+#include <pthread.h>
11 12
 
12 13
 #include "shared/cfgparser.h"
13 14
 
... ...
@@ -36,6 +36,7 @@
36 36
 #include <netdb.h>
37 37
 
38 38
 #include "shared/output.h"
39
+#include "libclamav/others.h"
39 40
 #include "netcode.h"
40 41
 
41 42
 
... ...
@@ -54,9 +55,10 @@ struct LOCALNET {
54 54
 };
55 55
 
56 56
 struct LOCALNET *lnet = NULL;
57
+char *tempdir = NULL;
57 58
 
58
-/* FIXME: for connect and send */
59
-#define TIMEOUT 60
59
+/* for connect and send */
60
+#define TIMEOUT 30
60 61
 /* for recv */
61 62
 long readtimeout;
62 63
 
... ...
@@ -288,13 +290,13 @@ int nc_connect_rand(int *main, int *alt, int *local) {
288 288
     if(!cpe) return 1;
289 289
     *local = (cpe->server->sa_family == AF_UNIX);
290 290
     if(*local) {
291
-	char tmpn[] = "/tmp/clamav-milter-XXXXXX"; 
292
-	if((*alt = mkstemp(tmpn))==-1) { /* FIXME */
291
+	char *unlinkme;
292
+	if(cli_gentempfd(tempdir, &unlinkme, alt) != CL_SUCCESS) {
293 293
 	    logg("!Failed to create temporary file\n");
294 294
 	    close(*main);
295 295
 	    return 1;
296 296
 	}
297
-	unlink(tmpn);
297
+	unlink(unlinkme);
298 298
     } else {
299 299
 	char *reply=NULL, *port;
300 300
 	int nport;
... ...
@@ -349,11 +351,7 @@ int resolve(char *name, uint32_t *family, uint32_t *host) {
349 349
     }
350 350
 
351 351
     memset(&hints, 0, sizeof(hints));
352
-#ifdef SUPPORT_IPv6
353 352
     hints.ai_family = AF_UNSPEC;
354
-#else
355
-    hints.ai_family = AF_INET;
356
-#endif
357 353
     hints.ai_socktype = SOCK_STREAM;
358 354
 
359 355
     if(getaddrinfo(name, NULL, &hints, &res)) {
... ...
@@ -19,5 +19,6 @@ int islocalnet_name(char *name);
19 19
 int islocalnet_sock(struct sockaddr *sa);
20 20
 
21 21
 extern long readtimeout;
22
+extern char *tempdir;
22 23
 
23 24
 #endif
... ...
@@ -58,6 +58,16 @@ Example
58 58
 # Default: unset (don't chroot)
59 59
 ##Chroot /newroot
60 60
 
61
+# This option allows you to save a process identifier of the listening
62
+# daemon (main thread).
63
+#
64
+# Default: disabled
65
+##PidFile /var/run/clamd.pid
66
+
67
+# Optional path to the global temporary directory.
68
+# Default: system specific (usually /tmp or /var/tmp).
69
+#
70
+#TemporaryDirectory /var/tmp
61 71
 
62 72
 ##
63 73
 ## Clamd options
... ...
@@ -188,12 +198,6 @@ Example
188 188
 # Default: no
189 189
 ##LogTime yes
190 190
 
191
-# Also log clean files. Useful in debugging but drastically increases the
192
-# log size.
193
-#
194
-# Default: no
195
-##LogClean yes
196
-
197 191
 # Use system logger (can work together with LogFile).
198 192
 #
199 193
 # Default: no
... ...
@@ -215,7 +219,7 @@ Example
215 215
 ## Limits
216 216
 ##
217 217
 
218
-# Files larger than this value won't be scanned.
218
+# Messages larger than this value won't be scanned.
219 219
 # Default: 25M
220 220
 ##MaxFileSize 150M
221 221
 
... ...
@@ -244,19 +248,17 @@ Example
244 244
 #MaxRecursion
245 245
 #MaxFiles
246 246
 #PhishingSignatures
247
-#PidFile
248 247
 #ScanArchive
249 248
 #ScanHTML
250 249
 #ScanMail
251 250
 #ScanOLE2
252 251
 #ScanPE
253
-#TemporaryDirectory
254 252
 
255 253
 
256 254
 #Todo
257 255
 ##-C --chroot
258 256
 #-D --debug
259
-#-i --pidfile
257
+##-i --pidfile
260 258
 ##-I --ignore
261 259
 ##-W --whitelist-file
262 260
 
... ...
@@ -39,12 +39,12 @@ struct cfgoption cfg_options[] = {
39 39
     {"LogFileUnlock", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_MILTER},
40 40
     {"LogFileMaxSize", OPT_COMPSIZE, 1048576, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
41 41
     {"LogTime", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
42
-    {"LogClean", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_MILTER},
42
+    {"LogClean", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
43 43
     {"LogVerbose", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
44 44
     {"LogSyslog", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
45 45
     {"LogFacility", OPT_QUOTESTR, -1, "LOG_LOCAL6", 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
46
-    {"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
47
-    {"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
46
+    {"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER},
47
+    {"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_MILTER},
48 48
     {"ScanPE", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
49 49
     {"ScanELF", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
50 50
     {"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
... ...
@@ -166,7 +166,6 @@ struct cfgoption cfg_options[] = {
166 166
     {"MaxFiles", OPT_NUM, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
167 167
     {"MaxRecursion", OPT_NUM, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
168 168
     {"PhishingSignatures", OPT_BOOL, 1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
169
-    {"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
170 169
     {"ScanArchive", OPT_BOOL, 1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
171 170
     {"ScanHTML", OPT_BOOL, 1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
172 171
     {"ScanMail", OPT_BOOL, 1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},