122712Sdist /* 222712Sdist ** Sendmail 322712Sdist ** Copyright (c) 1983 Eric P. Allman 422712Sdist ** Berkeley, California 522712Sdist ** 622712Sdist ** Copyright (c) 1983 Regents of the University of California. 722712Sdist ** All rights reserved. The Berkeley software License Agreement 822712Sdist ** specifies the terms and conditions for redistribution. 922712Sdist */ 1022712Sdist 1122712Sdist 129339Seric # include <errno.h> 134549Seric # include "sendmail.h" 1411728Seric # include <signal.h> 154549Seric 165181Seric # ifndef SMTP 1723122Seric # ifndef lint 18*24981Seric static char SccsId[] = "@(#)srvrsmtp.c 5.12 (Berkeley) 09/21/85 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*24981Seric static char SccsId[] = "@(#)srvrsmtp.c 5.12 (Berkeley) 09/21/85"; 2423122Seric # endif not lint 255181Seric 264549Seric /* 274549Seric ** SMTP -- run the SMTP protocol. 284549Seric ** 294549Seric ** Parameters: 304549Seric ** none. 314549Seric ** 324549Seric ** Returns: 334549Seric ** never. 344549Seric ** 354549Seric ** Side Effects: 364549Seric ** Reads commands from the input channel and processes 374549Seric ** them. 384549Seric */ 394549Seric 404549Seric struct cmd 414549Seric { 424549Seric char *cmdname; /* command name */ 434549Seric int cmdcode; /* internal code, see below */ 444549Seric }; 454549Seric 464549Seric /* values for cmdcode */ 474549Seric # define CMDERROR 0 /* bad command */ 484549Seric # define CMDMAIL 1 /* mail -- designate sender */ 494976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 504549Seric # define CMDDATA 3 /* data -- send message text */ 519339Seric # define CMDRSET 4 /* rset -- reset state */ 529339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 539339Seric # define CMDHELP 6 /* help -- give usage info */ 549339Seric # define CMDNOOP 7 /* noop -- do nothing */ 559339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 569339Seric # define CMDHELO 9 /* helo -- be polite */ 579339Seric # define CMDDBGQSHOW 10 /* showq -- show send queue (DEBUG) */ 589339Seric # define CMDDBGDEBUG 11 /* debug -- set debug mode */ 599339Seric # define CMDVERB 12 /* verb -- go into verbose mode */ 609339Seric # define CMDDBGKILL 13 /* kill -- kill sendmail */ 619339Seric # define CMDDBGWIZ 14 /* wiz -- become a wizard */ 629339Seric # define CMDONEX 15 /* onex -- sending one transaction only */ 634549Seric 644549Seric static struct cmd CmdTab[] = 654549Seric { 664549Seric "mail", CMDMAIL, 674976Seric "rcpt", CMDRCPT, 684549Seric "data", CMDDATA, 694549Seric "rset", CMDRSET, 704549Seric "vrfy", CMDVRFY, 717762Seric "expn", CMDVRFY, 724549Seric "help", CMDHELP, 734549Seric "noop", CMDNOOP, 744549Seric "quit", CMDQUIT, 754976Seric "helo", CMDHELO, 768544Seric "verb", CMDVERB, 779314Seric "onex", CMDONEX, 785003Seric # ifdef DEBUG 799339Seric "showq", CMDDBGQSHOW, 808544Seric "debug", CMDDBGDEBUG, 8124945Seric # endif DEBUG 8224945Seric # ifdef WIZ 838544Seric "kill", CMDDBGKILL, 8424945Seric # endif WIZ 858544Seric "wiz", CMDDBGWIZ, 864549Seric NULL, CMDERROR, 874549Seric }; 884549Seric 8924955Seric # ifdef WIZ 908544Seric bool IsWiz = FALSE; /* set if we are a wizard */ 9124955Seric # endif WIZ 9215596Seric char *WizWord; /* the wizard word to compare against */ 939339Seric bool InChild = FALSE; /* true if running in a subprocess */ 949378Seric bool OneXact = FALSE; /* one xaction only this run */ 9511146Seric 969339Seric #define EX_QUIT 22 /* special code for QUIT command */ 978544Seric 984549Seric smtp() 994549Seric { 1004549Seric register char *p; 1018544Seric register struct cmd *c; 1024549Seric char *cmd; 1034549Seric extern char *skipword(); 1044549Seric extern bool sameword(); 1054549Seric bool hasmail; /* mail command received */ 1065003Seric auto ADDRESS *vrfyqueue; 10712612Seric ADDRESS *a; 1088544Seric char inp[MAXLINE]; 109*24981Seric char cmdbuf[100]; 1107124Seric extern char Version[]; 1117356Seric extern tick(); 1128544Seric extern bool iswiz(); 1139349Seric extern char *arpadate(); 11411151Seric extern char *macvalue(); 11512612Seric extern ADDRESS *recipient(); 11624943Seric extern ENVELOPE BlankEnvelope; 11724943Seric extern ENVELOPE *newenvelope(); 1184549Seric 1195003Seric hasmail = FALSE; 1207363Seric if (OutChannel != stdout) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 1237363Seric (void) close(1); 1247363Seric (void) dup(fileno(OutChannel)); 1257363Seric } 12611931Seric settime(); 12724971Seric if (RealHostName != NULL) 128*24981Seric setproctitle("talking to %s", RealHostName); 12916153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 13010708Seric message("220", inp); 13124943Seric SmtpPhase = "startup"; 1324549Seric for (;;) 1334549Seric { 13412612Seric /* arrange for backout */ 13512612Seric if (setjmp(TopFrame) > 0 && InChild) 13612612Seric finis(); 13712612Seric QuickAbort = FALSE; 13812612Seric HoldErrs = FALSE; 13912612Seric 1407356Seric /* setup for the read */ 1416907Seric CurEnv->e_to = NULL; 1424577Seric Errors = 0; 1437275Seric (void) fflush(stdout); 1447356Seric 1457356Seric /* read the input line */ 1467685Seric p = sfgets(inp, sizeof inp, InChannel); 1477356Seric 1487685Seric /* handle errors */ 1497356Seric if (p == NULL) 1507356Seric { 1514549Seric /* end of file, just die */ 1524558Seric message("421", "%s Lost input channel", HostName); 1534549Seric finis(); 1544549Seric } 1554549Seric 1564549Seric /* clean up end of line */ 1574558Seric fixcrlf(inp, TRUE); 1584549Seric 1594713Seric /* echo command to transcript */ 1609545Seric if (CurEnv->e_xfp != NULL) 1619545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1624713Seric 1634549Seric /* break off command */ 1644549Seric for (p = inp; isspace(*p); p++) 1654549Seric continue; 1664549Seric cmd = p; 167*24981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 168*24981Seric *cmd++ = *p++; 169*24981Seric *cmd = '\0'; 1704549Seric 1714549Seric /* decode command */ 1724549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1734549Seric { 1744549Seric if (sameword(c->cmdname, cmd)) 1754549Seric break; 1764549Seric } 1774549Seric 1784549Seric /* process command */ 1794549Seric switch (c->cmdcode) 1804549Seric { 1814976Seric case CMDHELO: /* hello -- introduce yourself */ 18224943Seric SmtpPhase = "HELO"; 183*24981Seric setproctitle("talking to %s (%s)", RealHostName, inp); 18414877Seric if (sameword(p, HostName)) 18514877Seric { 18614877Seric /* connected to an echo server */ 18714877Seric message("553", "%s I refuse to talk to myself", 18814877Seric HostName); 18914877Seric break; 19014877Seric } 19111146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 19211146Seric { 193*24981Seric char hostbuf[MAXNAME]; 19411146Seric 195*24981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 196*24981Seric define('s', newstr(hostbuf), CurEnv); 19711146Seric } 19811146Seric else 19911146Seric define('s', newstr(p), CurEnv); 2004997Seric message("250", "%s Hello %s, pleased to meet you", 2014997Seric HostName, p); 2024976Seric break; 2034976Seric 2044549Seric case CMDMAIL: /* mail -- designate sender */ 20524943Seric SmtpPhase = "MAIL"; 20624943Seric 20711151Seric /* force a sending host even if no HELO given */ 20811151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 20911151Seric define('s', RealHostName, CurEnv); 21011151Seric 2119314Seric /* check for validity of this command */ 2124558Seric if (hasmail) 2134558Seric { 2144558Seric message("503", "Sender already specified"); 2154558Seric break; 2164558Seric } 2179339Seric if (InChild) 2189339Seric { 2199339Seric syserr("Nested MAIL command"); 2209339Seric exit(0); 2219339Seric } 2229339Seric 2239339Seric /* fork a subprocess to process this command */ 2249339Seric if (runinchild("SMTP-MAIL") > 0) 2259339Seric break; 2269339Seric initsys(); 227*24981Seric setproctitle("talking to %s (%s - %s)", RealHostName, 228*24981Seric CurEnv->e_id, inp); 2299339Seric 2309339Seric /* child -- go do the processing */ 2314549Seric p = skipword(p, "from"); 2324549Seric if (p == NULL) 2334549Seric break; 2344549Seric setsender(p); 2354577Seric if (Errors == 0) 2364549Seric { 2374549Seric message("250", "Sender ok"); 2384549Seric hasmail = TRUE; 2394549Seric } 2409339Seric else if (InChild) 2419339Seric finis(); 2424549Seric break; 2434549Seric 2444976Seric case CMDRCPT: /* rcpt -- designate recipient */ 24524943Seric SmtpPhase = "RCPT"; 246*24981Seric setproctitle("talking to %s (%s - %s)", RealHostName, 247*24981Seric CurEnv->e_id, inp); 24812612Seric if (setjmp(TopFrame) > 0) 24914785Seric { 25014785Seric CurEnv->e_flags &= ~EF_FATALERRS; 25112612Seric break; 25214785Seric } 25312612Seric QuickAbort = TRUE; 2544549Seric p = skipword(p, "to"); 2554549Seric if (p == NULL) 2564549Seric break; 25716140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 25812612Seric if (a == NULL) 25912612Seric break; 26016886Seric a->q_flags |= QPRIMARY; 26112612Seric a = recipient(a, &CurEnv->e_sendqueue); 26212612Seric if (Errors != 0) 26312612Seric break; 26412612Seric 26512612Seric /* no errors during parsing, but might be a duplicate */ 26612612Seric CurEnv->e_to = p; 26712612Seric if (!bitset(QBADADDR, a->q_flags)) 26812612Seric message("250", "Recipient ok"); 26912612Seric else 2704549Seric { 27112612Seric /* punt -- should keep message in ADDRESS.... */ 27212612Seric message("550", "Addressee unknown"); 2734549Seric } 27412612Seric CurEnv->e_to = NULL; 2754549Seric break; 2764549Seric 2774549Seric case CMDDATA: /* data -- text of mail */ 27824943Seric SmtpPhase = "DATA"; 2794976Seric if (!hasmail) 2804549Seric { 2814976Seric message("503", "Need MAIL command"); 2824976Seric break; 2834549Seric } 28424943Seric else if (CurEnv->e_nrcpts <= 0) 2854549Seric { 2864976Seric message("503", "Need RCPT (recipient)"); 2874976Seric break; 2884549Seric } 2894976Seric 2904976Seric /* collect the text of the message */ 29124943Seric SmtpPhase = "collect"; 292*24981Seric setproctitle("talking to %s (%s - %s)", RealHostName, 293*24981Seric CurEnv->e_id, inp); 2944976Seric collect(TRUE); 2954976Seric if (Errors != 0) 2964976Seric break; 2974976Seric 2988238Seric /* 2998238Seric ** Arrange to send to everyone. 3008238Seric ** If sending to multiple people, mail back 3018238Seric ** errors rather than reporting directly. 3028238Seric ** In any case, don't mail back errors for 3038238Seric ** anything that has happened up to 3048238Seric ** now (the other end will do this). 30510197Seric ** Truncate our transcript -- the mail has gotten 30610197Seric ** to us successfully, and if we have 30710197Seric ** to mail this back, it will be easier 30810197Seric ** on the reader. 3098238Seric ** Then send to everyone. 3108238Seric ** Finally give a reply code. If an error has 3118238Seric ** already been given, don't mail a 3128238Seric ** message back. 3139339Seric ** We goose error returns by clearing error bit. 3148238Seric */ 3158238Seric 31624943Seric SmtpPhase = "delivery"; 31724943Seric if (CurEnv->e_nrcpts != 1) 3189378Seric { 3199378Seric HoldErrs = TRUE; 32016886Seric ErrorMode = EM_MAIL; 3219378Seric } 3229339Seric CurEnv->e_flags &= ~EF_FATALERRS; 32310197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3244976Seric 3254976Seric /* send to all recipients */ 32614877Seric sendall(CurEnv, SM_DEFAULT); 3276907Seric CurEnv->e_to = NULL; 3284976Seric 32923516Seric /* save statistics */ 33023516Seric markstats(CurEnv, (ADDRESS *) NULL); 33123516Seric 3328238Seric /* issue success if appropriate and reset */ 3338238Seric if (Errors == 0 || HoldErrs) 3349283Seric message("250", "Ok"); 3358238Seric else 3369339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3379339Seric 3389339Seric /* if in a child, pop back to our parent */ 3399339Seric if (InChild) 3409339Seric finis(); 34124943Seric 34224943Seric /* clean up a bit */ 34324943Seric hasmail = 0; 34424943Seric dropenvelope(CurEnv); 34524943Seric CurEnv = newenvelope(CurEnv); 34624943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3474549Seric break; 3484549Seric 3494549Seric case CMDRSET: /* rset -- reset state */ 3504549Seric message("250", "Reset state"); 3519339Seric if (InChild) 3529339Seric finis(); 3539339Seric break; 3544549Seric 3554549Seric case CMDVRFY: /* vrfy -- verify address */ 3569339Seric if (runinchild("SMTP-VRFY") > 0) 3579339Seric break; 358*24981Seric setproctitle("talking to %s (%s)", RealHostName, inp); 3595003Seric vrfyqueue = NULL; 3607762Seric QuickAbort = TRUE; 3619619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3627762Seric if (Errors != 0) 3639339Seric { 3649339Seric if (InChild) 3659339Seric finis(); 3667762Seric break; 3679339Seric } 3685003Seric while (vrfyqueue != NULL) 3695003Seric { 3705003Seric register ADDRESS *a = vrfyqueue->q_next; 3715003Seric char *code; 3725003Seric 3737685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3745003Seric a = a->q_next; 3755003Seric 3767685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3775003Seric { 3785003Seric if (a != NULL) 3795003Seric code = "250-"; 3805003Seric else 3815003Seric code = "250"; 3825003Seric if (vrfyqueue->q_fullname == NULL) 3835003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3845003Seric else 3855003Seric message(code, "%s <%s>", 3865003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 3875003Seric } 3885003Seric else if (a == NULL) 3895003Seric message("554", "Self destructive alias loop"); 3905003Seric vrfyqueue = a; 3915003Seric } 3929339Seric if (InChild) 3939339Seric finis(); 3944549Seric break; 3954549Seric 3964549Seric case CMDHELP: /* help -- give user info */ 3974577Seric if (*p == '\0') 3984577Seric p = "SMTP"; 3994577Seric help(p); 4004549Seric break; 4014549Seric 4024549Seric case CMDNOOP: /* noop -- do nothing */ 4034549Seric message("200", "OK"); 4044549Seric break; 4054549Seric 4064549Seric case CMDQUIT: /* quit -- leave mail */ 4074549Seric message("221", "%s closing connection", HostName); 4089339Seric if (InChild) 4099339Seric ExitStat = EX_QUIT; 4104549Seric finis(); 4114549Seric 4128544Seric case CMDVERB: /* set verbose mode */ 4138544Seric Verbose = TRUE; 4148544Seric message("200", "Verbose mode"); 4158544Seric break; 4168544Seric 4179314Seric case CMDONEX: /* doing one transaction only */ 4189378Seric OneXact = TRUE; 4199314Seric message("200", "Only one transaction"); 4209314Seric break; 4219314Seric 4225003Seric # ifdef DEBUG 4239339Seric case CMDDBGQSHOW: /* show queues */ 4246907Seric printf("Send Queue="); 4256907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4265003Seric break; 4277275Seric 4287275Seric case CMDDBGDEBUG: /* set debug mode */ 4297676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4307676Seric tTflag(p); 4317676Seric message("200", "Debug set"); 4327275Seric break; 43324945Seric # endif DEBUG 4347275Seric 43524945Seric # ifdef WIZ 4367282Seric case CMDDBGKILL: /* kill the parent */ 4378544Seric if (!iswiz()) 4388544Seric break; 4397282Seric if (kill(MotherPid, SIGTERM) >= 0) 4407282Seric message("200", "Mother is dead"); 4417282Seric else 4427282Seric message("500", "Can't kill Mom"); 4437282Seric break; 4448544Seric 4458544Seric case CMDDBGWIZ: /* become a wizard */ 4468544Seric if (WizWord != NULL) 4478544Seric { 4488544Seric char seed[3]; 4498544Seric extern char *crypt(); 4508544Seric 45123106Seric (void) strncpy(seed, WizWord, 2); 45215596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4538544Seric { 45415596Seric IsWiz = TRUE; 45515596Seric message("200", "Please pass, oh mighty wizard"); 4568544Seric break; 4578544Seric } 4588544Seric } 45915596Seric message("500", "You are no wizard!"); 4608544Seric break; 4615003Seric 46224945Seric # else WIZ 46324945Seric case CMDDBGWIZ: /* try to become a wizard */ 46424945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 46524945Seric break; 46624945Seric # endif WIZ 46724945Seric 4684549Seric case CMDERROR: /* unknown command */ 4694549Seric message("500", "Command unrecognized"); 4704549Seric break; 4714549Seric 4724549Seric default: 4734549Seric syserr("smtp: unknown code %d", c->cmdcode); 4744549Seric break; 4754549Seric } 4764549Seric } 4774549Seric } 4784549Seric /* 4794549Seric ** SKIPWORD -- skip a fixed word. 4804549Seric ** 4814549Seric ** Parameters: 4824549Seric ** p -- place to start looking. 4834549Seric ** w -- word to skip. 4844549Seric ** 4854549Seric ** Returns: 4864549Seric ** p following w. 4874549Seric ** NULL on error. 4884549Seric ** 4894549Seric ** Side Effects: 4904549Seric ** clobbers the p data area. 4914549Seric */ 4924549Seric 4934549Seric static char * 4944549Seric skipword(p, w) 4954549Seric register char *p; 4964549Seric char *w; 4974549Seric { 4984549Seric register char *q; 4994549Seric extern bool sameword(); 5004549Seric 5014549Seric /* find beginning of word */ 5024549Seric while (isspace(*p)) 5034549Seric p++; 5044549Seric q = p; 5054549Seric 5064549Seric /* find end of word */ 5074549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5084549Seric p++; 5094549Seric while (isspace(*p)) 5104549Seric *p++ = '\0'; 5114549Seric if (*p != ':') 5124549Seric { 5134549Seric syntax: 5144549Seric message("501", "Syntax error"); 5154549Seric Errors++; 5164549Seric return (NULL); 5174549Seric } 5184549Seric *p++ = '\0'; 5194549Seric while (isspace(*p)) 5204549Seric p++; 5214549Seric 5224549Seric /* see if the input word matches desired word */ 5234549Seric if (!sameword(q, w)) 5244549Seric goto syntax; 5254549Seric 5264549Seric return (p); 5274549Seric } 5284577Seric /* 5294577Seric ** HELP -- implement the HELP command. 5304577Seric ** 5314577Seric ** Parameters: 5324577Seric ** topic -- the topic we want help for. 5334577Seric ** 5344577Seric ** Returns: 5354577Seric ** none. 5364577Seric ** 5374577Seric ** Side Effects: 5384577Seric ** outputs the help file to message output. 5394577Seric */ 5404577Seric 5414577Seric help(topic) 5424577Seric char *topic; 5434577Seric { 5444577Seric register FILE *hf; 5454577Seric int len; 5464577Seric char buf[MAXLINE]; 5474577Seric bool noinfo; 5484577Seric 5498269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5504577Seric { 5514577Seric /* no help */ 55211931Seric errno = 0; 5534577Seric message("502", "HELP not implemented"); 5544577Seric return; 5554577Seric } 5564577Seric 5574577Seric len = strlen(topic); 5584577Seric makelower(topic); 5594577Seric noinfo = TRUE; 5604577Seric 5614577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5624577Seric { 5634577Seric if (strncmp(buf, topic, len) == 0) 5644577Seric { 5654577Seric register char *p; 5664577Seric 5674577Seric p = index(buf, '\t'); 5684577Seric if (p == NULL) 5694577Seric p = buf; 5704577Seric else 5714577Seric p++; 5724577Seric fixcrlf(p, TRUE); 5734577Seric message("214-", p); 5744577Seric noinfo = FALSE; 5754577Seric } 5764577Seric } 5774577Seric 5784577Seric if (noinfo) 5794577Seric message("504", "HELP topic unknown"); 5804577Seric else 5814577Seric message("214", "End of HELP info"); 5824628Seric (void) fclose(hf); 5834577Seric } 5848544Seric /* 5858544Seric ** ISWIZ -- tell us if we are a wizard 5868544Seric ** 5878544Seric ** If not, print a nasty message. 5888544Seric ** 5898544Seric ** Parameters: 5908544Seric ** none. 5918544Seric ** 5928544Seric ** Returns: 5938544Seric ** TRUE if we are a wizard. 5948544Seric ** FALSE if we are not a wizard. 5958544Seric ** 5968544Seric ** Side Effects: 5978544Seric ** Prints a 500 exit stat if we are not a wizard. 5988544Seric */ 5995181Seric 60024945Seric #ifdef WIZ 60119038Seric 6028544Seric bool 6038544Seric iswiz() 6048544Seric { 6058544Seric if (!IsWiz) 6068544Seric message("500", "Mere mortals musn't mutter that mantra"); 6078544Seric return (IsWiz); 6088544Seric } 60919038Seric 61024945Seric #endif WIZ 6119339Seric /* 6129339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6139339Seric ** 6149339Seric ** Parameters: 6159339Seric ** label -- a string used in error messages 6169339Seric ** 6179339Seric ** Returns: 6189339Seric ** zero in the child 6199339Seric ** one in the parent 6209339Seric ** 6219339Seric ** Side Effects: 6229339Seric ** none. 6239339Seric */ 6248544Seric 6259339Seric runinchild(label) 6269339Seric char *label; 6279339Seric { 6289339Seric int childpid; 6299339Seric 63016158Seric if (!OneXact) 6319339Seric { 63216158Seric childpid = dofork(); 63316158Seric if (childpid < 0) 63416158Seric { 63516158Seric syserr("%s: cannot fork", label); 63616158Seric return (1); 63716158Seric } 63816158Seric if (childpid > 0) 63916158Seric { 64016158Seric auto int st; 6419339Seric 64216158Seric /* parent -- wait for child to complete */ 64316158Seric st = waitfor(childpid); 64416158Seric if (st == -1) 64516158Seric syserr("%s: lost child", label); 6469339Seric 64716158Seric /* if we exited on a QUIT command, complete the process */ 64816158Seric if (st == (EX_QUIT << 8)) 64916158Seric finis(); 6509339Seric 65116158Seric return (1); 65216158Seric } 65316158Seric else 65416158Seric { 65516158Seric /* child */ 65616158Seric InChild = TRUE; 65724945Seric clearenvelope(CurEnv); 65816158Seric } 6599339Seric } 66015256Seric 66116158Seric /* open alias database */ 66216158Seric initaliases(AliasFile, FALSE); 66316158Seric 66416158Seric return (0); 6659339Seric } 6669339Seric 6675181Seric # endif SMTP 668