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*24945Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.8 (Berkeley) 09/19/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*24945Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.8 (Berkeley) 09/19/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,
81*24945Seric # endif DEBUG
82*24945Seric # ifdef WIZ
838544Seric 	"kill",		CMDDBGKILL,
84*24945Seric # endif WIZ
858544Seric 	"wiz",		CMDDBGWIZ,
864549Seric 	NULL,		CMDERROR,
874549Seric };
884549Seric 
898544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
9015596Seric char	*WizWord;			/* the wizard word to compare against */
919339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
929378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9311146Seric 
949339Seric #define EX_QUIT		22		/* special code for QUIT command */
958544Seric 
964549Seric smtp()
974549Seric {
984549Seric 	register char *p;
998544Seric 	register struct cmd *c;
1004549Seric 	char *cmd;
1014549Seric 	extern char *skipword();
1024549Seric 	extern bool sameword();
1034549Seric 	bool hasmail;			/* mail command received */
1044713Seric 	int rcps;			/* number of recipients */
1055003Seric 	auto ADDRESS *vrfyqueue;
10612612Seric 	ADDRESS *a;
1078544Seric 	char inp[MAXLINE];
1087124Seric 	extern char Version[];
1097356Seric 	extern tick();
1108544Seric 	extern bool iswiz();
1119349Seric 	extern char *arpadate();
11211151Seric 	extern char *macvalue();
11312612Seric 	extern ADDRESS *recipient();
11424943Seric 	extern ENVELOPE BlankEnvelope;
11524943Seric 	extern ENVELOPE *newenvelope();
1164549Seric 
1175003Seric 	hasmail = FALSE;
1184713Seric 	rcps = 0;
1197363Seric 	if (OutChannel != stdout)
1207363Seric 	{
1217363Seric 		/* arrange for debugging output to go to remote host */
1227363Seric 		(void) close(1);
1237363Seric 		(void) dup(fileno(OutChannel));
1247363Seric 	}
12511931Seric 	settime();
12616153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12710708Seric 	message("220", inp);
12824943Seric 	SmtpPhase = "startup";
1294549Seric 	for (;;)
1304549Seric 	{
13112612Seric 		/* arrange for backout */
13212612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13312612Seric 			finis();
13412612Seric 		QuickAbort = FALSE;
13512612Seric 		HoldErrs = FALSE;
13612612Seric 
1377356Seric 		/* setup for the read */
1386907Seric 		CurEnv->e_to = NULL;
1394577Seric 		Errors = 0;
1407275Seric 		(void) fflush(stdout);
1417356Seric 
1427356Seric 		/* read the input line */
1437685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1447356Seric 
1457685Seric 		/* handle errors */
1467356Seric 		if (p == NULL)
1477356Seric 		{
1484549Seric 			/* end of file, just die */
1494558Seric 			message("421", "%s Lost input channel", HostName);
1504549Seric 			finis();
1514549Seric 		}
1524549Seric 
1534549Seric 		/* clean up end of line */
1544558Seric 		fixcrlf(inp, TRUE);
1554549Seric 
1564713Seric 		/* echo command to transcript */
1579545Seric 		if (CurEnv->e_xfp != NULL)
1589545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1594713Seric 
1604549Seric 		/* break off command */
1614549Seric 		for (p = inp; isspace(*p); p++)
1624549Seric 			continue;
1634549Seric 		cmd = p;
1644549Seric 		while (*++p != '\0' && !isspace(*p))
1654549Seric 			continue;
1664549Seric 		if (*p != '\0')
1674549Seric 			*p++ = '\0';
1684549Seric 
1694549Seric 		/* decode command */
1704549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1714549Seric 		{
1724549Seric 			if (sameword(c->cmdname, cmd))
1734549Seric 				break;
1744549Seric 		}
1754549Seric 
1764549Seric 		/* process command */
1774549Seric 		switch (c->cmdcode)
1784549Seric 		{
1794976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
18024943Seric 			SmtpPhase = "HELO";
18114877Seric 			if (sameword(p, HostName))
18214877Seric 			{
18314877Seric 				/* connected to an echo server */
18414877Seric 				message("553", "%s I refuse to talk to myself",
18514877Seric 					HostName);
18614877Seric 				break;
18714877Seric 			}
18811146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
18911146Seric 			{
19011146Seric 				char buf[MAXNAME];
19111146Seric 
19211146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
19311146Seric 				define('s', newstr(buf), CurEnv);
19411146Seric 			}
19511146Seric 			else
19611146Seric 				define('s', newstr(p), CurEnv);
1974997Seric 			message("250", "%s Hello %s, pleased to meet you",
1984997Seric 				HostName, p);
1994976Seric 			break;
2004976Seric 
2014549Seric 		  case CMDMAIL:		/* mail -- designate sender */
20224943Seric 			SmtpPhase = "MAIL";
20324943Seric 
20411151Seric 			/* force a sending host even if no HELO given */
20511151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
20611151Seric 				define('s', RealHostName, CurEnv);
20711151Seric 
2089314Seric 			/* check for validity of this command */
2094558Seric 			if (hasmail)
2104558Seric 			{
2114558Seric 				message("503", "Sender already specified");
2124558Seric 				break;
2134558Seric 			}
2149339Seric 			if (InChild)
2159339Seric 			{
2169339Seric 				syserr("Nested MAIL command");
2179339Seric 				exit(0);
2189339Seric 			}
2199339Seric 
2209339Seric 			/* fork a subprocess to process this command */
2219339Seric 			if (runinchild("SMTP-MAIL") > 0)
2229339Seric 				break;
2239339Seric 			initsys();
2249339Seric 
2259339Seric 			/* child -- go do the processing */
2264549Seric 			p = skipword(p, "from");
2274549Seric 			if (p == NULL)
2284549Seric 				break;
2294549Seric 			setsender(p);
2304577Seric 			if (Errors == 0)
2314549Seric 			{
2324549Seric 				message("250", "Sender ok");
2334549Seric 				hasmail = TRUE;
2344549Seric 			}
2359339Seric 			else if (InChild)
2369339Seric 				finis();
2374549Seric 			break;
2384549Seric 
2394976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
24024943Seric 			SmtpPhase = "RCPT";
24112612Seric 			if (setjmp(TopFrame) > 0)
24214785Seric 			{
24314785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
24412612Seric 				break;
24514785Seric 			}
24612612Seric 			QuickAbort = TRUE;
2474549Seric 			p = skipword(p, "to");
2484549Seric 			if (p == NULL)
2494549Seric 				break;
25016140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
25112612Seric 			if (a == NULL)
25212612Seric 				break;
25316886Seric 			a->q_flags |= QPRIMARY;
25412612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
25512612Seric 			if (Errors != 0)
25612612Seric 				break;
25712612Seric 
25812612Seric 			/* no errors during parsing, but might be a duplicate */
25912612Seric 			CurEnv->e_to = p;
26012612Seric 			if (!bitset(QBADADDR, a->q_flags))
26112612Seric 				message("250", "Recipient ok");
26212612Seric 			else
2634549Seric 			{
26412612Seric 				/* punt -- should keep message in ADDRESS.... */
26512612Seric 				message("550", "Addressee unknown");
2664549Seric 			}
26712612Seric 			CurEnv->e_to = NULL;
26812612Seric 			rcps++;
2694549Seric 			break;
2704549Seric 
2714549Seric 		  case CMDDATA:		/* data -- text of mail */
27224943Seric 			SmtpPhase = "DATA";
2734976Seric 			if (!hasmail)
2744549Seric 			{
2754976Seric 				message("503", "Need MAIL command");
2764976Seric 				break;
2774549Seric 			}
27824943Seric 			else if (CurEnv->e_nrcpts <= 0)
2794549Seric 			{
2804976Seric 				message("503", "Need RCPT (recipient)");
2814976Seric 				break;
2824549Seric 			}
2834976Seric 
2844976Seric 			/* collect the text of the message */
28524943Seric 			SmtpPhase = "collect";
2864976Seric 			collect(TRUE);
2874976Seric 			if (Errors != 0)
2884976Seric 				break;
2894976Seric 
2908238Seric 			/*
2918238Seric 			**  Arrange to send to everyone.
2928238Seric 			**	If sending to multiple people, mail back
2938238Seric 			**		errors rather than reporting directly.
2948238Seric 			**	In any case, don't mail back errors for
2958238Seric 			**		anything that has happened up to
2968238Seric 			**		now (the other end will do this).
29710197Seric 			**	Truncate our transcript -- the mail has gotten
29810197Seric 			**		to us successfully, and if we have
29910197Seric 			**		to mail this back, it will be easier
30010197Seric 			**		on the reader.
3018238Seric 			**	Then send to everyone.
3028238Seric 			**	Finally give a reply code.  If an error has
3038238Seric 			**		already been given, don't mail a
3048238Seric 			**		message back.
3059339Seric 			**	We goose error returns by clearing error bit.
3068238Seric 			*/
3078238Seric 
30824943Seric 			SmtpPhase = "delivery";
30924943Seric 			if (CurEnv->e_nrcpts != 1)
3109378Seric 			{
3119378Seric 				HoldErrs = TRUE;
31216886Seric 				ErrorMode = EM_MAIL;
3139378Seric 			}
3149339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
31510197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3164976Seric 
3174976Seric 			/* send to all recipients */
31814877Seric 			sendall(CurEnv, SM_DEFAULT);
3196907Seric 			CurEnv->e_to = NULL;
3204976Seric 
32123516Seric 			/* save statistics */
32223516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
32323516Seric 
3248238Seric 			/* issue success if appropriate and reset */
3258238Seric 			if (Errors == 0 || HoldErrs)
3269283Seric 				message("250", "Ok");
3278238Seric 			else
3289339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3299339Seric 
3309339Seric 			/* if in a child, pop back to our parent */
3319339Seric 			if (InChild)
3329339Seric 				finis();
33324943Seric 
33424943Seric 			/* clean up a bit */
33524943Seric 			hasmail = 0;
33624943Seric 			rcps = 0;
33724943Seric 			dropenvelope(CurEnv);
33824943Seric 			CurEnv = newenvelope(CurEnv);
33924943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3404549Seric 			break;
3414549Seric 
3424549Seric 		  case CMDRSET:		/* rset -- reset state */
3434549Seric 			message("250", "Reset state");
3449339Seric 			if (InChild)
3459339Seric 				finis();
3469339Seric 			break;
3474549Seric 
3484549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3499339Seric 			if (runinchild("SMTP-VRFY") > 0)
3509339Seric 				break;
3515003Seric 			vrfyqueue = NULL;
3527762Seric 			QuickAbort = TRUE;
3539619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3547762Seric 			if (Errors != 0)
3559339Seric 			{
3569339Seric 				if (InChild)
3579339Seric 					finis();
3587762Seric 				break;
3599339Seric 			}
3605003Seric 			while (vrfyqueue != NULL)
3615003Seric 			{
3625003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3635003Seric 				char *code;
3645003Seric 
3657685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3665003Seric 					a = a->q_next;
3675003Seric 
3687685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3695003Seric 				{
3705003Seric 					if (a != NULL)
3715003Seric 						code = "250-";
3725003Seric 					else
3735003Seric 						code = "250";
3745003Seric 					if (vrfyqueue->q_fullname == NULL)
3755003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3765003Seric 					else
3775003Seric 						message(code, "%s <%s>",
3785003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3795003Seric 				}
3805003Seric 				else if (a == NULL)
3815003Seric 					message("554", "Self destructive alias loop");
3825003Seric 				vrfyqueue = a;
3835003Seric 			}
3849339Seric 			if (InChild)
3859339Seric 				finis();
3864549Seric 			break;
3874549Seric 
3884549Seric 		  case CMDHELP:		/* help -- give user info */
3894577Seric 			if (*p == '\0')
3904577Seric 				p = "SMTP";
3914577Seric 			help(p);
3924549Seric 			break;
3934549Seric 
3944549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3954549Seric 			message("200", "OK");
3964549Seric 			break;
3974549Seric 
3984549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3994549Seric 			message("221", "%s closing connection", HostName);
4009339Seric 			if (InChild)
4019339Seric 				ExitStat = EX_QUIT;
4024549Seric 			finis();
4034549Seric 
4048544Seric 		  case CMDVERB:		/* set verbose mode */
4058544Seric 			Verbose = TRUE;
4068544Seric 			message("200", "Verbose mode");
4078544Seric 			break;
4088544Seric 
4099314Seric 		  case CMDONEX:		/* doing one transaction only */
4109378Seric 			OneXact = TRUE;
4119314Seric 			message("200", "Only one transaction");
4129314Seric 			break;
4139314Seric 
4145003Seric # ifdef DEBUG
4159339Seric 		  case CMDDBGQSHOW:	/* show queues */
4166907Seric 			printf("Send Queue=");
4176907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4185003Seric 			break;
4197275Seric 
4207275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4217676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4227676Seric 			tTflag(p);
4237676Seric 			message("200", "Debug set");
4247275Seric 			break;
425*24945Seric # endif DEBUG
4267275Seric 
427*24945Seric # ifdef WIZ
4287282Seric 		  case CMDDBGKILL:	/* kill the parent */
4298544Seric 			if (!iswiz())
4308544Seric 				break;
4317282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4327282Seric 				message("200", "Mother is dead");
4337282Seric 			else
4347282Seric 				message("500", "Can't kill Mom");
4357282Seric 			break;
4368544Seric 
4378544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4388544Seric 			if (WizWord != NULL)
4398544Seric 			{
4408544Seric 				char seed[3];
4418544Seric 				extern char *crypt();
4428544Seric 
44323106Seric 				(void) strncpy(seed, WizWord, 2);
44415596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4458544Seric 				{
44615596Seric 					IsWiz = TRUE;
44715596Seric 					message("200", "Please pass, oh mighty wizard");
4488544Seric 					break;
4498544Seric 				}
4508544Seric 			}
45115596Seric 			message("500", "You are no wizard!");
4528544Seric 			break;
4535003Seric 
454*24945Seric # else WIZ
455*24945Seric 		  case CMDDBGWIZ:	/* try to become a wizard */
456*24945Seric 			message("500", "You wascal wabbit!  Wandering wizards won't win!");
457*24945Seric 			break;
458*24945Seric # endif WIZ
459*24945Seric 
4604549Seric 		  case CMDERROR:	/* unknown command */
4614549Seric 			message("500", "Command unrecognized");
4624549Seric 			break;
4634549Seric 
4644549Seric 		  default:
4654549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4664549Seric 			break;
4674549Seric 		}
4684549Seric 	}
4694549Seric }
4704549Seric /*
4714549Seric **  SKIPWORD -- skip a fixed word.
4724549Seric **
4734549Seric **	Parameters:
4744549Seric **		p -- place to start looking.
4754549Seric **		w -- word to skip.
4764549Seric **
4774549Seric **	Returns:
4784549Seric **		p following w.
4794549Seric **		NULL on error.
4804549Seric **
4814549Seric **	Side Effects:
4824549Seric **		clobbers the p data area.
4834549Seric */
4844549Seric 
4854549Seric static char *
4864549Seric skipword(p, w)
4874549Seric 	register char *p;
4884549Seric 	char *w;
4894549Seric {
4904549Seric 	register char *q;
4914549Seric 	extern bool sameword();
4924549Seric 
4934549Seric 	/* find beginning of word */
4944549Seric 	while (isspace(*p))
4954549Seric 		p++;
4964549Seric 	q = p;
4974549Seric 
4984549Seric 	/* find end of word */
4994549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5004549Seric 		p++;
5014549Seric 	while (isspace(*p))
5024549Seric 		*p++ = '\0';
5034549Seric 	if (*p != ':')
5044549Seric 	{
5054549Seric 	  syntax:
5064549Seric 		message("501", "Syntax error");
5074549Seric 		Errors++;
5084549Seric 		return (NULL);
5094549Seric 	}
5104549Seric 	*p++ = '\0';
5114549Seric 	while (isspace(*p))
5124549Seric 		p++;
5134549Seric 
5144549Seric 	/* see if the input word matches desired word */
5154549Seric 	if (!sameword(q, w))
5164549Seric 		goto syntax;
5174549Seric 
5184549Seric 	return (p);
5194549Seric }
5204577Seric /*
5214577Seric **  HELP -- implement the HELP command.
5224577Seric **
5234577Seric **	Parameters:
5244577Seric **		topic -- the topic we want help for.
5254577Seric **
5264577Seric **	Returns:
5274577Seric **		none.
5284577Seric **
5294577Seric **	Side Effects:
5304577Seric **		outputs the help file to message output.
5314577Seric */
5324577Seric 
5334577Seric help(topic)
5344577Seric 	char *topic;
5354577Seric {
5364577Seric 	register FILE *hf;
5374577Seric 	int len;
5384577Seric 	char buf[MAXLINE];
5394577Seric 	bool noinfo;
5404577Seric 
5418269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5424577Seric 	{
5434577Seric 		/* no help */
54411931Seric 		errno = 0;
5454577Seric 		message("502", "HELP not implemented");
5464577Seric 		return;
5474577Seric 	}
5484577Seric 
5494577Seric 	len = strlen(topic);
5504577Seric 	makelower(topic);
5514577Seric 	noinfo = TRUE;
5524577Seric 
5534577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5544577Seric 	{
5554577Seric 		if (strncmp(buf, topic, len) == 0)
5564577Seric 		{
5574577Seric 			register char *p;
5584577Seric 
5594577Seric 			p = index(buf, '\t');
5604577Seric 			if (p == NULL)
5614577Seric 				p = buf;
5624577Seric 			else
5634577Seric 				p++;
5644577Seric 			fixcrlf(p, TRUE);
5654577Seric 			message("214-", p);
5664577Seric 			noinfo = FALSE;
5674577Seric 		}
5684577Seric 	}
5694577Seric 
5704577Seric 	if (noinfo)
5714577Seric 		message("504", "HELP topic unknown");
5724577Seric 	else
5734577Seric 		message("214", "End of HELP info");
5744628Seric 	(void) fclose(hf);
5754577Seric }
5768544Seric /*
5778544Seric **  ISWIZ -- tell us if we are a wizard
5788544Seric **
5798544Seric **	If not, print a nasty message.
5808544Seric **
5818544Seric **	Parameters:
5828544Seric **		none.
5838544Seric **
5848544Seric **	Returns:
5858544Seric **		TRUE if we are a wizard.
5868544Seric **		FALSE if we are not a wizard.
5878544Seric **
5888544Seric **	Side Effects:
5898544Seric **		Prints a 500 exit stat if we are not a wizard.
5908544Seric */
5915181Seric 
592*24945Seric #ifdef WIZ
59319038Seric 
5948544Seric bool
5958544Seric iswiz()
5968544Seric {
5978544Seric 	if (!IsWiz)
5988544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5998544Seric 	return (IsWiz);
6008544Seric }
60119038Seric 
602*24945Seric #endif WIZ
6039339Seric /*
6049339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6059339Seric **
6069339Seric **	Parameters:
6079339Seric **		label -- a string used in error messages
6089339Seric **
6099339Seric **	Returns:
6109339Seric **		zero in the child
6119339Seric **		one in the parent
6129339Seric **
6139339Seric **	Side Effects:
6149339Seric **		none.
6159339Seric */
6168544Seric 
6179339Seric runinchild(label)
6189339Seric 	char *label;
6199339Seric {
6209339Seric 	int childpid;
6219339Seric 
62216158Seric 	if (!OneXact)
6239339Seric 	{
62416158Seric 		childpid = dofork();
62516158Seric 		if (childpid < 0)
62616158Seric 		{
62716158Seric 			syserr("%s: cannot fork", label);
62816158Seric 			return (1);
62916158Seric 		}
63016158Seric 		if (childpid > 0)
63116158Seric 		{
63216158Seric 			auto int st;
6339339Seric 
63416158Seric 			/* parent -- wait for child to complete */
63516158Seric 			st = waitfor(childpid);
63616158Seric 			if (st == -1)
63716158Seric 				syserr("%s: lost child", label);
6389339Seric 
63916158Seric 			/* if we exited on a QUIT command, complete the process */
64016158Seric 			if (st == (EX_QUIT << 8))
64116158Seric 				finis();
6429339Seric 
64316158Seric 			return (1);
64416158Seric 		}
64516158Seric 		else
64616158Seric 		{
64716158Seric 			/* child */
64816158Seric 			InChild = TRUE;
649*24945Seric 			clearenvelope(CurEnv);
65016158Seric 		}
6519339Seric 	}
65215256Seric 
65316158Seric 	/* open alias database */
65416158Seric 	initaliases(AliasFile, FALSE);
65516158Seric 
65616158Seric 	return (0);
6579339Seric }
6589339Seric 
6595181Seric # endif SMTP
660