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*24969Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.10 (Berkeley) 09/19/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*24969Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.10 (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,
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;
108*24969Seric 	char state[100];
1098544Seric 	char inp[MAXLINE];
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();
12716153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12810708Seric 	message("220", inp);
12924943Seric 	SmtpPhase = "startup";
1304549Seric 	for (;;)
1314549Seric 	{
13212612Seric 		/* arrange for backout */
13312612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13412612Seric 			finis();
13512612Seric 		QuickAbort = FALSE;
13612612Seric 		HoldErrs = FALSE;
13712612Seric 
1387356Seric 		/* setup for the read */
1396907Seric 		CurEnv->e_to = NULL;
1404577Seric 		Errors = 0;
1417275Seric 		(void) fflush(stdout);
1427356Seric 
1437356Seric 		/* read the input line */
1447685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1457356Seric 
1467685Seric 		/* handle errors */
1477356Seric 		if (p == NULL)
1487356Seric 		{
1494549Seric 			/* end of file, just die */
1504558Seric 			message("421", "%s Lost input channel", HostName);
1514549Seric 			finis();
1524549Seric 		}
1534549Seric 
1544549Seric 		/* clean up end of line */
1554558Seric 		fixcrlf(inp, TRUE);
1564549Seric 
1574713Seric 		/* echo command to transcript */
1589545Seric 		if (CurEnv->e_xfp != NULL)
1599545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1604713Seric 
1614549Seric 		/* break off command */
1624549Seric 		for (p = inp; isspace(*p); p++)
1634549Seric 			continue;
1644549Seric 		cmd = p;
1654549Seric 		while (*++p != '\0' && !isspace(*p))
1664549Seric 			continue;
1674549Seric 		if (*p != '\0')
1684549Seric 			*p++ = '\0';
1694549Seric 
1704549Seric 		/* decode command */
1714549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1724549Seric 		{
1734549Seric 			if (sameword(c->cmdname, cmd))
1744549Seric 				break;
1754549Seric 		}
1764549Seric 
1774549Seric 		/* process command */
1784549Seric 		switch (c->cmdcode)
1794549Seric 		{
1804976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
18124943Seric 			SmtpPhase = "HELO";
18214877Seric 			if (sameword(p, HostName))
18314877Seric 			{
18414877Seric 				/* connected to an echo server */
18514877Seric 				message("553", "%s I refuse to talk to myself",
18614877Seric 					HostName);
18714877Seric 				break;
18814877Seric 			}
18911146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
19011146Seric 			{
19111146Seric 				char buf[MAXNAME];
19211146Seric 
19311146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
19411146Seric 				define('s', newstr(buf), CurEnv);
19511146Seric 			}
19611146Seric 			else
19711146Seric 				define('s', newstr(p), CurEnv);
1984997Seric 			message("250", "%s Hello %s, pleased to meet you",
1994997Seric 				HostName, p);
2004976Seric 			break;
2014976Seric 
2024549Seric 		  case CMDMAIL:		/* mail -- designate sender */
20324943Seric 			SmtpPhase = "MAIL";
20424943Seric 
20511151Seric 			/* force a sending host even if no HELO given */
20611151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
20711151Seric 				define('s', RealHostName, CurEnv);
20811151Seric 
2099314Seric 			/* check for validity of this command */
2104558Seric 			if (hasmail)
2114558Seric 			{
2124558Seric 				message("503", "Sender already specified");
2134558Seric 				break;
2144558Seric 			}
2159339Seric 			if (InChild)
2169339Seric 			{
2179339Seric 				syserr("Nested MAIL command");
2189339Seric 				exit(0);
2199339Seric 			}
2209339Seric 
2219339Seric 			/* fork a subprocess to process this command */
2229339Seric 			if (runinchild("SMTP-MAIL") > 0)
2239339Seric 				break;
2249339Seric 			initsys();
225*24969Seric 			(void) sprintf(state, "srvrsmtp %s", CurEnv->e_id);
226*24969Seric 			setproctitle(state);
2279339Seric 
2289339Seric 			/* child -- go do the processing */
2294549Seric 			p = skipword(p, "from");
2304549Seric 			if (p == NULL)
2314549Seric 				break;
2324549Seric 			setsender(p);
2334577Seric 			if (Errors == 0)
2344549Seric 			{
2354549Seric 				message("250", "Sender ok");
2364549Seric 				hasmail = TRUE;
2374549Seric 			}
2389339Seric 			else if (InChild)
2399339Seric 				finis();
2404549Seric 			break;
2414549Seric 
2424976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
24324943Seric 			SmtpPhase = "RCPT";
24412612Seric 			if (setjmp(TopFrame) > 0)
24514785Seric 			{
24614785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
24712612Seric 				break;
24814785Seric 			}
24912612Seric 			QuickAbort = TRUE;
2504549Seric 			p = skipword(p, "to");
2514549Seric 			if (p == NULL)
2524549Seric 				break;
25316140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
25412612Seric 			if (a == NULL)
25512612Seric 				break;
25616886Seric 			a->q_flags |= QPRIMARY;
25712612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
25812612Seric 			if (Errors != 0)
25912612Seric 				break;
26012612Seric 
26112612Seric 			/* no errors during parsing, but might be a duplicate */
26212612Seric 			CurEnv->e_to = p;
26312612Seric 			if (!bitset(QBADADDR, a->q_flags))
26412612Seric 				message("250", "Recipient ok");
26512612Seric 			else
2664549Seric 			{
26712612Seric 				/* punt -- should keep message in ADDRESS.... */
26812612Seric 				message("550", "Addressee unknown");
2694549Seric 			}
27012612Seric 			CurEnv->e_to = NULL;
2714549Seric 			break;
2724549Seric 
2734549Seric 		  case CMDDATA:		/* data -- text of mail */
27424943Seric 			SmtpPhase = "DATA";
2754976Seric 			if (!hasmail)
2764549Seric 			{
2774976Seric 				message("503", "Need MAIL command");
2784976Seric 				break;
2794549Seric 			}
28024943Seric 			else if (CurEnv->e_nrcpts <= 0)
2814549Seric 			{
2824976Seric 				message("503", "Need RCPT (recipient)");
2834976Seric 				break;
2844549Seric 			}
2854976Seric 
2864976Seric 			/* collect the text of the message */
28724943Seric 			SmtpPhase = "collect";
2884976Seric 			collect(TRUE);
2894976Seric 			if (Errors != 0)
2904976Seric 				break;
2914976Seric 
2928238Seric 			/*
2938238Seric 			**  Arrange to send to everyone.
2948238Seric 			**	If sending to multiple people, mail back
2958238Seric 			**		errors rather than reporting directly.
2968238Seric 			**	In any case, don't mail back errors for
2978238Seric 			**		anything that has happened up to
2988238Seric 			**		now (the other end will do this).
29910197Seric 			**	Truncate our transcript -- the mail has gotten
30010197Seric 			**		to us successfully, and if we have
30110197Seric 			**		to mail this back, it will be easier
30210197Seric 			**		on the reader.
3038238Seric 			**	Then send to everyone.
3048238Seric 			**	Finally give a reply code.  If an error has
3058238Seric 			**		already been given, don't mail a
3068238Seric 			**		message back.
3079339Seric 			**	We goose error returns by clearing error bit.
3088238Seric 			*/
3098238Seric 
31024943Seric 			SmtpPhase = "delivery";
31124943Seric 			if (CurEnv->e_nrcpts != 1)
3129378Seric 			{
3139378Seric 				HoldErrs = TRUE;
31416886Seric 				ErrorMode = EM_MAIL;
3159378Seric 			}
3169339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
31710197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3184976Seric 
3194976Seric 			/* send to all recipients */
32014877Seric 			sendall(CurEnv, SM_DEFAULT);
3216907Seric 			CurEnv->e_to = NULL;
3224976Seric 
32323516Seric 			/* save statistics */
32423516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
32523516Seric 
3268238Seric 			/* issue success if appropriate and reset */
3278238Seric 			if (Errors == 0 || HoldErrs)
3289283Seric 				message("250", "Ok");
3298238Seric 			else
3309339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3319339Seric 
3329339Seric 			/* if in a child, pop back to our parent */
3339339Seric 			if (InChild)
3349339Seric 				finis();
33524943Seric 
33624943Seric 			/* clean up a bit */
33724943Seric 			hasmail = 0;
33824943Seric 			dropenvelope(CurEnv);
33924943Seric 			CurEnv = newenvelope(CurEnv);
34024943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3414549Seric 			break;
3424549Seric 
3434549Seric 		  case CMDRSET:		/* rset -- reset state */
3444549Seric 			message("250", "Reset state");
3459339Seric 			if (InChild)
3469339Seric 				finis();
3479339Seric 			break;
3484549Seric 
3494549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3509339Seric 			if (runinchild("SMTP-VRFY") > 0)
3519339Seric 				break;
352*24969Seric 			setproctitle("SMTP-VRFY");
3535003Seric 			vrfyqueue = NULL;
3547762Seric 			QuickAbort = TRUE;
3559619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3567762Seric 			if (Errors != 0)
3579339Seric 			{
3589339Seric 				if (InChild)
3599339Seric 					finis();
3607762Seric 				break;
3619339Seric 			}
3625003Seric 			while (vrfyqueue != NULL)
3635003Seric 			{
3645003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3655003Seric 				char *code;
3665003Seric 
3677685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3685003Seric 					a = a->q_next;
3695003Seric 
3707685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3715003Seric 				{
3725003Seric 					if (a != NULL)
3735003Seric 						code = "250-";
3745003Seric 					else
3755003Seric 						code = "250";
3765003Seric 					if (vrfyqueue->q_fullname == NULL)
3775003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3785003Seric 					else
3795003Seric 						message(code, "%s <%s>",
3805003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3815003Seric 				}
3825003Seric 				else if (a == NULL)
3835003Seric 					message("554", "Self destructive alias loop");
3845003Seric 				vrfyqueue = a;
3855003Seric 			}
3869339Seric 			if (InChild)
3879339Seric 				finis();
3884549Seric 			break;
3894549Seric 
3904549Seric 		  case CMDHELP:		/* help -- give user info */
3914577Seric 			if (*p == '\0')
3924577Seric 				p = "SMTP";
3934577Seric 			help(p);
3944549Seric 			break;
3954549Seric 
3964549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3974549Seric 			message("200", "OK");
3984549Seric 			break;
3994549Seric 
4004549Seric 		  case CMDQUIT:		/* quit -- leave mail */
4014549Seric 			message("221", "%s closing connection", HostName);
4029339Seric 			if (InChild)
4039339Seric 				ExitStat = EX_QUIT;
4044549Seric 			finis();
4054549Seric 
4068544Seric 		  case CMDVERB:		/* set verbose mode */
4078544Seric 			Verbose = TRUE;
4088544Seric 			message("200", "Verbose mode");
4098544Seric 			break;
4108544Seric 
4119314Seric 		  case CMDONEX:		/* doing one transaction only */
4129378Seric 			OneXact = TRUE;
4139314Seric 			message("200", "Only one transaction");
4149314Seric 			break;
4159314Seric 
4165003Seric # ifdef DEBUG
4179339Seric 		  case CMDDBGQSHOW:	/* show queues */
4186907Seric 			printf("Send Queue=");
4196907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4205003Seric 			break;
4217275Seric 
4227275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4237676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4247676Seric 			tTflag(p);
4257676Seric 			message("200", "Debug set");
4267275Seric 			break;
42724945Seric # endif DEBUG
4287275Seric 
42924945Seric # ifdef WIZ
4307282Seric 		  case CMDDBGKILL:	/* kill the parent */
4318544Seric 			if (!iswiz())
4328544Seric 				break;
4337282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4347282Seric 				message("200", "Mother is dead");
4357282Seric 			else
4367282Seric 				message("500", "Can't kill Mom");
4377282Seric 			break;
4388544Seric 
4398544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4408544Seric 			if (WizWord != NULL)
4418544Seric 			{
4428544Seric 				char seed[3];
4438544Seric 				extern char *crypt();
4448544Seric 
44523106Seric 				(void) strncpy(seed, WizWord, 2);
44615596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4478544Seric 				{
44815596Seric 					IsWiz = TRUE;
44915596Seric 					message("200", "Please pass, oh mighty wizard");
4508544Seric 					break;
4518544Seric 				}
4528544Seric 			}
45315596Seric 			message("500", "You are no wizard!");
4548544Seric 			break;
4555003Seric 
45624945Seric # else WIZ
45724945Seric 		  case CMDDBGWIZ:	/* try to become a wizard */
45824945Seric 			message("500", "You wascal wabbit!  Wandering wizards won't win!");
45924945Seric 			break;
46024945Seric # endif WIZ
46124945Seric 
4624549Seric 		  case CMDERROR:	/* unknown command */
4634549Seric 			message("500", "Command unrecognized");
4644549Seric 			break;
4654549Seric 
4664549Seric 		  default:
4674549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4684549Seric 			break;
4694549Seric 		}
4704549Seric 	}
4714549Seric }
4724549Seric /*
4734549Seric **  SKIPWORD -- skip a fixed word.
4744549Seric **
4754549Seric **	Parameters:
4764549Seric **		p -- place to start looking.
4774549Seric **		w -- word to skip.
4784549Seric **
4794549Seric **	Returns:
4804549Seric **		p following w.
4814549Seric **		NULL on error.
4824549Seric **
4834549Seric **	Side Effects:
4844549Seric **		clobbers the p data area.
4854549Seric */
4864549Seric 
4874549Seric static char *
4884549Seric skipword(p, w)
4894549Seric 	register char *p;
4904549Seric 	char *w;
4914549Seric {
4924549Seric 	register char *q;
4934549Seric 	extern bool sameword();
4944549Seric 
4954549Seric 	/* find beginning of word */
4964549Seric 	while (isspace(*p))
4974549Seric 		p++;
4984549Seric 	q = p;
4994549Seric 
5004549Seric 	/* find end of word */
5014549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5024549Seric 		p++;
5034549Seric 	while (isspace(*p))
5044549Seric 		*p++ = '\0';
5054549Seric 	if (*p != ':')
5064549Seric 	{
5074549Seric 	  syntax:
5084549Seric 		message("501", "Syntax error");
5094549Seric 		Errors++;
5104549Seric 		return (NULL);
5114549Seric 	}
5124549Seric 	*p++ = '\0';
5134549Seric 	while (isspace(*p))
5144549Seric 		p++;
5154549Seric 
5164549Seric 	/* see if the input word matches desired word */
5174549Seric 	if (!sameword(q, w))
5184549Seric 		goto syntax;
5194549Seric 
5204549Seric 	return (p);
5214549Seric }
5224577Seric /*
5234577Seric **  HELP -- implement the HELP command.
5244577Seric **
5254577Seric **	Parameters:
5264577Seric **		topic -- the topic we want help for.
5274577Seric **
5284577Seric **	Returns:
5294577Seric **		none.
5304577Seric **
5314577Seric **	Side Effects:
5324577Seric **		outputs the help file to message output.
5334577Seric */
5344577Seric 
5354577Seric help(topic)
5364577Seric 	char *topic;
5374577Seric {
5384577Seric 	register FILE *hf;
5394577Seric 	int len;
5404577Seric 	char buf[MAXLINE];
5414577Seric 	bool noinfo;
5424577Seric 
5438269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5444577Seric 	{
5454577Seric 		/* no help */
54611931Seric 		errno = 0;
5474577Seric 		message("502", "HELP not implemented");
5484577Seric 		return;
5494577Seric 	}
5504577Seric 
5514577Seric 	len = strlen(topic);
5524577Seric 	makelower(topic);
5534577Seric 	noinfo = TRUE;
5544577Seric 
5554577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5564577Seric 	{
5574577Seric 		if (strncmp(buf, topic, len) == 0)
5584577Seric 		{
5594577Seric 			register char *p;
5604577Seric 
5614577Seric 			p = index(buf, '\t');
5624577Seric 			if (p == NULL)
5634577Seric 				p = buf;
5644577Seric 			else
5654577Seric 				p++;
5664577Seric 			fixcrlf(p, TRUE);
5674577Seric 			message("214-", p);
5684577Seric 			noinfo = FALSE;
5694577Seric 		}
5704577Seric 	}
5714577Seric 
5724577Seric 	if (noinfo)
5734577Seric 		message("504", "HELP topic unknown");
5744577Seric 	else
5754577Seric 		message("214", "End of HELP info");
5764628Seric 	(void) fclose(hf);
5774577Seric }
5788544Seric /*
5798544Seric **  ISWIZ -- tell us if we are a wizard
5808544Seric **
5818544Seric **	If not, print a nasty message.
5828544Seric **
5838544Seric **	Parameters:
5848544Seric **		none.
5858544Seric **
5868544Seric **	Returns:
5878544Seric **		TRUE if we are a wizard.
5888544Seric **		FALSE if we are not a wizard.
5898544Seric **
5908544Seric **	Side Effects:
5918544Seric **		Prints a 500 exit stat if we are not a wizard.
5928544Seric */
5935181Seric 
59424945Seric #ifdef WIZ
59519038Seric 
5968544Seric bool
5978544Seric iswiz()
5988544Seric {
5998544Seric 	if (!IsWiz)
6008544Seric 		message("500", "Mere mortals musn't mutter that mantra");
6018544Seric 	return (IsWiz);
6028544Seric }
60319038Seric 
60424945Seric #endif WIZ
6059339Seric /*
6069339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6079339Seric **
6089339Seric **	Parameters:
6099339Seric **		label -- a string used in error messages
6109339Seric **
6119339Seric **	Returns:
6129339Seric **		zero in the child
6139339Seric **		one in the parent
6149339Seric **
6159339Seric **	Side Effects:
6169339Seric **		none.
6179339Seric */
6188544Seric 
6199339Seric runinchild(label)
6209339Seric 	char *label;
6219339Seric {
6229339Seric 	int childpid;
6239339Seric 
62416158Seric 	if (!OneXact)
6259339Seric 	{
62616158Seric 		childpid = dofork();
62716158Seric 		if (childpid < 0)
62816158Seric 		{
62916158Seric 			syserr("%s: cannot fork", label);
63016158Seric 			return (1);
63116158Seric 		}
63216158Seric 		if (childpid > 0)
63316158Seric 		{
63416158Seric 			auto int st;
6359339Seric 
63616158Seric 			/* parent -- wait for child to complete */
63716158Seric 			st = waitfor(childpid);
63816158Seric 			if (st == -1)
63916158Seric 				syserr("%s: lost child", label);
6409339Seric 
64116158Seric 			/* if we exited on a QUIT command, complete the process */
64216158Seric 			if (st == (EX_QUIT << 8))
64316158Seric 				finis();
6449339Seric 
64516158Seric 			return (1);
64616158Seric 		}
64716158Seric 		else
64816158Seric 		{
64916158Seric 			/* child */
65016158Seric 			InChild = TRUE;
65124945Seric 			clearenvelope(CurEnv);
65216158Seric 		}
6539339Seric 	}
65415256Seric 
65516158Seric 	/* open alias database */
65616158Seric 	initaliases(AliasFile, FALSE);
65716158Seric 
65816158Seric 	return (0);
6599339Seric }
6609339Seric 
6615181Seric # endif SMTP
662