xref: /freebsd/contrib/sendmail/src/main.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
1 /*
2  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * By using this file, you agree to the terms and conditions set
8  * forth in the LICENSE file which can be found at the top level of
9  * the sendmail distribution.
10  *
11  */
12 
13 #ifndef lint
14 static char copyright[] =
15 "@(#) Copyright (c) 1998 Sendmail, Inc.  All rights reserved.\n\
16      Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.\n\
17      Copyright (c) 1988, 1993\n\
18 	The Regents of the University of California.  All rights reserved.\n";
19 #endif /* not lint */
20 
21 #ifndef lint
22 static char sccsid[] = "@(#)main.c	8.322 (Berkeley) 12/18/1998";
23 #endif /* not lint */
24 
25 #define	_DEFINE
26 
27 #include "sendmail.h"
28 #include <arpa/inet.h>
29 #include <grp.h>
30 #if NAMED_BIND
31 #include <resolv.h>
32 #endif
33 
34 /*
35 **  SENDMAIL -- Post mail to a set of destinations.
36 **
37 **	This is the basic mail router.  All user mail programs should
38 **	call this routine to actually deliver mail.  Sendmail in
39 **	turn calls a bunch of mail servers that do the real work of
40 **	delivering the mail.
41 **
42 **	Sendmail is driven by settings read in from /etc/sendmail.cf
43 **	(read by readcf.c).
44 **
45 **	Usage:
46 **		/usr/lib/sendmail [flags] addr ...
47 **
48 **		See the associated documentation for details.
49 **
50 **	Author:
51 **		Eric Allman, UCB/INGRES (until 10/81).
52 **			     Britton-Lee, Inc., purveyors of fine
53 **				database computers (11/81 - 10/88).
54 **			     International Computer Science Institute
55 **				(11/88 - 9/89).
56 **			     UCB/Mammoth Project (10/89 - 7/95).
57 **			     InReference, Inc. (8/95 - 1/97).
58 **			     Sendmail, Inc. (1/98 - present).
59 **		The support of the my employers is gratefully acknowledged.
60 **			Few of them (Britton-Lee in particular) have had
61 **			anything to gain from my involvement in this project.
62 */
63 
64 
65 int		NextMailer;	/* "free" index into Mailer struct */
66 char		*FullName;	/* sender's full name */
67 ENVELOPE	BlankEnvelope;	/* a "blank" envelope */
68 ENVELOPE	MainEnvelope;	/* the envelope around the basic letter */
69 ADDRESS		NullAddress =	/* a null address */
70 		{ "", "", NULL, "" };
71 char		*CommandLineArgs;	/* command line args for pid file */
72 bool		Warn_Q_option = FALSE;	/* warn about Q option use */
73 char		**SaveArgv;	/* argument vector for re-execing */
74 int		MissingFds = 0;	/* bit map of fds missing on startup */
75 
76 #ifdef NGROUPS_MAX
77 GIDSET_T	InitialGidSet[NGROUPS_MAX];
78 #endif
79 
80 static void	obsolete __P((char **));
81 extern void	printmailer __P((MAILER *));
82 extern void	tTflag __P((char *));
83 
84 #if DAEMON && !SMTP
85 ERROR %%%%   Cannot have DAEMON mode without SMTP   %%%% ERROR
86 #endif /* DAEMON && !SMTP */
87 #if SMTP && !QUEUE
88 ERROR %%%%   Cannot have SMTP mode without QUEUE   %%%% ERROR
89 #endif /* DAEMON && !SMTP */
90 
91 #define MAXCONFIGLEVEL	8	/* highest config version level known */
92 
93 int
94 main(argc, argv, envp)
95 	int argc;
96 	char **argv;
97 	char **envp;
98 {
99 	register char *p;
100 	char **av;
101 	extern char Version[];
102 	char *ep, *from;
103 	STAB *st;
104 	register int i;
105 	int j;
106 	bool queuemode = FALSE;		/* process queue requests */
107 	bool safecf = TRUE;
108 	bool warn_C_flag = FALSE;
109 	char warn_f_flag = '\0';
110 	bool run_in_foreground = FALSE;	/* -bD mode */
111 	static bool reenter = FALSE;
112 	struct passwd *pw;
113 	struct hostent *hp;
114 	char *nullserver = NULL;
115 	bool forged;
116 	char jbuf[MAXHOSTNAMELEN];	/* holds MyHostName */
117 	static char rnamebuf[MAXNAME];	/* holds RealUserName */
118 	char *emptyenviron[1];
119 	QUEUE_CHAR *new;
120 	extern int DtableSize;
121 	extern int optind;
122 	extern int opterr;
123 	extern char *optarg;
124 	extern char **environ;
125 	extern time_t convtime __P((char *, char));
126 	extern SIGFUNC_DECL intsig __P((int));
127 	extern struct hostent *myhostname __P((char *, int));
128 	extern char *getauthinfo __P((int, bool *));
129 	extern char *getcfname __P((void));
130 	extern SIGFUNC_DECL sigusr1 __P((int));
131 	extern SIGFUNC_DECL sighup __P((int));
132 	extern SIGFUNC_DECL quiesce __P((int));
133 	extern void initmacros __P((ENVELOPE *));
134 	extern void init_md __P((int, char **));
135 	extern int getdtsize __P((void));
136 	extern void tTsetup __P((u_char *, int, char *));
137 	extern void setdefaults __P((ENVELOPE *));
138 	extern void initsetproctitle __P((int, char **, char **));
139 	extern void init_vendor_macros __P((ENVELOPE *));
140 	extern void load_if_names __P((void));
141 	extern void vendor_pre_defaults __P((ENVELOPE *));
142 	extern void vendor_post_defaults __P((ENVELOPE *));
143 	extern void readcf __P((char *, bool, ENVELOPE *));
144 	extern void printqueue __P((void));
145 	extern void sendtoargv __P((char **, ENVELOPE *));
146 	extern void resetlimits __P((void));
147 #ifndef HASUNSETENV
148 	extern void unsetenv __P((char *));
149 #endif
150 
151 	/*
152 	**  Check to see if we reentered.
153 	**	This would normally happen if e_putheader or e_putbody
154 	**	were NULL when invoked.
155 	*/
156 
157 	if (reenter)
158 	{
159 		syserr("main: reentered!");
160 		abort();
161 	}
162 	reenter = TRUE;
163 
164 	/* avoid null pointer dereferences */
165 	TermEscape.te_rv_on = TermEscape.te_rv_off = "";
166 
167 	/* do machine-dependent initializations */
168 	init_md(argc, argv);
169 
170 	/* in 4.4BSD, the table can be huge; impose a reasonable limit */
171 	DtableSize = getdtsize();
172 	if (DtableSize > 256)
173 		DtableSize = 256;
174 
175 	/*
176 	**  Be sure we have enough file descriptors.
177 	**	But also be sure that 0, 1, & 2 are open.
178 	*/
179 
180 	fill_fd(STDIN_FILENO, NULL);
181 	fill_fd(STDOUT_FILENO, NULL);
182 	fill_fd(STDERR_FILENO, NULL);
183 
184 	i = DtableSize;
185 	while (--i > 0)
186 	{
187 		if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
188 			(void) close(i);
189 	}
190 	errno = 0;
191 
192 #if LOG
193 # ifdef LOG_MAIL
194 	openlog("sendmail", LOG_PID, LOG_MAIL);
195 # else
196 	openlog("sendmail", LOG_PID);
197 # endif
198 #endif
199 
200 	if (MissingFds != 0)
201 	{
202 		char mbuf[MAXLINE];
203 
204 		mbuf[0] = '\0';
205 		if (bitset(1 << STDIN_FILENO, MissingFds))
206 			strcat(mbuf, ", stdin");
207 		if (bitset(1 << STDOUT_FILENO, MissingFds))
208 			strcat(mbuf, ", stdout");
209 		if (bitset(1 << STDERR_FILENO, MissingFds))
210 			strcat(mbuf, ", stderr");
211 		syserr("File descriptors missing on startup: %s", &mbuf[2]);
212 	}
213 
214 	/* reset status from syserr() calls for missing file descriptors */
215 	Errors = 0;
216 	ExitStat = EX_OK;
217 
218 #if XDEBUG
219 	checkfd012("after openlog");
220 #endif
221 
222 	tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
223 
224 #ifdef NGROUPS_MAX
225 	/* save initial group set for future checks */
226 	i = getgroups(NGROUPS_MAX, InitialGidSet);
227 	if (i == 0)
228 		InitialGidSet[0] = (GID_T) -1;
229 	while (i < NGROUPS_MAX)
230 		InitialGidSet[i++] = InitialGidSet[0];
231 #endif
232 
233 	/* drop group id privileges (RunAsUser not yet set) */
234 	(void) drop_privileges(FALSE);
235 
236 #ifdef SIGUSR1
237 	/* arrange to dump state on user-1 signal */
238 	setsignal(SIGUSR1, sigusr1);
239 #endif
240 
241 	/* initialize for setproctitle */
242 	initsetproctitle(argc, argv, envp);
243 
244 	/* Handle any non-getoptable constructions. */
245 	obsolete(argv);
246 
247 	/*
248 	**  Do a quick prescan of the argument list.
249 	*/
250 
251 #if defined(__osf__) || defined(_AIX3)
252 # define OPTIONS	"B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x"
253 #endif
254 #if defined(sony_news)
255 # define OPTIONS	"B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:"
256 #endif
257 #ifndef OPTIONS
258 # define OPTIONS	"B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:"
259 #endif
260 	opterr = 0;
261 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
262 	{
263 		switch (j)
264 		{
265 		  case 'd':
266 			/* hack attack -- see if should use ANSI mode */
267 			if (strcmp(optarg, "ANSI") == 0)
268 			{
269 				TermEscape.te_rv_on = "\033[7m";
270 				TermEscape.te_rv_off = "\033[0m";
271 				break;
272 			}
273 			tTflag(optarg);
274 			setbuf(stdout, (char *) NULL);
275 			break;
276 		}
277 	}
278 	opterr = 1;
279 
280 	/* set up the blank envelope */
281 	BlankEnvelope.e_puthdr = putheader;
282 	BlankEnvelope.e_putbody = putbody;
283 	BlankEnvelope.e_xfp = NULL;
284 	STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
285 	CurEnv = &BlankEnvelope;
286 	STRUCTCOPY(NullAddress, MainEnvelope.e_from);
287 
288 	/*
289 	**  Set default values for variables.
290 	**	These cannot be in initialized data space.
291 	*/
292 
293 	setdefaults(&BlankEnvelope);
294 
295 	RealUid = getuid();
296 	RealGid = getgid();
297 
298 	pw = sm_getpwuid(RealUid);
299 	if (pw != NULL)
300 		(void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
301 	else
302 		(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", RealUid);
303 	RealUserName = rnamebuf;
304 
305 	if (tTd(0, 101))
306 	{
307 		printf("Version %s\n", Version);
308 		finis(FALSE, EX_OK);
309 	}
310 
311 	/*
312 	**  if running non-setuid binary as non-root, pretend
313 	**  we are the RunAsUid
314 	*/
315 	if (RealUid != 0 && geteuid() == RealUid)
316 	{
317 		if (tTd(47, 1))
318 			printf("Non-setuid binary: RunAsUid = RealUid = %d\n",
319 				(int)RealUid);
320 		RunAsUid = RealUid;
321 	}
322 	else if (geteuid() != 0)
323 		RunAsUid = geteuid();
324 
325 	if (RealUid != 0 && getegid() == RealGid)
326 		RunAsGid = RealGid;
327 
328 	if (tTd(47, 5))
329 	{
330 		printf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
331 			(int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
332 		printf("main: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
333 	}
334 
335 	/* save command line arguments */
336 	i = 0;
337 	for (av = argv; *av != NULL; )
338 		i += strlen(*av++) + 1;
339 	SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
340 	CommandLineArgs = xalloc(i);
341 	p = CommandLineArgs;
342 	for (av = argv, i = 0; *av != NULL; )
343 	{
344 		SaveArgv[i++] = newstr(*av);
345 		if (av != argv)
346 			*p++ = ' ';
347 		strcpy(p, *av++);
348 		p += strlen(p);
349 	}
350 	SaveArgv[i] = NULL;
351 
352 	if (tTd(0, 1))
353 	{
354 		int ll;
355 		extern char *CompileOptions[];
356 
357 		printf("Version %s\n Compiled with:", Version);
358 		av = CompileOptions;
359 		ll = 7;
360 		while (*av != NULL)
361 		{
362 			if (ll + strlen(*av) > 63)
363 			{
364 				putchar('\n');
365 				ll = 0;
366 			}
367 			if (ll == 0)
368 			{
369 				putchar('\t');
370 				putchar('\t');
371 			}
372 			else
373 				putchar(' ');
374 			printf("%s", *av);
375 			ll += strlen(*av++) + 1;
376 		}
377 		putchar('\n');
378 	}
379 	if (tTd(0, 10))
380 	{
381 		int ll;
382 		extern char *OsCompileOptions[];
383 
384 		printf("    OS Defines:");
385 		av = OsCompileOptions;
386 		ll = 7;
387 		while (*av != NULL)
388 		{
389 			if (ll + strlen(*av) > 63)
390 			{
391 				putchar('\n');
392 				ll = 0;
393 			}
394 			if (ll == 0)
395 			{
396 				putchar('\t');
397 				putchar('\t');
398 			}
399 			else
400 				putchar(' ');
401 			printf("%s", *av);
402 			ll += strlen(*av++) + 1;
403 		}
404 		putchar('\n');
405 #ifdef _PATH_UNIX
406 		printf("Kernel symbols:\t%s\n", _PATH_UNIX);
407 #endif
408 		printf(" Def Conf file:\t%s\n", getcfname());
409 		printf("      Pid file:\t%s\n", PidFile);
410 	}
411 
412 	InChannel = stdin;
413 	OutChannel = stdout;
414 
415 	/* clear sendmail's environment */
416 	ExternalEnviron = environ;
417 	emptyenviron[0] = NULL;
418 	environ = emptyenviron;
419 
420 	/*
421 	**  restore any original TZ setting until TimeZoneSpec has been
422 	**  determined - or early log messages may get bogus time stamps
423 	*/
424 	if ((p = getextenv("TZ")) != NULL)
425 	{
426 		char *tz;
427 		int tzlen;
428 
429 		tzlen = strlen(p) + 4;
430 		tz = xalloc(tzlen);
431 		snprintf(tz, tzlen, "TZ=%s", p);
432 		putenv(tz);
433 	}
434 
435 	/* prime the child environment */
436 	setuserenv("AGENT", "sendmail");
437 
438 	if (setsignal(SIGINT, SIG_IGN) != SIG_IGN)
439 		(void) setsignal(SIGINT, intsig);
440 	(void) setsignal(SIGTERM, intsig);
441 	(void) setsignal(SIGPIPE, SIG_IGN);
442 	OldUmask = umask(022);
443 	OpMode = MD_DELIVER;
444 	FullName = getextenv("NAME");
445 
446 	/*
447 	**  Initialize name server if it is going to be used.
448 	*/
449 
450 #if NAMED_BIND
451 	if (!bitset(RES_INIT, _res.options))
452 		res_init();
453 	if (tTd(8, 8))
454 		_res.options |= RES_DEBUG;
455 	else
456 		_res.options &= ~RES_DEBUG;
457 # ifdef RES_NOALIASES
458 	_res.options |= RES_NOALIASES;
459 # endif
460 #endif
461 
462 	errno = 0;
463 	from = NULL;
464 
465 	/* initialize some macros, etc. */
466 	initmacros(CurEnv);
467 	init_vendor_macros(CurEnv);
468 
469 	/* version */
470 	define('v', Version, CurEnv);
471 
472 	/* hostname */
473 	hp = myhostname(jbuf, sizeof jbuf);
474 	if (jbuf[0] != '\0')
475 	{
476 		struct	utsname	utsname;
477 
478 		if (tTd(0, 4))
479 			printf("canonical name: %s\n", jbuf);
480 		define('w', newstr(jbuf), CurEnv);	/* must be new string */
481 		define('j', newstr(jbuf), CurEnv);
482 		setclass('w', jbuf);
483 
484 		p = strchr(jbuf, '.');
485 		if (p != NULL)
486 		{
487 			if (p[1] != '\0')
488 			{
489 				define('m', newstr(&p[1]), CurEnv);
490 			}
491 			while (p != NULL && strchr(&p[1], '.') != NULL)
492 			{
493 				*p = '\0';
494 				if (tTd(0, 4))
495 					printf("\ta.k.a.: %s\n", jbuf);
496 				setclass('w', jbuf);
497 				*p++ = '.';
498 				p = strchr(p, '.');
499 			}
500 		}
501 
502 		if (uname(&utsname) >= 0)
503 			p = utsname.nodename;
504 		else
505 		{
506 			if (tTd(0, 22))
507 				printf("uname failed (%s)\n", errstring(errno));
508 			makelower(jbuf);
509 			p = jbuf;
510 		}
511 		if (tTd(0, 4))
512 			printf(" UUCP nodename: %s\n", p);
513 		p = newstr(p);
514 		define('k', p, CurEnv);
515 		setclass('k', p);
516 		setclass('w', p);
517 	}
518 	if (hp != NULL)
519 	{
520 		for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
521 		{
522 			if (tTd(0, 4))
523 				printf("\ta.k.a.: %s\n", *av);
524 			setclass('w', *av);
525 		}
526 #if NETINET
527 		if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ)
528 		{
529 			for (i = 0; hp->h_addr_list[i] != NULL; i++)
530 			{
531 				char ipbuf[103];
532 
533 				snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
534 					inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
535 				if (tTd(0, 4))
536 					printf("\ta.k.a.: %s\n", ipbuf);
537 				setclass('w', ipbuf);
538 			}
539 		}
540 #endif
541 	}
542 
543 	/* current time */
544 	define('b', arpadate((char *) NULL), CurEnv);
545 
546 	QueueLimitRecipient = (QUEUE_CHAR *) NULL;
547 	QueueLimitSender = (QUEUE_CHAR *) NULL;
548 	QueueLimitId = (QUEUE_CHAR *) NULL;
549 
550 	/*
551 	**  Crack argv.
552 	*/
553 
554 	av = argv;
555 	p = strrchr(*av, '/');
556 	if (p++ == NULL)
557 		p = *av;
558 	if (strcmp(p, "newaliases") == 0)
559 		OpMode = MD_INITALIAS;
560 	else if (strcmp(p, "mailq") == 0)
561 		OpMode = MD_PRINT;
562 	else if (strcmp(p, "smtpd") == 0)
563 		OpMode = MD_DAEMON;
564 	else if (strcmp(p, "hoststat") == 0)
565 		OpMode = MD_HOSTSTAT;
566 	else if (strcmp(p, "purgestat") == 0)
567 		OpMode = MD_PURGESTAT;
568 
569 	optind = 1;
570 	while ((j = getopt(argc, argv, OPTIONS)) != -1)
571 	{
572 		switch (j)
573 		{
574 		  case 'b':	/* operations mode */
575 			switch (j = *optarg)
576 			{
577 			  case MD_DAEMON:
578 			  case MD_FGDAEMON:
579 # if !DAEMON
580 				usrerr("Daemon mode not implemented");
581 				ExitStat = EX_USAGE;
582 				break;
583 # endif /* DAEMON */
584 			  case MD_SMTP:
585 # if !SMTP
586 				usrerr("I don't speak SMTP");
587 				ExitStat = EX_USAGE;
588 				break;
589 # endif /* SMTP */
590 
591 			  case MD_INITALIAS:
592 			  case MD_DELIVER:
593 			  case MD_VERIFY:
594 			  case MD_TEST:
595 			  case MD_PRINT:
596 			  case MD_HOSTSTAT:
597 			  case MD_PURGESTAT:
598 			  case MD_ARPAFTP:
599 				OpMode = j;
600 				break;
601 
602 			  case MD_FREEZE:
603 				usrerr("Frozen configurations unsupported");
604 				ExitStat = EX_USAGE;
605 				break;
606 
607 			  default:
608 				usrerr("Invalid operation mode %c", j);
609 				ExitStat = EX_USAGE;
610 				break;
611 			}
612 			break;
613 
614 		  case 'B':	/* body type */
615 			CurEnv->e_bodytype = optarg;
616 			break;
617 
618 		  case 'C':	/* select configuration file (already done) */
619 			if (RealUid != 0)
620 				warn_C_flag = TRUE;
621 			ConfFile = optarg;
622 			(void) drop_privileges(TRUE);
623 			safecf = FALSE;
624 			break;
625 
626 		  case 'd':	/* debugging -- already done */
627 			break;
628 
629 		  case 'f':	/* from address */
630 		  case 'r':	/* obsolete -f flag */
631 			if (from != NULL)
632 			{
633 				usrerr("More than one \"from\" person");
634 				ExitStat = EX_USAGE;
635 				break;
636 			}
637 			from = newstr(denlstring(optarg, TRUE, TRUE));
638 			if (strcmp(RealUserName, from) != 0)
639 				warn_f_flag = j;
640 			break;
641 
642 		  case 'F':	/* set full name */
643 			FullName = newstr(optarg);
644 			break;
645 
646 		  case 'h':	/* hop count */
647 			CurEnv->e_hopcount = strtol(optarg, &ep, 10);
648 			if (*ep)
649 			{
650 				usrerr("Bad hop count (%s)", optarg);
651 				ExitStat = EX_USAGE;
652 			}
653 			break;
654 
655 		  case 'n':	/* don't alias */
656 			NoAlias = TRUE;
657 			break;
658 
659 		  case 'N':	/* delivery status notifications */
660 			DefaultNotify |= QHASNOTIFY;
661 			if (strcasecmp(optarg, "never") == 0)
662 				break;
663 			for (p = optarg; p != NULL; optarg = p)
664 			{
665 				p = strchr(p, ',');
666 				if (p != NULL)
667 					*p++ = '\0';
668 				if (strcasecmp(optarg, "success") == 0)
669 					DefaultNotify |= QPINGONSUCCESS;
670 				else if (strcasecmp(optarg, "failure") == 0)
671 					DefaultNotify |= QPINGONFAILURE;
672 				else if (strcasecmp(optarg, "delay") == 0)
673 					DefaultNotify |= QPINGONDELAY;
674 				else
675 				{
676 					usrerr("Invalid -N argument");
677 					ExitStat = EX_USAGE;
678 				}
679 			}
680 			break;
681 
682 		  case 'o':	/* set option */
683 			setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
684 			break;
685 
686 		  case 'O':	/* set option (long form) */
687 			setoption(' ', optarg, FALSE, TRUE, CurEnv);
688 			break;
689 
690 		  case 'p':	/* set protocol */
691 			p = strchr(optarg, ':');
692 			if (p != NULL)
693 			{
694 				*p++ = '\0';
695 				if (*p != '\0')
696 				{
697 					ep = xalloc(strlen(p) + 1);
698 					cleanstrcpy(ep, p, MAXNAME);
699 					define('s', ep, CurEnv);
700 				}
701 			}
702 			if (*optarg != '\0')
703 			{
704 				ep = xalloc(strlen(optarg) + 1);
705 				cleanstrcpy(ep, optarg, MAXNAME);
706 				define('r', ep, CurEnv);
707 			}
708 			break;
709 
710 		  case 'q':	/* run queue files at intervals */
711 # if QUEUE
712 			FullName = NULL;
713 			queuemode = TRUE;
714 			switch (optarg[0])
715 			{
716 			  case 'I':
717 				if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
718 					syserr("!Out of memory!!");
719 				new->queue_match = newstr(&optarg[1]);
720 				new->queue_next = QueueLimitId;
721 				QueueLimitId = new;
722 				break;
723 
724 			  case 'R':
725 				if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
726 					syserr("!Out of memory!!");
727 				new->queue_match = newstr(&optarg[1]);
728 				new->queue_next = QueueLimitRecipient;
729 				QueueLimitRecipient = new;
730 				break;
731 
732 			  case 'S':
733 				if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL)
734 					syserr("!Out of memory!!");
735 				new->queue_match = newstr(&optarg[1]);
736 				new->queue_next = QueueLimitSender;
737 				QueueLimitSender = new;
738 				break;
739 
740 			  default:
741 				QueueIntvl = convtime(optarg, 'm');
742 				break;
743 			}
744 # else /* QUEUE */
745 			usrerr("I don't know about queues");
746 			ExitStat = EX_USAGE;
747 # endif /* QUEUE */
748 			break;
749 
750 		  case 'R':	/* DSN RET: what to return */
751 			if (bitset(EF_RET_PARAM, CurEnv->e_flags))
752 			{
753 				usrerr("Duplicate -R flag");
754 				ExitStat = EX_USAGE;
755 				break;
756 			}
757 			CurEnv->e_flags |= EF_RET_PARAM;
758 			if (strcasecmp(optarg, "hdrs") == 0)
759 				CurEnv->e_flags |= EF_NO_BODY_RETN;
760 			else if (strcasecmp(optarg, "full") != 0)
761 			{
762 				usrerr("Invalid -R value");
763 				ExitStat = EX_USAGE;
764 			}
765 			break;
766 
767 		  case 't':	/* read recipients from message */
768 			GrabTo = TRUE;
769 			break;
770 
771 		  case 'U':	/* initial (user) submission */
772 			UserSubmission = TRUE;
773 			break;
774 
775 		  case 'V':	/* DSN ENVID: set "original" envelope id */
776 			if (!xtextok(optarg))
777 			{
778 				usrerr("Invalid syntax in -V flag");
779 				ExitStat = EX_USAGE;
780 			}
781 			else
782 				CurEnv->e_envid = newstr(optarg);
783 			break;
784 
785 		  case 'X':	/* traffic log file */
786 			(void) drop_privileges(TRUE);
787 			TrafficLogFile = fopen(optarg, "a");
788 			if (TrafficLogFile == NULL)
789 			{
790 				syserr("cannot open %s", optarg);
791 				ExitStat = EX_CANTCREAT;
792 				break;
793 			}
794 #ifdef HASSETVBUF
795 			setvbuf(TrafficLogFile, NULL, _IOLBF, 0);
796 #else
797 			setlinebuf(TrafficLogFile);
798 #endif
799 			break;
800 
801 			/* compatibility flags */
802 		  case 'c':	/* connect to non-local mailers */
803 		  case 'i':	/* don't let dot stop me */
804 		  case 'm':	/* send to me too */
805 		  case 'T':	/* set timeout interval */
806 		  case 'v':	/* give blow-by-blow description */
807 			setoption(j, "T", FALSE, TRUE, CurEnv);
808 			break;
809 
810 		  case 'e':	/* error message disposition */
811 		  case 'M':	/* define macro */
812 			setoption(j, optarg, FALSE, TRUE, CurEnv);
813 			break;
814 
815 		  case 's':	/* save From lines in headers */
816 			setoption('f', "T", FALSE, TRUE, CurEnv);
817 			break;
818 
819 # ifdef DBM
820 		  case 'I':	/* initialize alias DBM file */
821 			OpMode = MD_INITALIAS;
822 			break;
823 # endif /* DBM */
824 
825 # if defined(__osf__) || defined(_AIX3)
826 		  case 'x':	/* random flag that OSF/1 & AIX mailx passes */
827 			break;
828 # endif
829 # if defined(sony_news)
830 		  case 'E':
831 		  case 'J':	/* ignore flags for Japanese code conversion
832 				   impremented on Sony NEWS */
833 			break;
834 # endif
835 
836 		  default:
837 			finis(TRUE, EX_USAGE);
838 			break;
839 		}
840 	}
841 	av += optind;
842 
843 	/*
844 	**  Do basic initialization.
845 	**	Read system control file.
846 	**	Extract special fields for local use.
847 	*/
848 
849 	/* set up ${opMode} for use in config file */
850 	{
851 		char mbuf[2];
852 
853 		mbuf[0] = OpMode;
854 		mbuf[1] = '\0';
855 		define(MID_OPMODE, newstr(mbuf), CurEnv);
856 	}
857 
858 #if XDEBUG
859 	checkfd012("before readcf");
860 #endif
861 	vendor_pre_defaults(CurEnv);
862 	readcf(getcfname(), safecf, CurEnv);
863 	ConfigFileRead = TRUE;
864 	vendor_post_defaults(CurEnv);
865 
866 	/* Enforce use of local time (null string overrides this) */
867 	if (TimeZoneSpec == NULL)
868 		unsetenv("TZ");
869 	else if (TimeZoneSpec[0] != '\0')
870 		setuserenv("TZ", TimeZoneSpec);
871 	else
872 		setuserenv("TZ", NULL);
873 	tzset();
874 
875 	/* avoid denial-of-service attacks */
876 	resetlimits();
877 
878 	if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
879 	{
880 		/* drop privileges -- daemon mode done after socket/bind */
881 		(void) drop_privileges(FALSE);
882 	}
883 
884 	/*
885 	**  Find our real host name for future logging.
886 	*/
887 
888 	p = getauthinfo(STDIN_FILENO, &forged);
889 	define('_', p, CurEnv);
890 
891 	/* suppress error printing if errors mailed back or whatever */
892 	if (CurEnv->e_errormode != EM_PRINT)
893 		HoldErrs = TRUE;
894 
895 	/* set up the $=m class now, after .cf has a chance to redefine $m */
896 	expand("\201m", jbuf, sizeof jbuf, CurEnv);
897 	setclass('m', jbuf);
898 
899 	/* probe interfaces and locate any additional names */
900 	if (!DontProbeInterfaces)
901 		load_if_names();
902 
903 	if (tTd(0, 1))
904 	{
905 		printf("\n============ SYSTEM IDENTITY (after readcf) ============");
906 		printf("\n      (short domain name) $w = ");
907 		xputs(macvalue('w', CurEnv));
908 		printf("\n  (canonical domain name) $j = ");
909 		xputs(macvalue('j', CurEnv));
910 		printf("\n         (subdomain name) $m = ");
911 		xputs(macvalue('m', CurEnv));
912 		printf("\n              (node name) $k = ");
913 		xputs(macvalue('k', CurEnv));
914 		printf("\n========================================================\n\n");
915 	}
916 
917 	/*
918 	**  Do more command line checking -- these are things that
919 	**  have to modify the results of reading the config file.
920 	*/
921 
922 	/* process authorization warnings from command line */
923 	if (warn_C_flag)
924 		auth_warning(CurEnv, "Processed by %s with -C %s",
925 			RealUserName, ConfFile);
926 	if (Warn_Q_option)
927 		auth_warning(CurEnv, "Processed from queue %s", QueueDir);
928 
929 	/* check body type for legality */
930 	if (CurEnv->e_bodytype == NULL)
931 		/* nothing */ ;
932 	else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0)
933 		SevenBitInput = TRUE;
934 	else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0)
935 		SevenBitInput = FALSE;
936 	else
937 	{
938 		usrerr("Illegal body type %s", CurEnv->e_bodytype);
939 		CurEnv->e_bodytype = NULL;
940 	}
941 
942 	/* tweak default DSN notifications */
943 	if (DefaultNotify == 0)
944 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
945 
946 	/* be sure we don't pick up bogus HOSTALIASES environment variable */
947 	if (queuemode && RealUid != 0)
948 		(void) unsetenv("HOSTALIASES");
949 
950 	/* check for sane configuration level */
951 	if (ConfigLevel > MAXCONFIGLEVEL)
952 	{
953 		syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
954 			ConfigLevel, Version, MAXCONFIGLEVEL);
955 	}
956 
957 	/* need MCI cache to have persistence */
958 	if (HostStatDir != NULL && MaxMciCache == 0)
959 	{
960 		HostStatDir = NULL;
961 		printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
962 	}
963 
964 	/* need HostStatusDir in order to have SingleThreadDelivery */
965 	if (SingleThreadDelivery && HostStatDir == NULL)
966 	{
967 		SingleThreadDelivery = FALSE;
968 		printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n");
969 	}
970 
971 	/* check for permissions */
972 	if ((OpMode == MD_DAEMON ||
973 	     OpMode == MD_FGDAEMON ||
974 	     OpMode == MD_PURGESTAT) &&
975 	    RealUid != 0 &&
976 	    RealUid != TrustedUid)
977 	{
978 		if (LogLevel > 1)
979 			sm_syslog(LOG_ALERT, NOQID,
980 				"user %d attempted to %s",
981 				RealUid,
982 				OpMode != MD_PURGESTAT ? "run daemon"
983 						       : "purge host status");
984 		usrerr("Permission denied");
985 		finis(FALSE, EX_USAGE);
986 	}
987 	if (OpMode == MD_INITALIAS &&
988 	    RealUid != 0 &&
989 	    RealUid != TrustedUid &&
990 	    !wordinclass(RealUserName, 't'))
991 	{
992 		if (LogLevel > 1)
993 			sm_syslog(LOG_ALERT, NOQID,
994 				  "user %d attempted to rebuild the alias map",
995 				  RealUid);
996  		usrerr("Permission denied");
997  		finis(FALSE, EX_USAGE);
998  	}
999 
1000 	if (MeToo)
1001 		BlankEnvelope.e_flags |= EF_METOO;
1002 
1003 	switch (OpMode)
1004 	{
1005 	  case MD_TEST:
1006 		/* don't have persistent host status in test mode */
1007 		HostStatDir = NULL;
1008 		if (Verbose == 0)
1009 			Verbose = 2;
1010 		CurEnv->e_errormode = EM_PRINT;
1011 		HoldErrs = FALSE;
1012 		break;
1013 
1014 	  case MD_VERIFY:
1015 		CurEnv->e_errormode = EM_PRINT;
1016 		HoldErrs = FALSE;
1017 		/* arrange to exit cleanly on hangup signal */
1018 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1019 			setsignal(SIGHUP, intsig);
1020 		break;
1021 
1022 	  case MD_FGDAEMON:
1023 		run_in_foreground = TRUE;
1024 		OpMode = MD_DAEMON;
1025 		/* fall through ... */
1026 
1027 	  case MD_DAEMON:
1028 		vendor_daemon_setup(CurEnv);
1029 
1030 		/* remove things that don't make sense in daemon mode */
1031 		FullName = NULL;
1032 		GrabTo = FALSE;
1033 
1034 		/* arrange to restart on hangup signal */
1035 		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1036 			sm_syslog(LOG_WARNING, NOQID,
1037 				"daemon invoked without full pathname; kill -1 won't work");
1038 		setsignal(SIGHUP, sighup);
1039 
1040 		/* workaround: can't seem to release the signal in the parent */
1041 		releasesignal(SIGHUP);
1042 		break;
1043 
1044 	  case MD_INITALIAS:
1045 		Verbose = 2;
1046 		CurEnv->e_errormode = EM_PRINT;
1047 		HoldErrs = FALSE;
1048 		/* fall through... */
1049 
1050 	  case MD_PRINT:
1051 		/* to handle sendmail -bp -qSfoobar properly */
1052 		queuemode = FALSE;
1053 		/* fall through... */
1054 
1055 	  default:
1056 		/* arrange to exit cleanly on hangup signal */
1057 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1058 			setsignal(SIGHUP, intsig);
1059 		break;
1060 	}
1061 
1062 	/* special considerations for FullName */
1063 	if (FullName != NULL)
1064 	{
1065 		char *full = NULL;
1066 		extern bool rfc822_string __P((char *));
1067 
1068 		/* full names can't have newlines */
1069 		if (strchr(FullName, '\n') != NULL)
1070 		{
1071 			FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
1072 		}
1073 		/* check for characters that may have to be quoted */
1074 		if (!rfc822_string(FullName))
1075 		{
1076 			extern char *addquotes __P((char *));
1077 
1078 			/*
1079 			**  Quote a full name with special characters
1080 			**  as a comment so crackaddr() doesn't destroy
1081 			**  the name portion of the address.
1082 			*/
1083 			FullName = addquotes(FullName);
1084 			if (full != NULL)
1085 				free(full);
1086 		}
1087 	}
1088 
1089 	/* do heuristic mode adjustment */
1090 	if (Verbose)
1091 	{
1092 		/* turn off noconnect option */
1093 		setoption('c', "F", TRUE, FALSE, CurEnv);
1094 
1095 		/* turn on interactive delivery */
1096 		setoption('d', "", TRUE, FALSE, CurEnv);
1097 	}
1098 
1099 #ifdef VENDOR_CODE
1100 	/* check for vendor mismatch */
1101 	if (VendorCode != VENDOR_CODE)
1102 	{
1103 		extern char *getvendor __P((int));
1104 
1105 		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1106 			getvendor(VENDOR_CODE), getvendor(VendorCode));
1107 	}
1108 #endif
1109 
1110 	/* check for out of date configuration level */
1111 	if (ConfigLevel < MAXCONFIGLEVEL)
1112 	{
1113 		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1114 			Version, MAXCONFIGLEVEL, ConfigLevel);
1115 	}
1116 
1117 	if (ConfigLevel < 3)
1118 	{
1119 		UseErrorsTo = TRUE;
1120 	}
1121 
1122 	/* set options that were previous macros */
1123 	if (SmtpGreeting == NULL)
1124 	{
1125 		if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
1126 			SmtpGreeting = newstr(p);
1127 		else
1128 			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1129 	}
1130 	if (UnixFromLine == NULL)
1131 	{
1132 		if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
1133 			UnixFromLine = newstr(p);
1134 		else
1135 			UnixFromLine = "From \201g  \201d";
1136 	}
1137 
1138 	/* our name for SMTP codes */
1139 	expand("\201j", jbuf, sizeof jbuf, CurEnv);
1140 	MyHostName = jbuf;
1141 	if (strchr(jbuf, '.') == NULL)
1142 		message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1143 			jbuf);
1144 
1145 	/* make certain that this name is part of the $=w class */
1146 	setclass('w', MyHostName);
1147 
1148 	/* the indices of built-in mailers */
1149 	st = stab("local", ST_MAILER, ST_FIND);
1150 	if (st != NULL)
1151 		LocalMailer = st->s_mailer;
1152 	else if (OpMode != MD_TEST || !warn_C_flag)
1153 		syserr("No local mailer defined");
1154 
1155 	st = stab("prog", ST_MAILER, ST_FIND);
1156 	if (st == NULL)
1157 		syserr("No prog mailer defined");
1158 	else
1159 	{
1160 		ProgMailer = st->s_mailer;
1161 		clrbitn(M_MUSER, ProgMailer->m_flags);
1162 	}
1163 
1164 	st = stab("*file*", ST_MAILER, ST_FIND);
1165 	if (st == NULL)
1166 		syserr("No *file* mailer defined");
1167 	else
1168 	{
1169 		FileMailer = st->s_mailer;
1170 		clrbitn(M_MUSER, FileMailer->m_flags);
1171 	}
1172 
1173 	st = stab("*include*", ST_MAILER, ST_FIND);
1174 	if (st == NULL)
1175 		syserr("No *include* mailer defined");
1176 	else
1177 		InclMailer = st->s_mailer;
1178 
1179 	if (ConfigLevel < 6)
1180 	{
1181 		/* heuristic tweaking of local mailer for back compat */
1182 		if (LocalMailer != NULL)
1183 		{
1184 			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1185 			setbitn(M_HASPWENT, LocalMailer->m_flags);
1186 			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1187 			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1188 			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1189 			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1190 			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1191 		}
1192 		if (ProgMailer != NULL)
1193 			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1194 		if (FileMailer != NULL)
1195 			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1196 	}
1197 	if (ConfigLevel < 7)
1198 	{
1199 		if (LocalMailer != NULL)
1200 			setbitn(M_VRFY250, LocalMailer->m_flags);
1201 		if (ProgMailer != NULL)
1202 			setbitn(M_VRFY250, ProgMailer->m_flags);
1203 		if (FileMailer != NULL)
1204 			setbitn(M_VRFY250, FileMailer->m_flags);
1205 	}
1206 
1207 	/* MIME Content-Types that cannot be transfer encoded */
1208 	setclass('n', "multipart/signed");
1209 
1210 	/* MIME message/xxx subtypes that can be treated as messages */
1211 	setclass('s', "rfc822");
1212 
1213 	/* MIME Content-Transfer-Encodings that can be encoded */
1214 	setclass('e', "7bit");
1215 	setclass('e', "8bit");
1216 	setclass('e', "binary");
1217 
1218 #ifdef USE_B_CLASS
1219 	/* MIME Content-Types that should be treated as binary */
1220 	setclass('b', "image");
1221 	setclass('b', "audio");
1222 	setclass('b', "video");
1223 	setclass('b', "application/octet-stream");
1224 #endif
1225 
1226 #if _FFR_MAX_MIME_HEADER_LENGTH
1227 	/* MIME headers which have fields to check for overflow */
1228 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
1229 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
1230 
1231 	/* MIME headers to check for length overflow */
1232 	setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
1233 
1234 	/* MIME headers to check for overflow and rebalance */
1235 	setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
1236 	setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
1237 	setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
1238 	setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
1239 	setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
1240 #endif
1241 
1242 	/* operate in queue directory */
1243 	if (QueueDir == NULL)
1244 	{
1245 		if (OpMode != MD_TEST)
1246 		{
1247 			syserr("QueueDirectory (Q) option must be set");
1248 			ExitStat = EX_CONFIG;
1249 		}
1250 	}
1251 	else
1252 	{
1253 		/* test path to get warning messages */
1254 		(void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE);
1255 		if (OpMode != MD_TEST && chdir(QueueDir) < 0)
1256 		{
1257 			syserr("cannot chdir(%s)", QueueDir);
1258 			ExitStat = EX_CONFIG;
1259 		}
1260 	}
1261 
1262 	/* check host status directory for validity */
1263 	if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
1264 	{
1265 		/* cannot use this value */
1266 		if (tTd(0, 2))
1267 			printf("Cannot use HostStatusDirectory = %s: %s\n",
1268 				HostStatDir, errstring(errno));
1269 		HostStatDir = NULL;
1270 	}
1271 
1272 # if QUEUE
1273 	if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1274 	{
1275 		struct stat stbuf;
1276 
1277 		/* check to see if we own the queue directory */
1278 		if (stat(".", &stbuf) < 0)
1279 			syserr("main: cannot stat %s", QueueDir);
1280 		if (stbuf.st_uid != RealUid)
1281 		{
1282 			/* nope, really a botch */
1283 			usrerr("You do not have permission to process the queue");
1284 			finis(FALSE, EX_NOPERM);
1285 		}
1286 	}
1287 # endif /* QUEUE */
1288 
1289 	/* if we've had errors so far, exit now */
1290 	if (ExitStat != EX_OK && OpMode != MD_TEST)
1291 		finis(FALSE, ExitStat);
1292 
1293 #if XDEBUG
1294 	checkfd012("before main() initmaps");
1295 #endif
1296 
1297 	/*
1298 	**  Do operation-mode-dependent initialization.
1299 	*/
1300 
1301 	switch (OpMode)
1302 	{
1303 	  case MD_PRINT:
1304 		/* print the queue */
1305 #if QUEUE
1306 		dropenvelope(CurEnv, TRUE);
1307 		signal(SIGPIPE, quiesce);
1308 		printqueue();
1309 		finis(FALSE, EX_OK);
1310 #else /* QUEUE */
1311 		usrerr("No queue to print");
1312 		finis(FALSE, ExitStat);
1313 #endif /* QUEUE */
1314 		break;
1315 
1316 	  case MD_HOSTSTAT:
1317 		signal(SIGPIPE, quiesce);
1318 		mci_traverse_persistent(mci_print_persistent, NULL);
1319 		finis(FALSE, EX_OK);
1320 	    	break;
1321 
1322 	  case MD_PURGESTAT:
1323 		mci_traverse_persistent(mci_purge_persistent, NULL);
1324 		finis(FALSE, EX_OK);
1325 	    	break;
1326 
1327 	  case MD_INITALIAS:
1328 		/* initialize maps */
1329 		initmaps(TRUE, CurEnv);
1330 		finis(FALSE, ExitStat);
1331 		break;
1332 
1333 	  case MD_SMTP:
1334 	  case MD_DAEMON:
1335 		/* reset DSN parameters */
1336 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1337 		CurEnv->e_envid = NULL;
1338 		CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
1339 
1340 		/* don't open maps for daemon -- done below in child */
1341 		break;
1342 
1343 	  default:
1344 		/* open the maps */
1345 		initmaps(FALSE, CurEnv);
1346 		break;
1347 	}
1348 
1349 	if (tTd(0, 15))
1350 	{
1351 		extern void printrules __P((void));
1352 
1353 		/* print configuration table (or at least part of it) */
1354 		if (tTd(0, 90))
1355 			printrules();
1356 		for (i = 0; i < MAXMAILERS; i++)
1357 		{
1358 			if (Mailer[i] != NULL)
1359 				printmailer(Mailer[i]);
1360 		}
1361 	}
1362 
1363 	/*
1364 	**  Switch to the main envelope.
1365 	*/
1366 
1367 	CurEnv = newenvelope(&MainEnvelope, CurEnv);
1368 	MainEnvelope.e_flags = BlankEnvelope.e_flags;
1369 
1370 	/*
1371 	**  If test mode, read addresses from stdin and process.
1372 	*/
1373 
1374 	if (OpMode == MD_TEST)
1375 	{
1376 		char buf[MAXLINE];
1377 		SIGFUNC_DECL intindebug __P((int));
1378 
1379 		if (isatty(fileno(stdin)))
1380 			Verbose = 2;
1381 
1382 		if (Verbose)
1383 		{
1384 			printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1385 			printf("Enter <ruleset> <address>\n");
1386 		}
1387 		if (setjmp(TopFrame) > 0)
1388 			printf("\n");
1389 		(void) setsignal(SIGINT, intindebug);
1390 		for (;;)
1391 		{
1392 			extern void testmodeline __P((char *, ENVELOPE *));
1393 
1394 			if (Verbose == 2)
1395 				printf("> ");
1396 			(void) fflush(stdout);
1397 			if (fgets(buf, sizeof buf, stdin) == NULL)
1398 				finis(TRUE, ExitStat);
1399 			p = strchr(buf, '\n');
1400 			if (p != NULL)
1401 				*p = '\0';
1402 			if (Verbose < 2)
1403 				printf("> %s\n", buf);
1404 			testmodeline(buf, CurEnv);
1405 		}
1406 	}
1407 
1408 # if QUEUE
1409 	/*
1410 	**  If collecting stuff from the queue, go start doing that.
1411 	*/
1412 
1413 	if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
1414 	{
1415 		(void) runqueue(FALSE, Verbose);
1416 		finis(TRUE, ExitStat);
1417 	}
1418 # endif /* QUEUE */
1419 
1420 	/*
1421 	**  If a daemon, wait for a request.
1422 	**	getrequests will always return in a child.
1423 	**	If we should also be processing the queue, start
1424 	**		doing it in background.
1425 	**	We check for any errors that might have happened
1426 	**		during startup.
1427 	*/
1428 
1429 	if (OpMode == MD_DAEMON || QueueIntvl != 0)
1430 	{
1431 		char dtype[200];
1432 		extern void getrequests __P((ENVELOPE *));
1433 
1434 		if (!run_in_foreground && !tTd(99, 100))
1435 		{
1436 			/* put us in background */
1437 			i = fork();
1438 			if (i < 0)
1439 				syserr("daemon: cannot fork");
1440 			if (i != 0)
1441 				finis(FALSE, EX_OK);
1442 
1443 			/* disconnect from our controlling tty */
1444 			disconnect(2, CurEnv);
1445 		}
1446 
1447 		dtype[0] = '\0';
1448 		if (OpMode == MD_DAEMON)
1449 			strcat(dtype, "+SMTP");
1450 		if (QueueIntvl != 0)
1451 		{
1452 			strcat(dtype, "+queueing@");
1453 			strcat(dtype, pintvl(QueueIntvl, TRUE));
1454 		}
1455 		if (tTd(0, 1))
1456 			strcat(dtype, "+debugging");
1457 
1458 		sm_syslog(LOG_INFO, NOQID,
1459 			"starting daemon (%s): %s", Version, dtype + 1);
1460 #ifdef XLA
1461 		xla_create_file();
1462 #endif
1463 
1464 # if QUEUE
1465 		if (queuemode)
1466 		{
1467 			(void) runqueue(TRUE, FALSE);
1468 			if (OpMode != MD_DAEMON)
1469 			{
1470 				for (;;)
1471 				{
1472 					pause();
1473 					if (DoQueueRun)
1474 						(void) runqueue(TRUE, FALSE);
1475 				}
1476 			}
1477 		}
1478 # endif /* QUEUE */
1479 		dropenvelope(CurEnv, TRUE);
1480 
1481 #if DAEMON
1482 		getrequests(CurEnv);
1483 
1484 		/* drop privileges */
1485 		(void) drop_privileges(FALSE);
1486 
1487 		/* at this point we are in a child: reset state */
1488 		(void) newenvelope(CurEnv, CurEnv);
1489 
1490 		/*
1491 		**  Get authentication data
1492 		*/
1493 
1494 		p = getauthinfo(fileno(InChannel), &forged);
1495 		define('_', p, &BlankEnvelope);
1496 #endif /* DAEMON */
1497 	}
1498 
1499 # if SMTP
1500 	/*
1501 	**  If running SMTP protocol, start collecting and executing
1502 	**  commands.  This will never return.
1503 	*/
1504 
1505 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1506 	{
1507 		char pbuf[20];
1508 		extern void smtp __P((char *, ENVELOPE *));
1509 
1510 		/*
1511 		**  Save some macros for check_* rulesets.
1512 		*/
1513 
1514 		if (forged)
1515 		{
1516 			char ipbuf[103];
1517 
1518 			snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
1519 				 inet_ntoa(RealHostAddr.sin.sin_addr));
1520 
1521 			define(macid("{client_name}", NULL),
1522 			       newstr(ipbuf), &BlankEnvelope);
1523 		}
1524 		else
1525 			define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope);
1526 		define(macid("{client_addr}", NULL),
1527 		       newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
1528 		if (RealHostAddr.sa.sa_family == AF_INET)
1529 			snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
1530 		else
1531 			snprintf(pbuf, sizeof pbuf, "0");
1532 		define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
1533 
1534 		/* initialize maps now for check_relay ruleset */
1535 		initmaps(FALSE, CurEnv);
1536 
1537 		if (OpMode == MD_DAEMON)
1538 		{
1539 			/* validate the connection */
1540 			HoldErrs = TRUE;
1541 			nullserver = validate_connection(&RealHostAddr,
1542 							 RealHostName, CurEnv);
1543 			HoldErrs = FALSE;
1544 		}
1545 		smtp(nullserver, CurEnv);
1546 	}
1547 # endif /* SMTP */
1548 
1549 	clearenvelope(CurEnv, FALSE);
1550 	if (OpMode == MD_VERIFY)
1551 	{
1552 		CurEnv->e_sendmode = SM_VERIFY;
1553 		PostMasterCopy = NULL;
1554 	}
1555 	else
1556 	{
1557 		/* interactive -- all errors are global */
1558 		CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
1559 	}
1560 
1561 	/*
1562 	**  Do basic system initialization and set the sender
1563 	*/
1564 
1565 	initsys(CurEnv);
1566 	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't'))
1567 		auth_warning(CurEnv, "%s set sender to %s using -%c",
1568 			RealUserName, from, warn_f_flag);
1569 	setsender(from, CurEnv, NULL, '\0', FALSE);
1570 	if (macvalue('s', CurEnv) == NULL)
1571 		define('s', RealHostName, CurEnv);
1572 
1573 	if (*av == NULL && !GrabTo)
1574 	{
1575 		CurEnv->e_flags |= EF_GLOBALERRS;
1576 		usrerr("Recipient names must be specified");
1577 
1578 		/* collect body for UUCP return */
1579 		if (OpMode != MD_VERIFY)
1580 			collect(InChannel, FALSE, NULL, CurEnv);
1581 		finis(TRUE, ExitStat);
1582 	}
1583 
1584 	/*
1585 	**  Scan argv and deliver the message to everyone.
1586 	*/
1587 
1588 	sendtoargv(av, CurEnv);
1589 
1590 	/* if we have had errors sofar, arrange a meaningful exit stat */
1591 	if (Errors > 0 && ExitStat == EX_OK)
1592 		ExitStat = EX_USAGE;
1593 
1594 #if _FFR_FIX_DASHT
1595 	/*
1596 	**  If using -t, force not sending to argv recipients, even
1597 	**  if they are mentioned in the headers.
1598 	*/
1599 
1600 	if (GrabTo)
1601 	{
1602 		ADDRESS *q;
1603 
1604 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
1605 			q->q_flags |= QDONTSEND;
1606 	}
1607 #endif
1608 
1609 	/*
1610 	**  Read the input mail.
1611 	*/
1612 
1613 	CurEnv->e_to = NULL;
1614 	if (OpMode != MD_VERIFY || GrabTo)
1615 	{
1616 		long savedflags = CurEnv->e_flags & EF_FATALERRS;
1617 
1618 		CurEnv->e_flags |= EF_GLOBALERRS;
1619 		CurEnv->e_flags &= ~EF_FATALERRS;
1620 		collect(InChannel, FALSE, NULL, CurEnv);
1621 
1622 		/* bail out if message too large */
1623 		if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
1624 		{
1625 			finis(TRUE, ExitStat);
1626 			/*NOTREACHED*/
1627 			return -1;
1628 		}
1629 		CurEnv->e_flags |= savedflags;
1630 	}
1631 	errno = 0;
1632 
1633 	if (tTd(1, 1))
1634 		printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
1635 
1636 	/*
1637 	**  Actually send everything.
1638 	**	If verifying, just ack.
1639 	*/
1640 
1641 	CurEnv->e_from.q_flags |= QDONTSEND;
1642 	if (tTd(1, 5))
1643 	{
1644 		printf("main: QDONTSEND ");
1645 		printaddr(&CurEnv->e_from, FALSE);
1646 	}
1647 	CurEnv->e_to = NULL;
1648 	CurrentLA = getla();
1649 	GrabTo = FALSE;
1650 	sendall(CurEnv, SM_DEFAULT);
1651 
1652 	/*
1653 	**  All done.
1654 	**	Don't send return error message if in VERIFY mode.
1655 	*/
1656 
1657 	finis(TRUE, ExitStat);
1658 	/*NOTREACHED*/
1659 	return -1;
1660 }
1661 
1662 /* ARGSUSED */
1663 SIGFUNC_DECL
1664 quiesce(sig)
1665 	int sig;
1666 {
1667 	finis(FALSE, EX_OK);
1668 }
1669 
1670 /* ARGSUSED */
1671 SIGFUNC_DECL
1672 intindebug(sig)
1673 	int sig;
1674 {
1675 	longjmp(TopFrame, 1);
1676 	return SIGFUNC_RETURN;
1677 }
1678 
1679 
1680 /*
1681 **  FINIS -- Clean up and exit.
1682 **
1683 **	Parameters:
1684 **		drop -- whether or not to drop CurEnv envelope
1685 **		exitstat -- exit status to use for exit() call
1686 **
1687 **	Returns:
1688 **		never
1689 **
1690 **	Side Effects:
1691 **		exits sendmail
1692 */
1693 
1694 void
1695 finis(drop, exitstat)
1696 	bool drop;
1697 	volatile int exitstat;
1698 {
1699 	extern void closemaps __P((void));
1700 #ifdef USERDB
1701 	extern void _udbx_close __P((void));
1702 #endif
1703 
1704 	if (tTd(2, 1))
1705 	{
1706 		extern void printenvflags __P((ENVELOPE *));
1707 
1708 		printf("\n====finis: stat %d e_id=%s e_flags=",
1709 			exitstat,
1710 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
1711 		printenvflags(CurEnv);
1712 	}
1713 	if (tTd(2, 9))
1714 		printopenfds(FALSE);
1715 
1716 	/* if we fail in finis(), just exit */
1717 	if (setjmp(TopFrame) != 0)
1718 	{
1719 		/* failed -- just give it up */
1720 		goto forceexit;
1721 	}
1722 
1723 	/* clean up temp files */
1724 	CurEnv->e_to = NULL;
1725 	if (drop && CurEnv->e_id != NULL)
1726 		dropenvelope(CurEnv, TRUE);
1727 
1728 	/* flush any cached connections */
1729 	mci_flush(TRUE, NULL);
1730 
1731 	/* close maps belonging to this pid */
1732 	closemaps();
1733 
1734 #ifdef USERDB
1735 	/* close UserDatabase */
1736 	_udbx_close();
1737 #endif
1738 
1739 # ifdef XLA
1740 	/* clean up extended load average stuff */
1741 	xla_all_end();
1742 # endif
1743 
1744 	/* and exit */
1745   forceexit:
1746 	if (LogLevel > 78)
1747 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
1748 			"finis, pid=%d",
1749 			getpid());
1750 	if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
1751 		exitstat = EX_OK;
1752 
1753 	/* reset uid for process accounting */
1754 	endpwent();
1755 	setuid(RealUid);
1756 
1757 	exit(exitstat);
1758 }
1759 /*
1760 **  INTSIG -- clean up on interrupt
1761 **
1762 **	This just arranges to exit.  It pessimises in that it
1763 **	may resend a message.
1764 **
1765 **	Parameters:
1766 **		none.
1767 **
1768 **	Returns:
1769 **		none.
1770 **
1771 **	Side Effects:
1772 **		Unlocks the current job.
1773 */
1774 
1775 /* ARGSUSED */
1776 SIGFUNC_DECL
1777 intsig(sig)
1778 	int sig;
1779 {
1780 	if (LogLevel > 79)
1781 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
1782 	FileName = NULL;
1783 	unlockqueue(CurEnv);
1784 	closecontrolsocket(TRUE);
1785 #ifdef XLA
1786 	xla_all_end();
1787 #endif
1788 	finis(FALSE, EX_OK);
1789 }
1790 /*
1791 **  INITMACROS -- initialize the macro system
1792 **
1793 **	This just involves defining some macros that are actually
1794 **	used internally as metasymbols to be themselves.
1795 **
1796 **	Parameters:
1797 **		none.
1798 **
1799 **	Returns:
1800 **		none.
1801 **
1802 **	Side Effects:
1803 **		initializes several macros to be themselves.
1804 */
1805 
1806 struct metamac	MetaMacros[] =
1807 {
1808 	/* LHS pattern matching characters */
1809 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
1810 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
1811 
1812 	/* these are RHS metasymbols */
1813 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
1814 	{ '>', CALLSUBR },
1815 
1816 	/* the conditional operations */
1817 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
1818 
1819 	/* the hostname lookup characters */
1820 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
1821 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
1822 
1823 	/* miscellaneous control characters */
1824 	{ '&', MACRODEXPAND },
1825 
1826 	{ '\0' }
1827 };
1828 
1829 #define MACBINDING(name, mid) \
1830 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
1831 		MacroName[mid] = name;
1832 
1833 void
1834 initmacros(e)
1835 	register ENVELOPE *e;
1836 {
1837 	register struct metamac *m;
1838 	register int c;
1839 	char buf[5];
1840 	extern char *MacroName[256];
1841 
1842 	for (m = MetaMacros; m->metaname != '\0'; m++)
1843 	{
1844 		buf[0] = m->metaval;
1845 		buf[1] = '\0';
1846 		define(m->metaname, newstr(buf), e);
1847 	}
1848 	buf[0] = MATCHREPL;
1849 	buf[2] = '\0';
1850 	for (c = '0'; c <= '9'; c++)
1851 	{
1852 		buf[1] = c;
1853 		define(c, newstr(buf), e);
1854 	}
1855 
1856 	/* set defaults for some macros sendmail will use later */
1857 	define('n', "MAILER-DAEMON", e);
1858 
1859 	/* set up external names for some internal macros */
1860 	MACBINDING("opMode", MID_OPMODE);
1861 	/*XXX should probably add equivalents for all short macros here XXX*/
1862 }
1863 /*
1864 **  DISCONNECT -- remove our connection with any foreground process
1865 **
1866 **	Parameters:
1867 **		droplev -- how "deeply" we should drop the line.
1868 **			0 -- ignore signals, mail back errors, make sure
1869 **			     output goes to stdout.
1870 **			1 -- also, make stdout go to transcript.
1871 **			2 -- also, disconnect from controlling terminal
1872 **			     (only for daemon mode).
1873 **		e -- the current envelope.
1874 **
1875 **	Returns:
1876 **		none
1877 **
1878 **	Side Effects:
1879 **		Trys to insure that we are immune to vagaries of
1880 **		the controlling tty.
1881 */
1882 
1883 void
1884 disconnect(droplev, e)
1885 	int droplev;
1886 	register ENVELOPE *e;
1887 {
1888 	int fd;
1889 
1890 	if (tTd(52, 1))
1891 		printf("disconnect: In %d Out %d, e=%lx\n",
1892 			fileno(InChannel), fileno(OutChannel), (u_long) e);
1893 	if (tTd(52, 100))
1894 	{
1895 		printf("don't\n");
1896 		return;
1897 	}
1898 	if (LogLevel > 93)
1899 		sm_syslog(LOG_DEBUG, e->e_id,
1900 			"disconnect level %d",
1901 			droplev);
1902 
1903 	/* be sure we don't get nasty signals */
1904 	(void) setsignal(SIGINT, SIG_IGN);
1905 	(void) setsignal(SIGQUIT, SIG_IGN);
1906 
1907 	/* we can't communicate with our caller, so.... */
1908 	HoldErrs = TRUE;
1909 	CurEnv->e_errormode = EM_MAIL;
1910 	Verbose = 0;
1911 	DisConnected = TRUE;
1912 
1913 	/* all input from /dev/null */
1914 	if (InChannel != stdin)
1915 	{
1916 		(void) fclose(InChannel);
1917 		InChannel = stdin;
1918 	}
1919 	if (freopen("/dev/null", "r", stdin) == NULL)
1920 		sm_syslog(LOG_ERR, e->e_id,
1921 			  "disconnect: freopen(\"/dev/null\") failed: %s",
1922 			  errstring(errno));
1923 
1924 	/* output to the transcript */
1925 	if (OutChannel != stdout)
1926 	{
1927 		(void) fclose(OutChannel);
1928 		OutChannel = stdout;
1929 	}
1930 	if (droplev > 0)
1931 	{
1932 		if (e->e_xfp == NULL)
1933 		{
1934 			fd = open("/dev/null", O_WRONLY, 0666);
1935 			if (fd == -1)
1936 				sm_syslog(LOG_ERR, e->e_id,
1937 					  "disconnect: open(\"/dev/null\") failed: %s",
1938 					  errstring(errno));
1939 		}
1940 		else
1941 		{
1942 			fd = fileno(e->e_xfp);
1943 			if (fd == -1)
1944 				sm_syslog(LOG_ERR, e->e_id,
1945 					  "disconnect: fileno(e->e_xfp) failed: %s",
1946 					  errstring(errno));
1947 		}
1948 		(void) fflush(stdout);
1949 		dup2(fd, STDOUT_FILENO);
1950 		dup2(fd, STDERR_FILENO);
1951 		if (e->e_xfp == NULL)
1952 			close(fd);
1953 	}
1954 
1955 	/* drop our controlling TTY completely if possible */
1956 	if (droplev > 1)
1957 	{
1958 		(void) setsid();
1959 		errno = 0;
1960 	}
1961 
1962 #if XDEBUG
1963 	checkfd012("disconnect");
1964 #endif
1965 
1966 	if (LogLevel > 71)
1967 		sm_syslog(LOG_DEBUG, e->e_id,
1968 			"in background, pid=%d",
1969 			getpid());
1970 
1971 	errno = 0;
1972 }
1973 
1974 static void
1975 obsolete(argv)
1976 	char *argv[];
1977 {
1978 	register char *ap;
1979 	register char *op;
1980 
1981 	while ((ap = *++argv) != NULL)
1982 	{
1983 		/* Return if "--" or not an option of any form. */
1984 		if (ap[0] != '-' || ap[1] == '-')
1985 			return;
1986 
1987 		/* skip over options that do have a value */
1988 		op = strchr(OPTIONS, ap[1]);
1989 		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
1990 		    ap[1] != 'd' &&
1991 #if defined(sony_news)
1992 		    ap[1] != 'E' && ap[1] != 'J' &&
1993 #endif
1994 		    argv[1] != NULL && argv[1][0] != '-')
1995 		{
1996 			argv++;
1997 			continue;
1998 		}
1999 
2000 		/* If -C doesn't have an argument, use sendmail.cf. */
2001 #define	__DEFPATH	"sendmail.cf"
2002 		if (ap[1] == 'C' && ap[2] == '\0')
2003 		{
2004 			*argv = xalloc(sizeof(__DEFPATH) + 2);
2005 			argv[0][0] = '-';
2006 			argv[0][1] = 'C';
2007 			(void)strcpy(&argv[0][2], __DEFPATH);
2008 		}
2009 
2010 		/* If -q doesn't have an argument, run it once. */
2011 		if (ap[1] == 'q' && ap[2] == '\0')
2012 			*argv = "-q0";
2013 
2014 		/* if -d doesn't have an argument, use 0-99.1 */
2015 		if (ap[1] == 'd' && ap[2] == '\0')
2016 			*argv = "-d0-99.1";
2017 
2018 # if defined(sony_news)
2019 		/* if -E doesn't have an argument, use -EC */
2020 		if (ap[1] == 'E' && ap[2] == '\0')
2021 			*argv = "-EC";
2022 
2023 		/* if -J doesn't have an argument, use -JJ */
2024 		if (ap[1] == 'J' && ap[2] == '\0')
2025 			*argv = "-JJ";
2026 # endif
2027 	}
2028 }
2029 /*
2030 **  AUTH_WARNING -- specify authorization warning
2031 **
2032 **	Parameters:
2033 **		e -- the current envelope.
2034 **		msg -- the text of the message.
2035 **		args -- arguments to the message.
2036 **
2037 **	Returns:
2038 **		none.
2039 */
2040 
2041 void
2042 #ifdef __STDC__
2043 auth_warning(register ENVELOPE *e, const char *msg, ...)
2044 #else
2045 auth_warning(e, msg, va_alist)
2046 	register ENVELOPE *e;
2047 	const char *msg;
2048 	va_dcl
2049 #endif
2050 {
2051 	char buf[MAXLINE];
2052 	VA_LOCAL_DECL
2053 
2054 	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
2055 	{
2056 		register char *p;
2057 		static char hostbuf[48];
2058 		extern struct hostent *myhostname __P((char *, int));
2059 
2060 		if (hostbuf[0] == '\0')
2061 			(void) myhostname(hostbuf, sizeof hostbuf);
2062 
2063 		(void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
2064 		p = &buf[strlen(buf)];
2065 		VA_START(msg);
2066 		vsnprintf(p, SPACELEFT(buf, p), msg, ap);
2067 		VA_END;
2068 		addheader("X-Authentication-Warning", buf, &e->e_header);
2069 		if (LogLevel > 3)
2070 			sm_syslog(LOG_INFO, e->e_id,
2071 				"Authentication-Warning: %.400s",
2072 				buf);
2073 	}
2074 }
2075 /*
2076 **  GETEXTENV -- get from external environment
2077 **
2078 **	Parameters:
2079 **		envar -- the name of the variable to retrieve
2080 **
2081 **	Returns:
2082 **		The value, if any.
2083 */
2084 
2085 char *
2086 getextenv(envar)
2087 	const char *envar;
2088 {
2089 	char **envp;
2090 	int l;
2091 
2092 	l = strlen(envar);
2093 	for (envp = ExternalEnviron; *envp != NULL; envp++)
2094 	{
2095 		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
2096 			return &(*envp)[l + 1];
2097 	}
2098 	return NULL;
2099 }
2100 /*
2101 **  SETUSERENV -- set an environment in the propogated environment
2102 **
2103 **	Parameters:
2104 **		envar -- the name of the environment variable.
2105 **		value -- the value to which it should be set.  If
2106 **			null, this is extracted from the incoming
2107 **			environment.  If that is not set, the call
2108 **			to setuserenv is ignored.
2109 **
2110 **	Returns:
2111 **		none.
2112 */
2113 
2114 void
2115 setuserenv(envar, value)
2116 	const char *envar;
2117 	const char *value;
2118 {
2119 	int i;
2120 	char **evp = UserEnviron;
2121 	char *p;
2122 
2123 	if (value == NULL)
2124 	{
2125 		value = getextenv(envar);
2126 		if (value == NULL)
2127 			return;
2128 	}
2129 
2130 	i = strlen(envar);
2131 	p = (char *) xalloc(strlen(value) + i + 2);
2132 	strcpy(p, envar);
2133 	p[i++] = '=';
2134 	strcpy(&p[i], value);
2135 
2136 	while (*evp != NULL && strncmp(*evp, p, i) != 0)
2137 		evp++;
2138 	if (*evp != NULL)
2139 	{
2140 		*evp++ = p;
2141 	}
2142 	else if (evp < &UserEnviron[MAXUSERENVIRON])
2143 	{
2144 		*evp++ = p;
2145 		*evp = NULL;
2146 	}
2147 
2148 	/* make sure it is in our environment as well */
2149 	if (putenv(p) < 0)
2150 		syserr("setuserenv: putenv(%s) failed", p);
2151 }
2152 /*
2153 **  DUMPSTATE -- dump state
2154 **
2155 **	For debugging.
2156 */
2157 
2158 void
2159 dumpstate(when)
2160 	char *when;
2161 {
2162 	register char *j = macvalue('j', CurEnv);
2163 	int rs;
2164 
2165 	sm_syslog(LOG_DEBUG, CurEnv->e_id,
2166 		"--- dumping state on %s: $j = %s ---",
2167 		when,
2168 		j == NULL ? "<NULL>" : j);
2169 	if (j != NULL)
2170 	{
2171 		if (!wordinclass(j, 'w'))
2172 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
2173 				"*** $j not in $=w ***");
2174 	}
2175 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
2176 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
2177 	printopenfds(TRUE);
2178 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
2179 	mci_dump_all(TRUE);
2180 	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
2181 	if (rs > 0)
2182 	{
2183 		int stat;
2184 		register char **pvp;
2185 		char *pv[MAXATOM + 1];
2186 
2187 		pv[0] = NULL;
2188 		stat = rewrite(pv, rs, 0, CurEnv);
2189 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
2190 		       "--- ruleset debug_dumpstate returns stat %d, pv: ---",
2191 		       stat);
2192 		for (pvp = pv; *pvp != NULL; pvp++)
2193 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
2194 	}
2195 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
2196 }
2197 
2198 
2199 /* ARGSUSED */
2200 SIGFUNC_DECL
2201 sigusr1(sig)
2202 	int sig;
2203 {
2204 	dumpstate("user signal");
2205 	return SIGFUNC_RETURN;
2206 }
2207 
2208 
2209 /* ARGSUSED */
2210 SIGFUNC_DECL
2211 sighup(sig)
2212 	int sig;
2213 {
2214 	if (SaveArgv[0][0] != '/')
2215 	{
2216 		if (LogLevel > 3)
2217 			sm_syslog(LOG_INFO, NOQID, "could not restart: need full path");
2218 		finis(FALSE, EX_OSFILE);
2219 	}
2220 	if (LogLevel > 3)
2221 		sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]);
2222 	alarm(0);
2223 	releasesignal(SIGHUP);
2224 	closecontrolsocket(TRUE);
2225 	if (drop_privileges(TRUE) != EX_OK)
2226 	{
2227 		if (LogLevel > 0)
2228 			sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m",
2229 				RunAsUid, RunAsGid);
2230 		finis(FALSE, EX_OSERR);
2231 	}
2232 	execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
2233 	if (LogLevel > 0)
2234 		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]);
2235 	finis(FALSE, EX_OSFILE);
2236 }
2237 /*
2238 **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
2239 **
2240 **	Parameters:
2241 **		to_real_uid -- if set, drop to the real uid instead
2242 **			of the RunAsUser.
2243 **
2244 **	Returns:
2245 **		EX_OSERR if the setuid failed.
2246 **		EX_OK otherwise.
2247 */
2248 
2249 int
2250 drop_privileges(to_real_uid)
2251 	bool to_real_uid;
2252 {
2253 	int rval = EX_OK;
2254 	GIDSET_T emptygidset[1];
2255 
2256 	if (tTd(47, 1))
2257 		printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
2258 			(int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
2259 
2260 	if (to_real_uid)
2261 	{
2262 		RunAsUserName = RealUserName;
2263 		RunAsUid = RealUid;
2264 		RunAsGid = RealGid;
2265 	}
2266 
2267 	/* make sure no one can grab open descriptors for secret files */
2268 	endpwent();
2269 
2270 	/* reset group permissions; these can be set later */
2271 	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
2272 	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
2273 		rval = EX_OSERR;
2274 
2275 	/* reset primary group and user id */
2276 	if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
2277 		rval = EX_OSERR;
2278 	if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
2279 		rval = EX_OSERR;
2280 	if (tTd(47, 5))
2281 	{
2282 		printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
2283 			(int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
2284 		printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
2285 	}
2286 	return rval;
2287 }
2288 /*
2289 **  FILL_FD -- make sure a file descriptor has been properly allocated
2290 **
2291 **	Used to make sure that stdin/out/err are allocated on startup
2292 **
2293 **	Parameters:
2294 **		fd -- the file descriptor to be filled.
2295 **		where -- a string used for logging.  If NULL, this is
2296 **			being called on startup, and logging should
2297 **			not be done.
2298 **
2299 **	Returns:
2300 **		none
2301 */
2302 
2303 void
2304 fill_fd(fd, where)
2305 	int fd;
2306 	char *where;
2307 {
2308 	int i;
2309 	struct stat stbuf;
2310 
2311 	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
2312 		return;
2313 
2314 	if (where != NULL)
2315 		syserr("fill_fd: %s: fd %d not open", where, fd);
2316 	else
2317 		MissingFds |= 1 << fd;
2318 	i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
2319 	if (i < 0)
2320 	{
2321 		syserr("!fill_fd: %s: cannot open /dev/null",
2322 			where == NULL ? "startup" : where);
2323 	}
2324 	if (fd != i)
2325 	{
2326 		(void) dup2(i, fd);
2327 		(void) close(i);
2328 	}
2329 }
2330 /*
2331 **  TESTMODELINE -- process a test mode input line
2332 **
2333 **	Parameters:
2334 **		line -- the input line.
2335 **		e -- the current environment.
2336 **	Syntax:
2337 **		#  a comment
2338 **		.X process X as a configuration line
2339 **		=X dump a configuration item (such as mailers)
2340 **		$X dump a macro or class
2341 **		/X try an activity
2342 **		X  normal process through rule set X
2343 */
2344 
2345 void
2346 testmodeline(line, e)
2347 	char *line;
2348 	ENVELOPE *e;
2349 {
2350 	register char *p;
2351 	char *q;
2352 	auto char *delimptr;
2353 	int mid;
2354 	int i, rs;
2355 	STAB *map;
2356 	char **s;
2357 	struct rewrite *rw;
2358 	ADDRESS a;
2359 	static int tryflags = RF_COPYNONE;
2360 	char exbuf[MAXLINE];
2361 	extern bool invalidaddr __P((char *, char *));
2362 	extern char *crackaddr __P((char *));
2363 	extern void dump_class __P((STAB *, int));
2364 	extern void translate_dollars __P((char *));
2365 	extern void help __P((char *));
2366 
2367 	switch (line[0])
2368 	{
2369 	  case '#':
2370 	  case 0:
2371 		return;
2372 
2373 	  case '?':
2374 		help("-bt");
2375 		return;
2376 
2377 	  case '.':		/* config-style settings */
2378 		switch (line[1])
2379 		{
2380 		  case 'D':
2381 			mid = macid(&line[2], &delimptr);
2382 			if (mid == '\0')
2383 				return;
2384 			translate_dollars(delimptr);
2385 			define(mid, newstr(delimptr), e);
2386 			break;
2387 
2388 		  case 'C':
2389 			if (line[2] == '\0')	/* not to call syserr() */
2390 				return;
2391 
2392 			mid = macid(&line[2], &delimptr);
2393 			if (mid == '\0')
2394 				return;
2395 			translate_dollars(delimptr);
2396 			expand(delimptr, exbuf, sizeof exbuf, e);
2397 			p = exbuf;
2398 			while (*p != '\0')
2399 			{
2400 				register char *wd;
2401 				char delim;
2402 
2403 				while (*p != '\0' && isascii(*p) && isspace(*p))
2404 					p++;
2405 				wd = p;
2406 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2407 					p++;
2408 				delim = *p;
2409 				*p = '\0';
2410 				if (wd[0] != '\0')
2411 					setclass(mid, wd);
2412 				*p = delim;
2413 			}
2414 			break;
2415 
2416 		  case '\0':
2417 			printf("Usage: .[DC]macro value(s)\n");
2418 			break;
2419 
2420 		  default:
2421 			printf("Unknown \".\" command %s\n", line);
2422 			break;
2423 		}
2424 		return;
2425 
2426 	  case '=':		/* config-style settings */
2427 		switch (line[1])
2428 		{
2429 		  case 'S':		/* dump rule set */
2430 			rs = strtorwset(&line[2], NULL, ST_FIND);
2431 			if (rs < 0)
2432 			{
2433 				printf("Undefined ruleset %s\n", &line[2]);
2434 				return;
2435 			}
2436 			rw = RewriteRules[rs];
2437 			if (rw == NULL)
2438 				return;
2439 			do
2440 			{
2441 				putchar('R');
2442 				s = rw->r_lhs;
2443 				while (*s != NULL)
2444 				{
2445 					xputs(*s++);
2446 					putchar(' ');
2447 				}
2448 				putchar('\t');
2449 				putchar('\t');
2450 				s = rw->r_rhs;
2451 				while (*s != NULL)
2452 				{
2453 					xputs(*s++);
2454 					putchar(' ');
2455 				}
2456 				putchar('\n');
2457 			} while ((rw = rw->r_next) != NULL);
2458 			break;
2459 
2460 		  case 'M':
2461 			for (i = 0; i < MAXMAILERS; i++)
2462 			{
2463 				if (Mailer[i] != NULL)
2464 					printmailer(Mailer[i]);
2465 			}
2466 			break;
2467 
2468 		  case '\0':
2469 			printf("Usage: =Sruleset or =M\n");
2470 			break;
2471 
2472 		  default:
2473 			printf("Unknown \"=\" command %s\n", line);
2474 			break;
2475 		}
2476 		return;
2477 
2478 	  case '-':		/* set command-line-like opts */
2479 		switch (line[1])
2480 		{
2481 		  case 'd':
2482 			tTflag(&line[2]);
2483 			break;
2484 
2485 		  case '\0':
2486 			printf("Usage: -d{debug arguments}\n");
2487 			break;
2488 
2489 		  default:
2490 			printf("Unknown \"-\" command %s\n", line);
2491 			break;
2492 		}
2493 		return;
2494 
2495 	  case '$':
2496 		if (line[1] == '=')
2497 		{
2498 			mid = macid(&line[2], NULL);
2499 			if (mid != '\0')
2500 				stabapply(dump_class, mid);
2501 			return;
2502 		}
2503 		mid = macid(&line[1], NULL);
2504 		if (mid == '\0')
2505 			return;
2506 		p = macvalue(mid, e);
2507 		if (p == NULL)
2508 			printf("Undefined\n");
2509 		else
2510 		{
2511 			xputs(p);
2512 			printf("\n");
2513 		}
2514 		return;
2515 
2516 	  case '/':		/* miscellaneous commands */
2517 		p = &line[strlen(line)];
2518 		while (--p >= line && isascii(*p) && isspace(*p))
2519 			*p = '\0';
2520 		p = strpbrk(line, " \t");
2521 		if (p != NULL)
2522 		{
2523 			while (isascii(*p) && isspace(*p))
2524 				*p++ = '\0';
2525 		}
2526 		else
2527 			p = "";
2528 		if (line[1] == '\0')
2529 		{
2530 			printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
2531 			return;
2532 		}
2533 		if (strcasecmp(&line[1], "mx") == 0)
2534 		{
2535 #if NAMED_BIND
2536 			/* look up MX records */
2537 			int nmx;
2538 			auto int rcode;
2539 			char *mxhosts[MAXMXHOSTS + 1];
2540 
2541 			if (*p == '\0')
2542 			{
2543 				printf("Usage: /mx address\n");
2544 				return;
2545 			}
2546 			nmx = getmxrr(p, mxhosts, FALSE, &rcode);
2547 			printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
2548 			for (i = 0; i < nmx; i++)
2549 				printf("\t%s\n", mxhosts[i]);
2550 #else
2551 			printf("No MX code compiled in\n");
2552 #endif
2553 		}
2554 		else if (strcasecmp(&line[1], "canon") == 0)
2555 		{
2556 			char host[MAXHOSTNAMELEN];
2557 
2558 			if (*p == '\0')
2559 			{
2560 				printf("Usage: /canon address\n");
2561 				return;
2562 			}
2563 			else if (strlen(p) >= sizeof host)
2564 			{
2565 				printf("Name too long\n");
2566 				return;
2567 			}
2568 			strcpy(host, p);
2569 			(void) getcanonname(host, sizeof(host), HasWildcardMX);
2570 			printf("getcanonname(%s) returns %s\n", p, host);
2571 		}
2572 		else if (strcasecmp(&line[1], "map") == 0)
2573 		{
2574 			auto int rcode = EX_OK;
2575 			char *av[2];
2576 
2577 			if (*p == '\0')
2578 			{
2579 				printf("Usage: /map mapname key\n");
2580 				return;
2581 			}
2582 			for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
2583 				continue;
2584 			if (*q == '\0')
2585 			{
2586 				printf("No key specified\n");
2587 				return;
2588 			}
2589 			*q++ = '\0';
2590 			map = stab(p, ST_MAP, ST_FIND);
2591 			if (map == NULL)
2592 			{
2593 				printf("Map named \"%s\" not found\n", p);
2594 				return;
2595 			}
2596 			if (!bitset(MF_OPEN, map->s_map.map_mflags))
2597 			{
2598 				printf("Map named \"%s\" not open\n", p);
2599 				return;
2600 			}
2601 			printf("map_lookup: %s (%s) ", p, q);
2602 			av[0] = q;
2603 			av[1] = NULL;
2604 			p = (*map->s_map.map_class->map_lookup)
2605 					(&map->s_map, q, av, &rcode);
2606 			if (p == NULL)
2607 				printf("no match (%d)\n", rcode);
2608 			else
2609 				printf("returns %s (%d)\n", p, rcode);
2610 		}
2611 		else if (strcasecmp(&line[1], "try") == 0)
2612 		{
2613 			MAILER *m;
2614 			STAB *s;
2615 			auto int rcode = EX_OK;
2616 
2617 			q = strpbrk(p, " \t");
2618 			if (q != NULL)
2619 			{
2620 				while (isascii(*q) && isspace(*q))
2621 					*q++ = '\0';
2622 			}
2623 			if (q == NULL || *q == '\0')
2624 			{
2625 				printf("Usage: /try mailer address\n");
2626 				return;
2627 			}
2628 			s = stab(p, ST_MAILER, ST_FIND);
2629 			if (s == NULL)
2630 			{
2631 				printf("Unknown mailer %s\n", p);
2632 				return;
2633 			}
2634 			m = s->s_mailer;
2635 			printf("Trying %s %s address %s for mailer %s\n",
2636 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2637 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
2638 				q, p);
2639 			p = remotename(q, m, tryflags, &rcode, CurEnv);
2640 			printf("Rcode = %d, addr = %s\n",
2641 				rcode, p == NULL ? "<NULL>" : p);
2642 			e->e_to = NULL;
2643 		}
2644 		else if (strcasecmp(&line[1], "tryflags") == 0)
2645 		{
2646 			if (*p == '\0')
2647 			{
2648 				printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
2649 				return;
2650 			}
2651 			for (; *p != '\0'; p++)
2652 			{
2653 				switch (*p)
2654 				{
2655 				  case 'H':
2656 				  case 'h':
2657 					tryflags |= RF_HEADERADDR;
2658 					break;
2659 
2660 				  case 'E':
2661 				  case 'e':
2662 					tryflags &= ~RF_HEADERADDR;
2663 					break;
2664 
2665 				  case 'S':
2666 				  case 's':
2667 					tryflags |= RF_SENDERADDR;
2668 					break;
2669 
2670 				  case 'R':
2671 				  case 'r':
2672 					tryflags &= ~RF_SENDERADDR;
2673 					break;
2674 				}
2675 			}
2676 		}
2677 		else if (strcasecmp(&line[1], "parse") == 0)
2678 		{
2679 			if (*p == '\0')
2680 			{
2681 				printf("Usage: /parse address\n");
2682 				return;
2683 			}
2684 			q = crackaddr(p);
2685 			printf("Cracked address = ");
2686 			xputs(q);
2687 			printf("\nParsing %s %s address\n",
2688 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2689 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
2690 			if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
2691 				printf("Cannot parse\n");
2692 			else if (a.q_host != NULL && a.q_host[0] != '\0')
2693 				printf("mailer %s, host %s, user %s\n",
2694 					a.q_mailer->m_name, a.q_host, a.q_user);
2695 			else
2696 				printf("mailer %s, user %s\n",
2697 					a.q_mailer->m_name, a.q_user);
2698 			e->e_to = NULL;
2699 		}
2700 		else
2701 		{
2702 			printf("Unknown \"/\" command %s\n", line);
2703 		}
2704 		return;
2705 	}
2706 
2707 	for (p = line; isascii(*p) && isspace(*p); p++)
2708 		continue;
2709 	q = p;
2710 	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2711 		p++;
2712 	if (*p == '\0')
2713 	{
2714 		printf("No address!\n");
2715 		return;
2716 	}
2717 	*p = '\0';
2718 	if (invalidaddr(p + 1, NULL))
2719 		return;
2720 	do
2721 	{
2722 		register char **pvp;
2723 		char pvpbuf[PSBUFSIZE];
2724 
2725 		pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
2726 			      &delimptr, NULL);
2727 		if (pvp == NULL)
2728 			continue;
2729 		p = q;
2730 		while (*p != '\0')
2731 		{
2732 			int stat;
2733 
2734 			rs = strtorwset(p, NULL, ST_FIND);
2735 			if (rs < 0)
2736 			{
2737 				printf("Undefined ruleset %s\n", p);
2738 				break;
2739 			}
2740 			stat = rewrite(pvp, rs, 0, e);
2741 			if (stat != EX_OK)
2742 				printf("== Ruleset %s (%d) status %d\n",
2743 					p, rs, stat);
2744 			while (*p != '\0' && *p++ != ',')
2745 				continue;
2746 		}
2747 	} while (*(p = delimptr) != '\0');
2748 }
2749 
2750 
2751 void
2752 dump_class(s, id)
2753 	register STAB *s;
2754 	int id;
2755 {
2756 	if (s->s_type != ST_CLASS)
2757 		return;
2758 	if (bitnset(id & 0xff, s->s_class))
2759 		printf("%s\n", s->s_name);
2760 }
2761