19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
311728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*16886Seric SCCSID(@(#)srvrsmtp.c	4.9		08/11/84	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*16886Seric SCCSID(@(#)srvrsmtp.c	4.9		08/11/84);
105181Seric 
114549Seric /*
124549Seric **  SMTP -- run the SMTP protocol.
134549Seric **
144549Seric **	Parameters:
154549Seric **		none.
164549Seric **
174549Seric **	Returns:
184549Seric **		never.
194549Seric **
204549Seric **	Side Effects:
214549Seric **		Reads commands from the input channel and processes
224549Seric **			them.
234549Seric */
244549Seric 
254549Seric struct cmd
264549Seric {
274549Seric 	char	*cmdname;	/* command name */
284549Seric 	int	cmdcode;	/* internal code, see below */
294549Seric };
304549Seric 
314549Seric /* values for cmdcode */
324549Seric # define CMDERROR	0	/* bad command */
334549Seric # define CMDMAIL	1	/* mail -- designate sender */
344976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
354549Seric # define CMDDATA	3	/* data -- send message text */
369339Seric # define CMDRSET	4	/* rset -- reset state */
379339Seric # define CMDVRFY	5	/* vrfy -- verify address */
389339Seric # define CMDHELP	6	/* help -- give usage info */
399339Seric # define CMDNOOP	7	/* noop -- do nothing */
409339Seric # define CMDQUIT	8	/* quit -- close connection and die */
419339Seric # define CMDHELO	9	/* helo -- be polite */
429339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
439339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
449339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
459339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
469339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
479339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
489339Seric # define CMDDBGSHELL	16	/* shell -- give us a shell */
494549Seric 
504549Seric static struct cmd	CmdTab[] =
514549Seric {
524549Seric 	"mail",		CMDMAIL,
534976Seric 	"rcpt",		CMDRCPT,
544549Seric 	"data",		CMDDATA,
554549Seric 	"rset",		CMDRSET,
564549Seric 	"vrfy",		CMDVRFY,
577762Seric 	"expn",		CMDVRFY,
584549Seric 	"help",		CMDHELP,
594549Seric 	"noop",		CMDNOOP,
604549Seric 	"quit",		CMDQUIT,
614976Seric 	"helo",		CMDHELO,
628544Seric 	"verb",		CMDVERB,
639314Seric 	"onex",		CMDONEX,
645003Seric # ifdef DEBUG
659339Seric 	"showq",	CMDDBGQSHOW,
668544Seric 	"debug",	CMDDBGDEBUG,
678544Seric 	"kill",		CMDDBGKILL,
688544Seric 	"wiz",		CMDDBGWIZ,
699339Seric 	"shell",	CMDDBGSHELL,
705003Seric # endif DEBUG
714549Seric 	NULL,		CMDERROR,
724549Seric };
734549Seric 
748544Seric # ifdef DEBUG
758544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
7615596Seric char	*WizWord;			/* the wizard word to compare against */
778544Seric # endif DEBUG
789339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
799378Seric bool	OneXact = FALSE;		/* one xaction only this run */
8011146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
8111146Seric 
829339Seric #define EX_QUIT		22		/* special code for QUIT command */
838544Seric 
844549Seric smtp()
854549Seric {
864549Seric 	register char *p;
878544Seric 	register struct cmd *c;
884549Seric 	char *cmd;
894549Seric 	extern char *skipword();
904549Seric 	extern bool sameword();
914549Seric 	bool hasmail;			/* mail command received */
924713Seric 	int rcps;			/* number of recipients */
935003Seric 	auto ADDRESS *vrfyqueue;
9412612Seric 	ADDRESS *a;
958544Seric 	char inp[MAXLINE];
967124Seric 	extern char Version[];
977356Seric 	extern tick();
988544Seric 	extern bool iswiz();
999349Seric 	extern char *arpadate();
10011151Seric 	extern char *macvalue();
10112612Seric 	extern ADDRESS *recipient();
1024549Seric 
1035003Seric 	hasmail = FALSE;
1044713Seric 	rcps = 0;
1057363Seric 	if (OutChannel != stdout)
1067363Seric 	{
1077363Seric 		/* arrange for debugging output to go to remote host */
1087363Seric 		(void) close(1);
1097363Seric 		(void) dup(fileno(OutChannel));
1107363Seric 	}
11111931Seric 	settime();
11216153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
11310708Seric 	message("220", inp);
1144549Seric 	for (;;)
1154549Seric 	{
11612612Seric 		/* arrange for backout */
11712612Seric 		if (setjmp(TopFrame) > 0 && InChild)
11812612Seric 			finis();
11912612Seric 		QuickAbort = FALSE;
12012612Seric 		HoldErrs = FALSE;
12112612Seric 
1227356Seric 		/* setup for the read */
1236907Seric 		CurEnv->e_to = NULL;
1244577Seric 		Errors = 0;
1257275Seric 		(void) fflush(stdout);
1267356Seric 
1277356Seric 		/* read the input line */
1287685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1297356Seric 
1307685Seric 		/* handle errors */
1317356Seric 		if (p == NULL)
1327356Seric 		{
1334549Seric 			/* end of file, just die */
1344558Seric 			message("421", "%s Lost input channel", HostName);
1354549Seric 			finis();
1364549Seric 		}
1374549Seric 
1384549Seric 		/* clean up end of line */
1394558Seric 		fixcrlf(inp, TRUE);
1404549Seric 
1414713Seric 		/* echo command to transcript */
1429545Seric 		if (CurEnv->e_xfp != NULL)
1439545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1444713Seric 
1454549Seric 		/* break off command */
1464549Seric 		for (p = inp; isspace(*p); p++)
1474549Seric 			continue;
1484549Seric 		cmd = p;
1494549Seric 		while (*++p != '\0' && !isspace(*p))
1504549Seric 			continue;
1514549Seric 		if (*p != '\0')
1524549Seric 			*p++ = '\0';
1534549Seric 
1544549Seric 		/* decode command */
1554549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1564549Seric 		{
1574549Seric 			if (sameword(c->cmdname, cmd))
1584549Seric 				break;
1594549Seric 		}
1604549Seric 
1614549Seric 		/* process command */
1624549Seric 		switch (c->cmdcode)
1634549Seric 		{
1644976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
16514877Seric 			if (sameword(p, HostName))
16614877Seric 			{
16714877Seric 				/* connected to an echo server */
16814877Seric 				message("553", "%s I refuse to talk to myself",
16914877Seric 					HostName);
17014877Seric 				break;
17114877Seric 			}
17211146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
17311146Seric 			{
17411146Seric 				char buf[MAXNAME];
17511146Seric 
17611146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
17711146Seric 				define('s', newstr(buf), CurEnv);
17811146Seric 			}
17911146Seric 			else
18011146Seric 				define('s', newstr(p), CurEnv);
1814997Seric 			message("250", "%s Hello %s, pleased to meet you",
1824997Seric 				HostName, p);
1834976Seric 			break;
1844976Seric 
1854549Seric 		  case CMDMAIL:		/* mail -- designate sender */
18611151Seric 			/* force a sending host even if no HELO given */
18711151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
18811151Seric 				define('s', RealHostName, CurEnv);
18911151Seric 
1909314Seric 			/* check for validity of this command */
1914558Seric 			if (hasmail)
1924558Seric 			{
1934558Seric 				message("503", "Sender already specified");
1944558Seric 				break;
1954558Seric 			}
1969339Seric 			if (InChild)
1979339Seric 			{
1989339Seric 				syserr("Nested MAIL command");
1999339Seric 				exit(0);
2009339Seric 			}
2019339Seric 
2029339Seric 			/* fork a subprocess to process this command */
2039339Seric 			if (runinchild("SMTP-MAIL") > 0)
2049339Seric 				break;
2059339Seric 			initsys();
2069339Seric 
2079339Seric 			/* child -- go do the processing */
2084549Seric 			p = skipword(p, "from");
2094549Seric 			if (p == NULL)
2104549Seric 				break;
2114549Seric 			setsender(p);
2124577Seric 			if (Errors == 0)
2134549Seric 			{
2144549Seric 				message("250", "Sender ok");
2154549Seric 				hasmail = TRUE;
2164549Seric 			}
2179339Seric 			else if (InChild)
2189339Seric 				finis();
2194549Seric 			break;
2204549Seric 
2214976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
22212612Seric 			if (setjmp(TopFrame) > 0)
22314785Seric 			{
22414785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
22512612Seric 				break;
22614785Seric 			}
22712612Seric 			QuickAbort = TRUE;
2284549Seric 			p = skipword(p, "to");
2294549Seric 			if (p == NULL)
2304549Seric 				break;
23116140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
23212612Seric 			if (a == NULL)
23312612Seric 				break;
234*16886Seric 			a->q_flags |= QPRIMARY;
23512612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
23612612Seric 			if (Errors != 0)
23712612Seric 				break;
23812612Seric 
23912612Seric 			/* no errors during parsing, but might be a duplicate */
24012612Seric 			CurEnv->e_to = p;
24112612Seric 			if (!bitset(QBADADDR, a->q_flags))
24212612Seric 				message("250", "Recipient ok");
24312612Seric 			else
2444549Seric 			{
24512612Seric 				/* punt -- should keep message in ADDRESS.... */
24612612Seric 				message("550", "Addressee unknown");
2474549Seric 			}
24812612Seric 			CurEnv->e_to = NULL;
24912612Seric 			rcps++;
2504549Seric 			break;
2514549Seric 
2524549Seric 		  case CMDDATA:		/* data -- text of mail */
2534976Seric 			if (!hasmail)
2544549Seric 			{
2554976Seric 				message("503", "Need MAIL command");
2564976Seric 				break;
2574549Seric 			}
2584713Seric 			else if (rcps <= 0)
2594549Seric 			{
2604976Seric 				message("503", "Need RCPT (recipient)");
2614976Seric 				break;
2624549Seric 			}
2634976Seric 
2644976Seric 			/* collect the text of the message */
2654976Seric 			collect(TRUE);
2664976Seric 			if (Errors != 0)
2674976Seric 				break;
2684976Seric 
2698238Seric 			/*
2708238Seric 			**  Arrange to send to everyone.
2718238Seric 			**	If sending to multiple people, mail back
2728238Seric 			**		errors rather than reporting directly.
2738238Seric 			**	In any case, don't mail back errors for
2748238Seric 			**		anything that has happened up to
2758238Seric 			**		now (the other end will do this).
27610197Seric 			**	Truncate our transcript -- the mail has gotten
27710197Seric 			**		to us successfully, and if we have
27810197Seric 			**		to mail this back, it will be easier
27910197Seric 			**		on the reader.
2808238Seric 			**	Then send to everyone.
2818238Seric 			**	Finally give a reply code.  If an error has
2828238Seric 			**		already been given, don't mail a
2838238Seric 			**		message back.
2849339Seric 			**	We goose error returns by clearing error bit.
2858238Seric 			*/
2868238Seric 
2874976Seric 			if (rcps != 1)
2889378Seric 			{
2899378Seric 				HoldErrs = TRUE;
290*16886Seric 				ErrorMode = EM_MAIL;
2919378Seric 			}
2929339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
29310197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2944976Seric 
2954976Seric 			/* send to all recipients */
29614877Seric 			sendall(CurEnv, SM_DEFAULT);
2976907Seric 			CurEnv->e_to = NULL;
2984976Seric 
2998238Seric 			/* issue success if appropriate and reset */
3008238Seric 			if (Errors == 0 || HoldErrs)
3019283Seric 				message("250", "Ok");
3028238Seric 			else
3039339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3049339Seric 
3059339Seric 			/* if in a child, pop back to our parent */
3069339Seric 			if (InChild)
3079339Seric 				finis();
3084549Seric 			break;
3094549Seric 
3104549Seric 		  case CMDRSET:		/* rset -- reset state */
3114549Seric 			message("250", "Reset state");
3129339Seric 			if (InChild)
3139339Seric 				finis();
3149339Seric 			break;
3154549Seric 
3164549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3179339Seric 			if (runinchild("SMTP-VRFY") > 0)
3189339Seric 				break;
3195003Seric 			vrfyqueue = NULL;
3207762Seric 			QuickAbort = TRUE;
3219619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3227762Seric 			if (Errors != 0)
3239339Seric 			{
3249339Seric 				if (InChild)
3259339Seric 					finis();
3267762Seric 				break;
3279339Seric 			}
3285003Seric 			while (vrfyqueue != NULL)
3295003Seric 			{
3305003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3315003Seric 				char *code;
3325003Seric 
3337685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3345003Seric 					a = a->q_next;
3355003Seric 
3367685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3375003Seric 				{
3385003Seric 					if (a != NULL)
3395003Seric 						code = "250-";
3405003Seric 					else
3415003Seric 						code = "250";
3425003Seric 					if (vrfyqueue->q_fullname == NULL)
3435003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3445003Seric 					else
3455003Seric 						message(code, "%s <%s>",
3465003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3475003Seric 				}
3485003Seric 				else if (a == NULL)
3495003Seric 					message("554", "Self destructive alias loop");
3505003Seric 				vrfyqueue = a;
3515003Seric 			}
3529339Seric 			if (InChild)
3539339Seric 				finis();
3544549Seric 			break;
3554549Seric 
3564549Seric 		  case CMDHELP:		/* help -- give user info */
3574577Seric 			if (*p == '\0')
3584577Seric 				p = "SMTP";
3594577Seric 			help(p);
3604549Seric 			break;
3614549Seric 
3624549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3634549Seric 			message("200", "OK");
3644549Seric 			break;
3654549Seric 
3664549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3674549Seric 			message("221", "%s closing connection", HostName);
3689339Seric 			if (InChild)
3699339Seric 				ExitStat = EX_QUIT;
3704549Seric 			finis();
3714549Seric 
3728544Seric 		  case CMDVERB:		/* set verbose mode */
3738544Seric 			Verbose = TRUE;
3748544Seric 			message("200", "Verbose mode");
3758544Seric 			break;
3768544Seric 
3779314Seric 		  case CMDONEX:		/* doing one transaction only */
3789378Seric 			OneXact = TRUE;
3799314Seric 			message("200", "Only one transaction");
3809314Seric 			break;
3819314Seric 
3825003Seric # ifdef DEBUG
3839339Seric 		  case CMDDBGQSHOW:	/* show queues */
3846907Seric 			printf("Send Queue=");
3856907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3865003Seric 			break;
3877275Seric 
3887275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3897676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3907676Seric 			tTflag(p);
3917676Seric 			message("200", "Debug set");
3927275Seric 			break;
3937275Seric 
3947282Seric 		  case CMDDBGKILL:	/* kill the parent */
3958544Seric 			if (!iswiz())
3968544Seric 				break;
3977282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3987282Seric 				message("200", "Mother is dead");
3997282Seric 			else
4007282Seric 				message("500", "Can't kill Mom");
4017282Seric 			break;
4028544Seric 
4039339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
4049339Seric 			if (!iswiz())
4059339Seric 				break;
4069378Seric 			if (fileno(InChannel) != 0)
4079378Seric 			{
4089378Seric 				(void) close(0);
4099378Seric 				(void) dup(fileno(InChannel));
41010346Seric 				if (fileno(InChannel) != fileno(OutChannel))
41110346Seric 					(void) fclose(InChannel);
4129378Seric 				InChannel = stdin;
4139378Seric 			}
4149378Seric 			if (fileno(OutChannel) != 1)
4159378Seric 			{
4169378Seric 				(void) close(1);
4179378Seric 				(void) dup(fileno(OutChannel));
4189378Seric 				(void) fclose(OutChannel);
4199378Seric 				OutChannel = stdout;
4209378Seric 			}
42110346Seric 			(void) close(2);
42210346Seric 			(void) dup(1);
4239339Seric 			execl("/bin/csh", "sendmail", 0);
4249339Seric 			execl("/bin/sh", "sendmail", 0);
4259339Seric 			message("500", "Can't");
4269378Seric 			exit(EX_UNAVAILABLE);
4279339Seric 
4288544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4298544Seric 			if (WizWord != NULL)
4308544Seric 			{
4318544Seric 				char seed[3];
4328544Seric 				extern char *crypt();
4338544Seric 
4348544Seric 				strncpy(seed, WizWord, 2);
43515596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4368544Seric 				{
43715596Seric 					IsWiz = TRUE;
43815596Seric 					message("200", "Please pass, oh mighty wizard");
4398544Seric 					break;
4408544Seric 				}
4418544Seric 			}
44215596Seric 			message("500", "You are no wizard!");
4438544Seric 			break;
4445003Seric # endif DEBUG
4455003Seric 
4464549Seric 		  case CMDERROR:	/* unknown command */
4474549Seric 			message("500", "Command unrecognized");
4484549Seric 			break;
4494549Seric 
4504549Seric 		  default:
4514549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4524549Seric 			break;
4534549Seric 		}
4544549Seric 	}
4554549Seric }
4564549Seric /*
4574549Seric **  SKIPWORD -- skip a fixed word.
4584549Seric **
4594549Seric **	Parameters:
4604549Seric **		p -- place to start looking.
4614549Seric **		w -- word to skip.
4624549Seric **
4634549Seric **	Returns:
4644549Seric **		p following w.
4654549Seric **		NULL on error.
4664549Seric **
4674549Seric **	Side Effects:
4684549Seric **		clobbers the p data area.
4694549Seric */
4704549Seric 
4714549Seric static char *
4724549Seric skipword(p, w)
4734549Seric 	register char *p;
4744549Seric 	char *w;
4754549Seric {
4764549Seric 	register char *q;
4774549Seric 	extern bool sameword();
4784549Seric 
4794549Seric 	/* find beginning of word */
4804549Seric 	while (isspace(*p))
4814549Seric 		p++;
4824549Seric 	q = p;
4834549Seric 
4844549Seric 	/* find end of word */
4854549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4864549Seric 		p++;
4874549Seric 	while (isspace(*p))
4884549Seric 		*p++ = '\0';
4894549Seric 	if (*p != ':')
4904549Seric 	{
4914549Seric 	  syntax:
4924549Seric 		message("501", "Syntax error");
4934549Seric 		Errors++;
4944549Seric 		return (NULL);
4954549Seric 	}
4964549Seric 	*p++ = '\0';
4974549Seric 	while (isspace(*p))
4984549Seric 		p++;
4994549Seric 
5004549Seric 	/* see if the input word matches desired word */
5014549Seric 	if (!sameword(q, w))
5024549Seric 		goto syntax;
5034549Seric 
5044549Seric 	return (p);
5054549Seric }
5064577Seric /*
5074577Seric **  HELP -- implement the HELP command.
5084577Seric **
5094577Seric **	Parameters:
5104577Seric **		topic -- the topic we want help for.
5114577Seric **
5124577Seric **	Returns:
5134577Seric **		none.
5144577Seric **
5154577Seric **	Side Effects:
5164577Seric **		outputs the help file to message output.
5174577Seric */
5184577Seric 
5194577Seric help(topic)
5204577Seric 	char *topic;
5214577Seric {
5224577Seric 	register FILE *hf;
5234577Seric 	int len;
5244577Seric 	char buf[MAXLINE];
5254577Seric 	bool noinfo;
5264577Seric 
5278269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5284577Seric 	{
5294577Seric 		/* no help */
53011931Seric 		errno = 0;
5314577Seric 		message("502", "HELP not implemented");
5324577Seric 		return;
5334577Seric 	}
5344577Seric 
5354577Seric 	len = strlen(topic);
5364577Seric 	makelower(topic);
5374577Seric 	noinfo = TRUE;
5384577Seric 
5394577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5404577Seric 	{
5414577Seric 		if (strncmp(buf, topic, len) == 0)
5424577Seric 		{
5434577Seric 			register char *p;
5444577Seric 
5454577Seric 			p = index(buf, '\t');
5464577Seric 			if (p == NULL)
5474577Seric 				p = buf;
5484577Seric 			else
5494577Seric 				p++;
5504577Seric 			fixcrlf(p, TRUE);
5514577Seric 			message("214-", p);
5524577Seric 			noinfo = FALSE;
5534577Seric 		}
5544577Seric 	}
5554577Seric 
5564577Seric 	if (noinfo)
5574577Seric 		message("504", "HELP topic unknown");
5584577Seric 	else
5594577Seric 		message("214", "End of HELP info");
5604628Seric 	(void) fclose(hf);
5614577Seric }
5628544Seric /*
5638544Seric **  ISWIZ -- tell us if we are a wizard
5648544Seric **
5658544Seric **	If not, print a nasty message.
5668544Seric **
5678544Seric **	Parameters:
5688544Seric **		none.
5698544Seric **
5708544Seric **	Returns:
5718544Seric **		TRUE if we are a wizard.
5728544Seric **		FALSE if we are not a wizard.
5738544Seric **
5748544Seric **	Side Effects:
5758544Seric **		Prints a 500 exit stat if we are not a wizard.
5768544Seric */
5775181Seric 
5788544Seric bool
5798544Seric iswiz()
5808544Seric {
5818544Seric 	if (!IsWiz)
5828544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5838544Seric 	return (IsWiz);
5848544Seric }
5859339Seric /*
5869339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5879339Seric **
5889339Seric **	Parameters:
5899339Seric **		label -- a string used in error messages
5909339Seric **
5919339Seric **	Returns:
5929339Seric **		zero in the child
5939339Seric **		one in the parent
5949339Seric **
5959339Seric **	Side Effects:
5969339Seric **		none.
5979339Seric */
5988544Seric 
5999339Seric runinchild(label)
6009339Seric 	char *label;
6019339Seric {
6029339Seric 	int childpid;
6039339Seric 
60416158Seric 	if (!OneXact)
6059339Seric 	{
60616158Seric 		childpid = dofork();
60716158Seric 		if (childpid < 0)
60816158Seric 		{
60916158Seric 			syserr("%s: cannot fork", label);
61016158Seric 			return (1);
61116158Seric 		}
61216158Seric 		if (childpid > 0)
61316158Seric 		{
61416158Seric 			auto int st;
6159339Seric 
61616158Seric 			/* parent -- wait for child to complete */
61716158Seric 			st = waitfor(childpid);
61816158Seric 			if (st == -1)
61916158Seric 				syserr("%s: lost child", label);
6209339Seric 
62116158Seric 			/* if we exited on a QUIT command, complete the process */
62216158Seric 			if (st == (EX_QUIT << 8))
62316158Seric 				finis();
6249339Seric 
62516158Seric 			return (1);
62616158Seric 		}
62716158Seric 		else
62816158Seric 		{
62916158Seric 			/* child */
63016158Seric 			InChild = TRUE;
63116158Seric 		}
6329339Seric 	}
63315256Seric 
63416158Seric 	/* child (or ONEX command specified) */
63516158Seric 	clearenvelope(CurEnv);
63615256Seric 
63716158Seric 	/* open alias database */
63816158Seric 	initaliases(AliasFile, FALSE);
63916158Seric 
64016158Seric 	return (0);
6419339Seric }
6429339Seric 
6435181Seric # endif SMTP
644