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*23516Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.5 (Berkeley) 06/17/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*23516Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.5 (Berkeley) 06/17/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,
818544Seric 	"kill",		CMDDBGKILL,
828544Seric 	"wiz",		CMDDBGWIZ,
835003Seric # endif DEBUG
844549Seric 	NULL,		CMDERROR,
854549Seric };
864549Seric 
878544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
8815596Seric char	*WizWord;			/* the wizard word to compare against */
899339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
909378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9111146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
9211146Seric 
939339Seric #define EX_QUIT		22		/* special code for QUIT command */
948544Seric 
954549Seric smtp()
964549Seric {
974549Seric 	register char *p;
988544Seric 	register struct cmd *c;
994549Seric 	char *cmd;
1004549Seric 	extern char *skipword();
1014549Seric 	extern bool sameword();
1024549Seric 	bool hasmail;			/* mail command received */
1034713Seric 	int rcps;			/* number of recipients */
1045003Seric 	auto ADDRESS *vrfyqueue;
10512612Seric 	ADDRESS *a;
1068544Seric 	char inp[MAXLINE];
1077124Seric 	extern char Version[];
1087356Seric 	extern tick();
1098544Seric 	extern bool iswiz();
1109349Seric 	extern char *arpadate();
11111151Seric 	extern char *macvalue();
11212612Seric 	extern ADDRESS *recipient();
1134549Seric 
1145003Seric 	hasmail = FALSE;
1154713Seric 	rcps = 0;
1167363Seric 	if (OutChannel != stdout)
1177363Seric 	{
1187363Seric 		/* arrange for debugging output to go to remote host */
1197363Seric 		(void) close(1);
1207363Seric 		(void) dup(fileno(OutChannel));
1217363Seric 	}
12211931Seric 	settime();
12316153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12410708Seric 	message("220", inp);
1254549Seric 	for (;;)
1264549Seric 	{
12712612Seric 		/* arrange for backout */
12812612Seric 		if (setjmp(TopFrame) > 0 && InChild)
12912612Seric 			finis();
13012612Seric 		QuickAbort = FALSE;
13112612Seric 		HoldErrs = FALSE;
13212612Seric 
1337356Seric 		/* setup for the read */
1346907Seric 		CurEnv->e_to = NULL;
1354577Seric 		Errors = 0;
1367275Seric 		(void) fflush(stdout);
1377356Seric 
1387356Seric 		/* read the input line */
1397685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1407356Seric 
1417685Seric 		/* handle errors */
1427356Seric 		if (p == NULL)
1437356Seric 		{
1444549Seric 			/* end of file, just die */
1454558Seric 			message("421", "%s Lost input channel", HostName);
1464549Seric 			finis();
1474549Seric 		}
1484549Seric 
1494549Seric 		/* clean up end of line */
1504558Seric 		fixcrlf(inp, TRUE);
1514549Seric 
1524713Seric 		/* echo command to transcript */
1539545Seric 		if (CurEnv->e_xfp != NULL)
1549545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1554713Seric 
1564549Seric 		/* break off command */
1574549Seric 		for (p = inp; isspace(*p); p++)
1584549Seric 			continue;
1594549Seric 		cmd = p;
1604549Seric 		while (*++p != '\0' && !isspace(*p))
1614549Seric 			continue;
1624549Seric 		if (*p != '\0')
1634549Seric 			*p++ = '\0';
1644549Seric 
1654549Seric 		/* decode command */
1664549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1674549Seric 		{
1684549Seric 			if (sameword(c->cmdname, cmd))
1694549Seric 				break;
1704549Seric 		}
1714549Seric 
1724549Seric 		/* process command */
1734549Seric 		switch (c->cmdcode)
1744549Seric 		{
1754976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
17614877Seric 			if (sameword(p, HostName))
17714877Seric 			{
17814877Seric 				/* connected to an echo server */
17914877Seric 				message("553", "%s I refuse to talk to myself",
18014877Seric 					HostName);
18114877Seric 				break;
18214877Seric 			}
18311146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
18411146Seric 			{
18511146Seric 				char buf[MAXNAME];
18611146Seric 
18711146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
18811146Seric 				define('s', newstr(buf), CurEnv);
18911146Seric 			}
19011146Seric 			else
19111146Seric 				define('s', newstr(p), CurEnv);
1924997Seric 			message("250", "%s Hello %s, pleased to meet you",
1934997Seric 				HostName, p);
1944976Seric 			break;
1954976Seric 
1964549Seric 		  case CMDMAIL:		/* mail -- designate sender */
19711151Seric 			/* force a sending host even if no HELO given */
19811151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
19911151Seric 				define('s', RealHostName, CurEnv);
20011151Seric 
2019314Seric 			/* check for validity of this command */
2024558Seric 			if (hasmail)
2034558Seric 			{
2044558Seric 				message("503", "Sender already specified");
2054558Seric 				break;
2064558Seric 			}
2079339Seric 			if (InChild)
2089339Seric 			{
2099339Seric 				syserr("Nested MAIL command");
2109339Seric 				exit(0);
2119339Seric 			}
2129339Seric 
2139339Seric 			/* fork a subprocess to process this command */
2149339Seric 			if (runinchild("SMTP-MAIL") > 0)
2159339Seric 				break;
2169339Seric 			initsys();
2179339Seric 
2189339Seric 			/* child -- go do the processing */
2194549Seric 			p = skipword(p, "from");
2204549Seric 			if (p == NULL)
2214549Seric 				break;
2224549Seric 			setsender(p);
2234577Seric 			if (Errors == 0)
2244549Seric 			{
2254549Seric 				message("250", "Sender ok");
2264549Seric 				hasmail = TRUE;
2274549Seric 			}
2289339Seric 			else if (InChild)
2299339Seric 				finis();
2304549Seric 			break;
2314549Seric 
2324976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
23312612Seric 			if (setjmp(TopFrame) > 0)
23414785Seric 			{
23514785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
23612612Seric 				break;
23714785Seric 			}
23812612Seric 			QuickAbort = TRUE;
2394549Seric 			p = skipword(p, "to");
2404549Seric 			if (p == NULL)
2414549Seric 				break;
24216140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
24312612Seric 			if (a == NULL)
24412612Seric 				break;
24516886Seric 			a->q_flags |= QPRIMARY;
24612612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
24712612Seric 			if (Errors != 0)
24812612Seric 				break;
24912612Seric 
25012612Seric 			/* no errors during parsing, but might be a duplicate */
25112612Seric 			CurEnv->e_to = p;
25212612Seric 			if (!bitset(QBADADDR, a->q_flags))
25312612Seric 				message("250", "Recipient ok");
25412612Seric 			else
2554549Seric 			{
25612612Seric 				/* punt -- should keep message in ADDRESS.... */
25712612Seric 				message("550", "Addressee unknown");
2584549Seric 			}
25912612Seric 			CurEnv->e_to = NULL;
26012612Seric 			rcps++;
2614549Seric 			break;
2624549Seric 
2634549Seric 		  case CMDDATA:		/* data -- text of mail */
2644976Seric 			if (!hasmail)
2654549Seric 			{
2664976Seric 				message("503", "Need MAIL command");
2674976Seric 				break;
2684549Seric 			}
2694713Seric 			else if (rcps <= 0)
2704549Seric 			{
2714976Seric 				message("503", "Need RCPT (recipient)");
2724976Seric 				break;
2734549Seric 			}
2744976Seric 
2754976Seric 			/* collect the text of the message */
2764976Seric 			collect(TRUE);
2774976Seric 			if (Errors != 0)
2784976Seric 				break;
2794976Seric 
2808238Seric 			/*
2818238Seric 			**  Arrange to send to everyone.
2828238Seric 			**	If sending to multiple people, mail back
2838238Seric 			**		errors rather than reporting directly.
2848238Seric 			**	In any case, don't mail back errors for
2858238Seric 			**		anything that has happened up to
2868238Seric 			**		now (the other end will do this).
28710197Seric 			**	Truncate our transcript -- the mail has gotten
28810197Seric 			**		to us successfully, and if we have
28910197Seric 			**		to mail this back, it will be easier
29010197Seric 			**		on the reader.
2918238Seric 			**	Then send to everyone.
2928238Seric 			**	Finally give a reply code.  If an error has
2938238Seric 			**		already been given, don't mail a
2948238Seric 			**		message back.
2959339Seric 			**	We goose error returns by clearing error bit.
2968238Seric 			*/
2978238Seric 
2984976Seric 			if (rcps != 1)
2999378Seric 			{
3009378Seric 				HoldErrs = TRUE;
30116886Seric 				ErrorMode = EM_MAIL;
3029378Seric 			}
3039339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
30410197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3054976Seric 
3064976Seric 			/* send to all recipients */
30714877Seric 			sendall(CurEnv, SM_DEFAULT);
3086907Seric 			CurEnv->e_to = NULL;
3094976Seric 
310*23516Seric 			/* save statistics */
311*23516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
312*23516Seric 
3138238Seric 			/* issue success if appropriate and reset */
3148238Seric 			if (Errors == 0 || HoldErrs)
3159283Seric 				message("250", "Ok");
3168238Seric 			else
3179339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3189339Seric 
3199339Seric 			/* if in a child, pop back to our parent */
3209339Seric 			if (InChild)
3219339Seric 				finis();
3224549Seric 			break;
3234549Seric 
3244549Seric 		  case CMDRSET:		/* rset -- reset state */
3254549Seric 			message("250", "Reset state");
3269339Seric 			if (InChild)
3279339Seric 				finis();
3289339Seric 			break;
3294549Seric 
3304549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3319339Seric 			if (runinchild("SMTP-VRFY") > 0)
3329339Seric 				break;
3335003Seric 			vrfyqueue = NULL;
3347762Seric 			QuickAbort = TRUE;
3359619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3367762Seric 			if (Errors != 0)
3379339Seric 			{
3389339Seric 				if (InChild)
3399339Seric 					finis();
3407762Seric 				break;
3419339Seric 			}
3425003Seric 			while (vrfyqueue != NULL)
3435003Seric 			{
3445003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3455003Seric 				char *code;
3465003Seric 
3477685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3485003Seric 					a = a->q_next;
3495003Seric 
3507685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3515003Seric 				{
3525003Seric 					if (a != NULL)
3535003Seric 						code = "250-";
3545003Seric 					else
3555003Seric 						code = "250";
3565003Seric 					if (vrfyqueue->q_fullname == NULL)
3575003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3585003Seric 					else
3595003Seric 						message(code, "%s <%s>",
3605003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3615003Seric 				}
3625003Seric 				else if (a == NULL)
3635003Seric 					message("554", "Self destructive alias loop");
3645003Seric 				vrfyqueue = a;
3655003Seric 			}
3669339Seric 			if (InChild)
3679339Seric 				finis();
3684549Seric 			break;
3694549Seric 
3704549Seric 		  case CMDHELP:		/* help -- give user info */
3714577Seric 			if (*p == '\0')
3724577Seric 				p = "SMTP";
3734577Seric 			help(p);
3744549Seric 			break;
3754549Seric 
3764549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3774549Seric 			message("200", "OK");
3784549Seric 			break;
3794549Seric 
3804549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3814549Seric 			message("221", "%s closing connection", HostName);
3829339Seric 			if (InChild)
3839339Seric 				ExitStat = EX_QUIT;
3844549Seric 			finis();
3854549Seric 
3868544Seric 		  case CMDVERB:		/* set verbose mode */
3878544Seric 			Verbose = TRUE;
3888544Seric 			message("200", "Verbose mode");
3898544Seric 			break;
3908544Seric 
3919314Seric 		  case CMDONEX:		/* doing one transaction only */
3929378Seric 			OneXact = TRUE;
3939314Seric 			message("200", "Only one transaction");
3949314Seric 			break;
3959314Seric 
3965003Seric # ifdef DEBUG
3979339Seric 		  case CMDDBGQSHOW:	/* show queues */
3986907Seric 			printf("Send Queue=");
3996907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4005003Seric 			break;
4017275Seric 
4027275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4037676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4047676Seric 			tTflag(p);
4057676Seric 			message("200", "Debug set");
4067275Seric 			break;
4077275Seric 
4087282Seric 		  case CMDDBGKILL:	/* kill the parent */
4098544Seric 			if (!iswiz())
4108544Seric 				break;
4117282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4127282Seric 				message("200", "Mother is dead");
4137282Seric 			else
4147282Seric 				message("500", "Can't kill Mom");
4157282Seric 			break;
4168544Seric 
4178544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4188544Seric 			if (WizWord != NULL)
4198544Seric 			{
4208544Seric 				char seed[3];
4218544Seric 				extern char *crypt();
4228544Seric 
42323106Seric 				(void) strncpy(seed, WizWord, 2);
42415596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4258544Seric 				{
42615596Seric 					IsWiz = TRUE;
42715596Seric 					message("200", "Please pass, oh mighty wizard");
4288544Seric 					break;
4298544Seric 				}
4308544Seric 			}
43115596Seric 			message("500", "You are no wizard!");
4328544Seric 			break;
4335003Seric # endif DEBUG
4345003Seric 
4354549Seric 		  case CMDERROR:	/* unknown command */
4364549Seric 			message("500", "Command unrecognized");
4374549Seric 			break;
4384549Seric 
4394549Seric 		  default:
4404549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4414549Seric 			break;
4424549Seric 		}
4434549Seric 	}
4444549Seric }
4454549Seric /*
4464549Seric **  SKIPWORD -- skip a fixed word.
4474549Seric **
4484549Seric **	Parameters:
4494549Seric **		p -- place to start looking.
4504549Seric **		w -- word to skip.
4514549Seric **
4524549Seric **	Returns:
4534549Seric **		p following w.
4544549Seric **		NULL on error.
4554549Seric **
4564549Seric **	Side Effects:
4574549Seric **		clobbers the p data area.
4584549Seric */
4594549Seric 
4604549Seric static char *
4614549Seric skipword(p, w)
4624549Seric 	register char *p;
4634549Seric 	char *w;
4644549Seric {
4654549Seric 	register char *q;
4664549Seric 	extern bool sameword();
4674549Seric 
4684549Seric 	/* find beginning of word */
4694549Seric 	while (isspace(*p))
4704549Seric 		p++;
4714549Seric 	q = p;
4724549Seric 
4734549Seric 	/* find end of word */
4744549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4754549Seric 		p++;
4764549Seric 	while (isspace(*p))
4774549Seric 		*p++ = '\0';
4784549Seric 	if (*p != ':')
4794549Seric 	{
4804549Seric 	  syntax:
4814549Seric 		message("501", "Syntax error");
4824549Seric 		Errors++;
4834549Seric 		return (NULL);
4844549Seric 	}
4854549Seric 	*p++ = '\0';
4864549Seric 	while (isspace(*p))
4874549Seric 		p++;
4884549Seric 
4894549Seric 	/* see if the input word matches desired word */
4904549Seric 	if (!sameword(q, w))
4914549Seric 		goto syntax;
4924549Seric 
4934549Seric 	return (p);
4944549Seric }
4954577Seric /*
4964577Seric **  HELP -- implement the HELP command.
4974577Seric **
4984577Seric **	Parameters:
4994577Seric **		topic -- the topic we want help for.
5004577Seric **
5014577Seric **	Returns:
5024577Seric **		none.
5034577Seric **
5044577Seric **	Side Effects:
5054577Seric **		outputs the help file to message output.
5064577Seric */
5074577Seric 
5084577Seric help(topic)
5094577Seric 	char *topic;
5104577Seric {
5114577Seric 	register FILE *hf;
5124577Seric 	int len;
5134577Seric 	char buf[MAXLINE];
5144577Seric 	bool noinfo;
5154577Seric 
5168269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5174577Seric 	{
5184577Seric 		/* no help */
51911931Seric 		errno = 0;
5204577Seric 		message("502", "HELP not implemented");
5214577Seric 		return;
5224577Seric 	}
5234577Seric 
5244577Seric 	len = strlen(topic);
5254577Seric 	makelower(topic);
5264577Seric 	noinfo = TRUE;
5274577Seric 
5284577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5294577Seric 	{
5304577Seric 		if (strncmp(buf, topic, len) == 0)
5314577Seric 		{
5324577Seric 			register char *p;
5334577Seric 
5344577Seric 			p = index(buf, '\t');
5354577Seric 			if (p == NULL)
5364577Seric 				p = buf;
5374577Seric 			else
5384577Seric 				p++;
5394577Seric 			fixcrlf(p, TRUE);
5404577Seric 			message("214-", p);
5414577Seric 			noinfo = FALSE;
5424577Seric 		}
5434577Seric 	}
5444577Seric 
5454577Seric 	if (noinfo)
5464577Seric 		message("504", "HELP topic unknown");
5474577Seric 	else
5484577Seric 		message("214", "End of HELP info");
5494628Seric 	(void) fclose(hf);
5504577Seric }
5518544Seric /*
5528544Seric **  ISWIZ -- tell us if we are a wizard
5538544Seric **
5548544Seric **	If not, print a nasty message.
5558544Seric **
5568544Seric **	Parameters:
5578544Seric **		none.
5588544Seric **
5598544Seric **	Returns:
5608544Seric **		TRUE if we are a wizard.
5618544Seric **		FALSE if we are not a wizard.
5628544Seric **
5638544Seric **	Side Effects:
5648544Seric **		Prints a 500 exit stat if we are not a wizard.
5658544Seric */
5665181Seric 
56719038Seric #ifdef DEBUG
56819038Seric 
5698544Seric bool
5708544Seric iswiz()
5718544Seric {
5728544Seric 	if (!IsWiz)
5738544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5748544Seric 	return (IsWiz);
5758544Seric }
57619038Seric 
57719038Seric #endif DEBUG
5789339Seric /*
5799339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5809339Seric **
5819339Seric **	Parameters:
5829339Seric **		label -- a string used in error messages
5839339Seric **
5849339Seric **	Returns:
5859339Seric **		zero in the child
5869339Seric **		one in the parent
5879339Seric **
5889339Seric **	Side Effects:
5899339Seric **		none.
5909339Seric */
5918544Seric 
5929339Seric runinchild(label)
5939339Seric 	char *label;
5949339Seric {
5959339Seric 	int childpid;
5969339Seric 
59716158Seric 	if (!OneXact)
5989339Seric 	{
59916158Seric 		childpid = dofork();
60016158Seric 		if (childpid < 0)
60116158Seric 		{
60216158Seric 			syserr("%s: cannot fork", label);
60316158Seric 			return (1);
60416158Seric 		}
60516158Seric 		if (childpid > 0)
60616158Seric 		{
60716158Seric 			auto int st;
6089339Seric 
60916158Seric 			/* parent -- wait for child to complete */
61016158Seric 			st = waitfor(childpid);
61116158Seric 			if (st == -1)
61216158Seric 				syserr("%s: lost child", label);
6139339Seric 
61416158Seric 			/* if we exited on a QUIT command, complete the process */
61516158Seric 			if (st == (EX_QUIT << 8))
61616158Seric 				finis();
6179339Seric 
61816158Seric 			return (1);
61916158Seric 		}
62016158Seric 		else
62116158Seric 		{
62216158Seric 			/* child */
62316158Seric 			InChild = TRUE;
62416158Seric 		}
6259339Seric 	}
62615256Seric 
62716158Seric 	/* child (or ONEX command specified) */
62816158Seric 	clearenvelope(CurEnv);
62915256Seric 
63016158Seric 	/* open alias database */
63116158Seric 	initaliases(AliasFile, FALSE);
63216158Seric 
63316158Seric 	return (0);
6349339Seric }
6359339Seric 
6365181Seric # endif SMTP
637