1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 11 #ifndef lint 12 #ifdef SMTP 13 static char sccsid[] = "@(#)srvrsmtp.c 6.50 (Berkeley) 05/04/93 (with SMTP)"; 14 #else 15 static char sccsid[] = "@(#)srvrsmtp.c 6.50 (Berkeley) 05/04/93 (without SMTP)"; 16 #endif 17 #endif /* not lint */ 18 19 # include <errno.h> 20 # include <signal.h> 21 22 # ifdef SMTP 23 24 /* 25 ** SMTP -- run the SMTP protocol. 26 ** 27 ** Parameters: 28 ** none. 29 ** 30 ** Returns: 31 ** never. 32 ** 33 ** Side Effects: 34 ** Reads commands from the input channel and processes 35 ** them. 36 */ 37 38 struct cmd 39 { 40 char *cmdname; /* command name */ 41 int cmdcode; /* internal code, see below */ 42 }; 43 44 /* values for cmdcode */ 45 # define CMDERROR 0 /* bad command */ 46 # define CMDMAIL 1 /* mail -- designate sender */ 47 # define CMDRCPT 2 /* rcpt -- designate recipient */ 48 # define CMDDATA 3 /* data -- send message text */ 49 # define CMDRSET 4 /* rset -- reset state */ 50 # define CMDVRFY 5 /* vrfy -- verify address */ 51 # define CMDEXPN 6 /* expn -- expand address */ 52 # define CMDNOOP 7 /* noop -- do nothing */ 53 # define CMDQUIT 8 /* quit -- close connection and die */ 54 # define CMDHELO 9 /* helo -- be polite */ 55 # define CMDHELP 10 /* help -- give usage info */ 56 # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 57 /* non-standard commands */ 58 # define CMDONEX 16 /* onex -- sending one transaction only */ 59 # define CMDVERB 17 /* verb -- go into verbose mode */ 60 /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 61 # define CMDDBGQSHOW 24 /* showq -- show send queue */ 62 # define CMDDBGDEBUG 25 /* debug -- set debug mode */ 63 64 static struct cmd CmdTab[] = 65 { 66 "mail", CMDMAIL, 67 "rcpt", CMDRCPT, 68 "data", CMDDATA, 69 "rset", CMDRSET, 70 "vrfy", CMDVRFY, 71 "expn", CMDEXPN, 72 "help", CMDHELP, 73 "noop", CMDNOOP, 74 "quit", CMDQUIT, 75 "helo", CMDHELO, 76 "ehlo", CMDEHLO, 77 "verb", CMDVERB, 78 "onex", CMDONEX, 79 /* 80 * remaining commands are here only 81 * to trap and log attempts to use them 82 */ 83 "showq", CMDDBGQSHOW, 84 "debug", CMDDBGDEBUG, 85 NULL, CMDERROR, 86 }; 87 88 bool InChild = FALSE; /* true if running in a subprocess */ 89 bool OneXact = FALSE; /* one xaction only this run */ 90 91 #define EX_QUIT 22 /* special code for QUIT command */ 92 93 smtp(e) 94 register ENVELOPE *e; 95 { 96 register char *p; 97 register struct cmd *c; 98 char *cmd; 99 static char *skipword(); 100 auto ADDRESS *vrfyqueue; 101 ADDRESS *a; 102 bool gotmail; /* mail command received */ 103 bool gothello; /* helo command received */ 104 bool vrfy; /* set if this is a vrfy command */ 105 char *protocol; /* sending protocol */ 106 char *sendinghost; /* sending hostname */ 107 long msize; /* approximate maximum message size */ 108 auto char *delimptr; 109 char *id; 110 char inp[MAXLINE]; 111 char cmdbuf[MAXLINE]; 112 extern char Version[]; 113 extern char *macvalue(); 114 extern ADDRESS *recipient(); 115 extern ENVELOPE BlankEnvelope; 116 extern ENVELOPE *newenvelope(); 117 extern char *anynet_ntoa(); 118 119 if (fileno(OutChannel) != fileno(stdout)) 120 { 121 /* arrange for debugging output to go to remote host */ 122 (void) dup2(fileno(OutChannel), fileno(stdout)); 123 } 124 settime(e); 125 CurHostName = RealHostName; 126 setproctitle("srvrsmtp %s startup", CurHostName); 127 expand("\201e", inp, &inp[sizeof inp], e); 128 message("220 %s", inp); 129 protocol = NULL; 130 sendinghost = macvalue('s', e); 131 gothello = FALSE; 132 gotmail = FALSE; 133 for (;;) 134 { 135 /* arrange for backout */ 136 if (setjmp(TopFrame) > 0 && InChild) 137 { 138 QuickAbort = FALSE; 139 SuprErrs = TRUE; 140 finis(); 141 } 142 QuickAbort = FALSE; 143 HoldErrs = FALSE; 144 LogUsrErrs = FALSE; 145 e->e_flags &= ~EF_VRFYONLY; 146 147 /* setup for the read */ 148 e->e_to = NULL; 149 Errors = 0; 150 (void) fflush(stdout); 151 152 /* read the input line */ 153 SmtpPhase = "srvrsmtp cmd read"; 154 setproctitle("srvrsmtp %s cmd read", CurHostName); 155 p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 156 157 /* handle errors */ 158 if (p == NULL) 159 { 160 /* end of file, just die */ 161 message("421 %s Lost input channel from %s", 162 MyHostName, CurHostName); 163 #ifdef LOG 164 if (LogLevel > 1) 165 syslog(LOG_NOTICE, "lost input channel from %s", 166 CurHostName); 167 #endif 168 if (InChild) 169 ExitStat = EX_QUIT; 170 finis(); 171 } 172 173 /* clean up end of line */ 174 fixcrlf(inp, TRUE); 175 176 /* echo command to transcript */ 177 if (e->e_xfp != NULL) 178 fprintf(e->e_xfp, "<<< %s\n", inp); 179 180 if (e->e_id == NULL) 181 setproctitle("%s: %s", CurHostName, inp); 182 else 183 setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 184 185 /* break off command */ 186 for (p = inp; isascii(*p) && isspace(*p); p++) 187 continue; 188 cmd = cmdbuf; 189 while (*p != '\0' && 190 !(isascii(*p) && isspace(*p)) && 191 cmd < &cmdbuf[sizeof cmdbuf - 2]) 192 *cmd++ = *p++; 193 *cmd = '\0'; 194 195 /* throw away leading whitespace */ 196 while (isascii(*p) && isspace(*p)) 197 p++; 198 199 /* decode command */ 200 for (c = CmdTab; c->cmdname != NULL; c++) 201 { 202 if (!strcasecmp(c->cmdname, cmdbuf)) 203 break; 204 } 205 206 /* reset errors */ 207 errno = 0; 208 209 /* process command */ 210 switch (c->cmdcode) 211 { 212 case CMDHELO: /* hello -- introduce yourself */ 213 case CMDEHLO: /* extended hello */ 214 if (c->cmdcode == CMDEHLO) 215 { 216 protocol = "ESMTP"; 217 SmtpPhase = "EHLO"; 218 } 219 else 220 { 221 protocol = "SMTP"; 222 SmtpPhase = "HELO"; 223 } 224 sendinghost = newstr(p); 225 if (strcasecmp(p, RealHostName) != 0) 226 { 227 auth_warning(e, "Host %s claimed to be %s", 228 RealHostName, p); 229 } 230 p = macvalue('_', e); 231 if (p == NULL) 232 p = RealHostName; 233 234 /* send ext. message -- old systems must ignore */ 235 message("250-%s Hello %s, pleased to meet you", 236 MyHostName, p); 237 if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 238 message("250-EXPN"); 239 if (MaxMessageSize > 0) 240 message("250-SIZE %ld", MaxMessageSize); 241 else 242 message("250-SIZE"); 243 message("250 HELP"); 244 gothello = TRUE; 245 break; 246 247 case CMDMAIL: /* mail -- designate sender */ 248 SmtpPhase = "MAIL"; 249 250 /* check for validity of this command */ 251 if (!gothello) 252 { 253 /* set sending host to our known value */ 254 if (sendinghost == NULL) 255 sendinghost = RealHostName; 256 257 if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 258 { 259 message("503 Polite people say HELO first"); 260 break; 261 } 262 else 263 { 264 auth_warning(e, 265 "Host %s didn't use HELO protocol", 266 RealHostName); 267 } 268 } 269 if (gotmail) 270 { 271 message("503 Sender already specified"); 272 break; 273 } 274 if (InChild) 275 { 276 errno = 0; 277 syserr("503 Nested MAIL command: MAIL %s", p); 278 finis(); 279 } 280 281 /* fork a subprocess to process this command */ 282 if (runinchild("SMTP-MAIL", e) > 0) 283 break; 284 if (protocol == NULL) 285 protocol = "SMTP"; 286 define('r', protocol, e); 287 define('s', sendinghost, e); 288 initsys(e); 289 setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 290 291 /* child -- go do the processing */ 292 p = skipword(p, "from"); 293 if (p == NULL) 294 break; 295 if (setjmp(TopFrame) > 0) 296 { 297 /* this failed -- undo work */ 298 if (InChild) 299 { 300 QuickAbort = FALSE; 301 SuprErrs = TRUE; 302 finis(); 303 } 304 break; 305 } 306 QuickAbort = TRUE; 307 308 /* must parse sender first */ 309 delimptr = NULL; 310 setsender(p, e, &delimptr, FALSE); 311 p = delimptr; 312 if (p != NULL && *p != '\0') 313 *p++ = '\0'; 314 315 /* now parse ESMTP arguments */ 316 msize = 0; 317 for (; p != NULL && *p != '\0'; p++) 318 { 319 char *kp; 320 char *vp; 321 322 /* locate the beginning of the keyword */ 323 while (isascii(*p) && isspace(*p)) 324 p++; 325 if (*p == '\0') 326 break; 327 kp = p; 328 329 /* skip to the value portion */ 330 while (isascii(*p) && isalnum(*p) || *p == '-') 331 p++; 332 if (*p == '=') 333 { 334 *p++ = '\0'; 335 vp = p; 336 337 /* skip to the end of the value */ 338 while (*p != '\0' && *p != ' ' && 339 !(isascii(*p) && iscntrl(*p)) && 340 *p != '=') 341 p++; 342 } 343 344 if (*p != '\0') 345 *p++ = '\0'; 346 347 if (tTd(19, 1)) 348 printf("MAIL: got arg %s=%s\n", kp, 349 vp == NULL ? "<null>" : vp); 350 351 if (strcasecmp(kp, "size") == 0) 352 { 353 if (vp == NULL) 354 { 355 usrerr("501 SIZE requires a value"); 356 /* NOTREACHED */ 357 } 358 msize = atol(vp); 359 } 360 else if (strcasecmp(kp, "body") == 0) 361 { 362 if (vp == NULL) 363 { 364 usrerr("501 BODY requires a value"); 365 /* NOTREACHED */ 366 } 367 # ifdef MIME 368 if (strcasecmp(vp, "8bitmime") == 0) 369 { 370 e->e_bodytype = "8BITMIME"; 371 SevenBit = FALSE; 372 } 373 else if (strcasecmp(vp, "7bit") == 0) 374 { 375 e->e_bodytype = "7BIT"; 376 SevenBit = TRUE; 377 } 378 else 379 { 380 usrerr("501 Unknown BODY type %s", 381 vp); 382 } 383 # endif 384 } 385 else 386 { 387 usrerr("501 %s parameter unrecognized", kp); 388 /* NOTREACHED */ 389 } 390 } 391 392 if (MaxMessageSize > 0 && msize > MaxMessageSize) 393 { 394 usrerr("552 Message size exceeds fixed maximum message size (%ld)", 395 MaxMessageSize); 396 /* NOTREACHED */ 397 } 398 399 if (!enoughspace(msize)) 400 { 401 message("452 Insufficient disk space; try again later"); 402 break; 403 } 404 message("250 Sender ok"); 405 gotmail = TRUE; 406 break; 407 408 case CMDRCPT: /* rcpt -- designate recipient */ 409 if (!gotmail) 410 { 411 usrerr("503 Need MAIL before RCPT"); 412 break; 413 } 414 SmtpPhase = "RCPT"; 415 if (setjmp(TopFrame) > 0) 416 { 417 e->e_flags &= ~EF_FATALERRS; 418 break; 419 } 420 QuickAbort = TRUE; 421 LogUsrErrs = TRUE; 422 423 if (e->e_sendmode != SM_DELIVER) 424 e->e_flags |= EF_VRFYONLY; 425 426 p = skipword(p, "to"); 427 if (p == NULL) 428 break; 429 a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 430 if (a == NULL) 431 break; 432 a->q_flags |= QPRIMARY; 433 a = recipient(a, &e->e_sendqueue, e); 434 if (Errors != 0) 435 break; 436 437 /* no errors during parsing, but might be a duplicate */ 438 e->e_to = p; 439 if (!bitset(QBADADDR, a->q_flags)) 440 message("250 Recipient ok"); 441 else 442 { 443 /* punt -- should keep message in ADDRESS.... */ 444 message("550 Addressee unknown"); 445 } 446 e->e_to = NULL; 447 break; 448 449 case CMDDATA: /* data -- text of mail */ 450 SmtpPhase = "DATA"; 451 if (!gotmail) 452 { 453 message("503 Need MAIL command"); 454 break; 455 } 456 else if (e->e_nrcpts <= 0) 457 { 458 message("503 Need RCPT (recipient)"); 459 break; 460 } 461 462 /* check to see if we need to re-expand aliases */ 463 for (a = e->e_sendqueue; a != NULL; a = a->q_next) 464 { 465 if (bitset(QVERIFIED, a->q_flags)) 466 break; 467 } 468 469 /* collect the text of the message */ 470 SmtpPhase = "collect"; 471 collect(TRUE, a != NULL, e); 472 e->e_flags &= ~EF_FATALERRS; 473 if (Errors != 0) 474 break; 475 476 /* 477 ** Arrange to send to everyone. 478 ** If sending to multiple people, mail back 479 ** errors rather than reporting directly. 480 ** In any case, don't mail back errors for 481 ** anything that has happened up to 482 ** now (the other end will do this). 483 ** Truncate our transcript -- the mail has gotten 484 ** to us successfully, and if we have 485 ** to mail this back, it will be easier 486 ** on the reader. 487 ** Then send to everyone. 488 ** Finally give a reply code. If an error has 489 ** already been given, don't mail a 490 ** message back. 491 ** We goose error returns by clearing error bit. 492 */ 493 494 SmtpPhase = "delivery"; 495 if (e->e_nrcpts != 1) 496 { 497 HoldErrs = TRUE; 498 e->e_errormode = EM_MAIL; 499 } 500 e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 501 id = e->e_id; 502 503 /* send to all recipients */ 504 sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 505 e->e_to = NULL; 506 507 /* save statistics */ 508 markstats(e, (ADDRESS *) NULL); 509 510 /* issue success if appropriate and reset */ 511 if (Errors == 0 || HoldErrs) 512 message("250 %s Message accepted for delivery", id); 513 if (bitset(EF_FATALERRS, e->e_flags)) 514 { 515 /* avoid sending back an extra message */ 516 e->e_flags &= ~EF_FATALERRS; 517 } 518 else 519 { 520 /* if we just queued, poke it */ 521 if (a != NULL && e->e_sendmode != SM_QUEUE) 522 { 523 unlockqueue(e); 524 dowork(id, TRUE, TRUE, e); 525 e->e_id = NULL; 526 } 527 } 528 529 /* if in a child, pop back to our parent */ 530 if (InChild) 531 finis(); 532 533 /* clean up a bit */ 534 gotmail = FALSE; 535 dropenvelope(e); 536 CurEnv = e = newenvelope(e, CurEnv); 537 e->e_flags = BlankEnvelope.e_flags; 538 break; 539 540 case CMDRSET: /* rset -- reset state */ 541 message("250 Reset state"); 542 if (InChild) 543 finis(); 544 545 /* clean up a bit */ 546 gotmail = FALSE; 547 dropenvelope(e); 548 CurEnv = e = newenvelope(e, CurEnv); 549 break; 550 551 case CMDVRFY: /* vrfy -- verify address */ 552 case CMDEXPN: /* expn -- expand address */ 553 vrfy = c->cmdcode == CMDVRFY; 554 if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 555 PrivacyFlags)) 556 { 557 if (vrfy) 558 message("252 Who's to say?"); 559 else 560 message("502 That's none of your business"); 561 break; 562 } 563 else if (!gothello && 564 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 565 PrivacyFlags)) 566 { 567 message("503 I demand that you introduce yourself first"); 568 break; 569 } 570 if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 571 break; 572 #ifdef LOG 573 if (LogLevel > 5) 574 syslog(LOG_INFO, "%s: %s", CurHostName, inp); 575 #endif 576 vrfyqueue = NULL; 577 QuickAbort = TRUE; 578 if (vrfy) 579 e->e_flags |= EF_VRFYONLY; 580 (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 581 if (Errors != 0) 582 { 583 if (InChild) 584 finis(); 585 break; 586 } 587 while (vrfyqueue != NULL) 588 { 589 register ADDRESS *a = vrfyqueue->q_next; 590 char *code; 591 592 while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 593 a = a->q_next; 594 595 if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 596 printvrfyaddr(vrfyqueue, a == NULL); 597 else if (a == NULL) 598 message("554 Self destructive alias loop"); 599 vrfyqueue = a; 600 } 601 if (InChild) 602 finis(); 603 break; 604 605 case CMDHELP: /* help -- give user info */ 606 help(p); 607 break; 608 609 case CMDNOOP: /* noop -- do nothing */ 610 message("200 OK"); 611 break; 612 613 case CMDQUIT: /* quit -- leave mail */ 614 message("221 %s closing connection", MyHostName); 615 if (InChild) 616 ExitStat = EX_QUIT; 617 finis(); 618 619 case CMDVERB: /* set verbose mode */ 620 Verbose = TRUE; 621 e->e_sendmode = SM_DELIVER; 622 message("200 Verbose mode"); 623 break; 624 625 case CMDONEX: /* doing one transaction only */ 626 OneXact = TRUE; 627 message("200 Only one transaction"); 628 break; 629 630 # ifdef SMTPDEBUG 631 case CMDDBGQSHOW: /* show queues */ 632 printf("Send Queue="); 633 printaddr(e->e_sendqueue, TRUE); 634 break; 635 636 case CMDDBGDEBUG: /* set debug mode */ 637 tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 638 tTflag(p); 639 message("200 Debug set"); 640 break; 641 642 # else /* not SMTPDEBUG */ 643 644 case CMDDBGQSHOW: /* show queues */ 645 case CMDDBGDEBUG: /* set debug mode */ 646 # ifdef LOG 647 if (LogLevel > 0) 648 syslog(LOG_NOTICE, 649 "\"%s\" command from %s (%s)", 650 c->cmdname, RealHostName, 651 anynet_ntoa(&RealHostAddr)); 652 # endif 653 /* FALL THROUGH */ 654 # endif /* SMTPDEBUG */ 655 656 case CMDERROR: /* unknown command */ 657 message("500 Command unrecognized"); 658 break; 659 660 default: 661 errno = 0; 662 syserr("500 smtp: unknown code %d", c->cmdcode); 663 break; 664 } 665 } 666 } 667 /* 668 ** SKIPWORD -- skip a fixed word. 669 ** 670 ** Parameters: 671 ** p -- place to start looking. 672 ** w -- word to skip. 673 ** 674 ** Returns: 675 ** p following w. 676 ** NULL on error. 677 ** 678 ** Side Effects: 679 ** clobbers the p data area. 680 */ 681 682 static char * 683 skipword(p, w) 684 register char *p; 685 char *w; 686 { 687 register char *q; 688 689 /* find beginning of word */ 690 while (isascii(*p) && isspace(*p)) 691 p++; 692 q = p; 693 694 /* find end of word */ 695 while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 696 p++; 697 while (isascii(*p) && isspace(*p)) 698 *p++ = '\0'; 699 if (*p != ':') 700 { 701 syntax: 702 message("501 Syntax error"); 703 Errors++; 704 return (NULL); 705 } 706 *p++ = '\0'; 707 while (isascii(*p) && isspace(*p)) 708 p++; 709 710 /* see if the input word matches desired word */ 711 if (strcasecmp(q, w)) 712 goto syntax; 713 714 return (p); 715 } 716 /* 717 ** PRINTVRFYADDR -- print an entry in the verify queue 718 ** 719 ** Parameters: 720 ** a -- the address to print 721 ** last -- set if this is the last one. 722 ** 723 ** Returns: 724 ** none. 725 ** 726 ** Side Effects: 727 ** Prints the appropriate 250 codes. 728 */ 729 730 printvrfyaddr(a, last) 731 register ADDRESS *a; 732 bool last; 733 { 734 char fmtbuf[20]; 735 736 strcpy(fmtbuf, "250"); 737 fmtbuf[3] = last ? ' ' : '-'; 738 739 if (strchr(a->q_paddr, '<') != NULL) 740 strcpy(&fmtbuf[4], "%s"); 741 else if (a->q_fullname == NULL) 742 strcpy(&fmtbuf[4], "<%s>"); 743 else 744 { 745 strcpy(&fmtbuf[4], "%s <%s>"); 746 message(fmtbuf, a->q_fullname, a->q_paddr); 747 return; 748 } 749 message(fmtbuf, a->q_paddr); 750 } 751 /* 752 ** HELP -- implement the HELP command. 753 ** 754 ** Parameters: 755 ** topic -- the topic we want help for. 756 ** 757 ** Returns: 758 ** none. 759 ** 760 ** Side Effects: 761 ** outputs the help file to message output. 762 */ 763 764 help(topic) 765 char *topic; 766 { 767 register FILE *hf; 768 int len; 769 char buf[MAXLINE]; 770 bool noinfo; 771 772 if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 773 { 774 /* no help */ 775 errno = 0; 776 message("502 HELP not implemented"); 777 return; 778 } 779 780 if (topic == NULL || *topic == '\0') 781 topic = "smtp"; 782 else 783 makelower(topic); 784 785 len = strlen(topic); 786 noinfo = TRUE; 787 788 while (fgets(buf, sizeof buf, hf) != NULL) 789 { 790 if (strncmp(buf, topic, len) == 0) 791 { 792 register char *p; 793 794 p = strchr(buf, '\t'); 795 if (p == NULL) 796 p = buf; 797 else 798 p++; 799 fixcrlf(p, TRUE); 800 message("214-%s", p); 801 noinfo = FALSE; 802 } 803 } 804 805 if (noinfo) 806 message("504 HELP topic unknown"); 807 else 808 message("214 End of HELP info"); 809 (void) fclose(hf); 810 } 811 /* 812 ** RUNINCHILD -- return twice -- once in the child, then in the parent again 813 ** 814 ** Parameters: 815 ** label -- a string used in error messages 816 ** 817 ** Returns: 818 ** zero in the child 819 ** one in the parent 820 ** 821 ** Side Effects: 822 ** none. 823 */ 824 825 runinchild(label, e) 826 char *label; 827 register ENVELOPE *e; 828 { 829 int childpid; 830 831 if (!OneXact) 832 { 833 childpid = dofork(); 834 if (childpid < 0) 835 { 836 syserr("%s: cannot fork", label); 837 return (1); 838 } 839 if (childpid > 0) 840 { 841 auto int st; 842 843 /* parent -- wait for child to complete */ 844 setproctitle("srvrsmtp %s child wait", CurHostName); 845 st = waitfor(childpid); 846 if (st == -1) 847 syserr("%s: lost child", label); 848 849 /* if we exited on a QUIT command, complete the process */ 850 if (st == (EX_QUIT << 8)) 851 finis(); 852 853 return (1); 854 } 855 else 856 { 857 /* child */ 858 InChild = TRUE; 859 QuickAbort = FALSE; 860 clearenvelope(e, FALSE); 861 } 862 } 863 864 /* open alias database */ 865 initaliases(FALSE, e); 866 867 return (0); 868 } 869 870 # endif /* SMTP */ 871