nmail-smtpd.c (18597B)
1 #include "sig.h" 2 #include "ndelay.h" 3 #include "readwrite.h" 4 #include "stralloc.h" 5 #include "substdio.h" 6 #include "alloc.h" 7 #include "auto_qmail.h" 8 #include "control.h" 9 #include "datetime.h" 10 #include "received.h" 11 #include "constmap.h" 12 #include "error.h" 13 #include "ipme.h" 14 #include "ip.h" 15 #include "qmail.h" 16 #include "str.h" 17 #include "fmt.h" 18 #include "scan.h" 19 #include "byte.h" 20 #include "case.h" 21 #include "env.h" 22 #include "now.h" 23 #include "exit.h" 24 #include "rcpthosts.h" 25 #include "realrcptto.h" 26 #include "timeoutread.h" 27 #include "timeoutwrite.h" 28 #include "commands.h" 29 #include "dns.h" 30 #include "fd.h" 31 32 #define MAXHOPS 100 33 unsigned int databytes = 0; 34 int timeout = 1200; 35 36 GEN_SAFE_TIMEOUTWRITE(safewrite, timeout, fd, _exit(10)) 37 38 char ssoutbuf[512]; 39 substdio ssout = SUBSTDIO_FDBUF(safewrite, 1, ssoutbuf, sizeof(ssoutbuf)); 40 41 void flush() { 42 substdio_flush(&ssout); 43 } 44 void out(s) 45 char *s; { 46 substdio_puts(&ssout, s); 47 } 48 49 void die_read() { 50 _exit(1); 51 } 52 void die_alarm() { 53 out("451 4.4.2 Timeout\r\n"); 54 flush(); 55 _exit(2); 56 } 57 void die_nomem() { 58 out("421 4.3.0 Out of memory\r\n"); 59 flush(); 60 _exit(3); 61 } 62 void die_control() { 63 out("421 4.3.0 Unable to read controls\r\n"); 64 flush(); 65 _exit(4); 66 } 67 void die_ipme() { 68 out("421 4.3.0 Unable to figure out my IP addresses\r\n"); 69 flush(); 70 _exit(5); 71 } 72 void die_ip6me() { 73 out("421 4.3.0 Unable to figure out my IPv6 addresses\r\n"); 74 flush(); 75 _exit(6); 76 } 77 void straynewline() { 78 out("451-You sent a stray newline. See https://cr.yp.to/docs/smtplf.html.\r\n451 This error should be going away soon."); 79 flush(); 80 _exit(1); 81 } 82 83 char ssebuf[1024]; 84 substdio sse = SUBSTDIO_FDBUF(write, 2, ssebuf, sizeof(ssebuf)); 85 void err(char *s){ 86 substdio_putsflush(&sse, s); 87 } 88 89 void err_bmf() { 90 out("553 5.7.1 Sorry, your envelope sender is in my badmailfrom list.\r\n"); 91 flush(); 92 } 93 void err_nogateway() { 94 out("553 5.7.1 Sorry, that domain isn't in my list of allowed rcpthosts\r\n"); 95 flush(); 96 } 97 void err_unimpl(char *arg){ 98 out("502 5.5.1 Unimplemented\r\n"); 99 flush(); 100 } 101 void err_syntax() { 102 out("555 5.5.4 Syntax error\r\n"); 103 flush(); 104 } 105 void die_wtf(int d, char *arg){ 106 out("421 4.3.2 inconsistent state: "); 107 out(arg); 108 out(" - shutting down!\r\n"); 109 flush(); 110 err("421 4.3.2 inconsistent state: "); 111 err(arg); 112 err(" - shutting down!\r\n"); 113 _exit(d); 114 } 115 void err_wantmail() { 116 out("503 5.5.1 You must execute MAIL first\r\n"); 117 flush(); 118 } 119 void err_wantrcpt() { 120 out("503 5.5.1 You must execute RCPT first\r\n"); 121 flush(); 122 } 123 void err_notlshere() { 124 out("454 4.7.6 STARTTLS is not available at this site.\r\n"); 125 flush(); 126 } 127 void err_alreadytlshere() { 128 out("454 5.7.6 STARTTLS is already active on this connection.\r\n"); 129 flush(); 130 } 131 void die_cdb() { 132 out("421 4.3.0 Unable to read cdb user database\r\n"); 133 flush(); 134 _exit(7); 135 } 136 void die_sys() { 137 out("421 4.3.0 Unable to read system user database\r\n"); 138 flush(); 139 _exit(8); 140 } 141 void die_addresses() { 142 out("501 5.3.0 That's too many addresses!\r\n"); 143 flush(); 144 _exit(11); 145 } 146 void err_addresses() { 147 out("501 5.3.0 That's too many addresses!\r\n"); 148 flush(); 149 } 150 void err_noop(char *arg){ 151 out("250 As requested, no operation performed.\r\n"); 152 flush(); 153 } 154 void err_vrfy(char *arg){ 155 out("252 Send something and we'll give it a shot.\r\n"); 156 flush(); 157 } 158 void err_qqt() { 159 out("451 4.3.0 Temporarily unavailable: cannot inject message into queue.\r\n"); 160 flush(); 161 } 162 void 163 die_dnsbl(char *arg) 164 { 165 out("421 Your IP is currently blacklisted. If available at this site, auth first. ("); 166 out(arg); 167 out(")\r\n"); 168 flush(); 169 _exit(9); 170 } 171 172 stralloc greeting = {0}; 173 int starttlsready = 0, sslctlfd = -1, sslrfd = -1, sslwfd = -1, isstarttls = 0, isesmtp = 0; 174 175 void 176 smtp_greet(code) 177 char *code; 178 { 179 substdio_puts(&ssout, code); 180 substdio_put(&ssout, greeting.s, greeting.len); 181 } 182 void 183 smtp_help(char *arg) 184 { 185 out("214-NightmareMail home page: <https://umbrellix.net./software/nightmaremail/index.html>\r\n"); 186 out("214-NightmareMail is based on notqmail. notqmail home page: <https://notqmail.org>\r\n"); 187 out("214-We accept the following commands: HELO, EHLO, (SEND/SOML/SAML/MAIL) FROM:<, RCPT TO:<, DATA, RSET"); 188 if (starttlsready) 189 out(", STARTTLS"); 190 out("\r\n"); 191 out("214 Note that SMTP is not a user interface. It should only be used thus to verify correct operation of the mail system.\r\n"); 192 } 193 void 194 smtp_quit(char *arg) 195 { 196 smtp_greet("221 "); 197 out("\r\n"); 198 flush(); 199 _exit(0); 200 } 201 202 char *remoteip; 203 char *remotehost; 204 char *remoteinfo; 205 char *local; 206 char *relayclient; 207 char *dnsblskip; 208 209 stralloc helohost = {0}; 210 char *fakehelo; /* pointer into helohost, or 0 */ 211 212 void 213 dohelo(char *arg) 214 { 215 if (!stralloc_copys(&helohost, arg)) 216 die_nomem(); 217 if (!stralloc_0(&helohost)) 218 die_nomem(); 219 fakehelo = case_diffs(remotehost, helohost.s) ? helohost.s : 0; 220 } 221 222 int liphostok = 0; 223 stralloc liphost = {0}; 224 int bmfok = 0; 225 stralloc bmf = {0}; 226 struct constmap mapbmf; 227 228 void 229 setuptls() 230 { 231 char *x; 232 unsigned long u; 233 234 x = env_get("SSLCTLFD"); 235 if (x) { 236 scan_ulong(x, &u); 237 sslctlfd = u; 238 } else 239 return; 240 x = env_get("SSLREADFD"); 241 if (x) { 242 scan_ulong(x, &u); 243 sslrfd = u; 244 } else 245 return; 246 x = env_get("SSLWRITEFD"); 247 if (x) { 248 scan_ulong(x, &u); 249 sslwfd = u; 250 } else 251 return; 252 ndelay_on(sslctlfd); 253 /* ndelay_on(sslrfd); */ 254 /* ndelay_on(sslwfd); */ 255 starttlsready = 1; /* when reached, then we can do starttls */ 256 return; 257 } 258 259 int seenmail = 0; 260 int flagbarf; /* defined when seenmail */ 261 stralloc mailfrom = {0}; 262 stralloc rcptto = {0}; 263 int rcpttos = 0, maxrcpttos = 5; 264 265 void 266 setup() 267 { 268 char *x; 269 unsigned long u; 270 271 if (control_init() == -1) 272 die_control(); 273 if (control_rldef(&greeting, "control/smtpgreeting", 1, NULL) != 1) 274 die_control(); 275 liphostok = control_rldef(&liphost, "control/localiphost", 1, NULL); 276 if (liphostok == -1) 277 die_control(); 278 if (control_readint(&timeout, "control/timeoutsmtpd") == -1) 279 die_control(); 280 if (timeout <= 0) 281 timeout = 1; 282 283 if (rcpthosts_init() == -1) 284 die_control(); 285 286 bmfok = control_readfile(&bmf, "control/badmailfrom", 0); 287 if (bmfok == -1) 288 die_control(); 289 if (bmfok) 290 if (!constmap_init(&mapbmf, bmf.s, bmf.len, 0)) 291 die_nomem(); 292 293 /* manually merged from prj's realrcptto patch */ 294 realrcptto_init(); 295 296 if (control_readint(&databytes, "control/databytes") == -1) 297 die_control(); 298 if (control_readint(&maxrcpttos, "control/maxrcpts") == -1) 299 maxrcpttos = 128; /* proceed with this limit */ 300 x = env_get("DATABYTES"); 301 if (x) { 302 scan_ulong(x, &u); 303 databytes = u; 304 } 305 if (!(databytes + 1)) 306 --databytes; 307 setuptls(); 308 309 remoteip = env_get("TCPREMOTEIP"); 310 if (!remoteip) 311 remoteip = "unknown"; 312 local = env_get("TCPLOCALHOST"); 313 if (!local) 314 local = env_get("TCPLOCALIP"); 315 if (!local) 316 local = "unknown"; 317 remotehost = env_get("TCPREMOTEHOST"); 318 if (!remotehost) 319 remotehost = "unknown"; 320 remoteinfo = env_get("TCPREMOTEINFO"); 321 relayclient = env_get("RELAYCLIENT"); 322 dnsblskip = env_get("DNSBLSKIP"); 323 dohelo(remotehost); 324 } 325 326 extern void realrcptto_init(); 327 extern void realrcptto_start(); 328 extern int realrcptto(); 329 extern int realrcptto_deny(); 330 331 stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ 332 333 int 334 addrparse(char *arg) 335 { 336 int i; 337 char ch; 338 char terminator; 339 struct ip_address ip; 340 int flagesc; 341 int flagquoted; 342 343 terminator = '>'; 344 i = str_chr(arg, '<'); 345 if (arg[i]) 346 arg += i + 1; 347 else { /* partner should go read rfc 821 */ 348 terminator = ' '; 349 arg += str_chr(arg, ':'); 350 if (*arg == ':') 351 ++arg; 352 while (*arg == ' ') 353 ++arg; 354 } 355 356 /* strip source route 357 * query: should source route really be stripped? L */ 358 if (*arg == '@') 359 while (*arg) 360 if (*arg++ == ':') 361 break; 362 363 if (!stralloc_copys(&addr, "")) 364 die_nomem(); 365 flagesc = 0; 366 flagquoted = 0; 367 for (i = 0; (ch = arg[i]); ++i) { /* copy arg to addr, stripping quotes */ 368 if (flagesc) { 369 if (!stralloc_append(&addr, &ch)) 370 die_nomem(); 371 flagesc = 0; 372 } else { 373 if (!flagquoted && (ch == terminator)) 374 break; 375 switch (ch) { 376 case '\\': 377 flagesc = 1; 378 break; 379 case '"': 380 flagquoted = !flagquoted; 381 break; 382 default: 383 if (!stralloc_append(&addr, &ch)) 384 die_nomem(); 385 } 386 } 387 } 388 /* could check for termination failure here, but why bother? */ 389 if (!stralloc_append(&addr, "")) 390 die_nomem(); 391 392 if (liphostok) { 393 i = byte_rchr(addr.s, addr.len, '@'); 394 if (i < addr.len) /* if not, partner should go read rfc 821 */ 395 if (addr.s[i + 1] == '[') 396 if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1, &ip)]) 397 if (ipme_is(&ip)) { 398 addr.len = i + 1; 399 if (!stralloc_cat(&addr, &liphost)) 400 die_nomem(); 401 if (!stralloc_0(&addr)) 402 die_nomem(); 403 } 404 } 405 406 if (addr.len > 900) 407 return 0; 408 return 1; 409 } 410 411 int 412 bmfcheck() 413 { 414 int j; 415 if (!bmfok) 416 return 0; 417 if (constmap(&mapbmf, addr.s, addr.len - 1)) 418 return 1; 419 j = byte_rchr(addr.s, addr.len, '@'); 420 if (j < addr.len) 421 if (constmap(&mapbmf, addr.s + j, addr.len - j - 1)) 422 return 1; 423 return 0; 424 } 425 426 int 427 addrallowed() 428 { 429 int r; 430 r = rcpthosts(addr.s, str_len(addr.s)); 431 if (r == -1) 432 die_control(); 433 return r; 434 } 435 436 int flagdnsbl = 0; 437 stralloc dnsblhost = {0}; 438 439 int 440 dnsblcheck() 441 { 442 char *ch; 443 static stralloc dnsblbyte = { 444 0 445 }; 446 static stralloc dnsblrev = { 447 0 448 }; 449 static ipalloc dnsblip = { 450 0 451 }; 452 static ip6alloc dnsblip6 = { 453 0 454 }; 455 static stralloc dnsbllist = { 456 0 457 }; 458 459 ch = remoteip; 460 if (control_readfile(&dnsbllist, "control/dnsbllist", 0) != 1) 461 return 0; 462 463 if (!stralloc_copys(&dnsblrev, "")) 464 return 0; 465 for (;;) { 466 if (!stralloc_copys(&dnsblbyte, "")) 467 return 0; 468 while (ch[0] && (ch[0] != '.')) { 469 if (!stralloc_append(&dnsblbyte, ch)) 470 return 0; 471 ch++; 472 } 473 if (!stralloc_append(&dnsblbyte, ".")) 474 return 0; 475 if (!stralloc_cat(&dnsblbyte, &dnsblrev)) 476 return 0; 477 if (!stralloc_copy(&dnsblrev, &dnsblbyte)) 478 return 0; 479 480 if (!ch[0]) 481 break; 482 ch++; 483 } 484 485 flagdnsbl = 1; 486 ch = dnsbllist.s; 487 while (ch < (dnsbllist.s + dnsbllist.len)) { 488 if (!stralloc_copy(&dnsblhost, &dnsblrev)) 489 return 0; 490 if (!stralloc_cats(&dnsblhost, ch)) 491 return 0; 492 if (!stralloc_0(&dnsblhost)) 493 return 0; 494 495 if (!dns_ip(&dnsblip, &dnsblhost)) 496 return 1; 497 while (*ch++); 498 } 499 500 return 0; 501 } 502 503 ssize_t 504 saferead(int fd, void *buf, size_t len) 505 { 506 ssize_t r; 507 r = timeoutread(timeout, fd, buf, len); 508 if (r == -1) 509 if (errno == error_timeout) 510 die_alarm(); 511 if (r == 0 || r == -1) 512 die_read(); 513 return r; 514 } 515 516 char ssinbuf[1024]; 517 substdio ssin = SUBSTDIO_FDBUF(saferead, 0, ssinbuf, sizeof(ssinbuf)); 518 519 520 void 521 smtp_starttls(char *arg) 522 { 523 char fdou[1920]; /* compare skarnet s-s-proxy: OUTSIZE 1920. Me thinks I cribbed too much. */ 524 ssize_t hsread = 0, hsr = 0; 525 if (str_len(arg) != 0) { 526 err_syntax(); 527 return; 528 } 529 if (!starttlsready) { 530 err_notlshere(); 531 return; 532 } 533 if (timeoutwrite(1, sslctlfd, "Y", 1) != 1) { 534 die_wtf(errno, "could not cut over to TLS in one second"); 535 } 536 out("220 2.7.0 Ready to start TLS\r\n"); 537 substdio_flush(&ssout); 538 for (;;) { 539 hsread += (hsr = timeoutread(1, sslctlfd, fdou, 1920)); 540 if (hsr < 0) { 541 if (errno != EAGAIN) 542 die_wtf(errno, "could not cut over to TLS in 1 second"); 543 } 544 if (!hsr) 545 break; 546 isstarttls = 1; /* just use the global variable (TODO: make TL when npthread) */ 547 } 548 if (!isstarttls) { 549 _exit(10); 550 } 551 /* At this point, we are starttls. We must now cut sslwfd to fd 1 and sslrfd to fd 0. */ 552 ssout.fd = sslwfd; 553 ssin.fd = sslrfd; 554 substdio_flush(&ssout); 555 substdio_flush(&sse); 556 } 557 void 558 smtp_helo(char *arg) 559 { 560 smtp_greet("250 "); 561 out("\r\n"); 562 seenmail = 0; 563 dohelo(arg); 564 } 565 void 566 smtp_ehlo(char *arg) 567 { 568 isesmtp = 1; 569 smtp_greet("250-"); 570 out("\r\n"); 571 out("250-PIPELINING\r\n"); 572 out("250-ENHANCEDSTATUSCODES\r\n"); 573 /* TODO: add startTLS cutover support */ 574 if (starttlsready && !isstarttls) { 575 out("250-8BITMIME\r\n"); 576 out("250 STARTTLS\r\n"); 577 } else 578 out("250 8BITMIME\r\n"); 579 seenmail = 0; 580 dohelo(arg); 581 } 582 void 583 smtp_rset(char *arg) 584 { 585 seenmail = 0; 586 out("250 Envelope flushed\r\n"); 587 } 588 void 589 smtp_mail(char *arg) 590 { 591 if (!addrparse(arg)) { 592 err_syntax(); 593 return; 594 } 595 flagbarf = bmfcheck(); 596 seenmail = 1; 597 if (!stralloc_copys(&rcptto, "")) 598 die_nomem(); 599 if (!stralloc_copys(&mailfrom, addr.s)) 600 die_nomem(); 601 if (!stralloc_0(&mailfrom)) 602 die_nomem(); 603 realrcptto_start(); 604 out("250 Go on...\r\n"); 605 } 606 void 607 smtp_rcpt(char *arg) 608 { 609 if (!seenmail) { 610 err_wantmail(); 611 return; 612 } 613 if (!addrparse(arg)) { 614 err_syntax(); 615 return; 616 } 617 if (flagbarf) { 618 err_bmf(); 619 return; 620 } 621 if (relayclient) { 622 --addr.len; 623 if (!stralloc_cats(&addr, relayclient)) 624 die_nomem(); 625 if (!stralloc_0(&addr)) 626 die_nomem(); 627 } else if (!addrallowed()) { 628 err_nogateway(); 629 return; 630 } 631 if (rcpttos > maxrcpttos) { 632 err_addresses(); 633 return; 634 } 635 if (!realrcptto(addr.s)) { 636 out("550 5.1.1 That user has elected not to receive emails.\r\n"); 637 return; 638 } 639 if (!(relayclient || dnsblskip || flagdnsbl)) 640 if (dnsblcheck()) 641 die_dnsbl(dnsblhost.s); 642 if (!stralloc_cats(&rcptto, "T")) 643 die_nomem(); 644 if (!stralloc_cats(&rcptto, addr.s)) 645 die_nomem(); 646 if (!stralloc_0(&rcptto)) 647 die_nomem(); 648 ++rcpttos; 649 out("250 Go on...\r\n"); 650 } 651 652 struct qmail qqt; 653 unsigned int bytestooverflow = 0; 654 655 void 656 put(char *ch) 657 { 658 if (bytestooverflow) 659 if (!--bytestooverflow) 660 qmail_fail(&qqt); 661 qmail_put(&qqt, ch, 1); 662 } 663 664 void 665 blast(int *hops) 666 { 667 char ch; 668 int state; 669 int flaginheader; 670 int pos; /* number of bytes since most recent \n, if fih */ 671 int flagmaybex; /* 1 if this line might match RECEIVED, if fih */ 672 int flagmaybey; /* 1 if this line might match \r\n, if fih */ 673 int flagmaybez; /* 1 if this line might match DELIVERED, if fih */ 674 675 state = 1; 676 *hops = 0; 677 flaginheader = 1; 678 pos = 0; 679 flagmaybex = flagmaybey = flagmaybez = 1; 680 for (;;) { 681 /* This isn't very optimized -- Amelia B */ 682 substdio_get(&ssin, &ch, 1); 683 if (flaginheader) { 684 if (pos >= 0 && pos < 9) { /* something about method and madness? bro literally just use strcmp it won't hurt you */ 685 if (ch != "delivered"[pos]) 686 if (ch != "DELIVERED"[pos]) 687 flagmaybez = 0; 688 if (flagmaybez) 689 if (pos == 8) 690 ++* hops; 691 if (pos < 8) 692 if (ch != "received"[pos]) 693 if (ch != "RECEIVED"[pos]) 694 flagmaybex = 0; 695 if (flagmaybex) 696 if (pos == 7) 697 ++* hops; 698 if (pos < 2) 699 if (ch != "\r\n"[pos]) 700 flagmaybey = 0; 701 if (flagmaybey) 702 if (pos == 1) 703 flaginheader = 0; 704 ++pos; 705 } 706 if (ch == '\n') { 707 pos = 0; 708 flagmaybex = flagmaybey = flagmaybez = 1; 709 } 710 } 711 switch (state) { 712 case 0: 713 if (ch == '\n') 714 straynewline(); 715 if (ch == '\r') { 716 state = 4; 717 continue; 718 } 719 break; 720 case 1: /* \r\n */ 721 if (ch == '\n') 722 straynewline(); 723 if (ch == '.') { 724 state = 2; 725 continue; 726 } 727 if (ch == '\r') { 728 state = 4; 729 continue; 730 } 731 state = 0; 732 break; 733 case 2: /* \r\n + . */ 734 if (ch == '\n') 735 straynewline(); 736 if (ch == '\r') { 737 state = 3; 738 continue; 739 } 740 state = 0; 741 break; 742 case 3: /* \r\n + .\r */ 743 if (ch == '\n') 744 return; 745 put("."); 746 put("\r"); 747 if (ch == '\r') { 748 state = 4; 749 continue; 750 } 751 state = 0; 752 break; 753 case 4: /* + \r */ 754 if (ch == '\n') { 755 state = 1; 756 break; 757 } 758 if (ch != '\r') { 759 put("\r"); 760 state = 0; 761 } 762 } 763 put(&ch); 764 } 765 } 766 767 char accept_buf[FMT_ULONG]; 768 void 769 acceptmessage(qp) 770 unsigned long qp; 771 { 772 datetime_sec when; 773 when = now(); 774 out("250 Accepted responsibility at time "); 775 accept_buf[fmt_ulong(accept_buf, (unsigned long)when)] = 0; 776 out(accept_buf); 777 out(" queue process "); 778 accept_buf[fmt_ulong(accept_buf, qp)] = 0; 779 out(accept_buf); 780 out(" - we'll do our best!\r\n"); 781 flush(); 782 } 783 784 /* 785 unsigned long alen, plen, len; 786 787 if (databytes && ((alen = str_len(arg)) != 0)) { 788 / We now accept the optional argument to DATA which is a ulong which must < databytes + 1. 789 plen = scan_ulong(arg, &len); 790 if (alen != plen) { err_syntax(); return; } // crap at the end of the argument 791 if (len > databytes) { out("552 5.3.4 This message is too big for me (rapid rejection).\r\n"); return; } 792 } 793 */ 794 void 795 smtp_data(char *arg) 796 { 797 int hops; 798 unsigned long qp; 799 char *qqx; 800 char *esmtps; 801 802 if (!seenmail) { 803 err_wantmail(); 804 return; 805 } 806 if (!rcptto.len) { 807 err_wantrcpt(); 808 return; 809 } 810 if (realrcptto_deny()) { 811 out("554 5.1.1 That user has elected not to receive emails.\r\n"); 812 return; 813 } 814 seenmail = 0; 815 if (databytes) 816 bytestooverflow = databytes + 1; 817 if (qmail_open(&qqt) == -1) { 818 err_qqt(); 819 return; 820 } 821 qp = qmail_qp(&qqt); 822 out("354 go ahead\r\n"); 823 substdio_flush(&ssout); 824 825 switch ((isesmtp & 1) + ((isstarttls & 1) << 1) + ((relayclient != NULL) << 2)) { 826 case 7: 827 esmtps = "ESMTPSA"; 828 break; 829 case 6: 830 esmtps = "SMTPSA"; /* Compliant clients should never do this, but it's not pathological. */ 831 break; 832 case 5: 833 esmtps = "ESMTPA"; 834 break; 835 case 4: 836 esmtps = "SMTPA"; /* Clients, at all, will never do this, as we don't process SMTP AUTH. */ 837 break; 838 case 3: 839 esmtps = "ESMTPS"; 840 break; 841 case 2: 842 esmtps = "SMTPS"; /* Compliant clients should never do this, but it's not pathological. */ 843 break; 844 case 1: 845 esmtps = "ESMTP"; 846 break; 847 default: 848 esmtps = "SMTP"; 849 } 850 received(&qqt, esmtps, local, remoteip, remotehost, remoteinfo, fakehelo); 851 blast(&hops); 852 hops = (hops >= MAXHOPS); 853 if (hops) 854 qmail_fail(&qqt); 855 qmail_from(&qqt, mailfrom.s); 856 qmail_put(&qqt, rcptto.s, rcptto.len); 857 858 qqx = qmail_close(&qqt); 859 if (!*qqx) { 860 acceptmessage(qp); 861 return; 862 } 863 if (hops) { 864 out("554 5.4.6 This message has gone through too many SMTP, QMTP or other mail protocol servers; it may be looping. It ends with me.\r\n"); 865 return; 866 } 867 if (databytes) 868 if (!bytestooverflow) { 869 out("552 5.3.4 This message is too big for me.\r\n"); 870 return; 871 } 872 if (*qqx == 'D') 873 out("554 "); 874 else 875 out("451 "); 876 out(qqx + 1); 877 out("\r\n"); 878 } 879 880 struct commands smtpcommands[] = { 881 {"rcpt", smtp_rcpt, flush} 882 ,{"mail", smtp_mail, flush} 883 ,{"send", smtp_mail, flush} /* not recommended */ 884 ,{"soml", smtp_mail, flush} /* not recommended */ 885 ,{"saml", smtp_mail, flush} /* not recommended */ 886 ,{"data", smtp_data, flush} 887 ,{"quit", smtp_quit, flush} 888 ,{"helo", smtp_helo, flush} 889 ,{"ehlo", smtp_ehlo, flush} 890 ,{"rset", smtp_rset, flush} 891 ,{"help", smtp_help, flush} 892 ,{"starttls", smtp_starttls, flush} 893 ,{"noop", err_noop, flush} 894 ,{"vrfy", err_vrfy, flush} 895 ,{0, err_unimpl, flush} 896 }; 897 898 int 899 main(void) 900 { 901 /* ndelay_on(0); */ 902 /* ndelay_on(1); */ 903 maxrcpttos = 5; // will be overwritten 904 sig_pipeignore(); 905 if (chdir(auto_qmail) == -1) 906 die_control(); 907 setup(); 908 if (ipme_init() != 1) 909 die_ipme(); 910 if (ip6me_init() != 1) 911 die_ip6me(); 912 smtp_greet("220 "); 913 out(" ESMTP\r\n"); 914 substdio_flush(&ssout); 915 if (commands(&ssin, &smtpcommands) == 0) 916 die_read(); 917 die_nomem(); 918 }