1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 # include "sendmail.h" 14 15 #ifndef lint 16 #if SMTP 17 static char sccsid[] = "@(#)srvrsmtp.c 8.181 (Berkeley) 6/15/98 (with SMTP)"; 18 #else 19 static char sccsid[] = "@(#)srvrsmtp.c 8.181 (Berkeley) 6/15/98 (without SMTP)"; 20 #endif 21 #endif /* not lint */ 22 23 # include <errno.h> 24 25 # if SMTP 26 27 /* 28 ** SMTP -- run the SMTP protocol. 29 ** 30 ** Parameters: 31 ** nullserver -- if non-NULL, rejection message for 32 ** all SMTP commands. 33 ** e -- the envelope. 34 ** 35 ** Returns: 36 ** never. 37 ** 38 ** Side Effects: 39 ** Reads commands from the input channel and processes 40 ** them. 41 */ 42 43 struct cmd 44 { 45 char *cmdname; /* command name */ 46 int cmdcode; /* internal code, see below */ 47 }; 48 49 /* values for cmdcode */ 50 # define CMDERROR 0 /* bad command */ 51 # define CMDMAIL 1 /* mail -- designate sender */ 52 # define CMDRCPT 2 /* rcpt -- designate recipient */ 53 # define CMDDATA 3 /* data -- send message text */ 54 # define CMDRSET 4 /* rset -- reset state */ 55 # define CMDVRFY 5 /* vrfy -- verify address */ 56 # define CMDEXPN 6 /* expn -- expand address */ 57 # define CMDNOOP 7 /* noop -- do nothing */ 58 # define CMDQUIT 8 /* quit -- close connection and die */ 59 # define CMDHELO 9 /* helo -- be polite */ 60 # define CMDHELP 10 /* help -- give usage info */ 61 # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 62 # define CMDETRN 12 /* etrn -- flush queue */ 63 /* non-standard commands */ 64 # define CMDONEX 16 /* onex -- sending one transaction only */ 65 # define CMDVERB 17 /* verb -- go into verbose mode */ 66 # define CMDXUSR 18 /* xusr -- initial (user) submission */ 67 /* use this to catch and log "door handle" attempts on your system */ 68 # define CMDLOGBOGUS 23 /* bogus command that should be logged */ 69 /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 70 # define CMDDBGQSHOW 24 /* showq -- show send queue */ 71 # define CMDDBGDEBUG 25 /* debug -- set debug mode */ 72 73 static struct cmd CmdTab[] = 74 { 75 { "mail", CMDMAIL }, 76 { "rcpt", CMDRCPT }, 77 { "data", CMDDATA }, 78 { "rset", CMDRSET }, 79 { "vrfy", CMDVRFY }, 80 { "expn", CMDEXPN }, 81 { "help", CMDHELP }, 82 { "noop", CMDNOOP }, 83 { "quit", CMDQUIT }, 84 { "helo", CMDHELO }, 85 { "ehlo", CMDEHLO }, 86 { "etrn", CMDETRN }, 87 { "verb", CMDVERB }, 88 { "onex", CMDONEX }, 89 { "xusr", CMDXUSR }, 90 /* remaining commands are here only to trap and log attempts to use them */ 91 { "showq", CMDDBGQSHOW }, 92 { "debug", CMDDBGDEBUG }, 93 { "wiz", CMDLOGBOGUS }, 94 95 { NULL, CMDERROR } 96 }; 97 98 bool OneXact = FALSE; /* one xaction only this run */ 99 char *CurSmtpClient; /* who's at the other end of channel */ 100 101 static char *skipword __P((char *volatile, char *)); 102 103 104 #define MAXBADCOMMANDS 25 /* maximum number of bad commands */ 105 #define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */ 106 #define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */ 107 #define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */ 108 #define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */ 109 110 void 111 smtp(nullserver, e) 112 char *nullserver; 113 register ENVELOPE *volatile e; 114 { 115 register char *volatile p; 116 register struct cmd *c; 117 char *cmd; 118 auto ADDRESS *vrfyqueue; 119 ADDRESS *a; 120 volatile bool gotmail; /* mail command received */ 121 volatile bool gothello; /* helo command received */ 122 bool vrfy; /* set if this is a vrfy command */ 123 char *volatile protocol; /* sending protocol */ 124 char *volatile sendinghost; /* sending hostname */ 125 char *volatile peerhostname; /* name of SMTP peer or "localhost" */ 126 auto char *delimptr; 127 char *id; 128 volatile int nrcpts = 0; /* number of RCPT commands */ 129 bool doublequeue; 130 bool discard; 131 volatile int badcommands = 0; /* count of bad commands */ 132 volatile int nverifies = 0; /* count of VRFY/EXPN commands */ 133 volatile int n_etrn = 0; /* count of ETRN commands */ 134 volatile int n_noop = 0; /* count of NOOP/VERB/ONEX etc cmds */ 135 volatile int n_helo = 0; /* count of HELO/EHLO commands */ 136 bool ok; 137 volatile int lognullconnection = TRUE; 138 register char *q; 139 QUEUE_CHAR *new; 140 char inp[MAXLINE]; 141 char cmdbuf[MAXLINE]; 142 extern ENVELOPE BlankEnvelope; 143 extern void help __P((char *)); 144 extern void settime __P((ENVELOPE *)); 145 extern bool enoughdiskspace __P((long)); 146 extern int runinchild __P((char *, ENVELOPE *)); 147 extern void checksmtpattack __P((volatile int *, int, char *, ENVELOPE *)); 148 149 if (fileno(OutChannel) != fileno(stdout)) 150 { 151 /* arrange for debugging output to go to remote host */ 152 (void) dup2(fileno(OutChannel), fileno(stdout)); 153 } 154 settime(e); 155 peerhostname = RealHostName; 156 if (peerhostname == NULL) 157 peerhostname = "localhost"; 158 CurHostName = peerhostname; 159 CurSmtpClient = macvalue('_', e); 160 if (CurSmtpClient == NULL) 161 CurSmtpClient = CurHostName; 162 163 /* check_relay may have set discard bit, save for later */ 164 discard = bitset(EF_DISCARD, e->e_flags); 165 166 setproctitle("server %s startup", CurSmtpClient); 167 #if DAEMON 168 if (LogLevel > 11) 169 { 170 /* log connection information */ 171 sm_syslog(LOG_INFO, NOQID, 172 "SMTP connect from %.100s (%.100s)", 173 CurSmtpClient, anynet_ntoa(&RealHostAddr)); 174 } 175 #endif 176 177 /* output the first line, inserting "ESMTP" as second word */ 178 expand(SmtpGreeting, inp, sizeof inp, e); 179 p = strchr(inp, '\n'); 180 if (p != NULL) 181 *p++ = '\0'; 182 id = strchr(inp, ' '); 183 if (id == NULL) 184 id = &inp[strlen(inp)]; 185 cmd = p == NULL ? "220 %.*s ESMTP%s" : "220-%.*s ESMTP%s"; 186 message(cmd, id - inp, inp, id); 187 188 /* output remaining lines */ 189 while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) 190 { 191 *p++ = '\0'; 192 if (isascii(*id) && isspace(*id)) 193 id++; 194 message("220-%s", id); 195 } 196 if (id != NULL) 197 { 198 if (isascii(*id) && isspace(*id)) 199 id++; 200 message("220 %s", id); 201 } 202 203 protocol = NULL; 204 sendinghost = macvalue('s', e); 205 gothello = FALSE; 206 gotmail = FALSE; 207 for (;;) 208 { 209 /* arrange for backout */ 210 (void) setjmp(TopFrame); 211 QuickAbort = FALSE; 212 HoldErrs = FALSE; 213 SuprErrs = FALSE; 214 LogUsrErrs = FALSE; 215 OnlyOneError = TRUE; 216 e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); 217 218 /* setup for the read */ 219 e->e_to = NULL; 220 Errors = 0; 221 (void) fflush(stdout); 222 223 /* read the input line */ 224 SmtpPhase = "server cmd read"; 225 setproctitle("server %s cmd read", CurSmtpClient); 226 p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand, 227 SmtpPhase); 228 229 /* handle errors */ 230 if (p == NULL) 231 { 232 /* end of file, just die */ 233 disconnect(1, e); 234 message("421 %s Lost input channel from %s", 235 MyHostName, CurSmtpClient); 236 if (LogLevel > (gotmail ? 1 : 19)) 237 sm_syslog(LOG_NOTICE, e->e_id, 238 "lost input channel from %.100s", 239 CurSmtpClient); 240 if (lognullconnection && LogLevel > 5) 241 sm_syslog(LOG_INFO, NULL, 242 "Null connection from %.100s", 243 CurSmtpClient); 244 245 /* 246 ** If have not accepted mail (DATA), do not bounce 247 ** bad addresses back to sender. 248 */ 249 if (bitset(EF_CLRQUEUE, e->e_flags)) 250 e->e_sendqueue = NULL; 251 252 if (InChild) 253 ExitStat = EX_QUIT; 254 finis(); 255 } 256 257 /* clean up end of line */ 258 fixcrlf(inp, TRUE); 259 260 /* echo command to transcript */ 261 if (e->e_xfp != NULL) 262 fprintf(e->e_xfp, "<<< %s\n", inp); 263 264 if (LogLevel >= 15) 265 sm_syslog(LOG_INFO, e->e_id, 266 "<-- %s", 267 inp); 268 269 if (e->e_id == NULL) 270 setproctitle("%s: %.80s", CurSmtpClient, inp); 271 else 272 setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); 273 274 /* break off command */ 275 for (p = inp; isascii(*p) && isspace(*p); p++) 276 continue; 277 cmd = cmdbuf; 278 while (*p != '\0' && 279 !(isascii(*p) && isspace(*p)) && 280 cmd < &cmdbuf[sizeof cmdbuf - 2]) 281 *cmd++ = *p++; 282 *cmd = '\0'; 283 284 /* throw away leading whitespace */ 285 while (isascii(*p) && isspace(*p)) 286 p++; 287 288 /* decode command */ 289 for (c = CmdTab; c->cmdname != NULL; c++) 290 { 291 if (!strcasecmp(c->cmdname, cmdbuf)) 292 break; 293 } 294 295 /* reset errors */ 296 errno = 0; 297 298 /* 299 ** Process command. 300 ** 301 ** If we are running as a null server, return 550 302 ** to everything. 303 */ 304 305 if (nullserver != NULL) 306 { 307 switch (c->cmdcode) 308 { 309 case CMDQUIT: 310 case CMDHELO: 311 case CMDEHLO: 312 case CMDNOOP: 313 /* process normally */ 314 break; 315 316 default: 317 if (++badcommands > MAXBADCOMMANDS) 318 sleep(1); 319 usrerr("550 %s", nullserver); 320 continue; 321 } 322 } 323 324 /* non-null server */ 325 switch (c->cmdcode) 326 { 327 case CMDMAIL: 328 case CMDEXPN: 329 case CMDVRFY: 330 case CMDETRN: 331 lognullconnection = FALSE; 332 } 333 334 switch (c->cmdcode) 335 { 336 case CMDHELO: /* hello -- introduce yourself */ 337 case CMDEHLO: /* extended hello */ 338 if (c->cmdcode == CMDEHLO) 339 { 340 protocol = "ESMTP"; 341 SmtpPhase = "server EHLO"; 342 } 343 else 344 { 345 protocol = "SMTP"; 346 SmtpPhase = "server HELO"; 347 } 348 349 /* avoid denial-of-service */ 350 checksmtpattack(&n_helo, MAXHELOCOMMANDS, "HELO/EHLO", e); 351 352 /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ 353 if (gothello) 354 { 355 usrerr("503 %s Duplicate HELO/EHLO", 356 MyHostName); 357 break; 358 } 359 360 /* check for valid domain name (re 1123 5.2.5) */ 361 if (*p == '\0' && !AllowBogusHELO) 362 { 363 usrerr("501 %s requires domain address", 364 cmdbuf); 365 break; 366 } 367 368 /* check for long domain name (hides Received: info) */ 369 if (strlen(p) > MAXNAME) 370 { 371 usrerr("501 Invalid domain name"); 372 break; 373 } 374 375 for (q = p; *q != '\0'; q++) 376 { 377 if (!isascii(*q)) 378 break; 379 if (isalnum(*q)) 380 continue; 381 if (isspace(*q)) 382 { 383 *q = '\0'; 384 break; 385 } 386 if (strchr("[].-_#", *q) == NULL) 387 break; 388 } 389 if (*q == '\0') 390 { 391 q = "pleased to meet you"; 392 sendinghost = newstr(p); 393 } 394 else if (!AllowBogusHELO) 395 { 396 usrerr("501 Invalid domain name"); 397 break; 398 } 399 else 400 { 401 q = "accepting invalid domain name"; 402 } 403 404 gothello = TRUE; 405 406 /* print HELO response message */ 407 if (c->cmdcode != CMDEHLO || nullserver != NULL) 408 { 409 message("250 %s Hello %s, %s", 410 MyHostName, CurSmtpClient, q); 411 break; 412 } 413 414 message("250-%s Hello %s, %s", 415 MyHostName, CurSmtpClient, q); 416 417 /* print EHLO features list */ 418 if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 419 { 420 message("250-EXPN"); 421 if (!bitset(PRIV_NOVERB, PrivacyFlags)) 422 message("250-VERB"); 423 } 424 #if MIME8TO7 425 message("250-8BITMIME"); 426 #endif 427 if (MaxMessageSize > 0) 428 message("250-SIZE %ld", MaxMessageSize); 429 else 430 message("250-SIZE"); 431 #if DSN 432 if (SendMIMEErrors) 433 message("250-DSN"); 434 #endif 435 message("250-ONEX"); 436 if (!bitset(PRIV_NOETRN, PrivacyFlags)) 437 message("250-ETRN"); 438 message("250-XUSR"); 439 message("250 HELP"); 440 break; 441 442 case CMDMAIL: /* mail -- designate sender */ 443 SmtpPhase = "server MAIL"; 444 445 /* check for validity of this command */ 446 if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 447 { 448 usrerr("503 Polite people say HELO first"); 449 break; 450 } 451 if (gotmail) 452 { 453 usrerr("503 Sender already specified"); 454 break; 455 } 456 if (InChild) 457 { 458 errno = 0; 459 syserr("503 Nested MAIL command: MAIL %s", p); 460 finis(); 461 } 462 463 /* make sure we know who the sending host is */ 464 if (sendinghost == NULL) 465 sendinghost = peerhostname; 466 467 p = skipword(p, "from"); 468 if (p == NULL) 469 break; 470 471 /* fork a subprocess to process this command */ 472 if (runinchild("SMTP-MAIL", e) > 0) 473 break; 474 if (Errors > 0) 475 goto undo_subproc_no_pm; 476 if (!gothello) 477 { 478 auth_warning(e, 479 "%s didn't use HELO protocol", 480 CurSmtpClient); 481 } 482 #ifdef PICKY_HELO_CHECK 483 if (strcasecmp(sendinghost, peerhostname) != 0 && 484 (strcasecmp(peerhostname, "localhost") != 0 || 485 strcasecmp(sendinghost, MyHostName) != 0)) 486 { 487 auth_warning(e, "Host %s claimed to be %s", 488 CurSmtpClient, sendinghost); 489 } 490 #endif 491 492 if (protocol == NULL) 493 protocol = "SMTP"; 494 define('r', protocol, e); 495 define('s', sendinghost, e); 496 initsys(e); 497 if (Errors > 0) 498 goto undo_subproc_no_pm; 499 nrcpts = 0; 500 e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE; 501 setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); 502 503 /* child -- go do the processing */ 504 if (setjmp(TopFrame) > 0) 505 { 506 /* this failed -- undo work */ 507 undo_subproc_no_pm: 508 e->e_flags &= ~EF_PM_NOTIFY; 509 undo_subproc: 510 if (InChild) 511 { 512 QuickAbort = FALSE; 513 SuprErrs = TRUE; 514 e->e_flags &= ~EF_FATALERRS; 515 finis(); 516 } 517 break; 518 } 519 QuickAbort = TRUE; 520 521 /* must parse sender first */ 522 delimptr = NULL; 523 setsender(p, e, &delimptr, ' ', FALSE); 524 if (delimptr != NULL && *delimptr != '\0') 525 *delimptr++ = '\0'; 526 if (Errors > 0) 527 goto undo_subproc_no_pm; 528 529 /* do config file checking of the sender */ 530 if (rscheck("check_mail", p, NULL, e) != EX_OK || 531 Errors > 0) 532 goto undo_subproc_no_pm; 533 534 /* check for possible spoofing */ 535 if (RealUid != 0 && OpMode == MD_SMTP && 536 !wordinclass(RealUserName, 't') && 537 !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 538 strcmp(e->e_from.q_user, RealUserName) != 0) 539 { 540 auth_warning(e, "%s owned process doing -bs", 541 RealUserName); 542 } 543 544 /* now parse ESMTP arguments */ 545 e->e_msgsize = 0; 546 p = delimptr; 547 while (p != NULL && *p != '\0') 548 { 549 char *kp; 550 char *vp = NULL; 551 extern void mail_esmtp_args __P((char *, char *, ENVELOPE *)); 552 553 /* locate the beginning of the keyword */ 554 while (isascii(*p) && isspace(*p)) 555 p++; 556 if (*p == '\0') 557 break; 558 kp = p; 559 560 /* skip to the value portion */ 561 while ((isascii(*p) && isalnum(*p)) || *p == '-') 562 p++; 563 if (*p == '=') 564 { 565 *p++ = '\0'; 566 vp = p; 567 568 /* skip to the end of the value */ 569 while (*p != '\0' && *p != ' ' && 570 !(isascii(*p) && iscntrl(*p)) && 571 *p != '=') 572 p++; 573 } 574 575 if (*p != '\0') 576 *p++ = '\0'; 577 578 if (tTd(19, 1)) 579 printf("MAIL: got arg %s=\"%s\"\n", kp, 580 vp == NULL ? "<null>" : vp); 581 582 mail_esmtp_args(kp, vp, e); 583 if (Errors > 0) 584 goto undo_subproc_no_pm; 585 } 586 if (Errors > 0) 587 goto undo_subproc_no_pm; 588 589 if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) 590 { 591 usrerr("552 Message size exceeds fixed maximum message size (%ld)", 592 MaxMessageSize); 593 goto undo_subproc_no_pm; 594 } 595 596 if (!enoughdiskspace(e->e_msgsize)) 597 { 598 usrerr("452 Insufficient disk space; try again later"); 599 goto undo_subproc_no_pm; 600 } 601 if (Errors > 0) 602 goto undo_subproc_no_pm; 603 message("250 Sender ok"); 604 gotmail = TRUE; 605 break; 606 607 case CMDRCPT: /* rcpt -- designate recipient */ 608 if (!gotmail) 609 { 610 usrerr("503 Need MAIL before RCPT"); 611 break; 612 } 613 SmtpPhase = "server RCPT"; 614 if (setjmp(TopFrame) > 0) 615 { 616 e->e_flags &= ~EF_FATALERRS; 617 break; 618 } 619 QuickAbort = TRUE; 620 LogUsrErrs = TRUE; 621 622 /* limit flooding of our machine */ 623 if (MaxRcptPerMsg > 0 && nrcpts >= MaxRcptPerMsg) 624 { 625 usrerr("452 Too many recipients"); 626 break; 627 } 628 629 if (e->e_sendmode != SM_DELIVER) 630 e->e_flags |= EF_VRFYONLY; 631 632 p = skipword(p, "to"); 633 if (p == NULL) 634 break; 635 a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e); 636 if (a == NULL || Errors > 0) 637 break; 638 if (delimptr != NULL && *delimptr != '\0') 639 *delimptr++ = '\0'; 640 641 /* do config file checking of the recipient */ 642 if (rscheck("check_rcpt", p, NULL, e) != EX_OK || 643 Errors > 0) 644 break; 645 646 /* now parse ESMTP arguments */ 647 p = delimptr; 648 while (p != NULL && *p != '\0') 649 { 650 char *kp; 651 char *vp = NULL; 652 extern void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *)); 653 654 /* locate the beginning of the keyword */ 655 while (isascii(*p) && isspace(*p)) 656 p++; 657 if (*p == '\0') 658 break; 659 kp = p; 660 661 /* skip to the value portion */ 662 while ((isascii(*p) && isalnum(*p)) || *p == '-') 663 p++; 664 if (*p == '=') 665 { 666 *p++ = '\0'; 667 vp = p; 668 669 /* skip to the end of the value */ 670 while (*p != '\0' && *p != ' ' && 671 !(isascii(*p) && iscntrl(*p)) && 672 *p != '=') 673 p++; 674 } 675 676 if (*p != '\0') 677 *p++ = '\0'; 678 679 if (tTd(19, 1)) 680 printf("RCPT: got arg %s=\"%s\"\n", kp, 681 vp == NULL ? "<null>" : vp); 682 683 rcpt_esmtp_args(a, kp, vp, e); 684 if (Errors > 0) 685 break; 686 } 687 if (Errors > 0) 688 break; 689 690 /* save in recipient list after ESMTP mods */ 691 a = recipient(a, &e->e_sendqueue, 0, e); 692 if (Errors > 0) 693 break; 694 695 /* no errors during parsing, but might be a duplicate */ 696 e->e_to = a->q_paddr; 697 if (!bitset(QBADADDR, a->q_flags)) 698 { 699 message("250 Recipient ok%s", 700 bitset(QQUEUEUP, a->q_flags) ? 701 " (will queue)" : ""); 702 nrcpts++; 703 } 704 else 705 { 706 /* punt -- should keep message in ADDRESS.... */ 707 usrerr("550 Addressee unknown"); 708 } 709 break; 710 711 case CMDDATA: /* data -- text of mail */ 712 SmtpPhase = "server DATA"; 713 if (!gotmail) 714 { 715 usrerr("503 Need MAIL command"); 716 break; 717 } 718 else if (nrcpts <= 0) 719 { 720 usrerr("503 Need RCPT (recipient)"); 721 break; 722 } 723 724 /* put back discard bit */ 725 if (discard) 726 e->e_flags |= EF_DISCARD; 727 728 /* check to see if we need to re-expand aliases */ 729 /* also reset QBADADDR on already-diagnosted addrs */ 730 doublequeue = FALSE; 731 for (a = e->e_sendqueue; a != NULL; a = a->q_next) 732 { 733 if (bitset(QVERIFIED, a->q_flags) && 734 !bitset(EF_DISCARD, e->e_flags)) 735 { 736 /* need to re-expand aliases */ 737 doublequeue = TRUE; 738 } 739 if (bitset(QBADADDR, a->q_flags)) 740 { 741 /* make this "go away" */ 742 a->q_flags |= QDONTSEND; 743 a->q_flags &= ~QBADADDR; 744 } 745 } 746 747 /* collect the text of the message */ 748 SmtpPhase = "collect"; 749 buffer_errors(); 750 collect(InChannel, TRUE, NULL, e); 751 if (Errors > 0) 752 { 753 flush_errors(TRUE); 754 buffer_errors(); 755 goto abortmessage; 756 } 757 758 /* make sure we actually do delivery */ 759 e->e_flags &= ~EF_CLRQUEUE; 760 761 /* from now on, we have to operate silently */ 762 buffer_errors(); 763 e->e_errormode = EM_MAIL; 764 765 /* 766 ** Arrange to send to everyone. 767 ** If sending to multiple people, mail back 768 ** errors rather than reporting directly. 769 ** In any case, don't mail back errors for 770 ** anything that has happened up to 771 ** now (the other end will do this). 772 ** Truncate our transcript -- the mail has gotten 773 ** to us successfully, and if we have 774 ** to mail this back, it will be easier 775 ** on the reader. 776 ** Then send to everyone. 777 ** Finally give a reply code. If an error has 778 ** already been given, don't mail a 779 ** message back. 780 ** We goose error returns by clearing error bit. 781 */ 782 783 SmtpPhase = "delivery"; 784 e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 785 id = e->e_id; 786 787 if (doublequeue) 788 { 789 /* make sure it is in the queue */ 790 queueup(e, FALSE); 791 } 792 else 793 { 794 /* send to all recipients */ 795 sendall(e, SM_DEFAULT); 796 } 797 e->e_to = NULL; 798 799 /* issue success message */ 800 message("250 %s Message accepted for delivery", id); 801 802 /* if we just queued, poke it */ 803 if (doublequeue && 804 e->e_sendmode != SM_QUEUE && 805 e->e_sendmode != SM_DEFER) 806 { 807 CurrentLA = getla(); 808 809 if (!shouldqueue(e->e_msgpriority, e->e_ctime)) 810 { 811 extern pid_t dowork __P((char *, bool, bool, ENVELOPE *)); 812 813 unlockqueue(e); 814 (void) dowork(id, TRUE, TRUE, e); 815 } 816 } 817 818 abortmessage: 819 /* if in a child, pop back to our parent */ 820 if (InChild) 821 finis(); 822 823 /* clean up a bit */ 824 gotmail = FALSE; 825 dropenvelope(e, TRUE); 826 CurEnv = e = newenvelope(e, CurEnv); 827 e->e_flags = BlankEnvelope.e_flags; 828 break; 829 830 case CMDRSET: /* rset -- reset state */ 831 if (tTd(94, 100)) 832 message("451 Test failure"); 833 else 834 message("250 Reset state"); 835 836 /* arrange to ignore any current send list */ 837 e->e_sendqueue = NULL; 838 e->e_flags |= EF_CLRQUEUE; 839 if (InChild) 840 finis(); 841 842 /* clean up a bit */ 843 gotmail = FALSE; 844 SuprErrs = TRUE; 845 dropenvelope(e, TRUE); 846 CurEnv = e = newenvelope(e, CurEnv); 847 break; 848 849 case CMDVRFY: /* vrfy -- verify address */ 850 case CMDEXPN: /* expn -- expand address */ 851 checksmtpattack(&nverifies, MAXVRFYCOMMANDS, 852 c->cmdcode == CMDVRFY ? "VRFY" : "EXPN", e); 853 vrfy = c->cmdcode == CMDVRFY; 854 if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 855 PrivacyFlags)) 856 { 857 if (vrfy) 858 message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); 859 else 860 message("502 Sorry, we do not allow this operation"); 861 if (LogLevel > 5) 862 sm_syslog(LOG_INFO, e->e_id, 863 "%.100s: %s [rejected]", 864 CurSmtpClient, 865 shortenstring(inp, MAXSHORTSTR)); 866 break; 867 } 868 else if (!gothello && 869 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 870 PrivacyFlags)) 871 { 872 usrerr("503 I demand that you introduce yourself first"); 873 break; 874 } 875 if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 876 break; 877 if (Errors > 0) 878 goto undo_subproc; 879 if (LogLevel > 5) 880 sm_syslog(LOG_INFO, e->e_id, 881 "%.100s: %s", 882 CurSmtpClient, 883 shortenstring(inp, MAXSHORTSTR)); 884 if (setjmp(TopFrame) > 0) 885 goto undo_subproc; 886 QuickAbort = TRUE; 887 vrfyqueue = NULL; 888 if (vrfy) 889 e->e_flags |= EF_VRFYONLY; 890 while (*p != '\0' && isascii(*p) && isspace(*p)) 891 p++; 892 if (*p == '\0') 893 { 894 usrerr("501 Argument required"); 895 } 896 else 897 { 898 (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); 899 } 900 if (Errors > 0) 901 goto undo_subproc; 902 if (vrfyqueue == NULL) 903 { 904 usrerr("554 Nothing to %s", vrfy ? "VRFY" : "EXPN"); 905 } 906 while (vrfyqueue != NULL) 907 { 908 extern void printvrfyaddr __P((ADDRESS *, bool, bool)); 909 910 a = vrfyqueue; 911 while ((a = a->q_next) != NULL && 912 bitset(QDONTSEND|QBADADDR, a->q_flags)) 913 continue; 914 if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 915 printvrfyaddr(vrfyqueue, a == NULL, vrfy); 916 vrfyqueue = vrfyqueue->q_next; 917 } 918 if (InChild) 919 finis(); 920 break; 921 922 case CMDETRN: /* etrn -- force queue flush */ 923 if (bitset(PRIV_NOETRN, PrivacyFlags)) 924 { 925 message("502 Sorry, we do not allow this operation"); 926 if (LogLevel > 5) 927 sm_syslog(LOG_INFO, e->e_id, 928 "%.100s: %s [rejected]", 929 CurSmtpClient, 930 shortenstring(inp, MAXSHORTSTR)); 931 break; 932 } 933 934 if (strlen(p) <= 0) 935 { 936 usrerr("500 Parameter required"); 937 break; 938 } 939 940 /* crude way to avoid denial-of-service attacks */ 941 checksmtpattack(&n_etrn, MAXETRNCOMMANDS, "ETRN", e); 942 943 if (LogLevel > 5) 944 sm_syslog(LOG_INFO, e->e_id, 945 "%.100s: ETRN %s", 946 CurSmtpClient, 947 shortenstring(p, MAXSHORTSTR)); 948 949 id = p; 950 if (*id == '@') 951 id++; 952 else 953 *--id = '@'; 954 955 if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) 956 { 957 syserr("500 ETRN out of memory"); 958 break; 959 } 960 new->queue_match = id; 961 new->queue_next = NULL; 962 QueueLimitRecipient = new; 963 ok = runqueue(TRUE, TRUE); 964 free(QueueLimitRecipient); 965 QueueLimitRecipient = NULL; 966 if (ok && Errors == 0) 967 message("250 Queuing for node %s started", p); 968 break; 969 970 case CMDHELP: /* help -- give user info */ 971 help(p); 972 break; 973 974 case CMDNOOP: /* noop -- do nothing */ 975 checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "NOOP", e); 976 message("250 OK"); 977 break; 978 979 case CMDQUIT: /* quit -- leave mail */ 980 message("221 %s closing connection", MyHostName); 981 982 doquit: 983 /* arrange to ignore any current send list */ 984 e->e_sendqueue = NULL; 985 986 /* avoid future 050 messages */ 987 disconnect(1, e); 988 989 if (InChild) 990 ExitStat = EX_QUIT; 991 if (lognullconnection && LogLevel > 5) 992 sm_syslog(LOG_INFO, NULL, 993 "Null connection from %.100s", 994 CurSmtpClient); 995 finis(); 996 997 case CMDVERB: /* set verbose mode */ 998 if (bitset(PRIV_NOEXPN, PrivacyFlags) || 999 bitset(PRIV_NOVERB, PrivacyFlags)) 1000 { 1001 /* this would give out the same info */ 1002 message("502 Verbose unavailable"); 1003 break; 1004 } 1005 checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "VERB", e); 1006 Verbose = 1; 1007 e->e_sendmode = SM_DELIVER; 1008 message("250 Verbose mode"); 1009 break; 1010 1011 case CMDONEX: /* doing one transaction only */ 1012 checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "ONEX", e); 1013 OneXact = TRUE; 1014 message("250 Only one transaction"); 1015 break; 1016 1017 case CMDXUSR: /* initial (user) submission */ 1018 checksmtpattack(&n_noop, MAXNOOPCOMMANDS, "XUSR", e); 1019 UserSubmission = TRUE; 1020 message("250 Initial submission"); 1021 break; 1022 1023 # if SMTPDEBUG 1024 case CMDDBGQSHOW: /* show queues */ 1025 printf("Send Queue="); 1026 printaddr(e->e_sendqueue, TRUE); 1027 break; 1028 1029 case CMDDBGDEBUG: /* set debug mode */ 1030 tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 1031 tTflag(p); 1032 message("200 Debug set"); 1033 break; 1034 1035 # else /* not SMTPDEBUG */ 1036 case CMDDBGQSHOW: /* show queues */ 1037 case CMDDBGDEBUG: /* set debug mode */ 1038 # endif /* SMTPDEBUG */ 1039 case CMDLOGBOGUS: /* bogus command */ 1040 if (LogLevel > 0) 1041 sm_syslog(LOG_CRIT, e->e_id, 1042 "\"%s\" command from %.100s (%.100s)", 1043 c->cmdname, CurSmtpClient, 1044 anynet_ntoa(&RealHostAddr)); 1045 /* FALL THROUGH */ 1046 1047 case CMDERROR: /* unknown command */ 1048 if (++badcommands > MAXBADCOMMANDS) 1049 { 1050 message("421 %s Too many bad commands; closing connection", 1051 MyHostName); 1052 goto doquit; 1053 } 1054 1055 usrerr("500 Command unrecognized: \"%s\"", 1056 shortenstring(inp, MAXSHORTSTR)); 1057 break; 1058 1059 default: 1060 errno = 0; 1061 syserr("500 smtp: unknown code %d", c->cmdcode); 1062 break; 1063 } 1064 } 1065 } 1066 /* 1067 ** CHECKSMTPATTACK -- check for denial-of-service attack by repetition 1068 ** 1069 ** Parameters: 1070 ** pcounter -- pointer to a counter for this command. 1071 ** maxcount -- maximum value for this counter before we 1072 ** slow down. 1073 ** cname -- command name for logging. 1074 ** e -- the current envelope. 1075 ** 1076 ** Returns: 1077 ** none. 1078 ** 1079 ** Side Effects: 1080 ** Slows down if we seem to be under attack. 1081 */ 1082 1083 void 1084 checksmtpattack(pcounter, maxcount, cname, e) 1085 volatile int *pcounter; 1086 int maxcount; 1087 char *cname; 1088 ENVELOPE *e; 1089 { 1090 if (++(*pcounter) >= maxcount) 1091 { 1092 if (*pcounter == maxcount && LogLevel > 5) 1093 { 1094 sm_syslog(LOG_INFO, e->e_id, 1095 "%.100s: %.40s attack?", 1096 CurSmtpClient, cname); 1097 } 1098 sleep(*pcounter / maxcount); 1099 } 1100 } 1101 /* 1102 ** SKIPWORD -- skip a fixed word. 1103 ** 1104 ** Parameters: 1105 ** p -- place to start looking. 1106 ** w -- word to skip. 1107 ** 1108 ** Returns: 1109 ** p following w. 1110 ** NULL on error. 1111 ** 1112 ** Side Effects: 1113 ** clobbers the p data area. 1114 */ 1115 1116 static char * 1117 skipword(p, w) 1118 register char *volatile p; 1119 char *w; 1120 { 1121 register char *q; 1122 char *firstp = p; 1123 1124 /* find beginning of word */ 1125 while (isascii(*p) && isspace(*p)) 1126 p++; 1127 q = p; 1128 1129 /* find end of word */ 1130 while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 1131 p++; 1132 while (isascii(*p) && isspace(*p)) 1133 *p++ = '\0'; 1134 if (*p != ':') 1135 { 1136 syntax: 1137 usrerr("501 Syntax error in parameters scanning \"%s\"", 1138 shortenstring(firstp, MAXSHORTSTR)); 1139 return (NULL); 1140 } 1141 *p++ = '\0'; 1142 while (isascii(*p) && isspace(*p)) 1143 p++; 1144 1145 if (*p == '\0') 1146 goto syntax; 1147 1148 /* see if the input word matches desired word */ 1149 if (strcasecmp(q, w)) 1150 goto syntax; 1151 1152 return (p); 1153 } 1154 /* 1155 ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 1156 ** 1157 ** Parameters: 1158 ** kp -- the parameter key. 1159 ** vp -- the value of that parameter. 1160 ** e -- the envelope. 1161 ** 1162 ** Returns: 1163 ** none. 1164 */ 1165 1166 void 1167 mail_esmtp_args(kp, vp, e) 1168 char *kp; 1169 char *vp; 1170 ENVELOPE *e; 1171 { 1172 if (strcasecmp(kp, "size") == 0) 1173 { 1174 if (vp == NULL) 1175 { 1176 usrerr("501 SIZE requires a value"); 1177 /* NOTREACHED */ 1178 } 1179 # if defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY) 1180 e->e_msgsize = strtoul(vp, (char **) NULL, 10); 1181 # else 1182 e->e_msgsize = strtol(vp, (char **) NULL, 10); 1183 # endif 1184 } 1185 else if (strcasecmp(kp, "body") == 0) 1186 { 1187 if (vp == NULL) 1188 { 1189 usrerr("501 BODY requires a value"); 1190 /* NOTREACHED */ 1191 } 1192 else if (strcasecmp(vp, "8bitmime") == 0) 1193 { 1194 SevenBitInput = FALSE; 1195 } 1196 else if (strcasecmp(vp, "7bit") == 0) 1197 { 1198 SevenBitInput = TRUE; 1199 } 1200 else 1201 { 1202 usrerr("501 Unknown BODY type %s", 1203 vp); 1204 /* NOTREACHED */ 1205 } 1206 e->e_bodytype = newstr(vp); 1207 } 1208 else if (strcasecmp(kp, "envid") == 0) 1209 { 1210 if (vp == NULL) 1211 { 1212 usrerr("501 ENVID requires a value"); 1213 /* NOTREACHED */ 1214 } 1215 if (!xtextok(vp)) 1216 { 1217 usrerr("501 Syntax error in ENVID parameter value"); 1218 /* NOTREACHED */ 1219 } 1220 if (e->e_envid != NULL) 1221 { 1222 usrerr("501 Duplicate ENVID parameter"); 1223 /* NOTREACHED */ 1224 } 1225 e->e_envid = newstr(vp); 1226 } 1227 else if (strcasecmp(kp, "ret") == 0) 1228 { 1229 if (vp == NULL) 1230 { 1231 usrerr("501 RET requires a value"); 1232 /* NOTREACHED */ 1233 } 1234 if (bitset(EF_RET_PARAM, e->e_flags)) 1235 { 1236 usrerr("501 Duplicate RET parameter"); 1237 /* NOTREACHED */ 1238 } 1239 e->e_flags |= EF_RET_PARAM; 1240 if (strcasecmp(vp, "hdrs") == 0) 1241 e->e_flags |= EF_NO_BODY_RETN; 1242 else if (strcasecmp(vp, "full") != 0) 1243 { 1244 usrerr("501 Bad argument \"%s\" to RET", vp); 1245 /* NOTREACHED */ 1246 } 1247 } 1248 else 1249 { 1250 usrerr("501 %s parameter unrecognized", kp); 1251 /* NOTREACHED */ 1252 } 1253 } 1254 /* 1255 ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line 1256 ** 1257 ** Parameters: 1258 ** a -- the address corresponding to the To: parameter. 1259 ** kp -- the parameter key. 1260 ** vp -- the value of that parameter. 1261 ** e -- the envelope. 1262 ** 1263 ** Returns: 1264 ** none. 1265 */ 1266 1267 void 1268 rcpt_esmtp_args(a, kp, vp, e) 1269 ADDRESS *a; 1270 char *kp; 1271 char *vp; 1272 ENVELOPE *e; 1273 { 1274 if (strcasecmp(kp, "notify") == 0) 1275 { 1276 char *p; 1277 1278 if (vp == NULL) 1279 { 1280 usrerr("501 NOTIFY requires a value"); 1281 /* NOTREACHED */ 1282 } 1283 a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); 1284 a->q_flags |= QHASNOTIFY; 1285 if (strcasecmp(vp, "never") == 0) 1286 return; 1287 for (p = vp; p != NULL; vp = p) 1288 { 1289 p = strchr(p, ','); 1290 if (p != NULL) 1291 *p++ = '\0'; 1292 if (strcasecmp(vp, "success") == 0) 1293 a->q_flags |= QPINGONSUCCESS; 1294 else if (strcasecmp(vp, "failure") == 0) 1295 a->q_flags |= QPINGONFAILURE; 1296 else if (strcasecmp(vp, "delay") == 0) 1297 a->q_flags |= QPINGONDELAY; 1298 else 1299 { 1300 usrerr("501 Bad argument \"%s\" to NOTIFY", 1301 vp); 1302 /* NOTREACHED */ 1303 } 1304 } 1305 } 1306 else if (strcasecmp(kp, "orcpt") == 0) 1307 { 1308 if (vp == NULL) 1309 { 1310 usrerr("501 ORCPT requires a value"); 1311 /* NOTREACHED */ 1312 } 1313 if (strchr(vp, ';') == NULL || !xtextok(vp)) 1314 { 1315 usrerr("501 Syntax error in ORCPT parameter value"); 1316 /* NOTREACHED */ 1317 } 1318 if (a->q_orcpt != NULL) 1319 { 1320 usrerr("501 Duplicate ORCPT parameter"); 1321 /* NOTREACHED */ 1322 } 1323 a->q_orcpt = newstr(vp); 1324 } 1325 else 1326 { 1327 usrerr("501 %s parameter unrecognized", kp); 1328 /* NOTREACHED */ 1329 } 1330 } 1331 /* 1332 ** PRINTVRFYADDR -- print an entry in the verify queue 1333 ** 1334 ** Parameters: 1335 ** a -- the address to print 1336 ** last -- set if this is the last one. 1337 ** vrfy -- set if this is a VRFY command. 1338 ** 1339 ** Returns: 1340 ** none. 1341 ** 1342 ** Side Effects: 1343 ** Prints the appropriate 250 codes. 1344 */ 1345 1346 void 1347 printvrfyaddr(a, last, vrfy) 1348 register ADDRESS *a; 1349 bool last; 1350 bool vrfy; 1351 { 1352 char fmtbuf[20]; 1353 1354 if (vrfy && a->q_mailer != NULL && 1355 !bitnset(M_VRFY250, a->q_mailer->m_flags)) 1356 strcpy(fmtbuf, "252"); 1357 else 1358 strcpy(fmtbuf, "250"); 1359 fmtbuf[3] = last ? ' ' : '-'; 1360 1361 if (a->q_fullname == NULL) 1362 { 1363 if (strchr(a->q_user, '@') == NULL) 1364 strcpy(&fmtbuf[4], "<%s@%s>"); 1365 else 1366 strcpy(&fmtbuf[4], "<%s>"); 1367 message(fmtbuf, a->q_user, MyHostName); 1368 } 1369 else 1370 { 1371 if (strchr(a->q_user, '@') == NULL) 1372 strcpy(&fmtbuf[4], "%s <%s@%s>"); 1373 else 1374 strcpy(&fmtbuf[4], "%s <%s>"); 1375 message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 1376 } 1377 } 1378 /* 1379 ** RUNINCHILD -- return twice -- once in the child, then in the parent again 1380 ** 1381 ** Parameters: 1382 ** label -- a string used in error messages 1383 ** 1384 ** Returns: 1385 ** zero in the child 1386 ** one in the parent 1387 ** 1388 ** Side Effects: 1389 ** none. 1390 */ 1391 1392 int 1393 runinchild(label, e) 1394 char *label; 1395 register ENVELOPE *e; 1396 { 1397 pid_t childpid; 1398 1399 if (!OneXact) 1400 { 1401 /* 1402 ** Disable child process reaping, in case ETRN has preceeded 1403 ** MAIL command, and then fork. 1404 */ 1405 1406 (void) blocksignal(SIGCHLD); 1407 1408 childpid = dofork(); 1409 if (childpid < 0) 1410 { 1411 syserr("451 %s: cannot fork", label); 1412 (void) releasesignal(SIGCHLD); 1413 return (1); 1414 } 1415 if (childpid > 0) 1416 { 1417 auto int st; 1418 1419 /* parent -- wait for child to complete */ 1420 setproctitle("server %s child wait", CurSmtpClient); 1421 st = waitfor(childpid); 1422 if (st == -1) 1423 syserr("451 %s: lost child", label); 1424 else if (!WIFEXITED(st)) 1425 syserr("451 %s: died on signal %d", 1426 label, st & 0177); 1427 1428 /* if we exited on a QUIT command, complete the process */ 1429 if (WEXITSTATUS(st) == EX_QUIT) 1430 { 1431 disconnect(1, e); 1432 finis(); 1433 } 1434 1435 /* restore the child signal */ 1436 (void) releasesignal(SIGCHLD); 1437 1438 return (1); 1439 } 1440 else 1441 { 1442 /* child */ 1443 InChild = TRUE; 1444 QuickAbort = FALSE; 1445 clearenvelope(e, FALSE); 1446 (void) setsignal(SIGCHLD, SIG_DFL); 1447 (void) releasesignal(SIGCHLD); 1448 } 1449 } 1450 1451 /* open alias database */ 1452 initmaps(FALSE, e); 1453 1454 return (0); 1455 } 1456 1457 # endif /* SMTP */ 1458 /* 1459 ** HELP -- implement the HELP command. 1460 ** 1461 ** Parameters: 1462 ** topic -- the topic we want help for. 1463 ** 1464 ** Returns: 1465 ** none. 1466 ** 1467 ** Side Effects: 1468 ** outputs the help file to message output. 1469 */ 1470 1471 void 1472 help(topic) 1473 char *topic; 1474 { 1475 register FILE *hf; 1476 int len; 1477 bool noinfo; 1478 int sff = SFF_OPENASROOT|SFF_REGONLY; 1479 char buf[MAXLINE]; 1480 extern char Version[]; 1481 1482 if (DontLockReadFiles) 1483 sff |= SFF_NOLOCK; 1484 if (!bitset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail)) 1485 sff |= SFF_SAFEDIRPATH; 1486 1487 if (HelpFile == NULL || 1488 (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL) 1489 { 1490 /* no help */ 1491 errno = 0; 1492 message("502 Sendmail %s -- HELP not implemented", Version); 1493 return; 1494 } 1495 1496 if (topic == NULL || *topic == '\0') 1497 { 1498 topic = "smtp"; 1499 message("214-This is Sendmail version %s", Version); 1500 noinfo = FALSE; 1501 } 1502 else 1503 { 1504 makelower(topic); 1505 noinfo = TRUE; 1506 } 1507 1508 len = strlen(topic); 1509 1510 while (fgets(buf, sizeof buf, hf) != NULL) 1511 { 1512 if (strncmp(buf, topic, len) == 0) 1513 { 1514 register char *p; 1515 1516 p = strchr(buf, '\t'); 1517 if (p == NULL) 1518 p = buf; 1519 else 1520 p++; 1521 fixcrlf(p, TRUE); 1522 message("214-%s", p); 1523 noinfo = FALSE; 1524 } 1525 } 1526 1527 if (noinfo) 1528 message("504 HELP topic \"%.10s\" unknown", topic); 1529 else 1530 message("214 End of HELP info"); 1531 (void) fclose(hf); 1532 } 1533