1 /* Copyright (C) 2005, 2006 by Eugene Kurmanin <me@kurmanin.info>
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18 #ifndef _REENTRANT
19 #error Compile with -D_REENTRANT flag
20 #endif
21
22 #include <arpa/inet.h>
23 #include <arpa/nameser.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #ifndef __sun__
28 #include <getopt.h>
29 #endif
30 #include <grp.h>
31 #include <libmilter/mfapi.h>
32 #include <netdb.h>
33 #include <netinet/in.h>
34 #include <pthread.h>
35 #include <pwd.h>
36 #include <regex.h>
37 #include <resolv.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/select.h>
43 #include <sys/socket.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <syslog.h>
47 #include <time.h>
48 #include <unistd.h>
49
50 #ifndef MSG_NOSIGNAL
51 #define MSG_NOSIGNAL 0
52 #endif
53
54 #define SAFE_FREE(x) if (x) { free(x); x = NULL; }
55
56 #define hash_size(x) ((unsigned long) 1 << x)
57 #define hash_mask(x) (hash_size(x) - 1)
58
59 #define CONFIG_FILE "/usr/local/etc/smf-sav.conf"
60 #define PUBLIC_NAME "yourhost.yourdomain.tld"
61 #define SAFE_CALLBACK "postmaster@yourdomain.tld"
62 #define SYSLOG_FACILITY LOG_MAIL
63 #define SAV 1
64 #define IGNORE_TEMPFAIL 0
65 #define BLOCK_IGNORANTS 0
66 #define FROM_PASS_TTL 86400
67 #define FROM_TEMPFAIL_TTL 300
68 #define FROM_FAIL_TTL 3600
69 #define TO_PASS_TTL 3600
70 #define TO_TEMPFAIL_TTL 300
71 #define TO_FAIL_TTL 3600
72 #define WORK_SPACE "/var/run/smfs"
73 #define OCONN "unix:" WORK_SPACE "/smf-sav.sock"
74 #define USER "smfs"
75
76 #define DNS_RETRANS 7
77 #define DNS_RETRY 4
78 #define SMTP_PORT 25
79 #define CONN_TIMEOUT 60
80 #define SEND_TIMEOUT 60
81 #define RECV_TIMEOUT 120
82 #define SLOW_DOWN_SLICE 5
83
84 #define MAXLINE 128
85 #define MAXMX 16
86 #define MXBUFFER (128 * MAXMX)
87 #define MAXPACKET 8192
88
89 #define QUIT_OK 1
90 #define QUIT_PERM 0
91 #define QUIT_FAIL -1
92
93 #define SMTP_CMD_OK(x) (200 <= (x) && (x) < 300)
94 #define SMTP_CMD_PERM(x) (500 <= (x) && (x) < 600)
95
96 #define CALLBACK "<>"
97 #define HASH_POWER 16
98 #define FACILITIES_AMOUNT 10
99 #define IPV4_DOT_DECIMAL "^[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.]?$"
100
101 #ifdef __sun__
daemon(int nochdir,int noclose)102 int daemon(int nochdir, int noclose) {
103 pid_t pid;
104 int fd = 0;
105
106 if ((pid = fork()) < 0) {
107 fprintf(stderr, "fork: %s\n", strerror(errno));
108 return 1;
109 }
110 else
111 if (pid > 0) _exit(0);
112 if ((pid = setsid()) == -1) {
113 fprintf(stderr, "setsid: %s\n", strerror(errno));
114 return 1;
115 }
116 if ((pid = fork()) < 0) {
117 fprintf(stderr, "fork: %s\n", strerror(errno));
118 return 1;
119 }
120 else
121 if (pid > 0) _exit(0);
122 if (!nochdir && chdir("/")) {
123 fprintf(stderr, "chdir: %s\n", strerror(errno));
124 return 1;
125 }
126 if (!noclose) {
127 dup2(fd, fileno(stdout));
128 dup2(fd, fileno(stderr));
129 dup2(open("/dev/null", O_RDONLY, 0), fileno(stdin));
130 }
131 return 0;
132 }
133 #endif
134
135 typedef enum cache_put_mode {
136 CACHE_KEEP = 0,
137 CACHE_OVER
138 } cache_put_mode;
139
140 typedef enum cache_item_type {
141 SENDERS = 0,
142 RECIPIENTS
143 } cache_item_type;
144
145 typedef enum cache_item_status {
146 ST_NONE = 0,
147 SENDER_PASS,
148 SENDER_FAIL,
149 SENDER_TEMPFAIL,
150 RECIPIENT_PASS,
151 RECIPIENT_FAIL,
152 RECIPIENT_TEMPFAIL
153 } cache_item_status;
154
155 typedef enum vrfy_status {
156 ST_OKEY = 0,
157 ST_SAV_FAIL,
158 ST_SAV_TEMPFAIL
159 } vrfy_status;
160
161 typedef struct cache_item {
162 char *item;
163 unsigned long hash;
164 cache_item_type type;
165 cache_item_status status;
166 time_t exptime;
167 struct cache_item *next;
168 } cache_item;
169
170 typedef struct CIDR {
171 unsigned long ip;
172 unsigned short int mask;
173 struct CIDR *next;
174 } CIDR;
175
176 typedef struct STR {
177 char *str;
178 struct STR *next;
179 } STR;
180
181 typedef struct config {
182 char *public_name;
183 char *safe_callback;
184 char *mail_store;
185 char *run_as_user;
186 char *sendmail_socket;
187 CIDR *cidrs;
188 STR *ptrs;
189 STR *froms;
190 STR *tos;
191 int syslog_facility;
192 int sav;
193 int ignore_tempfail;
194 int block_ignorants;
195 unsigned long from_pass_ttl;
196 unsigned long from_tempfail_ttl;
197 unsigned long from_fail_ttl;
198 unsigned long to_pass_ttl;
199 unsigned long to_tempfail_ttl;
200 unsigned long to_fail_ttl;
201 } config;
202
203 typedef struct facilities {
204 char *name;
205 int facility;
206 } facilities;
207
208 typedef union {
209 HEADER hdr;
210 unsigned char buf[MAXPACKET];
211 } querybuf;
212
213 static regex_t re_ipv4;
214 static cache_item **cache = NULL;
215 static const char *config_file = CONFIG_FILE;
216 static config conf;
217 static pthread_mutex_t cache_mutex;
218 static facilities syslog_facilities[] = {
219 { "daemon", LOG_DAEMON },
220 { "mail", LOG_MAIL },
221 { "local0", LOG_LOCAL0 },
222 { "local1", LOG_LOCAL1 },
223 { "local2", LOG_LOCAL2 },
224 { "local3", LOG_LOCAL3 },
225 { "local4", LOG_LOCAL4 },
226 { "local5", LOG_LOCAL5 },
227 { "local6", LOG_LOCAL6 },
228 { "local7", LOG_LOCAL7 }
229 };
230
231 struct context {
232 char addr[64];
233 char fqdn[MAXLINE];
234 char from[MAXLINE];
235 char sender[MAXLINE];
236 char rcpt[MAXLINE];
237 char recipient[MAXLINE];
238 int slowdown;
239 vrfy_status status;
240 };
241
242 static sfsistat smf_connect(SMFICTX *, char *, _SOCK_ADDR *);
243 static sfsistat smf_envfrom(SMFICTX *, char **);
244 static sfsistat smf_envrcpt(SMFICTX *, char **);
245 static sfsistat smf_close(SMFICTX *);
246
strscpy(register char * dst,register const char * src,size_t size)247 static void strscpy(register char *dst, register const char *src, size_t size) {
248 register size_t i;
249
250 for (i = 0; i < size && (dst[i] = src[i]) != 0; i++) continue;
251 dst[i] = '\0';
252 }
253
strtolower(register char * str)254 static void strtolower(register char *str) {
255
256 for (; *str; str++)
257 if (isascii(*str) && isupper(*str)) *str = tolower(*str);
258 }
259
translate(char * value)260 static unsigned long translate(char *value) {
261 unsigned long unit;
262 size_t len = strlen(value);
263
264 switch (value[len - 1]) {
265 case 'm':
266 case 'M':
267 unit = 60;
268 value[len - 1] = '\0';
269 break;
270 case 'h':
271 case 'H':
272 unit = 3600;
273 value[len - 1] = '\0';
274 break;
275 case 'd':
276 case 'D':
277 unit = 86400;
278 value[len - 1] = '\0';
279 break;
280 default:
281 return atol(value);
282 }
283 return (atol(value) * unit);
284 }
285
hash_code(register const unsigned char * key)286 static unsigned long hash_code(register const unsigned char *key) {
287 register unsigned long hash = 0;
288 register size_t i, len = strlen(key);
289
290 for (i = 0; i < len; i++) {
291 hash += key[i];
292 hash += (hash << 10);
293 hash ^= (hash >> 6);
294 }
295 hash += (hash << 3);
296 hash ^= (hash >> 11);
297 hash += (hash << 15);
298 return hash;
299 }
300
cache_init(void)301 static int cache_init(void) {
302
303 if (!(cache = calloc(1, hash_size(HASH_POWER) * sizeof(void *)))) return 0;
304 return 1;
305 }
306
cache_destroy(void)307 static void cache_destroy(void) {
308 unsigned long i, size = hash_size(HASH_POWER);
309 cache_item *it, *it_next;
310
311 for (i = 0; i < size; i++) {
312 it = cache[i];
313 while (it) {
314 it_next = it->next;
315 SAFE_FREE(it->item);
316 SAFE_FREE(it);
317 it = it_next;
318 }
319 }
320 SAFE_FREE(cache);
321 }
322
cache_get(const char * key,cache_item_type type)323 static cache_item_status cache_get(const char *key, cache_item_type type) {
324 unsigned long hash = hash_code(key);
325 cache_item *it = cache[hash & hash_mask(HASH_POWER)];
326 time_t curtime = time(NULL);
327
328 while (it) {
329 if (it->type == type && it->hash == hash && it->exptime > curtime && it->item && !strcmp(key, it->item)) return it->status;
330 it = it->next;
331 }
332 return ST_NONE;
333 }
334
cache_put(const char * key,unsigned long ttl,cache_item_type type,cache_item_status status,cache_put_mode mode)335 static void cache_put(const char *key, unsigned long ttl, cache_item_type type, cache_item_status status, cache_put_mode mode) {
336 unsigned long hash = hash_code(key);
337 time_t curtime = time(NULL);
338 cache_item *it, *parent = NULL;
339
340 it = cache[hash & hash_mask(HASH_POWER)];
341 while (it) {
342 if (it->type == type && it->hash == hash && it->exptime > curtime && it->item && !strcmp(key, it->item)) {
343 if (mode == CACHE_OVER) {
344 it->status = status;
345 it->exptime = curtime + ttl;
346 }
347 return;
348 }
349 it = it->next;
350 }
351 it = cache[hash & hash_mask(HASH_POWER)];
352 while (it) {
353 if (it->exptime < curtime) {
354 SAFE_FREE(it->item);
355 it->item = strdup(key);
356 it->hash = hash;
357 it->type = type;
358 it->status = status;
359 it->exptime = curtime + ttl;
360 return;
361 }
362 parent = it;
363 it = it->next;
364 }
365 if ((it = (cache_item *) calloc(1, sizeof(cache_item)))) {
366 it->item = strdup(key);
367 it->hash = hash;
368 it->type = type;
369 it->status = status;
370 it->exptime = curtime + ttl;
371 if (parent)
372 parent->next = it;
373 else
374 cache[hash & hash_mask(HASH_POWER)] = it;
375 }
376 }
377
free_config(void)378 static void free_config(void) {
379
380 SAFE_FREE(conf.public_name);
381 SAFE_FREE(conf.safe_callback);
382 SAFE_FREE(conf.mail_store);
383 SAFE_FREE(conf.run_as_user);
384 SAFE_FREE(conf.sendmail_socket);
385 if (conf.cidrs) {
386 CIDR *it = conf.cidrs, *it_next;
387
388 while (it) {
389 it_next = it->next;
390 SAFE_FREE(it);
391 it = it_next;
392 }
393 }
394 if (conf.ptrs) {
395 STR *it = conf.ptrs, *it_next;
396
397 while (it) {
398 it_next = it->next;
399 SAFE_FREE(it->str);
400 SAFE_FREE(it);
401 it = it_next;
402 }
403 }
404 if (conf.froms) {
405 STR *it = conf.froms, *it_next;
406
407 while (it) {
408 it_next = it->next;
409 SAFE_FREE(it->str);
410 SAFE_FREE(it);
411 it = it_next;
412 }
413 }
414 if (conf.tos) {
415 STR *it = conf.tos, *it_next;
416
417 while (it) {
418 it_next = it->next;
419 SAFE_FREE(it->str);
420 SAFE_FREE(it);
421 it = it_next;
422 }
423 }
424 }
425
load_config(void)426 static int load_config(void) {
427 FILE *fp;
428 char buf[2 * MAXLINE];
429
430 conf.public_name = strdup(PUBLIC_NAME);
431 conf.safe_callback = strdup(SAFE_CALLBACK);
432 conf.run_as_user = strdup(USER);
433 conf.sendmail_socket = strdup(OCONN);
434 conf.syslog_facility = SYSLOG_FACILITY;
435 conf.sav = SAV;
436 conf.ignore_tempfail = IGNORE_TEMPFAIL;
437 conf.block_ignorants = BLOCK_IGNORANTS;
438 conf.from_pass_ttl = FROM_PASS_TTL;
439 conf.from_tempfail_ttl = FROM_TEMPFAIL_TTL;
440 conf.from_fail_ttl = FROM_FAIL_TTL;
441 conf.to_pass_ttl = TO_PASS_TTL;
442 conf.to_tempfail_ttl = TO_TEMPFAIL_TTL;
443 conf.to_fail_ttl = TO_FAIL_TTL;
444 if (!(fp = fopen(config_file, "r"))) return 0;
445 while (fgets(buf, sizeof(buf) - 1, fp)) {
446 char key[MAXLINE];
447 char val[MAXLINE];
448 char *p = NULL;
449
450 if ((p = strchr(buf, '#'))) *p = '\0';
451 if (!(strlen(buf))) continue;
452 if (sscanf(buf, "%127s %127s", key, val) != 2) continue;
453 if (!strcasecmp(key, "whitelistip")) {
454 char *slash = NULL;
455 unsigned short int mask = 32;
456
457 if ((slash = strchr(val, '/'))) {
458 *slash = '\0';
459 if ((mask = atoi(++slash)) > 32) mask = 32;
460 }
461 if (val[0] && !regexec(&re_ipv4, val, 0, NULL, 0)) {
462 CIDR *it = NULL;
463 unsigned long ip;
464
465 if ((ip = inet_addr(val)) == 0xffffffff) continue;
466 if (!conf.cidrs)
467 conf.cidrs = (CIDR *) calloc(1, sizeof(CIDR));
468 else
469 if ((it = (CIDR *) calloc(1, sizeof(CIDR)))) {
470 it->next = conf.cidrs;
471 conf.cidrs = it;
472 }
473 if (conf.cidrs) {
474 conf.cidrs->ip = ip;
475 conf.cidrs->mask = mask;
476 }
477 }
478 continue;
479 }
480 if (!strcasecmp(key, "whitelistptr")) {
481 STR *it = NULL;
482
483 if (!conf.ptrs)
484 conf.ptrs = (STR *) calloc(1, sizeof(STR));
485 else
486 if ((it = (STR *) calloc(1, sizeof(STR)))) {
487 it->next = conf.ptrs;
488 conf.ptrs = it;
489 }
490 if (conf.ptrs && !conf.ptrs->str) conf.ptrs->str = strdup(val);
491 continue;
492 }
493 if (!strcasecmp(key, "whitelistfrom")) {
494 STR *it = NULL;
495
496 if (!conf.froms)
497 conf.froms = (STR *) calloc(1, sizeof(STR));
498 else
499 if ((it = (STR *) calloc(1, sizeof(STR)))) {
500 it->next = conf.froms;
501 conf.froms = it;
502 }
503 if (conf.froms && !conf.froms->str) {
504 strtolower(val);
505 conf.froms->str = strdup(val);
506 }
507 continue;
508 }
509 if (!strcasecmp(key, "whitelistto")) {
510 STR *it = NULL;
511
512 if (!conf.tos)
513 conf.tos = (STR *) calloc(1, sizeof(STR));
514 else
515 if ((it = (STR *) calloc(1, sizeof(STR)))) {
516 it->next = conf.tos;
517 conf.tos = it;
518 }
519 if (conf.tos && !conf.tos->str) {
520 strtolower(val);
521 conf.tos->str = strdup(val);
522 }
523 continue;
524 }
525 if (!strcasecmp(key, "publicname")) {
526 SAFE_FREE(conf.public_name);
527 conf.public_name = strdup(val);
528 continue;
529 }
530 if (!strcasecmp(key, "safecallback")) {
531 SAFE_FREE(conf.safe_callback);
532 conf.safe_callback = strdup(val);
533 continue;
534 }
535 if (!strcasecmp(key, "sav") && !strcasecmp(val, "off")) {
536 conf.sav = 0;
537 continue;
538 }
539 if (!strcasecmp(key, "ignoretempfail") && !strcasecmp(val, "on")) {
540 conf.ignore_tempfail = 1;
541 continue;
542 }
543 if (!strcasecmp(key, "blockignorants") && !strcasecmp(val, "on")) {
544 conf.block_ignorants = 1;
545 continue;
546 }
547 if (!strcasecmp(key, "mailstore")) {
548 SAFE_FREE(conf.mail_store);
549 conf.mail_store = strdup(val);
550 continue;
551 }
552 if (!strcasecmp(key, "frompassttl")) {
553 conf.from_pass_ttl = translate(val);
554 continue;
555 }
556 if (!strcasecmp(key, "fromtfailttl")) {
557 conf.from_tempfail_ttl = translate(val);
558 continue;
559 }
560 if (!strcasecmp(key, "fromfailttl")) {
561 conf.from_fail_ttl = translate(val);
562 continue;
563 }
564 if (!strcasecmp(key, "topassttl")) {
565 conf.to_pass_ttl = translate(val);
566 continue;
567 }
568 if (!strcasecmp(key, "totfailttl")) {
569 conf.to_tempfail_ttl = translate(val);
570 continue;
571 }
572 if (!strcasecmp(key, "tofailttl")) {
573 conf.to_fail_ttl = translate(val);
574 continue;
575 }
576 if (!strcasecmp(key, "user")) {
577 SAFE_FREE(conf.run_as_user);
578 conf.run_as_user = strdup(val);
579 continue;
580 }
581 if (!strcasecmp(key, "socket")) {
582 SAFE_FREE(conf.sendmail_socket);
583 conf.sendmail_socket = strdup(val);
584 continue;
585 }
586 if (!strcasecmp(key, "syslog")) {
587 int i;
588
589 for (i = 0; i < FACILITIES_AMOUNT; i++)
590 if (!strcasecmp(val, syslog_facilities[i].name))
591 conf.syslog_facility = syslog_facilities[i].facility;
592 continue;
593 }
594 }
595 fclose(fp);
596 return 1;
597 }
598
ip_cidr(const unsigned long ip,const short int mask,const unsigned long checkip)599 static int ip_cidr(const unsigned long ip, const short int mask, const unsigned long checkip) {
600 unsigned long ipaddr = 0;
601 unsigned long cidrip = 0;
602 unsigned long subnet = 0;
603
604 subnet = ~0;
605 subnet = subnet << (32 - mask);
606 cidrip = htonl(ip) & subnet;
607 ipaddr = ntohl(checkip) & subnet;
608 if (cidrip == ipaddr) return 1;
609 return 0;
610 }
611
ip_check(const unsigned long checkip)612 static int ip_check(const unsigned long checkip) {
613 CIDR *it = conf.cidrs;
614
615 while (it) {
616 if (ip_cidr(it->ip, it->mask, checkip)) return 1;
617 it = it->next;
618 }
619 return 0;
620 }
621
ptr_check(const char * ptr)622 static int ptr_check(const char *ptr) {
623 STR *it = conf.ptrs;
624
625 while (it) {
626 if (it->str && strlen(it->str) <= strlen(ptr) && !strcasecmp(ptr + strlen(ptr) - strlen(it->str), it->str)) return 1;
627 it = it->next;
628 }
629 return 0;
630 }
631
from_check(const char * from)632 static int from_check(const char *from) {
633 STR *it = conf.froms;
634
635 while (it) {
636 if (it->str && strstr(from, it->str)) return 1;
637 it = it->next;
638 }
639 return 0;
640 }
641
to_check(const char * to)642 static int to_check(const char *to) {
643 STR *it = conf.tos;
644
645 while (it) {
646 if (it->str && strstr(to, it->str)) return 1;
647 it = it->next;
648 }
649 return 0;
650 }
651
time_humanize(register char * dst,time_t tm)652 static void time_humanize(register char *dst, time_t tm) {
653 register int h, m, s;
654
655 h = tm / 3600;
656 tm = tm % 3600;
657 m = tm / 60;
658 tm = tm % 60;
659 s = tm;
660 snprintf(dst, 10, "%02d:%02d:%02d", h, m, s);
661 }
662
address_preparation(register char * dst,register const char * src)663 static int address_preparation(register char *dst, register const char *src) {
664 register const char *start = NULL, *stop = NULL;
665 int tail;
666
667 if (!(start = strchr(src, '<'))) return 0;
668 if (!(stop = strrchr(src, '>'))) return 0;
669 if (++start >= --stop) return 0;
670 strscpy(dst, start, stop - start + 1);
671 tail = strlen(dst) - 1;
672 if ((dst[0] >= 0x07 && dst[0] <= 0x0d) || dst[0] == 0x20) return 0;
673 if ((dst[tail] >= 0x07 && dst[tail] <= 0x0d) || dst[tail] == 0x20) return 0;
674 if (!strchr(dst, '@')) return 0;
675 return 1;
676 }
677
do_sleep(int sec)678 static void do_sleep(int sec) {
679 struct timeval req;
680 int ret = 0;
681
682 req.tv_sec = sec;
683 req.tv_usec = 0;
684 do {
685 ret = select(0, NULL, NULL, NULL, &req);
686 } while (ret < 0 && errno == EINTR);
687 }
688
die(const char * reason)689 static void die(const char *reason) {
690
691 syslog(LOG_ERR, "[ERROR] die: %s", reason);
692 smfi_stop();
693 do_sleep(60);
694 abort();
695 }
696
mutex_lock(pthread_mutex_t * mutex)697 static void mutex_lock(pthread_mutex_t *mutex) {
698
699 if (pthread_mutex_lock(mutex)) die("pthread_mutex_lock");
700 }
701
mutex_unlock(pthread_mutex_t * mutex)702 static void mutex_unlock(pthread_mutex_t *mutex) {
703
704 if (pthread_mutex_unlock(mutex)) die("pthread_mutex_unlock");
705 }
706
block_socket(int sock,int block)707 static int block_socket(int sock, int block) {
708 int flags;
709
710 if (sock < 0) return -1;
711 if ((flags = fcntl(sock, F_GETFL)) < 0) return -1;
712 if (block)
713 flags &= ~O_NONBLOCK;
714 else
715 flags |= O_NONBLOCK;
716 if (fcntl(sock, F_SETFL, flags) < 0) return -1;
717 return 0;
718 }
719
close_socket(int sock)720 static void close_socket(int sock) {
721 int ret;
722
723 if (sock < 0) return;
724 shutdown(sock, SHUT_RDWR);
725 do {
726 ret = close(sock);
727 } while (ret < 0 && errno == EINTR);
728 }
729
smtp_send(int sock,const char * buffer)730 static int smtp_send(int sock, const char *buffer) {
731 int ret;
732 fd_set wfds;
733 struct timeval tv;
734
735 if (sock < 0) return -1;
736 do {
737 FD_ZERO(&wfds);
738 FD_SET(sock, &wfds);
739 tv.tv_sec = SEND_TIMEOUT;
740 tv.tv_usec = 0;
741 ret = select(sock + 1, NULL, &wfds, NULL, &tv);
742 } while (ret < 0 && errno == EINTR);
743 if (ret <= 0) return -1;
744 if (!FD_ISSET(sock, &wfds)) return -1;
745 do {
746 ret = send(sock, buffer, strlen(buffer), MSG_NOSIGNAL);
747 } while (ret < 0 && errno == EINTR);
748 if (ret < strlen(buffer)) return -1;
749 return 0;
750 }
751
smtp_recv(int sock,char * buffer,int size)752 static int smtp_recv(int sock, char *buffer, int size) {
753 int ret;
754 fd_set rfds;
755 struct timeval tv;
756
757 if (sock < 0) return -1;
758 do {
759 FD_ZERO(&rfds);
760 FD_SET(sock, &rfds);
761 tv.tv_sec = RECV_TIMEOUT;
762 tv.tv_usec = 0;
763 ret = select(sock + 1, &rfds, NULL, NULL, &tv);
764 } while (ret < 0 && errno == EINTR);
765 if (ret <= 0) return -1;
766 if (!FD_ISSET(sock, &rfds)) return -1;
767 do {
768 ret = recv(sock, buffer, size - 1, MSG_NOSIGNAL);
769 } while (ret < 0 && errno == EINTR);
770 if (ret <= 0) return -1;
771 return 0;
772 }
773
smtp_connect(int sock,struct sockaddr * address,int addrlen)774 static int smtp_connect(int sock, struct sockaddr *address, int addrlen) {
775 int optval, ret;
776 fd_set wfds;
777 struct timeval tv;
778 socklen_t optlen = sizeof(optval);
779
780 if (sock < 0) return -1;
781 if (block_socket(sock, 0) < 0) return -1;
782 if ((ret = connect(sock, address, addrlen)) < 0)
783 if (errno != EINPROGRESS) return -1;
784 if (ret == 0) goto done;
785 do {
786 FD_ZERO(&wfds);
787 FD_SET(sock, &wfds);
788 tv.tv_sec = CONN_TIMEOUT;
789 tv.tv_usec = 0;
790 ret = select(sock + 1, NULL, &wfds, NULL, &tv);
791 } while (ret < 0 && errno == EINTR);
792 if (ret <= 0) return -1;
793 if (!FD_ISSET(sock, &wfds)) return -1;
794 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) return -1;
795 if (optval) return -1;
796 done:
797 if (block_socket(sock, 1) < 0) return -1;
798 return 0;
799 }
800
get_smtp_response(const char * buffer)801 static int get_smtp_response(const char *buffer) {
802 int ret = 0;
803
804 if (strlen(buffer) < 4) return -1;
805 sscanf(buffer, "%3d", &ret);
806 return ret;
807 }
808
smtp_chat(int sock,const char * cmd)809 static int smtp_chat(int sock, const char *cmd) {
810 int ret;
811 char *buffer = NULL;
812
813 if (sock < 0) return -1;
814 if (cmd && smtp_send(sock, cmd) < 0) return -1;
815 if (!(buffer = calloc(1, 2048))) {
816 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
817 return -1;
818 }
819 if (smtp_recv(sock, buffer, 2048) < 0) {
820 free(buffer);
821 return -1;
822 }
823 ret = get_smtp_response(buffer);
824 free(buffer);
825 return ret;
826 }
827
smtp_quit(int sock)828 static void smtp_quit(int sock) {
829 char cmd[8];
830
831 if (sock < 0) return;
832 strscpy(cmd, "RSET\r\n", sizeof(cmd) - 1);
833 if (smtp_chat(sock, cmd) <= 0) return;
834 strscpy(cmd, "QUIT\r\n", sizeof(cmd) - 1);
835 smtp_chat(sock, cmd);
836 }
837
mailer(const char * rcpt,const char * mxhost)838 static int mailer(const char *rcpt, const char *mxhost) {
839 struct sockaddr_in address;
840 char cmd[MAXLINE];
841 int sock, ret;
842 int optval = 1;
843 socklen_t optlen = sizeof(optval);
844
845 memset(&address, 0, sizeof(address));
846 if (!regexec(&re_ipv4, mxhost, 0, NULL, 0)) {
847 char host[32];
848
849 strscpy(host, mxhost, sizeof(host) - 1);
850 if (host[strlen(host) - 1] == '.') host[strlen(host) - 1] = '\0';
851 address.sin_addr.s_addr = inet_addr(host);
852 }
853 else {
854 struct addrinfo *ai = NULL;
855 struct addrinfo hints;
856
857 memset(&hints, 0, sizeof(hints));
858 hints.ai_family = AF_INET;
859 hints.ai_socktype = SOCK_STREAM;
860 hints.ai_protocol = IPPROTO_TCP;
861 if (getaddrinfo(mxhost, NULL, &hints, &ai)) {
862 if (ai) freeaddrinfo(ai);
863 return QUIT_FAIL;
864 }
865 address.sin_addr.s_addr = *(uint32_t *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
866 freeaddrinfo(ai);
867 }
868 if (address.sin_addr.s_addr == 0x0100007f || address.sin_addr.s_addr == 0xffffffff) return QUIT_FAIL;
869 address.sin_family = AF_INET;
870 address.sin_port = htons(SMTP_PORT);
871 sock = socket(PF_INET, SOCK_STREAM, 0);
872 if (sock < 0) return QUIT_FAIL;
873 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) goto quit_fail;
874 if (smtp_connect(sock, (struct sockaddr *) &address, sizeof(address)) < 0) goto quit_fail;
875 if ((ret = smtp_chat(sock, NULL)) <= 0) goto quit_fail;
876 if (SMTP_CMD_PERM(ret)) goto quit_perm;
877 if (!SMTP_CMD_OK(ret)) goto quit_temp;
878 snprintf(cmd, sizeof(cmd), "HELO %s\r\n", conf.public_name);
879 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
880 if (SMTP_CMD_PERM(ret)) goto quit_perm;
881 if (!SMTP_CMD_OK(ret)) goto quit_temp;
882 snprintf(cmd, sizeof(cmd), "MAIL FROM:%s\r\n", CALLBACK);
883 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
884 if (conf.block_ignorants && SMTP_CMD_PERM(ret)) goto quit_perm;
885 if (SMTP_CMD_PERM(ret) || !SMTP_CMD_OK(ret)) {
886 strscpy(cmd, "RSET\r\n", sizeof(cmd) - 1);
887 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
888 if (SMTP_CMD_PERM(ret)) goto quit_perm;
889 if (!SMTP_CMD_OK(ret)) goto quit_temp;
890 snprintf(cmd, sizeof(cmd), "MAIL FROM:<%s>\r\n", conf.safe_callback);
891 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
892 if (SMTP_CMD_PERM(ret)) goto quit_perm;
893 if (!SMTP_CMD_OK(ret)) goto quit_temp;
894 }
895 snprintf(cmd, sizeof(cmd), "RCPT TO:<%s>\r\n", rcpt);
896 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
897 if (conf.block_ignorants && SMTP_CMD_PERM(ret)) goto quit_perm;
898 if (SMTP_CMD_PERM(ret) || !SMTP_CMD_OK(ret)) {
899 strscpy(cmd, "RSET\r\n", sizeof(cmd) - 1);
900 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
901 if (SMTP_CMD_PERM(ret)) goto quit_perm;
902 if (!SMTP_CMD_OK(ret)) goto quit_temp;
903 snprintf(cmd, sizeof(cmd), "MAIL FROM:<%s>\r\n", conf.safe_callback);
904 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
905 if (SMTP_CMD_PERM(ret)) goto quit_perm;
906 if (!SMTP_CMD_OK(ret)) goto quit_temp;
907 snprintf(cmd, sizeof(cmd), "RCPT TO:<%s>\r\n", rcpt);
908 if ((ret = smtp_chat(sock, cmd)) <= 0) goto quit_fail;
909 if (SMTP_CMD_PERM(ret)) goto quit_perm;
910 if (!SMTP_CMD_OK(ret)) goto quit_temp;
911 }
912 smtp_quit(sock);
913 close_socket(sock);
914 return QUIT_OK;
915 quit_temp:
916 smtp_quit(sock);
917 close_socket(sock);
918 return QUIT_FAIL;
919 quit_perm:
920 smtp_quit(sock);
921 close_socket(sock);
922 return QUIT_PERM;
923 quit_fail:
924 close_socket(sock);
925 return QUIT_FAIL;
926 }
927
get_mx_rr(const char * host,char * MXHostBuf,char ** mxhosts,querybuf * answer)928 static int get_mx_rr(const char *host, char *MXHostBuf, char **mxhosts, querybuf *answer) {
929 unsigned char *eom, *cp;
930 unsigned short pref, type, prefs[MAXMX];
931 int i, j, n, ttl, ancount, qdcount, buflen, weight[MAXMX], nmx = 0;
932 char *bp;
933 HEADER *hp;
934 struct __res_state res_status;
935
936 memset(&res_status, 0, sizeof(res_status));
937 if (res_ninit(&res_status) < 0) return -1;
938 res_status.retrans = DNS_RETRANS;
939 res_status.retry = DNS_RETRY;
940 n = res_nquery(&res_status, host, C_IN, T_MX, (unsigned char *) answer, sizeof(querybuf));
941 if (n < 0) {
942 switch (res_status.res_h_errno) {
943 case NO_DATA:
944 res_nclose(&res_status);
945 goto done;
946 default:
947 res_nclose(&res_status);
948 return -1;
949 }
950 }
951 res_nclose(&res_status);
952 if (n > sizeof(querybuf)) n = sizeof(querybuf);
953 hp = (HEADER *) answer;
954 cp = (unsigned char *) answer + HFIXEDSZ;
955 eom = (unsigned char *) answer + n;
956 for (qdcount = ntohs((unsigned short) hp->qdcount); qdcount--; cp += n + QFIXEDSZ) {
957 if ((n = dn_skipname(cp, eom)) < 0) goto done;
958 }
959 buflen = MXBUFFER - 1;
960 bp = MXHostBuf;
961 ancount = ntohs((unsigned short) hp->ancount);
962 while (--ancount >= 0 && cp < eom && nmx < MAXMX - 1) {
963 if ((n = dn_expand((unsigned char *) answer, eom, cp, (unsigned char *) bp, buflen)) < 0) break;
964 cp += n;
965 GETSHORT(type, cp);
966 cp += INT16SZ;
967 GETLONG(ttl, cp);
968 GETSHORT(n, cp);
969 if (type != T_MX) {
970 cp += n;
971 continue;
972 }
973 GETSHORT(pref, cp);
974 if ((n = dn_expand((unsigned char *) answer, eom, cp, (unsigned char *) bp, buflen)) < 0) break;
975 cp += n;
976 n = strlen(bp);
977 if (n == 0) continue;
978 weight[nmx] = hash_code(bp) & 0xff;
979 prefs[nmx] = pref;
980 mxhosts[nmx++] = bp;
981 bp += n;
982 if (bp[-1] != '.') {
983 *bp++ = '.';
984 n++;
985 }
986 *bp++ = '\0';
987 if (buflen < n + 1) break;
988 buflen -= n + 1;
989 }
990 for (i = 0; i < nmx; i++)
991 for (j = i + 1; j < nmx; j++)
992 if (prefs[i] > prefs[j] || (prefs[i] == prefs[j] && weight[i] > weight[j])) {
993 int temp;
994 char *temp1;
995
996 temp = prefs[i];
997 prefs[i] = prefs[j];
998 prefs[j] = temp;
999 temp1 = mxhosts[i];
1000 mxhosts[i] = mxhosts[j];
1001 mxhosts[j] = temp1;
1002 temp = weight[i];
1003 weight[i] = weight[j];
1004 weight[j] = temp;
1005 }
1006 if (nmx == 0) {
1007 done:
1008 strscpy(MXHostBuf, host, MXBUFFER - 1);
1009 mxhosts[nmx++] = MXHostBuf;
1010 }
1011 return nmx;
1012 }
1013
check_sender(const char * sender)1014 static int check_sender(const char *sender) {
1015 querybuf *answer;
1016 char *MXHostBuf, *mxhosts[MAXMX + 1];
1017 int mxcount, i, rc;
1018
1019 if (!(MXHostBuf = calloc(1, MXBUFFER))) {
1020 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
1021 return -1;
1022 }
1023 if (!(answer = calloc(1, sizeof(querybuf)))) {
1024 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
1025 free(MXHostBuf);
1026 return -1;
1027 }
1028 if ((mxcount = get_mx_rr(strchr(sender, '@') + 1, MXHostBuf, mxhosts, answer)) <= 0) {
1029 free(MXHostBuf);
1030 free(answer);
1031 return -1;
1032 }
1033 free(answer);
1034 for (i = 0, rc = 0; i < mxcount; i++) {
1035 rc = mailer(sender, mxhosts[i]);
1036 if (rc >= 0) break;
1037 }
1038 free(MXHostBuf);
1039 return rc;
1040 }
1041
check_recipient(const char * recipient,const char * host)1042 static int check_recipient(const char *recipient, const char *host) {
1043 char *p = NULL;
1044
1045 if ((p = strchr(host, '['))) {
1046 char wildcardmxhost[MAXLINE];
1047
1048 strscpy(wildcardmxhost, p + 1, sizeof(wildcardmxhost) - 1);
1049 if ((p = strrchr(wildcardmxhost, ']'))) *p = '\0';
1050 return mailer(recipient, wildcardmxhost);
1051 }
1052 return mailer(recipient, host);
1053 }
1054
check_recipient_by_mx(const char * recipient,const char * domain)1055 static int check_recipient_by_mx(const char *recipient, const char *domain) {
1056 querybuf *answer;
1057 char *MXHostBuf, *mxhosts[MAXMX + 1];
1058 int mxcount, i, rc;
1059
1060 if (!(MXHostBuf = calloc(1, MXBUFFER))) {
1061 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
1062 return -1;
1063 }
1064 if (!(answer = calloc(1, sizeof(querybuf)))) {
1065 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
1066 free(MXHostBuf);
1067 return -1;
1068 }
1069 if ((mxcount = get_mx_rr(domain, MXHostBuf, mxhosts, answer)) <= 0) {
1070 free(MXHostBuf);
1071 free(answer);
1072 return -1;
1073 }
1074 free(answer);
1075 for (i = 0, rc = 0; i < mxcount; i++) {
1076 rc = mailer(recipient, mxhosts[i]);
1077 if (rc >= 0) break;
1078 }
1079 free(MXHostBuf);
1080 return rc;
1081 }
1082
smf_connect(SMFICTX * ctx,char * name,_SOCK_ADDR * sa)1083 static sfsistat smf_connect(SMFICTX *ctx, char *name, _SOCK_ADDR *sa) {
1084 struct context *context = NULL;
1085 char host[64];
1086
1087 strscpy(host, "undefined", sizeof(host) - 1);
1088 switch (sa->sa_family) {
1089 case AF_INET: {
1090 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1091
1092 inet_ntop(AF_INET, &sin->sin_addr.s_addr, host, sizeof(host));
1093 break;
1094 }
1095 case AF_INET6: {
1096 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
1097
1098 inet_ntop(AF_INET6, &sin6->sin6_addr, host, sizeof(host));
1099 break;
1100 }
1101 }
1102 if (conf.cidrs && ip_check(inet_addr(host))) return SMFIS_ACCEPT;
1103 if (conf.ptrs && ptr_check(name)) return SMFIS_ACCEPT;
1104 if (!(context = calloc(1, sizeof(*context)))) {
1105 syslog(LOG_ERR, "[ERROR] %s", strerror(errno));
1106 return SMFIS_ACCEPT;
1107 }
1108 smfi_setpriv(ctx, context);
1109 strscpy(context->addr, host, sizeof(context->addr) - 1);
1110 strscpy(context->fqdn, name, sizeof(context->fqdn) - 1);
1111 return SMFIS_CONTINUE;
1112 }
1113
smf_envfrom(SMFICTX * ctx,char ** args)1114 static sfsistat smf_envfrom(SMFICTX *ctx, char **args) {
1115 struct context *context = (struct context *)smfi_getpriv(ctx);
1116 const char *interface = smfi_getsymval(ctx, "{if_addr}");
1117 const char *verify = smfi_getsymval(ctx, "{verify}");
1118
1119 if (interface && strcmp(interface, context->addr) == 0) return SMFIS_ACCEPT;
1120 if (smfi_getsymval(ctx, "{auth_authen}")) return SMFIS_ACCEPT;
1121 if (verify && strcmp(verify, "OK") == 0) return SMFIS_ACCEPT;
1122 if (*args) strscpy(context->from, *args, sizeof(context->from) - 1);
1123 if (!strstr(context->from, "<>") && !address_preparation(context->sender, context->from)) {
1124 smfi_setreply(ctx, "550", "5.1.7", "Sender address does not conform to RFC-2821 syntax");
1125 return SMFIS_REJECT;
1126 }
1127 if (!strstr(context->from, "<>")) {
1128 strtolower(context->sender);
1129 if (conf.froms && from_check(context->sender)) return SMFIS_ACCEPT;
1130 }
1131 context->slowdown = 0;
1132 context->status = ST_OKEY;
1133 if (!strstr(context->from, "<>") && conf.sav) {
1134 char human_time[10];
1135 time_t tstart, tend;
1136 int ret = 1;
1137
1138 if (cache) {
1139 cache_item_status status;
1140
1141 mutex_lock(&cache_mutex);
1142 status = cache_get(context->sender, SENDERS);
1143 mutex_unlock(&cache_mutex);
1144 switch (status) {
1145 case SENDER_PASS:
1146 syslog(LOG_INFO, "sender check succeeded (cached): %s, %s, %s", context->from, context->addr, context->fqdn);
1147 return SMFIS_CONTINUE;
1148 case SENDER_FAIL:
1149 syslog(LOG_INFO, "sender check failed (cached): %s, %s, %s", context->from, context->addr, context->fqdn);
1150 if (!conf.tos) {
1151 do_sleep(1);
1152 smfi_setreply(ctx, "550", "5.1.8", "Sender address verification failed");
1153 return SMFIS_REJECT;
1154 }
1155 context->status = ST_SAV_FAIL;
1156 return SMFIS_CONTINUE;
1157 case SENDER_TEMPFAIL:
1158 syslog(LOG_INFO, "sender check tempfailed (cached): %s, %s, %s", context->from, context->addr, context->fqdn);
1159 if (!conf.tos) {
1160 do_sleep(1);
1161 smfi_setreply(ctx, "451", "4.1.8", "Sender address verification in progress");
1162 return SMFIS_TEMPFAIL;
1163 }
1164 context->status = ST_SAV_TEMPFAIL;
1165 return SMFIS_CONTINUE;
1166 default:
1167 break;
1168 }
1169 }
1170 time(&tstart);
1171 ret = check_sender(context->sender);
1172 time(&tend);
1173 time_humanize(human_time, tend - tstart);
1174 if (ret == 0) {
1175 if (cache && conf.from_fail_ttl) {
1176 mutex_lock(&cache_mutex);
1177 cache_put(context->sender, conf.from_fail_ttl, SENDERS, SENDER_FAIL, CACHE_KEEP);
1178 mutex_unlock(&cache_mutex);
1179 }
1180 syslog(LOG_NOTICE, "sender check failed: %s, %s, %s, [%s]", context->from, context->addr, context->fqdn, human_time);
1181 if (!conf.tos) {
1182 do_sleep(1);
1183 smfi_setreply(ctx, "550", "5.1.8", "Sender address verification failed");
1184 return SMFIS_REJECT;
1185 }
1186 context->status = ST_SAV_FAIL;
1187 return SMFIS_CONTINUE;
1188 }
1189 if (ret < 0 && !conf.ignore_tempfail) {
1190 if (cache && conf.from_tempfail_ttl) {
1191 mutex_lock(&cache_mutex);
1192 cache_put(context->sender, conf.from_tempfail_ttl, SENDERS, SENDER_TEMPFAIL, CACHE_KEEP);
1193 mutex_unlock(&cache_mutex);
1194 }
1195 syslog(LOG_NOTICE, "sender check tempfailed: %s, %s, %s, [%s]", context->from, context->addr, context->fqdn, human_time);
1196 if (!conf.tos) {
1197 do_sleep(1);
1198 smfi_setreply(ctx, "451", "4.1.8", "Sender address verification in progress");
1199 return SMFIS_TEMPFAIL;
1200 }
1201 context->status = ST_SAV_TEMPFAIL;
1202 return SMFIS_CONTINUE;
1203 }
1204 if (ret > 0) {
1205 if (cache && conf.from_pass_ttl) {
1206 mutex_lock(&cache_mutex);
1207 cache_put(context->sender, conf.from_pass_ttl, SENDERS, SENDER_PASS, CACHE_KEEP);
1208 mutex_unlock(&cache_mutex);
1209 }
1210 syslog(LOG_INFO, "sender check succeeded: %s, %s, %s, [%s]", context->from, context->addr, context->fqdn, human_time);
1211 }
1212 }
1213 return SMFIS_CONTINUE;
1214 }
1215
smf_envrcpt(SMFICTX * ctx,char ** args)1216 static sfsistat smf_envrcpt(SMFICTX *ctx, char **args) {
1217 struct context *context = (struct context *)smfi_getpriv(ctx);
1218 const char *rcpt_mailer = smfi_getsymval(ctx, "{rcpt_mailer}");
1219 const char *rcpt_host = smfi_getsymval(ctx, "{rcpt_host}");
1220 const char *rcpt_addr = smfi_getsymval(ctx, "{rcpt_addr}");
1221 char human_time[10];
1222 time_t tstart, tend;
1223 int ret = 1;
1224
1225 if (*args) strscpy(context->rcpt, *args, sizeof(context->rcpt) - 1);
1226 if (!address_preparation(context->recipient, context->rcpt)) {
1227 smfi_setreply(ctx, "550", "5.1.3", "Recipient address does not conform to RFC-2821 syntax");
1228 return SMFIS_REJECT;
1229 }
1230 strtolower(context->recipient);
1231 if (!conf.mail_store) goto penalty;
1232 if (context->slowdown) do_sleep(SLOW_DOWN_SLICE * context->slowdown);
1233 if (cache) {
1234 cache_item_status status;
1235
1236 mutex_lock(&cache_mutex);
1237 status = cache_get(context->recipient, RECIPIENTS);
1238 mutex_unlock(&cache_mutex);
1239 switch (status) {
1240 case RECIPIENT_PASS:
1241 syslog(LOG_INFO, "recipient check succeeded (cached): %s, %s, %s, %s", context->rcpt, context->addr, context->fqdn, context->from);
1242 goto penalty;
1243 case RECIPIENT_FAIL:
1244 context->slowdown++;
1245 do_sleep(1);
1246 syslog(LOG_INFO, "recipient check failed (cached): %s, %s, %s, %s", context->rcpt, context->addr, context->fqdn, context->from);
1247 smfi_setreply(ctx, "550", "5.1.1", "Sorry, no mailbox here by that name or mailbox is over quota");
1248 return SMFIS_REJECT;
1249 case RECIPIENT_TEMPFAIL:
1250 do_sleep(1);
1251 syslog(LOG_INFO, "recipient check tempfailed (cached): %s, %s, %s, %s", context->rcpt, context->addr, context->fqdn, context->from);
1252 smfi_setreply(ctx, "451", "4.2.1", "Mailbox is not available now, try again later");
1253 return SMFIS_TEMPFAIL;
1254 default:
1255 break;
1256 }
1257 }
1258 time(&tstart);
1259 if (rcpt_mailer && !strcasecmp(rcpt_mailer, "local"))
1260 ret = check_recipient(context->recipient, conf.mail_store);
1261 else
1262 if (rcpt_mailer && rcpt_host && rcpt_addr)
1263 if (!strcasecmp(rcpt_mailer, "smtp") || !strcasecmp(rcpt_mailer, "esmtp")) {
1264 if (strchr(rcpt_host, '['))
1265 ret = check_recipient(rcpt_addr, rcpt_host);
1266 else
1267 ret = check_recipient_by_mx(rcpt_addr, rcpt_host);
1268 }
1269 time(&tend);
1270 time_humanize(human_time, tend - tstart);
1271 if (ret == 0) {
1272 context->slowdown++;
1273 if (cache && conf.to_fail_ttl) {
1274 mutex_lock(&cache_mutex);
1275 cache_put(context->recipient, conf.to_fail_ttl, RECIPIENTS, RECIPIENT_FAIL, CACHE_KEEP);
1276 mutex_unlock(&cache_mutex);
1277 }
1278 do_sleep(1);
1279 syslog(LOG_NOTICE, "recipient check failed: %s, %s, %s, %s, [%s]", context->rcpt, context->addr, context->fqdn, context->from, human_time);
1280 smfi_setreply(ctx, "550", "5.1.1", "Sorry, no mailbox here by that name or mailbox is over quota");
1281 return SMFIS_REJECT;
1282 }
1283 if (ret < 0) {
1284 if (cache && conf.to_tempfail_ttl) {
1285 mutex_lock(&cache_mutex);
1286 cache_put(context->recipient, conf.to_tempfail_ttl, RECIPIENTS, RECIPIENT_TEMPFAIL, CACHE_KEEP);
1287 mutex_unlock(&cache_mutex);
1288 }
1289 do_sleep(1);
1290 syslog(LOG_NOTICE, "recipient check tempfailed: %s, %s, %s, %s, [%s]", context->rcpt, context->addr, context->fqdn, context->from, human_time);
1291 smfi_setreply(ctx, "451", "4.2.1", "Mailbox is not available now, try again later");
1292 return SMFIS_TEMPFAIL;
1293 }
1294 if (cache && conf.to_pass_ttl) {
1295 mutex_lock(&cache_mutex);
1296 cache_put(context->recipient, conf.to_pass_ttl, RECIPIENTS, RECIPIENT_PASS, CACHE_KEEP);
1297 mutex_unlock(&cache_mutex);
1298 }
1299 syslog(LOG_INFO, "recipient check succeeded: %s, %s, %s, %s, [%s]", context->rcpt, context->addr, context->fqdn, context->from, human_time);
1300 penalty:
1301 if (conf.tos) {
1302 if (to_check(context->recipient)) return SMFIS_CONTINUE;
1303 switch (context->status) {
1304 case ST_SAV_FAIL:
1305 do_sleep(1);
1306 smfi_setreply(ctx, "550", "5.7.1", "Sender address verification failed");
1307 return SMFIS_REJECT;
1308 case ST_SAV_TEMPFAIL:
1309 do_sleep(1);
1310 smfi_setreply(ctx, "451", "4.2.1", "Sender address verification in progress");
1311 return SMFIS_TEMPFAIL;
1312 default:
1313 break;
1314 }
1315 }
1316 return SMFIS_CONTINUE;
1317 }
1318
smf_close(SMFICTX * ctx)1319 static sfsistat smf_close(SMFICTX *ctx) {
1320 struct context *context = (struct context *)smfi_getpriv(ctx);
1321
1322 if (context) {
1323 free(context);
1324 smfi_setpriv(ctx, NULL);
1325 }
1326 return SMFIS_CONTINUE;
1327 }
1328
1329 struct smfiDesc smfilter = {
1330 "smf-sav",
1331 SMFI_VERSION,
1332 0,
1333 smf_connect,
1334 NULL,
1335 smf_envfrom,
1336 smf_envrcpt,
1337 NULL,
1338 NULL,
1339 NULL,
1340 NULL,
1341 NULL,
1342 smf_close
1343 };
1344
main(int argc,char ** argv)1345 int main(int argc, char **argv) {
1346 const char *ofile = NULL;
1347 int ch, ret = 0;
1348
1349 while ((ch = getopt(argc, argv, "hc:")) != -1) {
1350 switch (ch) {
1351 case 'h':
1352 fprintf(stderr, "Usage: smf-sav -c <config file>\n");
1353 return 0;
1354 case 'c':
1355 if (optarg) config_file = optarg;
1356 break;
1357 default:
1358 break;
1359 }
1360 }
1361 memset(&conf, 0, sizeof(conf));
1362 regcomp(&re_ipv4, IPV4_DOT_DECIMAL, REG_EXTENDED|REG_ICASE);
1363 if (!load_config()) fprintf(stderr, "Warning: smf-sav configuration file load failed\n");
1364 tzset();
1365 openlog("smf-sav", LOG_PID|LOG_NDELAY, conf.syslog_facility);
1366 if (!strncmp(conf.sendmail_socket, "unix:", 5))
1367 ofile = conf.sendmail_socket + 5;
1368 else
1369 if (!strncmp(conf.sendmail_socket, "local:", 6)) ofile = conf.sendmail_socket + 6;
1370 if (ofile) unlink(ofile);
1371 if (!getuid()) {
1372 struct passwd *pw;
1373
1374 if ((pw = getpwnam(conf.run_as_user)) == NULL) {
1375 fprintf(stderr, "%s: %s\n", conf.run_as_user, strerror(errno));
1376 goto done;
1377 }
1378 setgroups(1, &pw->pw_gid);
1379 if (setgid(pw->pw_gid)) {
1380 fprintf(stderr, "setgid: %s\n", strerror(errno));
1381 goto done;
1382 }
1383 if (setuid(pw->pw_uid)) {
1384 fprintf(stderr, "setuid: %s\n", strerror(errno));
1385 goto done;
1386 }
1387 }
1388 if (smfi_setconn((char *)conf.sendmail_socket) != MI_SUCCESS) {
1389 fprintf(stderr, "smfi_setconn failed: %s\n", conf.sendmail_socket);
1390 goto done;
1391 }
1392 if (smfi_register(smfilter) != MI_SUCCESS) {
1393 fprintf(stderr, "smfi_register failed\n");
1394 goto done;
1395 }
1396 if (daemon(0, 0)) {
1397 fprintf(stderr, "daemonize failed: %s\n", strerror(errno));
1398 goto done;
1399 }
1400 if (pthread_mutex_init(&cache_mutex, 0)) {
1401 fprintf(stderr, "pthread_mutex_init failed\n");
1402 goto done;
1403 }
1404 umask(0177);
1405 signal(SIGPIPE, SIG_IGN);
1406 if (!cache_init()) syslog(LOG_ERR, "[ERROR] cache engine init failed");
1407 ret = smfi_main();
1408 if (ret != MI_SUCCESS) syslog(LOG_ERR, "[ERROR] terminated due to a fatal error");
1409 if (cache) cache_destroy();
1410 pthread_mutex_destroy(&cache_mutex);
1411 done:
1412 free_config();
1413 closelog();
1414 return ret;
1415 }
1416