"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "bogom-1.9.2/milter.c" of archive bogom-1.9.2.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* $Id: milter.c,v 1.40 2008/06/25 21:41:42 reidrac Exp reidrac $ */
2
3 /*
4 * bogom, simple sendmail milter to interface bogofilter
5 * Copyright (C) 2004-2007 Juan J. Martinez <jjm*at*usebox*dot*net>
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 Version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22 #include <sys/param.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <pwd.h>
35 #include <syslog.h>
36 #include <regex.h>
37 #include <time.h>
38 #include <netdb.h>
39
40 #ifdef __sun__
41 #include <fcntl.h>
42 #endif
43
44 #include "libmilter/mfapi.h"
45 #include "conf.h"
46
47 /* defaults */
48 #ifndef DEF_USER
49 #define DEF_USER "bogofilter"
50 #endif
51 #ifndef DEF_CONN
52 #define DEF_CONN "unix:/var/spool/bogofilter/milter.sock"
53 #endif
54 #ifndef DEF_CONF
55 #define DEF_CONF "/etc/bogom.conf"
56 #endif
57 #ifndef DEF_PIDFILE
58 #define DEF_PIDFILE "/var/spool/bogofilter/bogom.pid"
59 #endif
60
61 struct mlfiPriv
62 {
63 FILE *f;
64 char *fullpath;
65 char *filename;
66 char *subject;
67 int eom;
68 size_t bodylen;
69 int old_headers;
70 };
71
72 sfsistat mlfi_connect(SMFICTX *, char *, _SOCK_ADDR *);
73 sfsistat mlfi_envfrom(SMFICTX *, char **);
74 sfsistat mlfi_envrcpt(SMFICTX *, char **);
75 sfsistat mlfi_header(SMFICTX *, char *, char *);
76 sfsistat mlfi_eoh(SMFICTX *);
77 sfsistat mlfi_body(SMFICTX *, unsigned char *, size_t);
78 sfsistat mlfi_eom(SMFICTX *);
79 sfsistat mlfi_abort(SMFICTX *);
80 sfsistat mlfi_close(SMFICTX *);
81 void mlfi_clean(SMFICTX *);
82 void usage(const char *);
83 int to_maildir(char *, char *);
84 char *hostname_tmp();
85
86 #ifdef __sun__
87 int daemon(int, int);
88 #endif
89
90 struct smfiDesc smfilter=
91 {
92 "bogom", /* filter name */
93 SMFI_VERSION, /* version code -- do not change */
94 SMFIF_ADDHDRS | SMFIF_CHGHDRS | /* flags -- add and modify headers */
95 SMFIF_ADDRCPT, /* -- add rcpt */
96 mlfi_connect, /* connection info filter */
97 NULL, /* SMTP HELO command filter */
98 mlfi_envfrom, /* envelope sender filter */
99 mlfi_envrcpt, /* envelope recipient filter */
100 mlfi_header, /* header filter */
101 mlfi_eoh, /* end of header */
102 mlfi_body, /* body block filter */
103 mlfi_eom, /* end of message */
104 mlfi_abort, /* message aborted */
105 mlfi_close /* connection cleanup */
106 };
107
108 struct re_list
109 {
110 regex_t p;
111 const char *pat;
112 struct re_list *n;
113 };
114
115 #define new_re_list(x) do {\
116 x=(struct re_list *) \
117 malloc(sizeof(struct re_list));\
118 x->n=NULL;\
119 } while(0)
120
121 static const char rcsid[]="$Id: milter.c,v 1.40 2008/06/25 21:41:42 reidrac Exp reidrac $";
122
123 static int mode=SMFIS_CONTINUE;
124 static int train=0;
125 static int verbose=0;
126 static int debug=0;
127 static int spamicity=0;
128 static size_t bodylimit=0;
129 static const char *bogo="/usr/local/bin/bogofilter";
130 static const char *exclude=NULL;
131 static const char *subj_tag=NULL;
132 static const char *forward_spam=NULL;
133 static char *quarantine_mdir=NULL;
134
135 static char *reject=NULL;
136
137 static struct re_list *re_c=NULL; /* re connection */
138 static struct re_list *re_f=NULL; /* re envfrom */
139 static struct re_list *re_r=NULL; /* re envrcpt */
140
141 #ifdef __sun__
142 int
143 daemon(int nochdir, int noclose)
144 {
145 int fd;
146
147 switch(fork())
148 {
149 case 0:
150 break;
151
152 case -1:
153 return -1;
154
155 default:
156 _exit(0);
157 }
158
159 if(setsid()==-1)
160 return -1;
161
162 if(!nochdir && chdir("/"))
163 return -1;
164
165 if(!noclose)
166 {
167 fd=open("/dev/null", O_RDWR, 0);
168 if(fd==-1)
169 return -1;
170
171 dup2(fd, fileno(stdin));
172 dup2(fd, fileno(stdout));
173 dup2(fd, fileno(stderr));
174 }
175
176 return 0;
177 }
178 #endif
179
180 sfsistat
181 mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
182 {
183 struct mlfiPriv *priv;
184 struct re_list *tre; /* temporal iterator */
185
186 const void *mysaddr=NULL;
187 char host[INET6_ADDRSTRLEN];
188
189 if(hostaddr)
190 {
191 switch(hostaddr->sa_family)
192 {
193 default:
194 syslog(LOG_ERR, "mlfi_connet: unsupported sa_family");
195 break;
196
197 case AF_INET:
198 mysaddr=(const void *)&((struct sockaddr_in *)hostaddr)
199 ->sin_addr.s_addr;
200 break;
201
202 case AF_INET6:
203 mysaddr=(const void *)&((struct sockaddr_in6 *)hostaddr)
204 ->sin6_addr;
205 break;
206 }
207
208 if(!inet_ntop(hostaddr->sa_family, mysaddr, host, sizeof(host)))
209 {
210 syslog(LOG_ERR, "mlfi_connect: inet_ntop failed");
211 strcpy(host, "*");
212 }
213 }
214 else
215 strcpy(host, "*");
216
217 if(debug)
218 syslog(LOG_DEBUG, "connection from %s [ %s ]", hostname, host);
219
220 for(tre=re_c; tre; tre=tre->n)
221 {
222 if(!regexec(&tre->p, hostname, 0, NULL, 0))
223 {
224 if(verbose)
225 syslog(LOG_INFO,
226 "accepted due pattern match (connect): %s",
227 tre->pat);
228
229 return SMFIS_ACCEPT;
230 }
231
232 if(!regexec(&tre->p, host, 0, NULL, 0))
233 {
234 if(verbose)
235 syslog(LOG_INFO,
236 "accepted due pattern match (connect): %s",
237 tre->pat);
238 return SMFIS_ACCEPT;
239 }
240 }
241
242 priv=(struct mlfiPriv *)malloc(sizeof(struct mlfiPriv));
243 if(!priv)
244 {
245 syslog(LOG_ERR, "Unable to get memory: %s",
246 strerror(errno));
247 return SMFIS_TEMPFAIL;
248 }
249
250 priv->fullpath=NULL;
251 priv->filename=NULL;
252 priv->subject=NULL;
253 priv->f=NULL;
254 priv->eom=1;
255 priv->old_headers=0;
256
257 if(smfi_setpriv(ctx, priv)!=MI_SUCCESS)
258 {
259 syslog(LOG_ERR, "on mlfi_connect: smfi_setpriv");
260 return SMFIS_ACCEPT;
261 }
262
263 return SMFIS_CONTINUE;
264 }
265
266 sfsistat
267 mlfi_envfrom(SMFICTX *ctx, char **argv)
268 {
269 struct re_list *tre; /* temporal iterator */
270
271 if(debug)
272 syslog(LOG_DEBUG, "envfrom %s", argv[0]);
273
274 for(tre=re_f; tre; tre=tre->n)
275 if(!regexec(&tre->p, argv[0], 0, NULL, 0))
276 {
277 if(verbose)
278 syslog(LOG_INFO,
279 "accepted due pattern match (envfrom): %s",
280 tre->pat);
281 return SMFIS_ACCEPT;
282 }
283
284 return SMFIS_CONTINUE;
285 }
286
287 sfsistat
288 mlfi_envrcpt(SMFICTX *ctx, char **argv)
289 {
290 struct mlfiPriv *priv;
291 struct re_list *tre; /* temporal iterator */
292 int fd=-1;
293 char *tmp=NULL;
294
295 if(debug)
296 syslog(LOG_DEBUG, "envrcpt %s", argv[0]);
297
298 for(tre=re_r; tre; tre=tre->n)
299 if(!regexec(&tre->p, argv[0], 0, NULL, 0))
300 {
301 if(verbose)
302 syslog(LOG_INFO,
303 "accepted due pattern match (envrcpt): %s",
304 tre->pat);
305 return SMFIS_ACCEPT;
306 }
307
308 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
309 if(!priv)
310 {
311 syslog(LOG_ERR, "on mlfi_header: smfi_getpriv");
312 return SMFIS_ACCEPT;
313 }
314
315 if(priv->eom)
316 {
317 /* use tmp/ from quarantine maildir if available */
318 if(quarantine_mdir)
319 {
320 tmp=hostname_tmp();
321 if(!tmp)
322 {
323 syslog(LOG_ERR, "Unable to get memory: %s",
324 strerror(errno));
325 return SMFIS_TEMPFAIL;
326 }
327
328 priv->fullpath=(char *)calloc(strlen(quarantine_mdir)
329 +strlen(tmp)+6, sizeof(char));
330 }
331 else
332 priv->fullpath=strdup("/tmp/bogom-msg.XXXXXXXXXX");
333
334 if(!priv->fullpath)
335 {
336 syslog(LOG_ERR, "Unable to get memory: %s",
337 strerror(errno));
338 if(tmp)
339 free(tmp);
340 return SMFIS_TEMPFAIL;
341 }
342
343 if(quarantine_mdir)
344 {
345 snprintf(priv->fullpath, strlen(quarantine_mdir)+
346 strlen(tmp)+6, "%s/tmp/%s", quarantine_mdir,
347 tmp);
348 priv->filename=priv->fullpath+strlen(quarantine_mdir)
349 +5;
350 free(tmp);
351 }
352
353 fd=mkstemp(priv->fullpath);
354 if(fd==-1)
355 {
356 syslog(LOG_ERR, "Unable to create tmp file in %s: %s",
357 priv->fullpath, strerror(errno));
358
359 mlfi_clean(ctx);
360 return SMFIS_TEMPFAIL;
361 }
362
363 #ifdef __sun__
364 priv->f=fdopen(fd, "w+F");
365 #else
366 priv->f=fdopen(fd, "w+");
367 #endif
368 if(!priv->f)
369 {
370 syslog(LOG_ERR, "Unable to create tmp file in %s: %s",
371 priv->fullpath, strerror(errno));
372
373 if(fd!=-1)
374 close(fd);
375
376 mlfi_clean(ctx);
377 return SMFIS_TEMPFAIL;
378 }
379
380 priv->eom=0;
381 priv->bodylen=0;
382
383 if(debug)
384 syslog(LOG_DEBUG, "message begin...");
385 }
386
387 return SMFIS_CONTINUE;
388 }
389
390 sfsistat
391 mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
392 {
393 struct mlfiPriv *priv;
394
395 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
396 if(!priv)
397 {
398 syslog(LOG_ERR, "on mlfi_header: smfi_getpriv");
399 return SMFIS_ACCEPT;
400 }
401
402 if(exclude && headerv)
403 if(!strcasecmp(headerf, "Subject"))
404 if(strstr(headerv, exclude))
405 {
406 if(verbose)
407 syslog(LOG_INFO,
408 "exclude string found: '%s'",
409 headerv);
410 mlfi_clean(ctx);
411 return SMFIS_ACCEPT;
412 }
413
414 if(debug)
415 syslog(LOG_DEBUG, "header %s [%s]", headerf, headerv);
416
417 if(headerv && !strcasecmp(headerf, "X-Bogosity"))
418 priv->old_headers++;
419
420 if(subj_tag && headerv)
421 if(!strcasecmp(headerf, "Subject"))
422 {
423 if(priv->subject)
424 syslog(LOG_INFO,
425 "Subject header not unique");
426 else
427 {
428 priv->subject=strdup(headerv);
429 if(!priv->subject)
430 syslog(LOG_ERR,
431 "Unable to get memory (subject"
432 " tag): %s",
433 strerror(errno));
434 }
435 }
436
437 if(fprintf(priv->f, "%s: %s\n", headerf, headerv)==EOF)
438 {
439 syslog(LOG_ERR, "failed to write into %s: %s",
440 priv->fullpath, strerror(errno));
441 mlfi_clean(ctx);
442 return SMFIS_TEMPFAIL;
443 }
444
445 return SMFIS_CONTINUE;
446 }
447
448 sfsistat
449 mlfi_eoh(SMFICTX *ctx)
450 {
451 struct mlfiPriv *priv;
452
453 if(debug)
454 syslog(LOG_DEBUG, "headers ok");
455
456 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
457 if(!priv)
458 {
459 syslog(LOG_ERR, "on mlfi_eoh: smfi_getpriv");
460 return SMFIS_ACCEPT;
461 }
462
463 if(fprintf(priv->f, "\n")==EOF)
464 {
465 syslog(LOG_ERR, "failed to write into %s: %s",
466 priv->fullpath, strerror(errno));
467 mlfi_clean(ctx);
468 return SMFIS_TEMPFAIL;
469 }
470
471 return SMFIS_CONTINUE;
472 }
473
474 sfsistat
475 mlfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen)
476 {
477 struct mlfiPriv *priv;
478
479 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
480 if(!priv)
481 {
482 syslog(LOG_ERR, "on mlfi_body: smfi_getpriv");
483 return SMFIS_ACCEPT;
484 }
485
486 if(bodylimit)
487 {
488 if(bodylimit==priv->bodylen)
489 {
490 if(debug)
491 syslog(LOG_DEBUG, "body_limit reached, "
492 " %d bytes discarded", bodylen);
493
494 bodylen=0;
495 }
496 else
497 if(priv->bodylen+bodylen>bodylimit)
498 {
499 if(debug)
500 syslog(LOG_DEBUG, "body_limit reached, "
501 " %d bytes discarded",
502 bodylen-(bodylimit-priv->bodylen));
503
504 bodylen=bodylimit-priv->bodylen;
505 }
506 }
507
508 if(bodylen>0)
509 {
510 if(fwrite(bodyp, bodylen, 1, priv->f)!=1)
511 {
512 syslog(LOG_ERR, "failed to write into %s: %s",
513 priv->fullpath, strerror(errno));
514 mlfi_clean(ctx);
515 return SMFIS_TEMPFAIL;
516 }
517 else
518 {
519 if(debug)
520 syslog(LOG_DEBUG, "%d body bytes written",
521 bodylen);
522
523 priv->bodylen+=bodylen;
524 }
525 }
526
527 return SMFIS_CONTINUE;
528 }
529
530 sfsistat
531 mlfi_eom(SMFICTX *ctx)
532 {
533 struct mlfiPriv *priv;
534 int status, i;
535 char *bogocl, header[64];
536 float spamicity_val;
537 char *tmp_subj;
538 FILE *proc;
539
540 if(debug)
541 syslog(LOG_DEBUG, "...end of message");
542
543 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
544 if(!priv)
545 {
546 syslog(LOG_ERR, "on mlfi_eom: smfi_getpriv");
547 return SMFIS_ACCEPT;
548 }
549
550 fclose(priv->f);
551 priv->f=NULL;
552
553 bogocl=(char *)malloc(strlen(bogo)+strlen(priv->fullpath)+16);
554 if(!bogocl)
555 {
556 syslog(LOG_ERR, "on mlfi_eom: %s", strerror(errno));
557 mlfi_clean(ctx);
558 return SMFIS_CONTINUE;
559 }
560
561 sprintf(bogocl, "%s -", bogo);
562
563 if(train)
564 strcat(bogocl, "u");
565
566 if(verbose)
567 strcat(bogocl, "l");
568
569 if(spamicity)
570 strcat(bogocl, "TT");
571
572 strcat(bogocl, "B ");
573 strcat(bogocl, priv->fullpath);
574
575 #ifdef __sun__
576 proc=popen(bogocl, "rF");
577 #else
578 proc=popen(bogocl, "r");
579 #endif
580 if(!proc)
581 {
582 syslog(LOG_ERR, "failed to exec bogofilter: %s",
583 strerror(errno));
584 free(bogocl);
585 mlfi_clean(ctx);
586 return SMFIS_CONTINUE;
587 }
588 free(bogocl);
589
590 if(spamicity)
591 {
592 /* FIXME: spaces in the path will cause trouble */
593 if(fscanf(proc, "%*[^ ] %f\n", &spamicity_val)!=1)
594 {
595 syslog(LOG_ERR, "failed to get bogofilter spamicity "
596 "value");
597 spamicity_val=-1;
598 }
599 else
600 if(debug)
601 syslog(LOG_DEBUG, "spamicity value: %f",
602 spamicity_val);
603 }
604
605 status=pclose(proc);
606
607 if(!WIFEXITED(status))
608 {
609 syslog(LOG_ERR, "bogofilter didn't exit normally");
610 mlfi_clean(ctx);
611 return SMFIS_CONTINUE;
612 }
613
614 switch(WEXITSTATUS(status))
615 {
616 case 3:
617 case -1:
618 syslog(LOG_ERR, "bogofilter reply: I/O error");
619 mlfi_clean(ctx);
620 return SMFIS_CONTINUE;
621 case 0:
622 if(spamicity && spamicity_val!=-1)
623 snprintf(header, 64, "Spam, spamicity=%.6f",
624 spamicity_val);
625 else
626 strcpy(header, "Yes, tests=bogofilter");
627 smfi_insheader(ctx, 0, "X-Bogosity", header);
628
629 priv->old_headers++;
630
631 if(forward_spam)
632 {
633 if(smfi_addrcpt(ctx, (char *)forward_spam)
634 !=MI_SUCCESS)
635 syslog(LOG_ERR, "forward_spam failed:"
636 " '%s'", forward_spam);
637 else
638 if(debug)
639 syslog(LOG_DEBUG,
640 "forward_spam rcpt added: "
641 "'%s'", forward_spam);
642 }
643
644 if(subj_tag && priv->subject)
645 {
646 tmp_subj=(char *)calloc(strlen(subj_tag)+
647 strlen(priv->subject)+2, sizeof(char));
648
649 if(!tmp_subj)
650 syslog(LOG_ERR, "Unable to get memory:"
651 " %s", strerror(errno));
652 else
653 {
654 snprintf(tmp_subj, strlen(subj_tag)+
655 strlen(priv->subject)+2,
656 "%s %s", subj_tag,
657 priv->subject);
658
659 /* truncate if needed and be nice
660 with RFC */
661 if(strlen(tmp_subj)>998)
662 tmp_subj[998]=0;
663
664 if(smfi_chgheader(ctx, "Subject", 1,
665 tmp_subj)!=MI_SUCCESS)
666 syslog(LOG_ERR, "subject_tag"
667 " failed: '%s'",
668 tmp_subj);
669 else
670 if(debug)
671 syslog(LOG_DEBUG,
672 "subject_tag"
673 " added: '%s'",
674 tmp_subj);
675 free(tmp_subj);
676 }
677 }
678
679 if(verbose)
680 {
681 if(mode==SMFIS_CONTINUE)
682 syslog(LOG_NOTICE,
683 "bogofilter reply: spam");
684 else
685 if(mode==SMFIS_REJECT)
686 syslog(LOG_NOTICE,
687 "spam rejected");
688 else
689 syslog(LOG_NOTICE,
690 "spam discarded");
691 }
692
693 if(mode==SMFIS_REJECT && reject)
694 smfi_setreply(ctx, "554", "5.7.1", reject);
695
696 if(quarantine_mdir)
697 {
698 if(debug)
699 syslog(LOG_DEBUG, "copying message "
700 "to quarantine_mdir");
701
702 if(chdir(quarantine_mdir)==-1)
703 syslog(LOG_ERR, "failed to chdir to "
704 "quarantine_mdir: %s\n",
705 strerror(errno));
706 else
707 if(to_maildir(priv->fullpath,
708 priv->filename)==-1)
709 syslog(LOG_ERR, "failed to"
710 " copy message to "
711 "quarantine_mdir");
712 }
713
714 mlfi_clean(ctx);
715 return mode;
716 case 1:
717 if(spamicity && spamicity_val!=-1)
718 snprintf(header, 64, "Ham, spamicity=%.6f",
719 spamicity_val);
720 else
721 strcpy(header, "No, tests=bogofilter");
722 smfi_insheader(ctx, 0, "X-Bogosity", header);
723
724 priv->old_headers++;
725
726 if(verbose)
727 syslog(LOG_NOTICE, "bogofilter reply: ham");
728 break;
729 case 2:
730 if(spamicity && spamicity_val!=-1)
731 snprintf(header, 64, "Unsure, spamicity=%.6f",
732 spamicity_val);
733 else
734 strcpy(header, "Unsure, tests=bogofilter");
735 smfi_insheader(ctx, 0, "X-Bogosity", header);
736
737 priv->old_headers++;
738
739 if(verbose)
740 syslog(LOG_NOTICE, "bogofilter reply: unsure");
741 break;
742 default:
743 syslog(LOG_ERR, "bogofilter reply is unknown");
744 break;
745 }
746
747 if(priv->old_headers>1)
748 for(i=2, priv->old_headers++;i<priv->old_headers+1;i++)
749 {
750 smfi_chgheader(ctx, "X-Bogosity", i, NULL);
751 if(debug)
752 syslog(LOG_DEBUG, "previous header removed");
753 }
754
755 mlfi_clean(ctx);
756 return SMFIS_CONTINUE;
757 }
758
759 sfsistat
760 mlfi_abort(SMFICTX *ctx)
761 {
762 if(debug)
763 syslog(LOG_DEBUG, "message ABORTED");
764
765 mlfi_clean(ctx);
766
767 return SMFIS_CONTINUE;
768 }
769
770 sfsistat
771 mlfi_close(SMFICTX *ctx)
772 {
773 struct mlfiPriv *priv;
774
775 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
776 if(!priv)
777 return SMFIS_CONTINUE;
778
779 if(!priv->eom)
780 mlfi_clean(ctx);
781
782 smfi_setpriv(ctx, NULL);
783 free(priv);
784
785 if(debug)
786 syslog(LOG_DEBUG, "connection closed");
787
788 return SMFIS_CONTINUE;
789 }
790
791 void
792 mlfi_clean(SMFICTX *ctx)
793 {
794 struct mlfiPriv *priv;
795
796 if(debug)
797 syslog(LOG_DEBUG, "cleaning message...");
798
799 priv=(struct mlfiPriv *)smfi_getpriv(ctx);
800
801 if(!priv)
802 return;
803
804 if(priv->f)
805 {
806 if(debug)
807 syslog(LOG_DEBUG, "closing tmp file");
808 fclose(priv->f);
809 priv->f=NULL;
810 }
811
812 if(priv->fullpath)
813 {
814 if(debug)
815 syslog(LOG_DEBUG, "removing tmp file");
816 unlink(priv->fullpath);
817 free(priv->fullpath);
818 priv->fullpath=NULL;
819 }
820
821 if(priv->subject)
822 {
823 free(priv->subject);
824 priv->subject=NULL;
825 }
826
827 priv->eom=1;
828 priv->old_headers=0;
829
830 if(debug)
831 syslog(LOG_DEBUG, "...cleaning done");
832
833 return;
834 }
835
836 char *
837 hostname_tmp()
838 {
839 char *p;
840 char myhostname[MAXHOSTNAMELEN+128];
841 struct timeval tp;
842
843 if(gettimeofday(&tp, NULL)==-1)
844 tp.tv_sec=time(NULL);
845
846 /* time + hostname to make a unique filename NFS friendly */
847 snprintf(myhostname, 117, "bogom_%lu.%lu.", tp.tv_sec, tp.tv_usec);
848
849 if(gethostname(myhostname+strlen(myhostname), MAXHOSTNAMELEN)==-1)
850 {
851 syslog(LOG_NOTICE, "failed to get my hostname");
852 strcpy(myhostname, "unknown_hostname");
853 }
854
855 p=myhostname;
856 while((p=strstr(p, "/")))
857 *p='\057';
858
859 p=myhostname;
860 while((p=strstr(p, ":")))
861 *p='\072';
862
863 strcat(myhostname, ".XXXXXXXXXX");
864
865 return strdup(myhostname);
866 }
867
868 int
869 to_maildir(char *origin, char *filename)
870 {
871 char *p;
872 struct stat st;
873
874 /* caller must chdir to quarantine_mdir */
875
876 if(stat("new", &st)==-1 && errno==ENOENT)
877 if(mkdir("new", 0700)==-1)
878 {
879 syslog(LOG_ERR, "quarantine_mdir failed to "
880 "create new/: %s", strerror(errno));
881 return -1;
882 }
883
884 p=(char *)calloc(strlen(filename)+strlen(quarantine_mdir)+6,
885 sizeof(char));
886 if(!p)
887 {
888 syslog(LOG_ERR, "quarantine_mdir failed to get memory: %s",
889 strerror(errno));
890 return -1;
891 }
892
893 snprintf(p, strlen(filename)+strlen(quarantine_mdir)+6,
894 "%s/new/%s\n", quarantine_mdir, filename);
895
896 if(link(origin, p)==-1)
897 {
898 syslog(LOG_ERR, "quarantine_mdir failed to link file: %s",
899 strerror(errno));
900 free(p);
901 return -1;
902 }
903
904 free(p);
905
906 return 0;
907 }
908
909 void
910 usage(const char *argv0)
911 {
912 fprintf(stderr, "usage: %s\t[-R | -D] [-t] [-v] [-u user] [-s conn]\n"
913 "\t\t[-b bogo_path ] [-x exclude_string] "
914 "[-c conf_file]\n\t\t[-l body_limit] [-p pidfile] "
915 "[-f forward_spam]\n"
916 "\t\t[-q quarantine_mdir] [-S] [-d]\n", argv0);
917
918 return;
919 }
920
921 int
922 main(int argc, char *argv[])
923 {
924 const char *user=DEF_USER;
925 const char *conn=DEF_CONN;
926 const char *pipe=NULL;
927 const char *conffile=DEF_CONF;
928 const char *pidfile=DEF_PIDFILE;
929
930 FILE *pidfile_fd;
931 int result;
932
933 struct re_list *tre;
934 struct string_list *tsl, *tsl2;
935
936 /* configuration tokens */
937 struct conftoken conf[]=
938 {
939 { "verbose", REQ_BOOL, NULL, -1, NULL },
940 { "training", REQ_BOOL, NULL, -1, NULL },
941 { "user", REQ_QSTRING, NULL, 0, NULL },
942 { "connection", REQ_QSTRING, NULL, 0, NULL },
943 { "exclude_string", REQ_QSTRING, NULL, 0, NULL },
944 { "re_envfrom", REQ_LSTQSTRING, NULL, 0, NULL },
945 { "bogofilter", REQ_QSTRING, NULL, 0, NULL },
946 { "policy", REQ_STRING, NULL, 0, NULL },
947 { "reject", REQ_QSTRING, NULL, 0, NULL },
948 { "re_connection", REQ_LSTQSTRING, NULL, 0, NULL },
949 { "re_envrcpt", REQ_LSTQSTRING, NULL, 0, NULL },
950 { "body_limit", REQ_STRING, NULL, 0, NULL },
951 { "pidfile", REQ_QSTRING, NULL, 0, NULL },
952 { "subject_tag", REQ_QSTRING, NULL, 0, NULL },
953 { "forward_spam", REQ_QSTRING, NULL, 0, NULL },
954 { "quarantine_mdir", REQ_QSTRING, NULL, 0, NULL },
955 { "spamicity_header", REQ_BOOL, NULL, -1, NULL },
956 { NULL, 0, NULL, 0, NULL }
957 };
958
959 int opt;
960 const char *opts="hu:p:b:RDtvx:w:c:l:ds:f:q:S";
961
962 struct passwd *pw=NULL;
963 struct stat st;
964
965 while((opt=getopt(argc, argv, opts))!=-1)
966 switch(opt)
967 {
968 case 'h':
969 default:
970 usage(argv[0]