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