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