1 #include "common.h"
2 #include "smtpd.h"
3 #include "smtp.h"
4 #include <ctype.h>
5 #include <ip.h>
6 #include <ndb.h>
7 #include <mp.h>
8 #include <libsec.h>
9 #include <auth.h>
10 #include "../smtp/y.tab.h"
11
12 char *me;
13 char *him="";
14 char *dom;
15 process *pp;
16 String *mailer;
17 NetConnInfo *nci;
18
19 int filterstate = ACCEPT;
20 int trusted;
21 int logged;
22 int rejectcount;
23 int hardreject;
24
25 ulong starttime;
26
27 Biobuf bin;
28
29 int debug;
30 int Dflag;
31 int fflag;
32 int gflag;
33 int rflag;
34 int sflag;
35 int authenticate;
36 int authenticated;
37 int passwordinclear;
38 char *tlscert;
39
40 uchar rsysip[IPaddrlen];
41
42 List senders;
43 List rcvers;
44
45 char pipbuf[ERRMAX];
46 char *piperror;
47
48 String* mailerpath(char*);
49 int pipemsg(int*);
50 int rejectcheck(void);
51 String* startcmd(void);
52
53 static void logmsg(char *action);
54 static int delaysecs(void);
55
56 static int
catchalarm(void * a,char * msg)57 catchalarm(void *a, char *msg)
58 {
59 int rv;
60
61 USED(a);
62
63 /* log alarms but continue */
64 if(strstr(msg, "alarm") != nil){
65 if(senders.first && senders.first->p &&
66 rcvers.first && rcvers.first->p)
67 syslog(0, "smtpd", "note: %s->%s: %s",
68 s_to_c(senders.first->p),
69 s_to_c(rcvers.first->p), msg);
70 else
71 syslog(0, "smtpd", "note: %s", msg);
72 rv = Atnoterecog;
73 } else
74 rv = Atnoteunknown;
75 if (debug) {
76 seek(2, 0, 2);
77 fprint(2, "caught note: %s\n", msg);
78 }
79
80 /* kill the children if there are any */
81 if(pp && pp->pid > 0) {
82 syskillpg(pp->pid);
83 /* none can't syskillpg, so try a variant */
84 sleep(500);
85 syskill(pp->pid);
86 }
87
88 return rv;
89 }
90
91 /* override string error functions to do something reasonable */
92 void
s_error(char * f,char * status)93 s_error(char *f, char *status)
94 {
95 char errbuf[Errlen];
96
97 errbuf[0] = 0;
98 rerrstr(errbuf, sizeof(errbuf));
99 if(f && *f)
100 reply("452 4.3.0 out of memory %s: %s\r\n", f, errbuf);
101 else
102 reply("452 4.3.0 out of memory %s\r\n", errbuf);
103 syslog(0, "smtpd", "++Malloc failure %s [%s]", him, nci->rsys);
104 exits(status);
105 }
106
107 static void
usage(void)108 usage(void)
109 {
110 fprint(2,
111 "usage: smtpd [-adDfghprs] [-c cert] [-k ip] [-m mailer] [-n net]\n");
112 exits("usage");
113 }
114
115 void
main(int argc,char ** argv)116 main(int argc, char **argv)
117 {
118 char *netdir;
119 char buf[1024];
120
121 netdir = nil;
122 quotefmtinstall();
123 fmtinstall('I', eipfmt);
124 starttime = time(0);
125 ARGBEGIN{
126 case 'a':
127 authenticate = 1;
128 break;
129 case 'c':
130 tlscert = EARGF(usage());
131 break;
132 case 'D':
133 Dflag++;
134 break;
135 case 'd':
136 debug++;
137 break;
138 case 'f': /* disallow relaying */
139 fflag = 1;
140 break;
141 case 'g':
142 gflag = 1;
143 break;
144 case 'h': /* default domain name */
145 dom = EARGF(usage());
146 break;
147 case 'k': /* prohibited ip address */
148 addbadguy(EARGF(usage()));
149 break;
150 case 'm': /* set mail command */
151 mailer = mailerpath(EARGF(usage()));
152 break;
153 case 'n': /* log peer ip address */
154 netdir = EARGF(usage());
155 break;
156 case 'p':
157 passwordinclear = 1;
158 break;
159 case 'r':
160 rflag = 1; /* verify sender's domain */
161 break;
162 case 's': /* save blocked messages */
163 sflag = 1;
164 break;
165 case 't':
166 fprint(2, "%s: the -t option is no longer supported, see -c\n",
167 argv0);
168 tlscert = "/sys/lib/ssl/smtpd-cert.pem";
169 break;
170 default:
171 usage();
172 }ARGEND;
173
174 nci = getnetconninfo(netdir, 0);
175 if(nci == nil)
176 sysfatal("can't get remote system's address: %r");
177 parseip(rsysip, nci->rsys);
178
179 if(mailer == nil)
180 mailer = mailerpath("send");
181
182 if(debug){
183 snprint(buf, sizeof buf, "%s/smtpdb/%ld", UPASLOG, time(0));
184 close(2);
185 if (create(buf, OWRITE | OEXCL, 0662) >= 0) {
186 seek(2, 0, 2);
187 fprint(2, "%d smtpd %s\n", getpid(), thedate());
188 } else
189 debug = 0;
190 }
191 getconf();
192 if (isbadguy())
193 exits("banned");
194 Binit(&bin, 0, OREAD);
195
196 if (chdir(UPASLOG) < 0)
197 syslog(0, "smtpd", "no %s: %r", UPASLOG);
198 me = sysname_read();
199 if(dom == 0 || dom[0] == 0)
200 dom = domainname_read();
201 if(dom == 0 || dom[0] == 0)
202 dom = me;
203 parseinit();
204 sayhi();
205
206 /* allow 45 minutes to parse the header */
207 atnotify(catchalarm, 1);
208 alarm(45*60*1000);
209 zzparse();
210 exits(0);
211 }
212
213 void
listfree(List * l)214 listfree(List *l)
215 {
216 Link *lp, *next;
217
218 for(lp = l->first; lp; lp = next){
219 next = lp->next;
220 s_free(lp->p);
221 free(lp);
222 }
223 l->first = l->last = 0;
224 }
225
226 void
listadd(List * l,String * path)227 listadd(List *l, String *path)
228 {
229 Link *lp;
230
231 lp = (Link *)malloc(sizeof *lp);
232 lp->p = path;
233 lp->next = 0;
234
235 if(l->last)
236 l->last->next = lp;
237 else
238 l->first = lp;
239 l->last = lp;
240 }
241
242 void
stamp(void)243 stamp(void)
244 {
245 if(debug) {
246 seek(2, 0, 2);
247 fprint(2, "%3lud ", time(0) - starttime);
248 }
249 }
250
251 #define SIZE 4096
252
253 int
reply(char * fmt,...)254 reply(char *fmt, ...)
255 {
256 long n;
257 char buf[SIZE], *out;
258 va_list arg;
259
260 va_start(arg, fmt);
261 out = vseprint(buf, buf+SIZE, fmt, arg);
262 va_end(arg);
263
264 n = out - buf;
265 if(debug) {
266 seek(2, 0, 2);
267 stamp();
268 write(2, buf, n);
269 }
270 write(1, buf, n);
271 return n;
272 }
273
274 void
reset(void)275 reset(void)
276 {
277 if(rejectcheck())
278 return;
279 listfree(&rcvers);
280 listfree(&senders);
281 if(filterstate != DIALUP){
282 logged = 0;
283 filterstate = ACCEPT;
284 }
285 reply("250 2.0.0 ok\r\n");
286 }
287
288 void
sayhi(void)289 sayhi(void)
290 {
291 Dir *dp;
292
293 reply("220-%s ESMTP\r\n", dom);
294 sleep(3000);
295 dp = dirfstat(0);
296 if (dp && dp->length > 0) {
297 syslog(0, "smtpd", "Hung up on impatient spammer %s", nci->rsys);
298 if(Dflag)
299 sleep(delaysecs()*1000);
300 reply("554 5.7.0 Spammer!\r\n");
301 exits("spammer didn't wait for greeting to finish");
302 }
303 free(dp);
304 reply("220 \r\n");
305 }
306
307 /*
308 * make callers from class A networks infested by spammers
309 * wait longer.
310 */
311
312 static char netaspam[256] = {
313 [58] 1,
314 [66] 1,
315 [71] 1,
316
317 [76] 1,
318 [77] 1,
319 [78] 1,
320 [79] 1,
321 [80] 1,
322 [81] 1,
323 [82] 1,
324 [83] 1,
325 [84] 1,
326 [85] 1,
327 [86] 1,
328 [87] 1,
329 [88] 1,
330 [89] 1,
331
332 [190] 1,
333 [201] 1,
334 [217] 1,
335 };
336
337 static int
delaysecs(void)338 delaysecs(void)
339 {
340 if (trusted)
341 return 0;
342 if (0 && netaspam[rsysip[0]])
343 return 20;
344 return 12;
345 }
346
347 void
hello(String * himp,int extended)348 hello(String *himp, int extended)
349 {
350 char **mynames;
351 char *ldot, *rdot;
352
353 him = s_to_c(himp);
354 syslog(0, "smtpd", "%s from %s as %s", extended? "ehlo": "helo",
355 nci->rsys, him);
356 if(rejectcheck())
357 return;
358
359 if (strchr(him, '.') && nci && !trusted && fflag &&
360 strcmp(nci->rsys, nci->lsys) != 0){
361 /*
362 * We don't care if he lies about who he is, but it is
363 * not okay to pretend to be us. Many viruses do this,
364 * just parroting back what we say in the greeting.
365 */
366 if(strcmp(him, dom) == 0)
367 goto Liarliar;
368 for(mynames = sysnames_read(); mynames && *mynames; mynames++){
369 if(cistrcmp(*mynames, him) == 0){
370 Liarliar:
371 syslog(0, "smtpd",
372 "Hung up on %s; claimed to be %s",
373 nci->rsys, him);
374 if(Dflag)
375 sleep(delaysecs()*1000);
376 reply("554 5.7.0 Liar!\r\n");
377 exits("client pretended to be us");
378 return;
379 }
380 }
381 }
382
383 /*
384 * it is unacceptable to claim any string that doesn't look like
385 * a domain name (e.g., has at least one dot in it), but
386 * Microsoft mail client software gets this wrong, so let trusted
387 * (local) clients omit the dot.
388 */
389 rdot = strrchr(him, '.');
390 if (rdot && rdot[1] == '\0') {
391 *rdot = '\0'; /* clobber trailing dot */
392 rdot = strrchr(him, '.'); /* try again */
393 }
394 if (!trusted && rdot == nil)
395 goto Liarliar;
396 /*
397 * Reject obviously bogus domains and those reserved by RFC 2606.
398 */
399 if (rdot == nil)
400 rdot = him;
401 else
402 rdot++;
403 if (!trusted && (cistrcmp(rdot, "localdomain") == 0 ||
404 cistrcmp(rdot, "localhost") == 0 ||
405 cistrcmp(rdot, "example") == 0 ||
406 cistrcmp(rdot, "invalid") == 0 ||
407 cistrcmp(rdot, "test") == 0))
408 goto Liarliar; /* bad top-level domain */
409 /* check second-level RFC 2606 domains: example\.(com|net|org) */
410 if (rdot != him)
411 *--rdot = '\0';
412 ldot = strrchr(him, '.');
413 if (rdot != him)
414 *rdot = '.';
415 if (ldot == nil)
416 ldot = him;
417 else
418 ldot++;
419 if (cistrcmp(ldot, "example.com") == 0 ||
420 cistrcmp(ldot, "example.net") == 0 ||
421 cistrcmp(ldot, "example.org") == 0)
422 goto Liarliar;
423
424 /*
425 * similarly, if the claimed domain is not an address-literal,
426 * require at least one letter, which there will be in
427 * at least the last component (e.g., .com, .net) if it's real.
428 * this rejects non-address-literal IP addresses,
429 * among other bogosities.
430 */
431 if (!trusted && him[0] != '[') {
432 char *p;
433
434 for (p = him; *p != '\0'; p++)
435 if (isascii(*p) && isalpha(*p))
436 break;
437 if (*p == '\0')
438 goto Liarliar;
439 }
440 if(strchr(him, '.') == 0 && nci != nil && strchr(nci->rsys, '.') != nil)
441 him = nci->rsys;
442
443 if(Dflag)
444 sleep(delaysecs()*1000);
445 reply("250%c%s you are %s\r\n", extended ? '-' : ' ', dom, him);
446 if (extended) {
447 reply("250-ENHANCEDSTATUSCODES\r\n"); /* RFCs 2034 and 3463 */
448 if(tlscert != nil)
449 reply("250-STARTTLS\r\n");
450 if (passwordinclear)
451 reply("250 AUTH CRAM-MD5 PLAIN LOGIN\r\n");
452 else
453 reply("250 AUTH CRAM-MD5\r\n");
454 }
455 }
456
457 void
sender(String * path)458 sender(String *path)
459 {
460 String *s;
461 static char *lastsender;
462
463 if(rejectcheck())
464 return;
465 if (authenticate && !authenticated) {
466 rejectcount++;
467 reply("530 5.7.0 Authentication required\r\n");
468 return;
469 }
470 if(him == 0 || *him == 0){
471 rejectcount++;
472 reply("503 Start by saying HELO, please.\r\n", s_to_c(path));
473 return;
474 }
475
476 /* don't add the domain onto black holes or we will loop */
477 if(strchr(s_to_c(path), '!') == 0 && strcmp(s_to_c(path), "/dev/null") != 0){
478 s = s_new();
479 s_append(s, him);
480 s_append(s, "!");
481 s_append(s, s_to_c(path));
482 s_terminate(s);
483 s_free(path);
484 path = s;
485 }
486 if(shellchars(s_to_c(path))){
487 rejectcount++;
488 reply("501 5.1.3 Bad character in sender address %s.\r\n",
489 s_to_c(path));
490 return;
491 }
492
493 /*
494 * if the last sender address resulted in a rejection because the sending
495 * domain didn't exist and this sender has the same domain, reject
496 * immediately.
497 */
498 if(lastsender){
499 if (strncmp(lastsender, s_to_c(path), strlen(lastsender)) == 0){
500 filterstate = REFUSED;
501 rejectcount++;
502 reply("554 5.1.8 Sender domain must exist: %s\r\n",
503 s_to_c(path));
504 return;
505 }
506 free(lastsender); /* different sender domain */
507 lastsender = 0;
508 }
509
510 /*
511 * see if this ip address, domain name, user name or account is blocked
512 */
513 logged = 0;
514 filterstate = blocked(path);
515 /*
516 * permanently reject what we can before trying smtp ping, which
517 * often leads to merely temporary rejections.
518 */
519 switch (filterstate){
520 case DENIED:
521 syslog(0, "smtpd", "Denied %s (%s/%s)",
522 s_to_c(path), him, nci->rsys);
523 rejectcount++;
524 logged++;
525 reply("554-5.7.1 We don't accept mail from %s.\r\n",
526 s_to_c(path));
527 reply("554 5.7.1 Contact postmaster@%s for more information.\r\n",
528 dom);
529 return;
530 case REFUSED:
531 syslog(0, "smtpd", "Refused %s (%s/%s)",
532 s_to_c(path), him, nci->rsys);
533 rejectcount++;
534 logged++;
535 reply("554 5.7.1 Sender domain must exist: %s\r\n",
536 s_to_c(path));
537 return;
538 }
539
540 listadd(&senders, path);
541 reply("250 2.0.0 sender is %s\r\n", s_to_c(path));
542 }
543
544 enum { Rcpt, Domain, Ntoks };
545
546 typedef struct Sender Sender;
547 struct Sender {
548 Sender *next;
549 char *rcpt;
550 char *domain;
551 };
552 static Sender *sendlist, *sendlast;
553
554 static int
rdsenders(void)555 rdsenders(void)
556 {
557 int lnlen, nf, ok = 1;
558 char *line, *senderfile;
559 char *toks[Ntoks];
560 Biobuf *sf;
561 Sender *snd;
562 static int beenhere = 0;
563
564 if (beenhere)
565 return 1;
566 beenhere = 1;
567
568 /*
569 * we're sticking with a system-wide sender list because
570 * per-user lists would require fully resolving recipient
571 * addresses to determine which users they correspond to
572 * (barring exploiting syntactic conventions).
573 */
574 senderfile = smprint("%s/senders", UPASLIB);
575 sf = Bopen(senderfile, OREAD);
576 free(senderfile);
577 if (sf == nil)
578 return 1;
579 while ((line = Brdline(sf, '\n')) != nil) {
580 if (line[0] == '#' || line[0] == '\n')
581 continue;
582 lnlen = Blinelen(sf);
583 line[lnlen-1] = '\0'; /* clobber newline */
584 nf = tokenize(line, toks, nelem(toks));
585 if (nf != nelem(toks))
586 continue; /* malformed line */
587
588 snd = malloc(sizeof *snd);
589 if (snd == nil)
590 sysfatal("out of memory: %r");
591 memset(snd, 0, sizeof *snd);
592 snd->next = nil;
593
594 if (sendlast == nil)
595 sendlist = snd;
596 else
597 sendlast->next = snd;
598 sendlast = snd;
599 snd->rcpt = strdup(toks[Rcpt]);
600 snd->domain = strdup(toks[Domain]);
601 }
602 Bterm(sf);
603 return ok;
604 }
605
606 /*
607 * read (recipient, sender's DNS) pairs from /mail/lib/senders.
608 * Only allow mail to recipient from any of sender's IPs.
609 * A recipient not mentioned in the file is always permitted.
610 */
611 static int
senderok(char * rcpt)612 senderok(char *rcpt)
613 {
614 int mentioned = 0, matched = 0;
615 uchar dnsip[IPaddrlen];
616 Sender *snd;
617 Ndbtuple *nt, *next, *first;
618
619 rdsenders();
620 for (snd = sendlist; snd != nil; snd = snd->next) {
621 if (strcmp(rcpt, snd->rcpt) != 0)
622 continue;
623 /*
624 * see if this domain's ips match nci->rsys.
625 * if not, perhaps a later entry's domain will.
626 */
627 mentioned = 1;
628 if (parseip(dnsip, snd->domain) != -1 &&
629 memcmp(rsysip, dnsip, IPaddrlen) == 0)
630 return 1;
631 /*
632 * NB: nt->line links form a circular list(!).
633 * we need to make one complete pass over it to free it all.
634 */
635 first = nt = dnsquery(nci->root, snd->domain, "ip");
636 if (first == nil)
637 continue;
638 do {
639 if (strcmp(nt->attr, "ip") == 0 &&
640 parseip(dnsip, nt->val) != -1 &&
641 memcmp(rsysip, dnsip, IPaddrlen) == 0)
642 matched = 1;
643 next = nt->line;
644 free(nt);
645 nt = next;
646 } while (nt != first);
647 }
648 if (matched)
649 return 1;
650 else
651 return !mentioned;
652 }
653
654 void
receiver(String * path)655 receiver(String *path)
656 {
657 char *sender, *rcpt;
658
659 if(rejectcheck())
660 return;
661 if(him == 0 || *him == 0){
662 rejectcount++;
663 reply("503 Start by saying HELO, please\r\n");
664 return;
665 }
666 if(senders.last)
667 sender = s_to_c(senders.last->p);
668 else
669 sender = "<unknown>";
670
671 if(!recipok(s_to_c(path))){
672 rejectcount++;
673 syslog(0, "smtpd",
674 "Disallowed %s (%s/%s) to blocked, unknown or invalid name %s",
675 sender, him, nci->rsys, s_to_c(path));
676 reply("550 5.1.1 %s ... user unknown\r\n", s_to_c(path));
677 return;
678 }
679 rcpt = s_to_c(path);
680 if (!senderok(rcpt)) {
681 rejectcount++;
682 syslog(0, "smtpd", "Disallowed sending IP of %s (%s/%s) to %s",
683 sender, him, nci->rsys, rcpt);
684 reply("550 5.7.1 %s ... sending system not allowed\r\n", rcpt);
685 return;
686 }
687
688 logged = 0;
689
690 /* forwarding() can modify 'path' on loopback request */
691 if(filterstate == ACCEPT && fflag && !authenticated && forwarding(path)) {
692 syslog(0, "smtpd", "Bad Forward %s (%s/%s) (%s)",
693 senders.last && senders.last->p?
694 s_to_c(senders.last->p): sender,
695 him, nci->rsys, path? s_to_c(path): rcpt);
696 rejectcount++;
697 reply("550 5.7.1 we don't relay. send to your-path@[] for "
698 "loopback.\r\n");
699 return;
700 }
701 listadd(&rcvers, path);
702 reply("250 2.0.0 receiver is %s\r\n", s_to_c(path));
703 }
704
705 void
quit(void)706 quit(void)
707 {
708 reply("221 2.0.0 Successful termination\r\n");
709 if(debug){
710 seek(2, 0, 2);
711 stamp();
712 fprint(2, "# %d sent 221 reply to QUIT %s\n",
713 getpid(), thedate());
714 }
715 close(0);
716 exits(0);
717 }
718
719 void
noop(void)720 noop(void)
721 {
722 if(rejectcheck())
723 return;
724 reply("250 2.0.0 Nothing to see here. Move along ...\r\n");
725 }
726
727 void
help(String * cmd)728 help(String *cmd)
729 {
730 if(rejectcheck())
731 return;
732 if(cmd)
733 s_free(cmd);
734 reply("250 2.0.0 See http://www.ietf.org/rfc/rfc2821\r\n");
735 }
736
737 void
verify(String * path)738 verify(String *path)
739 {
740 char *p, *q;
741 char *av[4];
742
743 if(rejectcheck())
744 return;
745 if(shellchars(s_to_c(path))){
746 reply("503 5.1.3 Bad character in address %s.\r\n", s_to_c(path));
747 return;
748 }
749 av[0] = s_to_c(mailer);
750 av[1] = "-x";
751 av[2] = s_to_c(path);
752 av[3] = 0;
753
754 pp = noshell_proc_start(av, (stream *)0, outstream(), (stream *)0, 1, 0);
755 if (pp == 0) {
756 reply("450 4.3.2 We're busy right now, try later\r\n");
757 return;
758 }
759
760 p = Brdline(pp->std[1]->fp, '\n');
761 if(p == 0){
762 reply("550 5.1.0 String does not match anything.\r\n");
763 } else {
764 p[Blinelen(pp->std[1]->fp)-1] = 0;
765 if(strchr(p, ':'))
766 reply("550 5.1.0 String does not match anything.\r\n");
767 else{
768 q = strrchr(p, '!');
769 if(q)
770 p = q+1;
771 reply("250 2.0.0 %s <%s@%s>\r\n", s_to_c(path), p, dom);
772 }
773 }
774 proc_wait(pp);
775 proc_free(pp);
776 pp = 0;
777 }
778
779 /*
780 * get a line that ends in crnl or cr, turn terminating crnl into a nl
781 *
782 * return 0 on EOF
783 */
784 static int
getcrnl(String * s,Biobuf * fp)785 getcrnl(String *s, Biobuf *fp)
786 {
787 int c;
788
789 for(;;){
790 c = Bgetc(fp);
791 if(debug) {
792 seek(2, 0, 2);
793 fprint(2, "%c", c);
794 }
795 switch(c){
796 case 0:
797 break;
798 case -1:
799 goto out;
800 case '\r':
801 c = Bgetc(fp);
802 if(c == '\n'){
803 if(debug) {
804 seek(2, 0, 2);
805 fprint(2, "%c", c);
806 stamp();
807 }
808 s_putc(s, '\n');
809 goto out;
810 }
811 Bungetc(fp);
812 s_putc(s, '\r');
813 break;
814 case '\n':
815 s_putc(s, c);
816 goto out;
817 default:
818 s_putc(s, c);
819 break;
820 }
821 }
822 out:
823 s_terminate(s);
824 return s_len(s);
825 }
826
827 void
logcall(int nbytes)828 logcall(int nbytes)
829 {
830 Link *l;
831 String *to, *from;
832
833 to = s_new();
834 from = s_new();
835 for(l = senders.first; l; l = l->next){
836 if(l != senders.first)
837 s_append(from, ", ");
838 s_append(from, s_to_c(l->p));
839 }
840 for(l = rcvers.first; l; l = l->next){
841 if(l != rcvers.first)
842 s_append(to, ", ");
843 s_append(to, s_to_c(l->p));
844 }
845 syslog(0, "smtpd", "[%s/%s] %s sent %d bytes to %s", him, nci->rsys,
846 s_to_c(from), nbytes, s_to_c(to));
847 s_free(to);
848 s_free(from);
849 }
850
851 static void
logmsg(char * action)852 logmsg(char *action)
853 {
854 Link *l;
855
856 if(logged)
857 return;
858
859 logged = 1;
860 for(l = rcvers.first; l; l = l->next)
861 syslog(0, "smtpd", "%s %s (%s/%s) (%s)", action,
862 s_to_c(senders.last->p), him, nci->rsys, s_to_c(l->p));
863 }
864
865 static int
optoutall(int filterstate)866 optoutall(int filterstate)
867 {
868 Link *l;
869
870 switch(filterstate){
871 case ACCEPT:
872 case TRUSTED:
873 return filterstate;
874 }
875
876 for(l = rcvers.first; l; l = l->next)
877 if(!optoutofspamfilter(s_to_c(l->p)))
878 return filterstate;
879
880 return ACCEPT;
881 }
882
883 String*
startcmd(void)884 startcmd(void)
885 {
886 int n;
887 char *filename;
888 char **av;
889 Link *l;
890 String *cmd;
891
892 /*
893 * ignore the filterstate if the all the receivers prefer it.
894 */
895 filterstate = optoutall(filterstate);
896
897 switch (filterstate){
898 case BLOCKED:
899 case DELAY:
900 rejectcount++;
901 logmsg("Blocked");
902 filename = dumpfile(s_to_c(senders.last->p));
903 cmd = s_new();
904 s_append(cmd, "cat > ");
905 s_append(cmd, filename);
906 pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 0, 0);
907 break;
908 case DIALUP:
909 logmsg("Dialup");
910 rejectcount++;
911 reply("554 5.7.1 We don't accept mail from dial-up ports.\r\n");
912 /*
913 * we could exit here, because we're never going to accept mail
914 * from this ip address, but it's unclear that RFC821 allows
915 * that. Instead we set the hardreject flag and go stupid.
916 */
917 hardreject = 1;
918 return 0;
919 case DENIED:
920 logmsg("Denied");
921 rejectcount++;
922 reply("554-5.7.1 We don't accept mail from %s.\r\n",
923 s_to_c(senders.last->p));
924 reply("554 5.7.1 Contact postmaster@%s for more information.\r\n",
925 dom);
926 return 0;
927 case REFUSED:
928 logmsg("Refused");
929 rejectcount++;
930 reply("554 5.7.1 Sender domain must exist: %s\r\n",
931 s_to_c(senders.last->p));
932 return 0;
933 default:
934 case NONE:
935 logmsg("Confused");
936 rejectcount++;
937 reply("554-5.7.0 We have had an internal mailer error "
938 "classifying your message.\r\n");
939 reply("554-5.7.0 Filterstate is %d\r\n", filterstate);
940 reply("554 5.7.0 Contact postmaster@%s for more information.\r\n",
941 dom);
942 return 0;
943 case ACCEPT:
944 /*
945 * now that all other filters have been passed,
946 * do grey-list processing.
947 */
948 if(gflag)
949 vfysenderhostok();
950 /* fall through */
951
952 case TRUSTED:
953 /*
954 * set up mail command
955 */
956 cmd = s_clone(mailer);
957 n = 3;
958 for(l = rcvers.first; l; l = l->next)
959 n++;
960 av = malloc(n * sizeof(char*));
961 if(av == nil){
962 reply("450 4.3.2 We're busy right now, try later\r\n");
963 s_free(cmd);
964 return 0;
965 }
966
967 n = 0;
968 av[n++] = s_to_c(cmd);
969 av[n++] = "-r";
970 for(l = rcvers.first; l; l = l->next)
971 av[n++] = s_to_c(l->p);
972 av[n] = 0;
973 /*
974 * start mail process
975 */
976 pp = noshell_proc_start(av, instream(), outstream(),
977 outstream(), 0, 0);
978 free(av);
979 break;
980 }
981 if(pp == 0) {
982 reply("450 4.3.2 We're busy right now, try later\r\n");
983 s_free(cmd);
984 return 0;
985 }
986 return cmd;
987 }
988
989 /*
990 * print out a header line, expanding any domainless addresses into
991 * address@him
992 */
993 char*
bprintnode(Biobuf * b,Node * p,int * cntp)994 bprintnode(Biobuf *b, Node *p, int *cntp)
995 {
996 int len;
997
998 *cntp = 0;
999 if(p->s){
1000 if(p->addr && strchr(s_to_c(p->s), '@') == nil){
1001 if(Bprint(b, "%s@%s", s_to_c(p->s), him) < 0)
1002 return nil;
1003 *cntp += s_len(p->s) + 1 + strlen(him);
1004 } else {
1005 len = s_len(p->s);
1006 if(Bwrite(b, s_to_c(p->s), len) < 0)
1007 return nil;
1008 *cntp += len;
1009 }
1010 }else{
1011 if(Bputc(b, p->c) < 0)
1012 return nil;
1013 ++*cntp;
1014 }
1015 if(p->white) {
1016 len = s_len(p->white);
1017 if(Bwrite(b, s_to_c(p->white), len) < 0)
1018 return nil;
1019 *cntp += len;
1020 }
1021 return p->end+1;
1022 }
1023
1024 static String*
getaddr(Node * p)1025 getaddr(Node *p)
1026 {
1027 for(; p; p = p->next)
1028 if(p->s && p->addr)
1029 return p->s;
1030 return nil;
1031 }
1032
1033 /*
1034 * add warning headers of the form
1035 * X-warning: <reason>
1036 * for any headers that looked like they might be forged.
1037 *
1038 * return byte count of new headers
1039 */
1040 static int
forgedheaderwarnings(void)1041 forgedheaderwarnings(void)
1042 {
1043 int nbytes;
1044 Field *f;
1045
1046 nbytes = 0;
1047
1048 /* warn about envelope sender */
1049 if(senders.last != nil && senders.last->p != nil &&
1050 strcmp(s_to_c(senders.last->p), "/dev/null") != 0 &&
1051 masquerade(senders.last->p, nil))
1052 nbytes += Bprint(pp->std[0]->fp,
1053 "X-warning: suspect envelope domain\n");
1054
1055 /*
1056 * check Sender: field. If it's OK, ignore the others because this
1057 * is an exploded mailing list.
1058 */
1059 for(f = firstfield; f; f = f->next)
1060 if(f->node->c == SENDER)
1061 if(masquerade(getaddr(f->node), him))
1062 nbytes += Bprint(pp->std[0]->fp,
1063 "X-warning: suspect Sender: domain\n");
1064 else
1065 return nbytes;
1066
1067 /* check From: */
1068 for(f = firstfield; f; f = f->next){
1069 if(f->node->c == FROM && masquerade(getaddr(f->node), him))
1070 nbytes += Bprint(pp->std[0]->fp,
1071 "X-warning: suspect From: domain\n");
1072 }
1073 return nbytes;
1074 }
1075
1076 /*
1077 * pipe message to mailer with the following transformations:
1078 * - change \r\n into \n.
1079 * - add sender's domain to any addrs with no domain
1080 * - add a From: if none of From:, Sender:, or Replyto: exists
1081 * - add a Received: line
1082 */
1083 int
pipemsg(int * byteswritten)1084 pipemsg(int *byteswritten)
1085 {
1086 int n, nbytes, sawdot, status, nonhdr, bpr;
1087 char *cp;
1088 Field *f;
1089 Link *l;
1090 Node *p;
1091 String *hdr, *line;
1092
1093 pipesig(&status); /* set status to 1 on write to closed pipe */
1094 sawdot = 0;
1095 status = 0;
1096
1097 /*
1098 * add a 'From ' line as envelope
1099 */
1100 nbytes = 0;
1101 nbytes += Bprint(pp->std[0]->fp, "From %s %s remote from \n",
1102 s_to_c(senders.first->p), thedate());
1103
1104 /*
1105 * add our own Received: stamp
1106 */
1107 nbytes += Bprint(pp->std[0]->fp, "Received: from %s ", him);
1108 if(nci->rsys)
1109 nbytes += Bprint(pp->std[0]->fp, "([%s]) ", nci->rsys);
1110 nbytes += Bprint(pp->std[0]->fp, "by %s; %s\n", me, thedate());
1111
1112 /*
1113 * read first 16k obeying '.' escape. we're assuming
1114 * the header will all be there.
1115 */
1116 line = s_new();
1117 hdr = s_new();
1118 while(sawdot == 0 && s_len(hdr) < 16*1024){
1119 n = getcrnl(s_reset(line), &bin);
1120
1121 /* eof or error ends the message */
1122 if(n <= 0)
1123 break;
1124
1125 /* a line with only a '.' ends the message */
1126 cp = s_to_c(line);
1127 if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
1128 sawdot = 1;
1129 break;
1130 }
1131
1132 s_append(hdr, *cp == '.' ? cp+1 : cp);
1133 }
1134
1135 /*
1136 * parse header
1137 */
1138 yyinit(s_to_c(hdr), s_len(hdr));
1139 yyparse();
1140
1141 /*
1142 * Look for masquerades. Let Sender: trump From: to allow mailing list
1143 * forwarded messages.
1144 */
1145 if(fflag)
1146 nbytes += forgedheaderwarnings();
1147
1148 /*
1149 * add an orginator and/or destination if either is missing
1150 */
1151 if(originator == 0){
1152 if(senders.last == nil || senders.last->p == nil)
1153 nbytes += Bprint(pp->std[0]->fp, "From: /dev/null@%s\n",
1154 him);
1155 else
1156 nbytes += Bprint(pp->std[0]->fp, "From: %s\n",
1157 s_to_c(senders.last->p));
1158 }
1159 if(destination == 0){
1160 nbytes += Bprint(pp->std[0]->fp, "To: ");
1161 for(l = rcvers.first; l; l = l->next){
1162 if(l != rcvers.first)
1163 nbytes += Bprint(pp->std[0]->fp, ", ");
1164 nbytes += Bprint(pp->std[0]->fp, "%s", s_to_c(l->p));
1165 }
1166 nbytes += Bprint(pp->std[0]->fp, "\n");
1167 }
1168
1169 /*
1170 * add sender's domain to any domainless addresses
1171 * (to avoid forging local addresses)
1172 */
1173 cp = s_to_c(hdr);
1174 for(f = firstfield; cp != nil && f; f = f->next){
1175 for(p = f->node; cp != 0 && p; p = p->next) {
1176 bpr = 0;
1177 cp = bprintnode(pp->std[0]->fp, p, &bpr);
1178 nbytes += bpr;
1179 }
1180 if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0){
1181 piperror = "write error";
1182 status = 1;
1183 }
1184 nbytes++; /* for newline */
1185 }
1186 if(cp == nil){
1187 piperror = "sender domain";
1188 status = 1;
1189 }
1190
1191 /* write anything we read following the header */
1192 nonhdr = s_to_c(hdr) + s_len(hdr) - cp;
1193 if(status == 0 && Bwrite(pp->std[0]->fp, cp, nonhdr) < 0){
1194 piperror = "write error 2";
1195 status = 1;
1196 }
1197 nbytes += nonhdr;
1198 s_free(hdr);
1199
1200 /*
1201 * pass rest of message to mailer. take care of '.'
1202 * escapes.
1203 */
1204 while(sawdot == 0){
1205 n = getcrnl(s_reset(line), &bin);
1206
1207 /* eof or error ends the message */
1208 if(n <= 0)
1209 break;
1210
1211 /* a line with only a '.' ends the message */
1212 cp = s_to_c(line);
1213 if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
1214 sawdot = 1;
1215 break;
1216 }
1217 if(cp[0] == '.'){
1218 cp++;
1219 n--;
1220 }
1221 nbytes += n;
1222 if(status == 0 && Bwrite(pp->std[0]->fp, cp, n) < 0){
1223 piperror = "write error 3";
1224 status = 1;
1225 }
1226 }
1227 s_free(line);
1228 if(sawdot == 0){
1229 /* message did not terminate normally */
1230 snprint(pipbuf, sizeof pipbuf, "network eof: %r");
1231 piperror = pipbuf;
1232 if (pp->pid > 0) {
1233 syskillpg(pp->pid);
1234 /* none can't syskillpg, so try a variant */
1235 sleep(500);
1236 syskill(pp->pid);
1237 }
1238 status = 1;
1239 }
1240
1241 if(status == 0 && Bflush(pp->std[0]->fp) < 0){
1242 piperror = "write error 4";
1243 status = 1;
1244 }
1245 if (debug) {
1246 stamp();
1247 fprint(2, "at end of message; %s .\n",
1248 (sawdot? "saw": "didn't see"));
1249 }
1250 stream_free(pp->std[0]);
1251 pp->std[0] = 0;
1252 *byteswritten = nbytes;
1253 pipesigoff();
1254 if(status && !piperror)
1255 piperror = "write on closed pipe";
1256 return status;
1257 }
1258
1259 char*
firstline(char * x)1260 firstline(char *x)
1261 {
1262 char *p;
1263 static char buf[128];
1264
1265 strncpy(buf, x, sizeof(buf));
1266 buf[sizeof(buf)-1] = 0;
1267 p = strchr(buf, '\n');
1268 if(p)
1269 *p = 0;
1270 return buf;
1271 }
1272
1273 int
sendermxcheck(void)1274 sendermxcheck(void)
1275 {
1276 int pid;
1277 char *cp, *senddom, *user, *who;
1278 Waitmsg *w;
1279
1280 who = s_to_c(senders.first->p);
1281 if(strcmp(who, "/dev/null") == 0){
1282 /* /dev/null can only send to one rcpt at a time */
1283 if(rcvers.first != rcvers.last){
1284 werrstr("rejected: /dev/null sending to multiple "
1285 "recipients");
1286 return -1;
1287 }
1288 return 0;
1289 }
1290
1291 if(access("/mail/lib/validatesender", AEXEC) < 0)
1292 return 0;
1293
1294 senddom = strdup(who);
1295 if((cp = strchr(senddom, '!')) == nil){
1296 werrstr("rejected: domainless sender %s", who);
1297 free(senddom);
1298 return -1;
1299 }
1300 *cp++ = 0;
1301 user = cp;
1302
1303 switch(pid = fork()){
1304 case -1:
1305 werrstr("deferred: fork: %r");
1306 return -1;
1307 case 0:
1308 /*
1309 * Could add an option with the remote IP address
1310 * to allow validatesender to implement SPF eventually.
1311 */
1312 execl("/mail/lib/validatesender", "validatesender",
1313 "-n", nci->root, senddom, user, nil);
1314 _exits("exec validatesender: %r");
1315 default:
1316 break;
1317 }
1318
1319 free(senddom);
1320 w = wait();
1321 if(w == nil){
1322 werrstr("deferred: wait failed: %r");
1323 return -1;
1324 }
1325 if(w->pid != pid){
1326 werrstr("deferred: wait returned wrong pid %d != %d",
1327 w->pid, pid);
1328 free(w);
1329 return -1;
1330 }
1331 if(w->msg[0] == 0){
1332 free(w);
1333 return 0;
1334 }
1335 /*
1336 * skip over validatesender 143123132: prefix from rc.
1337 */
1338 cp = strchr(w->msg, ':');
1339 if(cp && *(cp+1) == ' ')
1340 werrstr("%s", cp+2);
1341 else
1342 werrstr("%s", w->msg);
1343 free(w);
1344 return -1;
1345 }
1346
1347 void
data(void)1348 data(void)
1349 {
1350 int status, nbytes;
1351 char *cp, *ep;
1352 char errx[ERRMAX];
1353 Link *l;
1354 String *cmd, *err;
1355
1356 if(rejectcheck())
1357 return;
1358 if(senders.last == 0){
1359 reply("503 2.5.2 Data without MAIL FROM:\r\n");
1360 rejectcount++;
1361 return;
1362 }
1363 if(rcvers.last == 0){
1364 reply("503 2.5.2 Data without RCPT TO:\r\n");
1365 rejectcount++;
1366 return;
1367 }
1368 if(!trusted && sendermxcheck()){
1369 rerrstr(errx, sizeof errx);
1370 if(strncmp(errx, "rejected:", 9) == 0)
1371 reply("554 5.7.1 %s\r\n", errx);
1372 else
1373 reply("450 4.7.0 %s\r\n", errx);
1374 for(l=rcvers.first; l; l=l->next)
1375 syslog(0, "smtpd", "[%s/%s] %s -> %s sendercheck: %s",
1376 him, nci->rsys, s_to_c(senders.first->p),
1377 s_to_c(l->p), errx);
1378 rejectcount++;
1379 return;
1380 }
1381
1382 cmd = startcmd();
1383 if(cmd == 0)
1384 return;
1385
1386 reply("354 Input message; end with <CRLF>.<CRLF>\r\n");
1387 if(debug){
1388 seek(2, 0, 2);
1389 stamp();
1390 fprint(2, "# sent 354; accepting DATA %s\n", thedate());
1391 }
1392
1393
1394 /*
1395 * allow 145 more minutes to move the data
1396 */
1397 alarm(145*60*1000);
1398
1399 status = pipemsg(&nbytes);
1400
1401 /*
1402 * read any error messages
1403 */
1404 err = s_new();
1405 if (debug) {
1406 stamp();
1407 fprint(2, "waiting for upas/send to close stderr\n");
1408 }
1409 while(s_read_line(pp->std[2]->fp, err))
1410 ;
1411
1412 alarm(0);
1413 atnotify(catchalarm, 0);
1414
1415 if (debug) {
1416 stamp();
1417 fprint(2, "waiting for upas/send to exit\n");
1418 }
1419 status |= proc_wait(pp);
1420 if(debug){
1421 seek(2, 0, 2);
1422 stamp();
1423 fprint(2, "# %d upas/send status %#ux at %s\n",
1424 getpid(), status, thedate());
1425 if(*s_to_c(err))
1426 fprint(2, "# %d error %s\n", getpid(), s_to_c(err));
1427 }
1428
1429 /*
1430 * if process terminated abnormally, send back error message
1431 */
1432 if(status){
1433 int code;
1434 char *ecode;
1435
1436 if(strstr(s_to_c(err), "mail refused")){
1437 syslog(0, "smtpd", "++[%s/%s] %s %s refused: %s",
1438 him, nci->rsys, s_to_c(senders.first->p),
1439 s_to_c(cmd), firstline(s_to_c(err)));
1440 code = 554;
1441 ecode = "5.0.0";
1442 } else {
1443 syslog(0, "smtpd", "++[%s/%s] %s %s %s%s%sreturned %#q %s",
1444 him, nci->rsys,
1445 s_to_c(senders.first->p), s_to_c(cmd),
1446 piperror? "error during pipemsg: ": "",
1447 piperror? piperror: "",
1448 piperror? "; ": "",
1449 pp->waitmsg->msg, firstline(s_to_c(err)));
1450 code = 450;
1451 ecode = "4.0.0";
1452 }
1453 for(cp = s_to_c(err); ep = strchr(cp, '\n'); cp = ep){
1454 *ep++ = 0;
1455 reply("%d-%s %s\r\n", code, ecode, cp);
1456 }
1457 reply("%d %s mail process terminated abnormally\r\n",
1458 code, ecode);
1459 } else {
1460 /*
1461 * if a message appeared on stderr, despite good status,
1462 * log it. this can happen if rewrite.in contains a bad
1463 * r.e., for example.
1464 */
1465 if(*s_to_c(err))
1466 syslog(0, "smtpd",
1467 "%s returned good status, but said: %s",
1468 s_to_c(mailer), s_to_c(err));
1469
1470 if(filterstate == BLOCKED)
1471 reply("554 5.7.1 we believe this is spam. "
1472 "we don't accept it.\r\n");
1473 else if(filterstate == DELAY)
1474 reply("450 4.3.0 There will be a delay in delivery "
1475 "of this message.\r\n");
1476 else {
1477 reply("250 2.5.0 sent\r\n");
1478 logcall(nbytes);
1479 if(debug){
1480 seek(2, 0, 2);
1481 stamp();
1482 fprint(2, "# %d sent 250 reply %s\n",
1483 getpid(), thedate());
1484 }
1485 }
1486 }
1487 proc_free(pp);
1488 pp = 0;
1489 s_free(cmd);
1490 s_free(err);
1491
1492 listfree(&senders);
1493 listfree(&rcvers);
1494 }
1495
1496 /*
1497 * when we have blocked a transaction based on IP address, there is nothing
1498 * that the sender can do to convince us to take the message. after the
1499 * first rejection, some spammers continually RSET and give a new MAIL FROM:
1500 * filling our logs with rejections. rejectcheck() limits the retries and
1501 * swiftly rejects all further commands after the first 500-series message
1502 * is issued.
1503 */
1504 int
rejectcheck(void)1505 rejectcheck(void)
1506 {
1507 if(rejectcount > MAXREJECTS){
1508 syslog(0, "smtpd", "Rejected (%s/%s)", him, nci->rsys);
1509 reply("554 5.5.0 too many errors. transaction failed.\r\n");
1510 exits("errcount");
1511 }
1512 if(hardreject){
1513 rejectcount++;
1514 reply("554 5.7.1 We don't accept mail from dial-up ports.\r\n");
1515 }
1516 return hardreject;
1517 }
1518
1519 /*
1520 * create abs path of the mailer
1521 */
1522 String*
mailerpath(char * p)1523 mailerpath(char *p)
1524 {
1525 String *s;
1526
1527 if(p == nil)
1528 return nil;
1529 if(*p == '/')
1530 return s_copy(p);
1531 s = s_new();
1532 s_append(s, UPASBIN);
1533 s_append(s, "/");
1534 s_append(s, p);
1535 return s;
1536 }
1537
1538 String *
s_dec64(String * sin)1539 s_dec64(String *sin)
1540 {
1541 int lin, lout;
1542 String *sout;
1543
1544 lin = s_len(sin);
1545
1546 /*
1547 * if the string is coming from smtpd.y, it will have no nl.
1548 * if it is coming from getcrnl below, it will have an nl.
1549 */
1550 if (*(s_to_c(sin)+lin-1) == '\n')
1551 lin--;
1552 sout = s_newalloc(lin+1);
1553 lout = dec64((uchar *)s_to_c(sout), lin, s_to_c(sin), lin);
1554 if (lout < 0) {
1555 s_free(sout);
1556 return nil;
1557 }
1558 sout->ptr = sout->base + lout;
1559 s_terminate(sout);
1560 return sout;
1561 }
1562
1563 void
starttls(void)1564 starttls(void)
1565 {
1566 int certlen, fd;
1567 uchar *cert;
1568 TLSconn *conn;
1569
1570 if (tlscert == nil) {
1571 reply("500 5.5.1 illegal command or bad syntax\r\n");
1572 return;
1573 }
1574 conn = mallocz(sizeof *conn, 1);
1575 cert = readcert(tlscert, &certlen);
1576 if (conn == nil || cert == nil) {
1577 if (conn != nil)
1578 free(conn);
1579 reply("454 4.7.5 TLS not available\r\n");
1580 return;
1581 }
1582 reply("220 2.0.0 Go ahead make my day\r\n");
1583 conn->cert = cert;
1584 conn->certlen = certlen;
1585 fd = tlsServer(Bfildes(&bin), conn);
1586 if (fd < 0) {
1587 free(cert);
1588 free(conn);
1589 syslog(0, "smtpd", "TLS start-up failed with %s", him);
1590
1591 /* force the client to hang up */
1592 close(Bfildes(&bin)); /* probably fd 0 */
1593 close(1);
1594 exits("tls failed");
1595 }
1596 Bterm(&bin);
1597 Binit(&bin, fd, OREAD);
1598 if (dup(fd, 1) < 0)
1599 fprint(2, "dup of %d failed: %r\n", fd);
1600 passwordinclear = 1;
1601 syslog(0, "smtpd", "started TLS with %s", him);
1602 }
1603
1604 void
auth(String * mech,String * resp)1605 auth(String *mech, String *resp)
1606 {
1607 char *user, *pass, *scratch = nil;
1608 AuthInfo *ai = nil;
1609 Chalstate *chs = nil;
1610 String *s_resp1_64 = nil, *s_resp2_64 = nil, *s_resp1 = nil;
1611 String *s_resp2 = nil;
1612
1613 if (rejectcheck())
1614 goto bomb_out;
1615
1616 syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech),
1617 "(protected)", him);
1618
1619 if (authenticated) {
1620 bad_sequence:
1621 rejectcount++;
1622 reply("503 5.5.2 Bad sequence of commands\r\n");
1623 goto bomb_out;
1624 }
1625 if (cistrcmp(s_to_c(mech), "plain") == 0) {
1626 if (!passwordinclear) {
1627 rejectcount++;
1628 reply("538 5.7.1 Encryption required for requested "
1629 "authentication mechanism\r\n");
1630 goto bomb_out;
1631 }
1632 s_resp1_64 = resp;
1633 if (s_resp1_64 == nil) {
1634 reply("334 \r\n");
1635 s_resp1_64 = s_new();
1636 if (getcrnl(s_resp1_64, &bin) <= 0)
1637 goto bad_sequence;
1638 }
1639 s_resp1 = s_dec64(s_resp1_64);
1640 if (s_resp1 == nil) {
1641 rejectcount++;
1642 reply("501 5.5.4 Cannot decode base64\r\n");
1643 goto bomb_out;
1644 }
1645 memset(s_to_c(s_resp1_64), 'X', s_len(s_resp1_64));
1646 user = s_to_c(s_resp1) + strlen(s_to_c(s_resp1)) + 1;
1647 pass = user + strlen(user) + 1;
1648 ai = auth_userpasswd(user, pass);
1649 authenticated = ai != nil;
1650 memset(pass, 'X', strlen(pass));
1651 goto windup;
1652 }
1653 else if (cistrcmp(s_to_c(mech), "login") == 0) {
1654 if (!passwordinclear) {
1655 rejectcount++;
1656 reply("538 5.7.1 Encryption required for requested "
1657 "authentication mechanism\r\n");
1658 goto bomb_out;
1659 }
1660 if (resp == nil) {
1661 reply("334 VXNlcm5hbWU6\r\n");
1662 s_resp1_64 = s_new();
1663 if (getcrnl(s_resp1_64, &bin) <= 0)
1664 goto bad_sequence;
1665 }
1666 reply("334 UGFzc3dvcmQ6\r\n");
1667 s_resp2_64 = s_new();
1668 if (getcrnl(s_resp2_64, &bin) <= 0)
1669 goto bad_sequence;
1670 s_resp1 = s_dec64(s_resp1_64);
1671 s_resp2 = s_dec64(s_resp2_64);
1672 memset(s_to_c(s_resp2_64), 'X', s_len(s_resp2_64));
1673 if (s_resp1 == nil || s_resp2 == nil) {
1674 rejectcount++;
1675 reply("501 5.5.4 Cannot decode base64\r\n");
1676 goto bomb_out;
1677 }
1678 ai = auth_userpasswd(s_to_c(s_resp1), s_to_c(s_resp2));
1679 authenticated = ai != nil;
1680 memset(s_to_c(s_resp2), 'X', s_len(s_resp2));
1681 windup:
1682 if (authenticated) {
1683 /* if you authenticated, we trust you despite your IP */
1684 trusted = 1;
1685 reply("235 2.0.0 Authentication successful\r\n");
1686 } else {
1687 rejectcount++;
1688 reply("535 5.7.1 Authentication failed\r\n");
1689 syslog(0, "smtpd", "authentication failed: %r");
1690 }
1691 goto bomb_out;
1692 }
1693 else if (cistrcmp(s_to_c(mech), "cram-md5") == 0) {
1694 int chal64n;
1695 char *resp, *t;
1696
1697 chs = auth_challenge("proto=cram role=server");
1698 if (chs == nil) {
1699 rejectcount++;
1700 reply("501 5.7.5 Couldn't get CRAM-MD5 challenge\r\n");
1701 goto bomb_out;
1702 }
1703 scratch = malloc(chs->nchal * 2 + 1);
1704 chal64n = enc64(scratch, chs->nchal * 2, (uchar *)chs->chal,
1705 chs->nchal);
1706 scratch[chal64n] = 0;
1707 reply("334 %s\r\n", scratch);
1708 s_resp1_64 = s_new();
1709 if (getcrnl(s_resp1_64, &bin) <= 0)
1710 goto bad_sequence;
1711 s_resp1 = s_dec64(s_resp1_64);
1712 if (s_resp1 == nil) {
1713 rejectcount++;
1714 reply("501 5.5.4 Cannot decode base64\r\n");
1715 goto bomb_out;
1716 }
1717 /* should be of form <user><space><response> */
1718 resp = s_to_c(s_resp1);
1719 t = strchr(resp, ' ');
1720 if (t == nil) {
1721 rejectcount++;
1722 reply("501 5.5.4 Poorly formed CRAM-MD5 response\r\n");
1723 goto bomb_out;
1724 }
1725 *t++ = 0;
1726 chs->user = resp;
1727 chs->resp = t;
1728 chs->nresp = strlen(t);
1729 ai = auth_response(chs);
1730 authenticated = ai != nil;
1731 goto windup;
1732 }
1733 rejectcount++;
1734 reply("501 5.5.1 Unrecognised authentication type %s\r\n", s_to_c(mech));
1735 bomb_out:
1736 if (ai)
1737 auth_freeAI(ai);
1738 if (chs)
1739 auth_freechal(chs);
1740 if (scratch)
1741 free(scratch);
1742 if (s_resp1)
1743 s_free(s_resp1);
1744 if (s_resp2)
1745 s_free(s_resp2);
1746 if (s_resp1_64)
1747 s_free(s_resp1_64);
1748 if (s_resp2_64)
1749 s_free(s_resp2_64);
1750 }
1751
1752