xref: /freebsd/contrib/sendmail/src/main.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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 
988 	if (MeToo)
989 		BlankEnvelope.e_flags |= EF_METOO;
990 
991 	switch (OpMode)
992 	{
993 	  case MD_TEST:
994 		/* don't have persistent host status in test mode */
995 		HostStatDir = NULL;
996 		if (Verbose == 0)
997 			Verbose = 2;
998 		CurEnv->e_errormode = EM_PRINT;
999 		HoldErrs = FALSE;
1000 		break;
1001 
1002 	  case MD_VERIFY:
1003 		CurEnv->e_errormode = EM_PRINT;
1004 		HoldErrs = FALSE;
1005 		/* arrange to exit cleanly on hangup signal */
1006 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1007 			setsignal(SIGHUP, intsig);
1008 		break;
1009 
1010 	  case MD_FGDAEMON:
1011 		run_in_foreground = TRUE;
1012 		OpMode = MD_DAEMON;
1013 		/* fall through ... */
1014 
1015 	  case MD_DAEMON:
1016 		vendor_daemon_setup(CurEnv);
1017 
1018 		/* remove things that don't make sense in daemon mode */
1019 		FullName = NULL;
1020 		GrabTo = FALSE;
1021 
1022 		/* arrange to restart on hangup signal */
1023 		if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1024 			sm_syslog(LOG_WARNING, NOQID,
1025 				"daemon invoked without full pathname; kill -1 won't work");
1026 		setsignal(SIGHUP, sighup);
1027 
1028 		/* workaround: can't seem to release the signal in the parent */
1029 		releasesignal(SIGHUP);
1030 		break;
1031 
1032 	  case MD_INITALIAS:
1033 		Verbose = 2;
1034 		CurEnv->e_errormode = EM_PRINT;
1035 		HoldErrs = FALSE;
1036 		/* fall through... */
1037 
1038 	  case MD_PRINT:
1039 		/* to handle sendmail -bp -qSfoobar properly */
1040 		queuemode = FALSE;
1041 		/* fall through... */
1042 
1043 	  default:
1044 		/* arrange to exit cleanly on hangup signal */
1045 		if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1046 			setsignal(SIGHUP, intsig);
1047 		break;
1048 	}
1049 
1050 	/* special considerations for FullName */
1051 	if (FullName != NULL)
1052 	{
1053 		char *full = NULL;
1054 		extern bool rfc822_string __P((char *));
1055 
1056 		/* full names can't have newlines */
1057 		if (strchr(FullName, '\n') != NULL)
1058 		{
1059 			FullName = full = newstr(denlstring(FullName, TRUE, TRUE));
1060 		}
1061 		/* check for characters that may have to be quoted */
1062 		if (!rfc822_string(FullName))
1063 		{
1064 			extern char *addquotes __P((char *));
1065 
1066 			/*
1067 			**  Quote a full name with special characters
1068 			**  as a comment so crackaddr() doesn't destroy
1069 			**  the name portion of the address.
1070 			*/
1071 			FullName = addquotes(FullName);
1072 			if (full != NULL)
1073 				free(full);
1074 		}
1075 	}
1076 
1077 	/* do heuristic mode adjustment */
1078 	if (Verbose)
1079 	{
1080 		/* turn off noconnect option */
1081 		setoption('c', "F", TRUE, FALSE, CurEnv);
1082 
1083 		/* turn on interactive delivery */
1084 		setoption('d', "", TRUE, FALSE, CurEnv);
1085 	}
1086 
1087 #ifdef VENDOR_CODE
1088 	/* check for vendor mismatch */
1089 	if (VendorCode != VENDOR_CODE)
1090 	{
1091 		extern char *getvendor __P((int));
1092 
1093 		message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1094 			getvendor(VENDOR_CODE), getvendor(VendorCode));
1095 	}
1096 #endif
1097 
1098 	/* check for out of date configuration level */
1099 	if (ConfigLevel < MAXCONFIGLEVEL)
1100 	{
1101 		message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1102 			Version, MAXCONFIGLEVEL, ConfigLevel);
1103 	}
1104 
1105 	if (ConfigLevel < 3)
1106 	{
1107 		UseErrorsTo = TRUE;
1108 	}
1109 
1110 	/* set options that were previous macros */
1111 	if (SmtpGreeting == NULL)
1112 	{
1113 		if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL)
1114 			SmtpGreeting = newstr(p);
1115 		else
1116 			SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1117 	}
1118 	if (UnixFromLine == NULL)
1119 	{
1120 		if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL)
1121 			UnixFromLine = newstr(p);
1122 		else
1123 			UnixFromLine = "From \201g  \201d";
1124 	}
1125 
1126 	/* our name for SMTP codes */
1127 	expand("\201j", jbuf, sizeof jbuf, CurEnv);
1128 	MyHostName = jbuf;
1129 	if (strchr(jbuf, '.') == NULL)
1130 		message("WARNING: local host name (%s) is not qualified; fix $j in config file",
1131 			jbuf);
1132 
1133 	/* make certain that this name is part of the $=w class */
1134 	setclass('w', MyHostName);
1135 
1136 	/* the indices of built-in mailers */
1137 	st = stab("local", ST_MAILER, ST_FIND);
1138 	if (st != NULL)
1139 		LocalMailer = st->s_mailer;
1140 	else if (OpMode != MD_TEST || !warn_C_flag)
1141 		syserr("No local mailer defined");
1142 
1143 	st = stab("prog", ST_MAILER, ST_FIND);
1144 	if (st == NULL)
1145 		syserr("No prog mailer defined");
1146 	else
1147 	{
1148 		ProgMailer = st->s_mailer;
1149 		clrbitn(M_MUSER, ProgMailer->m_flags);
1150 	}
1151 
1152 	st = stab("*file*", ST_MAILER, ST_FIND);
1153 	if (st == NULL)
1154 		syserr("No *file* mailer defined");
1155 	else
1156 	{
1157 		FileMailer = st->s_mailer;
1158 		clrbitn(M_MUSER, FileMailer->m_flags);
1159 	}
1160 
1161 	st = stab("*include*", ST_MAILER, ST_FIND);
1162 	if (st == NULL)
1163 		syserr("No *include* mailer defined");
1164 	else
1165 		InclMailer = st->s_mailer;
1166 
1167 	if (ConfigLevel < 6)
1168 	{
1169 		/* heuristic tweaking of local mailer for back compat */
1170 		if (LocalMailer != NULL)
1171 		{
1172 			setbitn(M_ALIASABLE, LocalMailer->m_flags);
1173 			setbitn(M_HASPWENT, LocalMailer->m_flags);
1174 			setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1175 			setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1176 			setbitn(M_CHECKPROG, LocalMailer->m_flags);
1177 			setbitn(M_CHECKFILE, LocalMailer->m_flags);
1178 			setbitn(M_CHECKUDB, LocalMailer->m_flags);
1179 		}
1180 		if (ProgMailer != NULL)
1181 			setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1182 		if (FileMailer != NULL)
1183 			setbitn(M_RUNASRCPT, FileMailer->m_flags);
1184 	}
1185 	if (ConfigLevel < 7)
1186 	{
1187 		if (LocalMailer != NULL)
1188 			setbitn(M_VRFY250, LocalMailer->m_flags);
1189 		if (ProgMailer != NULL)
1190 			setbitn(M_VRFY250, ProgMailer->m_flags);
1191 		if (FileMailer != NULL)
1192 			setbitn(M_VRFY250, FileMailer->m_flags);
1193 	}
1194 
1195 	/* MIME Content-Types that cannot be transfer encoded */
1196 	setclass('n', "multipart/signed");
1197 
1198 	/* MIME message/xxx subtypes that can be treated as messages */
1199 	setclass('s', "rfc822");
1200 
1201 	/* MIME Content-Transfer-Encodings that can be encoded */
1202 	setclass('e', "7bit");
1203 	setclass('e', "8bit");
1204 	setclass('e', "binary");
1205 
1206 #ifdef USE_B_CLASS
1207 	/* MIME Content-Types that should be treated as binary */
1208 	setclass('b', "image");
1209 	setclass('b', "audio");
1210 	setclass('b', "video");
1211 	setclass('b', "application/octet-stream");
1212 #endif
1213 
1214 #if _FFR_MAX_MIME_HEADER_LENGTH
1215 	/* MIME headers which have fields to check for overflow */
1216 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition");
1217 	setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type");
1218 
1219 	/* MIME headers to check for length overflow */
1220 	setclass(macid("{checkMIMETextHeaders}", NULL), "content-description");
1221 
1222 	/* MIME headers to check for overflow and rebalance */
1223 	setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition");
1224 	setclass(macid("{checkMIMEHeaders}", NULL), "content-id");
1225 	setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding");
1226 	setclass(macid("{checkMIMEHeaders}", NULL), "content-type");
1227 	setclass(macid("{checkMIMEHeaders}", NULL), "mime-version");
1228 #endif
1229 
1230 	/* operate in queue directory */
1231 	if (QueueDir == NULL)
1232 	{
1233 		if (OpMode != MD_TEST)
1234 		{
1235 			syserr("QueueDirectory (Q) option must be set");
1236 			ExitStat = EX_CONFIG;
1237 		}
1238 	}
1239 	else
1240 	{
1241 		/* test path to get warning messages */
1242 		(void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE);
1243 		if (OpMode != MD_TEST && chdir(QueueDir) < 0)
1244 		{
1245 			syserr("cannot chdir(%s)", QueueDir);
1246 			ExitStat = EX_CONFIG;
1247 		}
1248 	}
1249 
1250 	/* check host status directory for validity */
1251 	if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE))
1252 	{
1253 		/* cannot use this value */
1254 		if (tTd(0, 2))
1255 			printf("Cannot use HostStatusDirectory = %s: %s\n",
1256 				HostStatDir, errstring(errno));
1257 		HostStatDir = NULL;
1258 	}
1259 
1260 # if QUEUE
1261 	if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1262 	{
1263 		struct stat stbuf;
1264 
1265 		/* check to see if we own the queue directory */
1266 		if (stat(".", &stbuf) < 0)
1267 			syserr("main: cannot stat %s", QueueDir);
1268 		if (stbuf.st_uid != RealUid)
1269 		{
1270 			/* nope, really a botch */
1271 			usrerr("You do not have permission to process the queue");
1272 			finis(FALSE, EX_NOPERM);
1273 		}
1274 	}
1275 # endif /* QUEUE */
1276 
1277 	/* if we've had errors so far, exit now */
1278 	if (ExitStat != EX_OK && OpMode != MD_TEST)
1279 		finis(FALSE, ExitStat);
1280 
1281 #if XDEBUG
1282 	checkfd012("before main() initmaps");
1283 #endif
1284 
1285 	/*
1286 	**  Do operation-mode-dependent initialization.
1287 	*/
1288 
1289 	switch (OpMode)
1290 	{
1291 	  case MD_PRINT:
1292 		/* print the queue */
1293 #if QUEUE
1294 		dropenvelope(CurEnv, TRUE);
1295 		signal(SIGPIPE, quiesce);
1296 		printqueue();
1297 		finis(FALSE, EX_OK);
1298 #else /* QUEUE */
1299 		usrerr("No queue to print");
1300 		finis(FALSE, ExitStat);
1301 #endif /* QUEUE */
1302 		break;
1303 
1304 	  case MD_HOSTSTAT:
1305 		signal(SIGPIPE, quiesce);
1306 		mci_traverse_persistent(mci_print_persistent, NULL);
1307 		finis(FALSE, EX_OK);
1308 	    	break;
1309 
1310 	  case MD_PURGESTAT:
1311 		mci_traverse_persistent(mci_purge_persistent, NULL);
1312 		finis(FALSE, EX_OK);
1313 	    	break;
1314 
1315 	  case MD_INITALIAS:
1316 		/* initialize maps */
1317 		initmaps(TRUE, CurEnv);
1318 		finis(FALSE, ExitStat);
1319 		break;
1320 
1321 	  case MD_SMTP:
1322 	  case MD_DAEMON:
1323 		/* reset DSN parameters */
1324 		DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1325 		CurEnv->e_envid = NULL;
1326 		CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
1327 
1328 		/* don't open maps for daemon -- done below in child */
1329 		break;
1330 
1331 	  default:
1332 		/* open the maps */
1333 		initmaps(FALSE, CurEnv);
1334 		break;
1335 	}
1336 
1337 	if (tTd(0, 15))
1338 	{
1339 		extern void printrules __P((void));
1340 
1341 		/* print configuration table (or at least part of it) */
1342 		if (tTd(0, 90))
1343 			printrules();
1344 		for (i = 0; i < MAXMAILERS; i++)
1345 		{
1346 			if (Mailer[i] != NULL)
1347 				printmailer(Mailer[i]);
1348 		}
1349 	}
1350 
1351 	/*
1352 	**  Switch to the main envelope.
1353 	*/
1354 
1355 	CurEnv = newenvelope(&MainEnvelope, CurEnv);
1356 	MainEnvelope.e_flags = BlankEnvelope.e_flags;
1357 
1358 	/*
1359 	**  If test mode, read addresses from stdin and process.
1360 	*/
1361 
1362 	if (OpMode == MD_TEST)
1363 	{
1364 		char buf[MAXLINE];
1365 		SIGFUNC_DECL intindebug __P((int));
1366 
1367 		if (isatty(fileno(stdin)))
1368 			Verbose = 2;
1369 
1370 		if (Verbose)
1371 		{
1372 			printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
1373 			printf("Enter <ruleset> <address>\n");
1374 		}
1375 		if (setjmp(TopFrame) > 0)
1376 			printf("\n");
1377 		(void) setsignal(SIGINT, intindebug);
1378 		for (;;)
1379 		{
1380 			extern void testmodeline __P((char *, ENVELOPE *));
1381 
1382 			if (Verbose == 2)
1383 				printf("> ");
1384 			(void) fflush(stdout);
1385 			if (fgets(buf, sizeof buf, stdin) == NULL)
1386 				finis(TRUE, ExitStat);
1387 			p = strchr(buf, '\n');
1388 			if (p != NULL)
1389 				*p = '\0';
1390 			if (Verbose < 2)
1391 				printf("> %s\n", buf);
1392 			testmodeline(buf, CurEnv);
1393 		}
1394 	}
1395 
1396 # if QUEUE
1397 	/*
1398 	**  If collecting stuff from the queue, go start doing that.
1399 	*/
1400 
1401 	if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
1402 	{
1403 		(void) runqueue(FALSE, Verbose);
1404 		finis(TRUE, ExitStat);
1405 	}
1406 # endif /* QUEUE */
1407 
1408 	/*
1409 	**  If a daemon, wait for a request.
1410 	**	getrequests will always return in a child.
1411 	**	If we should also be processing the queue, start
1412 	**		doing it in background.
1413 	**	We check for any errors that might have happened
1414 	**		during startup.
1415 	*/
1416 
1417 	if (OpMode == MD_DAEMON || QueueIntvl != 0)
1418 	{
1419 		char dtype[200];
1420 		extern void getrequests __P((ENVELOPE *));
1421 
1422 		if (!run_in_foreground && !tTd(99, 100))
1423 		{
1424 			/* put us in background */
1425 			i = fork();
1426 			if (i < 0)
1427 				syserr("daemon: cannot fork");
1428 			if (i != 0)
1429 				finis(FALSE, EX_OK);
1430 
1431 			/* disconnect from our controlling tty */
1432 			disconnect(2, CurEnv);
1433 		}
1434 
1435 		dtype[0] = '\0';
1436 		if (OpMode == MD_DAEMON)
1437 			strcat(dtype, "+SMTP");
1438 		if (QueueIntvl != 0)
1439 		{
1440 			strcat(dtype, "+queueing@");
1441 			strcat(dtype, pintvl(QueueIntvl, TRUE));
1442 		}
1443 		if (tTd(0, 1))
1444 			strcat(dtype, "+debugging");
1445 
1446 		sm_syslog(LOG_INFO, NOQID,
1447 			"starting daemon (%s): %s", Version, dtype + 1);
1448 #ifdef XLA
1449 		xla_create_file();
1450 #endif
1451 
1452 # if QUEUE
1453 		if (queuemode)
1454 		{
1455 			(void) runqueue(TRUE, FALSE);
1456 			if (OpMode != MD_DAEMON)
1457 			{
1458 				for (;;)
1459 				{
1460 					pause();
1461 					if (DoQueueRun)
1462 						(void) runqueue(TRUE, FALSE);
1463 				}
1464 			}
1465 		}
1466 # endif /* QUEUE */
1467 		dropenvelope(CurEnv, TRUE);
1468 
1469 #if DAEMON
1470 		getrequests(CurEnv);
1471 
1472 		/* drop privileges */
1473 		(void) drop_privileges(FALSE);
1474 
1475 		/* at this point we are in a child: reset state */
1476 		(void) newenvelope(CurEnv, CurEnv);
1477 
1478 		/*
1479 		**  Get authentication data
1480 		*/
1481 
1482 		p = getauthinfo(fileno(InChannel), &forged);
1483 		define('_', p, &BlankEnvelope);
1484 #endif /* DAEMON */
1485 	}
1486 
1487 # if SMTP
1488 	/*
1489 	**  If running SMTP protocol, start collecting and executing
1490 	**  commands.  This will never return.
1491 	*/
1492 
1493 	if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
1494 	{
1495 		char pbuf[20];
1496 		extern void smtp __P((char *, ENVELOPE *));
1497 
1498 		/*
1499 		**  Save some macros for check_* rulesets.
1500 		*/
1501 
1502 		if (forged)
1503 		{
1504 			char ipbuf[103];
1505 
1506 			snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
1507 				 inet_ntoa(RealHostAddr.sin.sin_addr));
1508 
1509 			define(macid("{client_name}", NULL),
1510 			       newstr(ipbuf), &BlankEnvelope);
1511 		}
1512 		else
1513 			define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope);
1514 		define(macid("{client_addr}", NULL),
1515 		       newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope);
1516 		if (RealHostAddr.sa.sa_family == AF_INET)
1517 			snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port);
1518 		else
1519 			snprintf(pbuf, sizeof pbuf, "0");
1520 		define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope);
1521 
1522 		/* initialize maps now for check_relay ruleset */
1523 		initmaps(FALSE, CurEnv);
1524 
1525 		if (OpMode == MD_DAEMON)
1526 		{
1527 			/* validate the connection */
1528 			HoldErrs = TRUE;
1529 			nullserver = validate_connection(&RealHostAddr,
1530 							 RealHostName, CurEnv);
1531 			HoldErrs = FALSE;
1532 		}
1533 		smtp(nullserver, CurEnv);
1534 	}
1535 # endif /* SMTP */
1536 
1537 	clearenvelope(CurEnv, FALSE);
1538 	if (OpMode == MD_VERIFY)
1539 	{
1540 		CurEnv->e_sendmode = SM_VERIFY;
1541 		PostMasterCopy = NULL;
1542 	}
1543 	else
1544 	{
1545 		/* interactive -- all errors are global */
1546 		CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
1547 	}
1548 
1549 	/*
1550 	**  Do basic system initialization and set the sender
1551 	*/
1552 
1553 	initsys(CurEnv);
1554 	if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't'))
1555 		auth_warning(CurEnv, "%s set sender to %s using -%c",
1556 			RealUserName, from, warn_f_flag);
1557 	setsender(from, CurEnv, NULL, '\0', FALSE);
1558 	if (macvalue('s', CurEnv) == NULL)
1559 		define('s', RealHostName, CurEnv);
1560 
1561 	if (*av == NULL && !GrabTo)
1562 	{
1563 		CurEnv->e_flags |= EF_GLOBALERRS;
1564 		usrerr("Recipient names must be specified");
1565 
1566 		/* collect body for UUCP return */
1567 		if (OpMode != MD_VERIFY)
1568 			collect(InChannel, FALSE, NULL, CurEnv);
1569 		finis(TRUE, ExitStat);
1570 	}
1571 
1572 	/*
1573 	**  Scan argv and deliver the message to everyone.
1574 	*/
1575 
1576 	sendtoargv(av, CurEnv);
1577 
1578 	/* if we have had errors sofar, arrange a meaningful exit stat */
1579 	if (Errors > 0 && ExitStat == EX_OK)
1580 		ExitStat = EX_USAGE;
1581 
1582 #if _FFR_FIX_DASHT
1583 	/*
1584 	**  If using -t, force not sending to argv recipients, even
1585 	**  if they are mentioned in the headers.
1586 	*/
1587 
1588 	if (GrabTo)
1589 	{
1590 		ADDRESS *q;
1591 
1592 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
1593 			q->q_flags |= QDONTSEND;
1594 	}
1595 #endif
1596 
1597 	/*
1598 	**  Read the input mail.
1599 	*/
1600 
1601 	CurEnv->e_to = NULL;
1602 	if (OpMode != MD_VERIFY || GrabTo)
1603 	{
1604 		long savedflags = CurEnv->e_flags & EF_FATALERRS;
1605 
1606 		CurEnv->e_flags |= EF_GLOBALERRS;
1607 		CurEnv->e_flags &= ~EF_FATALERRS;
1608 		collect(InChannel, FALSE, NULL, CurEnv);
1609 
1610 		/* bail out if message too large */
1611 		if (bitset(EF_CLRQUEUE, CurEnv->e_flags))
1612 		{
1613 			finis(TRUE, ExitStat);
1614 			/*NOTREACHED*/
1615 			return -1;
1616 		}
1617 		CurEnv->e_flags |= savedflags;
1618 	}
1619 	errno = 0;
1620 
1621 	if (tTd(1, 1))
1622 		printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
1623 
1624 	/*
1625 	**  Actually send everything.
1626 	**	If verifying, just ack.
1627 	*/
1628 
1629 	CurEnv->e_from.q_flags |= QDONTSEND;
1630 	if (tTd(1, 5))
1631 	{
1632 		printf("main: QDONTSEND ");
1633 		printaddr(&CurEnv->e_from, FALSE);
1634 	}
1635 	CurEnv->e_to = NULL;
1636 	CurrentLA = getla();
1637 	GrabTo = FALSE;
1638 	sendall(CurEnv, SM_DEFAULT);
1639 
1640 	/*
1641 	**  All done.
1642 	**	Don't send return error message if in VERIFY mode.
1643 	*/
1644 
1645 	finis(TRUE, ExitStat);
1646 	/*NOTREACHED*/
1647 	return -1;
1648 }
1649 
1650 /* ARGSUSED */
1651 SIGFUNC_DECL
1652 quiesce(sig)
1653 	int sig;
1654 {
1655 	finis(FALSE, EX_OK);
1656 }
1657 
1658 /* ARGSUSED */
1659 SIGFUNC_DECL
1660 intindebug(sig)
1661 	int sig;
1662 {
1663 	longjmp(TopFrame, 1);
1664 	return SIGFUNC_RETURN;
1665 }
1666 
1667 
1668 /*
1669 **  FINIS -- Clean up and exit.
1670 **
1671 **	Parameters:
1672 **		drop -- whether or not to drop CurEnv envelope
1673 **		exitstat -- exit status to use for exit() call
1674 **
1675 **	Returns:
1676 **		never
1677 **
1678 **	Side Effects:
1679 **		exits sendmail
1680 */
1681 
1682 void
1683 finis(drop, exitstat)
1684 	bool drop;
1685 	volatile int exitstat;
1686 {
1687 	extern void closemaps __P((void));
1688 #ifdef USERDB
1689 	extern void _udbx_close __P((void));
1690 #endif
1691 
1692 	if (tTd(2, 1))
1693 	{
1694 		extern void printenvflags __P((ENVELOPE *));
1695 
1696 		printf("\n====finis: stat %d e_id=%s e_flags=",
1697 			exitstat,
1698 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
1699 		printenvflags(CurEnv);
1700 	}
1701 	if (tTd(2, 9))
1702 		printopenfds(FALSE);
1703 
1704 	/* if we fail in finis(), just exit */
1705 	if (setjmp(TopFrame) != 0)
1706 	{
1707 		/* failed -- just give it up */
1708 		goto forceexit;
1709 	}
1710 
1711 	/* clean up temp files */
1712 	CurEnv->e_to = NULL;
1713 	if (drop && CurEnv->e_id != NULL)
1714 		dropenvelope(CurEnv, TRUE);
1715 
1716 	/* flush any cached connections */
1717 	mci_flush(TRUE, NULL);
1718 
1719 	/* close maps belonging to this pid */
1720 	closemaps();
1721 
1722 #ifdef USERDB
1723 	/* close UserDatabase */
1724 	_udbx_close();
1725 #endif
1726 
1727 # ifdef XLA
1728 	/* clean up extended load average stuff */
1729 	xla_all_end();
1730 # endif
1731 
1732 	/* and exit */
1733   forceexit:
1734 	if (LogLevel > 78)
1735 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
1736 			"finis, pid=%d",
1737 			getpid());
1738 	if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET)
1739 		exitstat = EX_OK;
1740 
1741 	/* reset uid for process accounting */
1742 	endpwent();
1743 	setuid(RealUid);
1744 
1745 	exit(exitstat);
1746 }
1747 /*
1748 **  INTSIG -- clean up on interrupt
1749 **
1750 **	This just arranges to exit.  It pessimises in that it
1751 **	may resend a message.
1752 **
1753 **	Parameters:
1754 **		none.
1755 **
1756 **	Returns:
1757 **		none.
1758 **
1759 **	Side Effects:
1760 **		Unlocks the current job.
1761 */
1762 
1763 /* ARGSUSED */
1764 SIGFUNC_DECL
1765 intsig(sig)
1766 	int sig;
1767 {
1768 	if (LogLevel > 79)
1769 		sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
1770 	FileName = NULL;
1771 	unlockqueue(CurEnv);
1772 	closecontrolsocket(TRUE);
1773 #ifdef XLA
1774 	xla_all_end();
1775 #endif
1776 	finis(FALSE, EX_OK);
1777 }
1778 /*
1779 **  INITMACROS -- initialize the macro system
1780 **
1781 **	This just involves defining some macros that are actually
1782 **	used internally as metasymbols to be themselves.
1783 **
1784 **	Parameters:
1785 **		none.
1786 **
1787 **	Returns:
1788 **		none.
1789 **
1790 **	Side Effects:
1791 **		initializes several macros to be themselves.
1792 */
1793 
1794 struct metamac	MetaMacros[] =
1795 {
1796 	/* LHS pattern matching characters */
1797 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
1798 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
1799 
1800 	/* these are RHS metasymbols */
1801 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
1802 	{ '>', CALLSUBR },
1803 
1804 	/* the conditional operations */
1805 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
1806 
1807 	/* the hostname lookup characters */
1808 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
1809 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
1810 
1811 	/* miscellaneous control characters */
1812 	{ '&', MACRODEXPAND },
1813 
1814 	{ '\0' }
1815 };
1816 
1817 #define MACBINDING(name, mid) \
1818 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
1819 		MacroName[mid] = name;
1820 
1821 void
1822 initmacros(e)
1823 	register ENVELOPE *e;
1824 {
1825 	register struct metamac *m;
1826 	register int c;
1827 	char buf[5];
1828 	extern char *MacroName[256];
1829 
1830 	for (m = MetaMacros; m->metaname != '\0'; m++)
1831 	{
1832 		buf[0] = m->metaval;
1833 		buf[1] = '\0';
1834 		define(m->metaname, newstr(buf), e);
1835 	}
1836 	buf[0] = MATCHREPL;
1837 	buf[2] = '\0';
1838 	for (c = '0'; c <= '9'; c++)
1839 	{
1840 		buf[1] = c;
1841 		define(c, newstr(buf), e);
1842 	}
1843 
1844 	/* set defaults for some macros sendmail will use later */
1845 	define('n', "MAILER-DAEMON", e);
1846 
1847 	/* set up external names for some internal macros */
1848 	MACBINDING("opMode", MID_OPMODE);
1849 	/*XXX should probably add equivalents for all short macros here XXX*/
1850 }
1851 /*
1852 **  DISCONNECT -- remove our connection with any foreground process
1853 **
1854 **	Parameters:
1855 **		droplev -- how "deeply" we should drop the line.
1856 **			0 -- ignore signals, mail back errors, make sure
1857 **			     output goes to stdout.
1858 **			1 -- also, make stdout go to transcript.
1859 **			2 -- also, disconnect from controlling terminal
1860 **			     (only for daemon mode).
1861 **		e -- the current envelope.
1862 **
1863 **	Returns:
1864 **		none
1865 **
1866 **	Side Effects:
1867 **		Trys to insure that we are immune to vagaries of
1868 **		the controlling tty.
1869 */
1870 
1871 void
1872 disconnect(droplev, e)
1873 	int droplev;
1874 	register ENVELOPE *e;
1875 {
1876 	int fd;
1877 
1878 	if (tTd(52, 1))
1879 		printf("disconnect: In %d Out %d, e=%lx\n",
1880 			fileno(InChannel), fileno(OutChannel), (u_long) e);
1881 	if (tTd(52, 100))
1882 	{
1883 		printf("don't\n");
1884 		return;
1885 	}
1886 	if (LogLevel > 93)
1887 		sm_syslog(LOG_DEBUG, e->e_id,
1888 			"disconnect level %d",
1889 			droplev);
1890 
1891 	/* be sure we don't get nasty signals */
1892 	(void) setsignal(SIGINT, SIG_IGN);
1893 	(void) setsignal(SIGQUIT, SIG_IGN);
1894 
1895 	/* we can't communicate with our caller, so.... */
1896 	HoldErrs = TRUE;
1897 	CurEnv->e_errormode = EM_MAIL;
1898 	Verbose = 0;
1899 	DisConnected = TRUE;
1900 
1901 	/* all input from /dev/null */
1902 	if (InChannel != stdin)
1903 	{
1904 		(void) fclose(InChannel);
1905 		InChannel = stdin;
1906 	}
1907 	if (freopen("/dev/null", "r", stdin) == NULL)
1908 		sm_syslog(LOG_ERR, e->e_id,
1909 			  "disconnect: freopen(\"/dev/null\") failed: %s",
1910 			  errstring(errno));
1911 
1912 	/* output to the transcript */
1913 	if (OutChannel != stdout)
1914 	{
1915 		(void) fclose(OutChannel);
1916 		OutChannel = stdout;
1917 	}
1918 	if (droplev > 0)
1919 	{
1920 		if (e->e_xfp == NULL)
1921 		{
1922 			fd = open("/dev/null", O_WRONLY, 0666);
1923 			if (fd == -1)
1924 				sm_syslog(LOG_ERR, e->e_id,
1925 					  "disconnect: open(\"/dev/null\") failed: %s",
1926 					  errstring(errno));
1927 		}
1928 		else
1929 		{
1930 			fd = fileno(e->e_xfp);
1931 			if (fd == -1)
1932 				sm_syslog(LOG_ERR, e->e_id,
1933 					  "disconnect: fileno(e->e_xfp) failed: %s",
1934 					  errstring(errno));
1935 		}
1936 		(void) fflush(stdout);
1937 		dup2(fd, STDOUT_FILENO);
1938 		dup2(fd, STDERR_FILENO);
1939 		if (e->e_xfp == NULL)
1940 			close(fd);
1941 	}
1942 
1943 	/* drop our controlling TTY completely if possible */
1944 	if (droplev > 1)
1945 	{
1946 		(void) setsid();
1947 		errno = 0;
1948 	}
1949 
1950 #if XDEBUG
1951 	checkfd012("disconnect");
1952 #endif
1953 
1954 	if (LogLevel > 71)
1955 		sm_syslog(LOG_DEBUG, e->e_id,
1956 			"in background, pid=%d",
1957 			getpid());
1958 
1959 	errno = 0;
1960 }
1961 
1962 static void
1963 obsolete(argv)
1964 	char *argv[];
1965 {
1966 	register char *ap;
1967 	register char *op;
1968 
1969 	while ((ap = *++argv) != NULL)
1970 	{
1971 		/* Return if "--" or not an option of any form. */
1972 		if (ap[0] != '-' || ap[1] == '-')
1973 			return;
1974 
1975 		/* skip over options that do have a value */
1976 		op = strchr(OPTIONS, ap[1]);
1977 		if (op != NULL && *++op == ':' && ap[2] == '\0' &&
1978 		    ap[1] != 'd' &&
1979 #if defined(sony_news)
1980 		    ap[1] != 'E' && ap[1] != 'J' &&
1981 #endif
1982 		    argv[1] != NULL && argv[1][0] != '-')
1983 		{
1984 			argv++;
1985 			continue;
1986 		}
1987 
1988 		/* If -C doesn't have an argument, use sendmail.cf. */
1989 #define	__DEFPATH	"sendmail.cf"
1990 		if (ap[1] == 'C' && ap[2] == '\0')
1991 		{
1992 			*argv = xalloc(sizeof(__DEFPATH) + 2);
1993 			argv[0][0] = '-';
1994 			argv[0][1] = 'C';
1995 			(void)strcpy(&argv[0][2], __DEFPATH);
1996 		}
1997 
1998 		/* If -q doesn't have an argument, run it once. */
1999 		if (ap[1] == 'q' && ap[2] == '\0')
2000 			*argv = "-q0";
2001 
2002 		/* if -d doesn't have an argument, use 0-99.1 */
2003 		if (ap[1] == 'd' && ap[2] == '\0')
2004 			*argv = "-d0-99.1";
2005 
2006 # if defined(sony_news)
2007 		/* if -E doesn't have an argument, use -EC */
2008 		if (ap[1] == 'E' && ap[2] == '\0')
2009 			*argv = "-EC";
2010 
2011 		/* if -J doesn't have an argument, use -JJ */
2012 		if (ap[1] == 'J' && ap[2] == '\0')
2013 			*argv = "-JJ";
2014 # endif
2015 	}
2016 }
2017 /*
2018 **  AUTH_WARNING -- specify authorization warning
2019 **
2020 **	Parameters:
2021 **		e -- the current envelope.
2022 **		msg -- the text of the message.
2023 **		args -- arguments to the message.
2024 **
2025 **	Returns:
2026 **		none.
2027 */
2028 
2029 void
2030 #ifdef __STDC__
2031 auth_warning(register ENVELOPE *e, const char *msg, ...)
2032 #else
2033 auth_warning(e, msg, va_alist)
2034 	register ENVELOPE *e;
2035 	const char *msg;
2036 	va_dcl
2037 #endif
2038 {
2039 	char buf[MAXLINE];
2040 	VA_LOCAL_DECL
2041 
2042 	if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
2043 	{
2044 		register char *p;
2045 		static char hostbuf[48];
2046 		extern struct hostent *myhostname __P((char *, int));
2047 
2048 		if (hostbuf[0] == '\0')
2049 			(void) myhostname(hostbuf, sizeof hostbuf);
2050 
2051 		(void) snprintf(buf, sizeof buf, "%s: ", hostbuf);
2052 		p = &buf[strlen(buf)];
2053 		VA_START(msg);
2054 		vsnprintf(p, SPACELEFT(buf, p), msg, ap);
2055 		VA_END;
2056 		addheader("X-Authentication-Warning", buf, &e->e_header);
2057 		if (LogLevel > 3)
2058 			sm_syslog(LOG_INFO, e->e_id,
2059 				"Authentication-Warning: %.400s",
2060 				buf);
2061 	}
2062 }
2063 /*
2064 **  GETEXTENV -- get from external environment
2065 **
2066 **	Parameters:
2067 **		envar -- the name of the variable to retrieve
2068 **
2069 **	Returns:
2070 **		The value, if any.
2071 */
2072 
2073 char *
2074 getextenv(envar)
2075 	const char *envar;
2076 {
2077 	char **envp;
2078 	int l;
2079 
2080 	l = strlen(envar);
2081 	for (envp = ExternalEnviron; *envp != NULL; envp++)
2082 	{
2083 		if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
2084 			return &(*envp)[l + 1];
2085 	}
2086 	return NULL;
2087 }
2088 /*
2089 **  SETUSERENV -- set an environment in the propogated environment
2090 **
2091 **	Parameters:
2092 **		envar -- the name of the environment variable.
2093 **		value -- the value to which it should be set.  If
2094 **			null, this is extracted from the incoming
2095 **			environment.  If that is not set, the call
2096 **			to setuserenv is ignored.
2097 **
2098 **	Returns:
2099 **		none.
2100 */
2101 
2102 void
2103 setuserenv(envar, value)
2104 	const char *envar;
2105 	const char *value;
2106 {
2107 	int i;
2108 	char **evp = UserEnviron;
2109 	char *p;
2110 
2111 	if (value == NULL)
2112 	{
2113 		value = getextenv(envar);
2114 		if (value == NULL)
2115 			return;
2116 	}
2117 
2118 	i = strlen(envar);
2119 	p = (char *) xalloc(strlen(value) + i + 2);
2120 	strcpy(p, envar);
2121 	p[i++] = '=';
2122 	strcpy(&p[i], value);
2123 
2124 	while (*evp != NULL && strncmp(*evp, p, i) != 0)
2125 		evp++;
2126 	if (*evp != NULL)
2127 	{
2128 		*evp++ = p;
2129 	}
2130 	else if (evp < &UserEnviron[MAXUSERENVIRON])
2131 	{
2132 		*evp++ = p;
2133 		*evp = NULL;
2134 	}
2135 
2136 	/* make sure it is in our environment as well */
2137 	if (putenv(p) < 0)
2138 		syserr("setuserenv: putenv(%s) failed", p);
2139 }
2140 /*
2141 **  DUMPSTATE -- dump state
2142 **
2143 **	For debugging.
2144 */
2145 
2146 void
2147 dumpstate(when)
2148 	char *when;
2149 {
2150 	register char *j = macvalue('j', CurEnv);
2151 	int rs;
2152 
2153 	sm_syslog(LOG_DEBUG, CurEnv->e_id,
2154 		"--- dumping state on %s: $j = %s ---",
2155 		when,
2156 		j == NULL ? "<NULL>" : j);
2157 	if (j != NULL)
2158 	{
2159 		if (!wordinclass(j, 'w'))
2160 			sm_syslog(LOG_DEBUG, CurEnv->e_id,
2161 				"*** $j not in $=w ***");
2162 	}
2163 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
2164 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
2165 	printopenfds(TRUE);
2166 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
2167 	mci_dump_all(TRUE);
2168 	rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
2169 	if (rs > 0)
2170 	{
2171 		int stat;
2172 		register char **pvp;
2173 		char *pv[MAXATOM + 1];
2174 
2175 		pv[0] = NULL;
2176 		stat = rewrite(pv, rs, 0, CurEnv);
2177 		sm_syslog(LOG_DEBUG, CurEnv->e_id,
2178 		       "--- ruleset debug_dumpstate returns stat %d, pv: ---",
2179 		       stat);
2180 		for (pvp = pv; *pvp != NULL; pvp++)
2181 			sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
2182 	}
2183 	sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
2184 }
2185 
2186 
2187 /* ARGSUSED */
2188 SIGFUNC_DECL
2189 sigusr1(sig)
2190 	int sig;
2191 {
2192 	dumpstate("user signal");
2193 	return SIGFUNC_RETURN;
2194 }
2195 
2196 
2197 /* ARGSUSED */
2198 SIGFUNC_DECL
2199 sighup(sig)
2200 	int sig;
2201 {
2202 	if (SaveArgv[0][0] != '/')
2203 	{
2204 		if (LogLevel > 3)
2205 			sm_syslog(LOG_INFO, NOQID, "could not restart: need full path");
2206 		finis(FALSE, EX_OSFILE);
2207 	}
2208 	if (LogLevel > 3)
2209 		sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]);
2210 	alarm(0);
2211 	releasesignal(SIGHUP);
2212 	closecontrolsocket(TRUE);
2213 	if (drop_privileges(TRUE) != EX_OK)
2214 	{
2215 		if (LogLevel > 0)
2216 			sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m",
2217 				RunAsUid, RunAsGid);
2218 		finis(FALSE, EX_OSERR);
2219 	}
2220 	execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
2221 	if (LogLevel > 0)
2222 		sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]);
2223 	finis(FALSE, EX_OSFILE);
2224 }
2225 /*
2226 **  DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
2227 **
2228 **	Parameters:
2229 **		to_real_uid -- if set, drop to the real uid instead
2230 **			of the RunAsUser.
2231 **
2232 **	Returns:
2233 **		EX_OSERR if the setuid failed.
2234 **		EX_OK otherwise.
2235 */
2236 
2237 int
2238 drop_privileges(to_real_uid)
2239 	bool to_real_uid;
2240 {
2241 	int rval = EX_OK;
2242 	GIDSET_T emptygidset[1];
2243 
2244 	if (tTd(47, 1))
2245 		printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n",
2246 			(int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid);
2247 
2248 	if (to_real_uid)
2249 	{
2250 		RunAsUserName = RealUserName;
2251 		RunAsUid = RealUid;
2252 		RunAsGid = RealGid;
2253 	}
2254 
2255 	/* make sure no one can grab open descriptors for secret files */
2256 	endpwent();
2257 
2258 	/* reset group permissions; these can be set later */
2259 	emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
2260 	if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
2261 		rval = EX_OSERR;
2262 
2263 	/* reset primary group and user id */
2264 	if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0)
2265 		rval = EX_OSERR;
2266 	if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0)
2267 		rval = EX_OSERR;
2268 	if (tTd(47, 5))
2269 	{
2270 		printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
2271 			(int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid());
2272 		printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid);
2273 	}
2274 	return rval;
2275 }
2276 /*
2277 **  FILL_FD -- make sure a file descriptor has been properly allocated
2278 **
2279 **	Used to make sure that stdin/out/err are allocated on startup
2280 **
2281 **	Parameters:
2282 **		fd -- the file descriptor to be filled.
2283 **		where -- a string used for logging.  If NULL, this is
2284 **			being called on startup, and logging should
2285 **			not be done.
2286 **
2287 **	Returns:
2288 **		none
2289 */
2290 
2291 void
2292 fill_fd(fd, where)
2293 	int fd;
2294 	char *where;
2295 {
2296 	int i;
2297 	struct stat stbuf;
2298 
2299 	if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
2300 		return;
2301 
2302 	if (where != NULL)
2303 		syserr("fill_fd: %s: fd %d not open", where, fd);
2304 	else
2305 		MissingFds |= 1 << fd;
2306 	i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666);
2307 	if (i < 0)
2308 	{
2309 		syserr("!fill_fd: %s: cannot open /dev/null",
2310 			where == NULL ? "startup" : where);
2311 	}
2312 	if (fd != i)
2313 	{
2314 		(void) dup2(i, fd);
2315 		(void) close(i);
2316 	}
2317 }
2318 /*
2319 **  TESTMODELINE -- process a test mode input line
2320 **
2321 **	Parameters:
2322 **		line -- the input line.
2323 **		e -- the current environment.
2324 **	Syntax:
2325 **		#  a comment
2326 **		.X process X as a configuration line
2327 **		=X dump a configuration item (such as mailers)
2328 **		$X dump a macro or class
2329 **		/X try an activity
2330 **		X  normal process through rule set X
2331 */
2332 
2333 void
2334 testmodeline(line, e)
2335 	char *line;
2336 	ENVELOPE *e;
2337 {
2338 	register char *p;
2339 	char *q;
2340 	auto char *delimptr;
2341 	int mid;
2342 	int i, rs;
2343 	STAB *map;
2344 	char **s;
2345 	struct rewrite *rw;
2346 	ADDRESS a;
2347 	static int tryflags = RF_COPYNONE;
2348 	char exbuf[MAXLINE];
2349 	extern bool invalidaddr __P((char *, char *));
2350 	extern char *crackaddr __P((char *));
2351 	extern void dump_class __P((STAB *, int));
2352 	extern void translate_dollars __P((char *));
2353 	extern void help __P((char *));
2354 
2355 	switch (line[0])
2356 	{
2357 	  case '#':
2358 	  case 0:
2359 		return;
2360 
2361 	  case '?':
2362 		help("-bt");
2363 		return;
2364 
2365 	  case '.':		/* config-style settings */
2366 		switch (line[1])
2367 		{
2368 		  case 'D':
2369 			mid = macid(&line[2], &delimptr);
2370 			if (mid == '\0')
2371 				return;
2372 			translate_dollars(delimptr);
2373 			define(mid, newstr(delimptr), e);
2374 			break;
2375 
2376 		  case 'C':
2377 			if (line[2] == '\0')	/* not to call syserr() */
2378 				return;
2379 
2380 			mid = macid(&line[2], &delimptr);
2381 			if (mid == '\0')
2382 				return;
2383 			translate_dollars(delimptr);
2384 			expand(delimptr, exbuf, sizeof exbuf, e);
2385 			p = exbuf;
2386 			while (*p != '\0')
2387 			{
2388 				register char *wd;
2389 				char delim;
2390 
2391 				while (*p != '\0' && isascii(*p) && isspace(*p))
2392 					p++;
2393 				wd = p;
2394 				while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2395 					p++;
2396 				delim = *p;
2397 				*p = '\0';
2398 				if (wd[0] != '\0')
2399 					setclass(mid, wd);
2400 				*p = delim;
2401 			}
2402 			break;
2403 
2404 		  case '\0':
2405 			printf("Usage: .[DC]macro value(s)\n");
2406 			break;
2407 
2408 		  default:
2409 			printf("Unknown \".\" command %s\n", line);
2410 			break;
2411 		}
2412 		return;
2413 
2414 	  case '=':		/* config-style settings */
2415 		switch (line[1])
2416 		{
2417 		  case 'S':		/* dump rule set */
2418 			rs = strtorwset(&line[2], NULL, ST_FIND);
2419 			if (rs < 0)
2420 			{
2421 				printf("Undefined ruleset %s\n", &line[2]);
2422 				return;
2423 			}
2424 			rw = RewriteRules[rs];
2425 			if (rw == NULL)
2426 				return;
2427 			do
2428 			{
2429 				putchar('R');
2430 				s = rw->r_lhs;
2431 				while (*s != NULL)
2432 				{
2433 					xputs(*s++);
2434 					putchar(' ');
2435 				}
2436 				putchar('\t');
2437 				putchar('\t');
2438 				s = rw->r_rhs;
2439 				while (*s != NULL)
2440 				{
2441 					xputs(*s++);
2442 					putchar(' ');
2443 				}
2444 				putchar('\n');
2445 			} while ((rw = rw->r_next) != NULL);
2446 			break;
2447 
2448 		  case 'M':
2449 			for (i = 0; i < MAXMAILERS; i++)
2450 			{
2451 				if (Mailer[i] != NULL)
2452 					printmailer(Mailer[i]);
2453 			}
2454 			break;
2455 
2456 		  case '\0':
2457 			printf("Usage: =Sruleset or =M\n");
2458 			break;
2459 
2460 		  default:
2461 			printf("Unknown \"=\" command %s\n", line);
2462 			break;
2463 		}
2464 		return;
2465 
2466 	  case '-':		/* set command-line-like opts */
2467 		switch (line[1])
2468 		{
2469 		  case 'd':
2470 			tTflag(&line[2]);
2471 			break;
2472 
2473 		  case '\0':
2474 			printf("Usage: -d{debug arguments}\n");
2475 			break;
2476 
2477 		  default:
2478 			printf("Unknown \"-\" command %s\n", line);
2479 			break;
2480 		}
2481 		return;
2482 
2483 	  case '$':
2484 		if (line[1] == '=')
2485 		{
2486 			mid = macid(&line[2], NULL);
2487 			if (mid != '\0')
2488 				stabapply(dump_class, mid);
2489 			return;
2490 		}
2491 		mid = macid(&line[1], NULL);
2492 		if (mid == '\0')
2493 			return;
2494 		p = macvalue(mid, e);
2495 		if (p == NULL)
2496 			printf("Undefined\n");
2497 		else
2498 		{
2499 			xputs(p);
2500 			printf("\n");
2501 		}
2502 		return;
2503 
2504 	  case '/':		/* miscellaneous commands */
2505 		p = &line[strlen(line)];
2506 		while (--p >= line && isascii(*p) && isspace(*p))
2507 			*p = '\0';
2508 		p = strpbrk(line, " \t");
2509 		if (p != NULL)
2510 		{
2511 			while (isascii(*p) && isspace(*p))
2512 				*p++ = '\0';
2513 		}
2514 		else
2515 			p = "";
2516 		if (line[1] == '\0')
2517 		{
2518 			printf("Usage: /[canon|map|mx|parse|try|tryflags]\n");
2519 			return;
2520 		}
2521 		if (strcasecmp(&line[1], "mx") == 0)
2522 		{
2523 #if NAMED_BIND
2524 			/* look up MX records */
2525 			int nmx;
2526 			auto int rcode;
2527 			char *mxhosts[MAXMXHOSTS + 1];
2528 
2529 			if (*p == '\0')
2530 			{
2531 				printf("Usage: /mx address\n");
2532 				return;
2533 			}
2534 			nmx = getmxrr(p, mxhosts, FALSE, &rcode);
2535 			printf("getmxrr(%s) returns %d value(s):\n", p, nmx);
2536 			for (i = 0; i < nmx; i++)
2537 				printf("\t%s\n", mxhosts[i]);
2538 #else
2539 			printf("No MX code compiled in\n");
2540 #endif
2541 		}
2542 		else if (strcasecmp(&line[1], "canon") == 0)
2543 		{
2544 			char host[MAXHOSTNAMELEN];
2545 
2546 			if (*p == '\0')
2547 			{
2548 				printf("Usage: /canon address\n");
2549 				return;
2550 			}
2551 			else if (strlen(p) >= sizeof host)
2552 			{
2553 				printf("Name too long\n");
2554 				return;
2555 			}
2556 			strcpy(host, p);
2557 			(void) getcanonname(host, sizeof(host), HasWildcardMX);
2558 			printf("getcanonname(%s) returns %s\n", p, host);
2559 		}
2560 		else if (strcasecmp(&line[1], "map") == 0)
2561 		{
2562 			auto int rcode = EX_OK;
2563 			char *av[2];
2564 
2565 			if (*p == '\0')
2566 			{
2567 				printf("Usage: /map mapname key\n");
2568 				return;
2569 			}
2570 			for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
2571 				continue;
2572 			if (*q == '\0')
2573 			{
2574 				printf("No key specified\n");
2575 				return;
2576 			}
2577 			*q++ = '\0';
2578 			map = stab(p, ST_MAP, ST_FIND);
2579 			if (map == NULL)
2580 			{
2581 				printf("Map named \"%s\" not found\n", p);
2582 				return;
2583 			}
2584 			if (!bitset(MF_OPEN, map->s_map.map_mflags))
2585 			{
2586 				printf("Map named \"%s\" not open\n", p);
2587 				return;
2588 			}
2589 			printf("map_lookup: %s (%s) ", p, q);
2590 			av[0] = q;
2591 			av[1] = NULL;
2592 			p = (*map->s_map.map_class->map_lookup)
2593 					(&map->s_map, q, av, &rcode);
2594 			if (p == NULL)
2595 				printf("no match (%d)\n", rcode);
2596 			else
2597 				printf("returns %s (%d)\n", p, rcode);
2598 		}
2599 		else if (strcasecmp(&line[1], "try") == 0)
2600 		{
2601 			MAILER *m;
2602 			STAB *s;
2603 			auto int rcode = EX_OK;
2604 
2605 			q = strpbrk(p, " \t");
2606 			if (q != NULL)
2607 			{
2608 				while (isascii(*q) && isspace(*q))
2609 					*q++ = '\0';
2610 			}
2611 			if (q == NULL || *q == '\0')
2612 			{
2613 				printf("Usage: /try mailer address\n");
2614 				return;
2615 			}
2616 			s = stab(p, ST_MAILER, ST_FIND);
2617 			if (s == NULL)
2618 			{
2619 				printf("Unknown mailer %s\n", p);
2620 				return;
2621 			}
2622 			m = s->s_mailer;
2623 			printf("Trying %s %s address %s for mailer %s\n",
2624 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2625 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient",
2626 				q, p);
2627 			p = remotename(q, m, tryflags, &rcode, CurEnv);
2628 			printf("Rcode = %d, addr = %s\n",
2629 				rcode, p == NULL ? "<NULL>" : p);
2630 			e->e_to = NULL;
2631 		}
2632 		else if (strcasecmp(&line[1], "tryflags") == 0)
2633 		{
2634 			if (*p == '\0')
2635 			{
2636 				printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
2637 				return;
2638 			}
2639 			for (; *p != '\0'; p++)
2640 			{
2641 				switch (*p)
2642 				{
2643 				  case 'H':
2644 				  case 'h':
2645 					tryflags |= RF_HEADERADDR;
2646 					break;
2647 
2648 				  case 'E':
2649 				  case 'e':
2650 					tryflags &= ~RF_HEADERADDR;
2651 					break;
2652 
2653 				  case 'S':
2654 				  case 's':
2655 					tryflags |= RF_SENDERADDR;
2656 					break;
2657 
2658 				  case 'R':
2659 				  case 'r':
2660 					tryflags &= ~RF_SENDERADDR;
2661 					break;
2662 				}
2663 			}
2664 		}
2665 		else if (strcasecmp(&line[1], "parse") == 0)
2666 		{
2667 			if (*p == '\0')
2668 			{
2669 				printf("Usage: /parse address\n");
2670 				return;
2671 			}
2672 			q = crackaddr(p);
2673 			printf("Cracked address = ");
2674 			xputs(q);
2675 			printf("\nParsing %s %s address\n",
2676 				bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope",
2677 				bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient");
2678 			if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL)
2679 				printf("Cannot parse\n");
2680 			else if (a.q_host != NULL && a.q_host[0] != '\0')
2681 				printf("mailer %s, host %s, user %s\n",
2682 					a.q_mailer->m_name, a.q_host, a.q_user);
2683 			else
2684 				printf("mailer %s, user %s\n",
2685 					a.q_mailer->m_name, a.q_user);
2686 			e->e_to = NULL;
2687 		}
2688 		else
2689 		{
2690 			printf("Unknown \"/\" command %s\n", line);
2691 		}
2692 		return;
2693 	}
2694 
2695 	for (p = line; isascii(*p) && isspace(*p); p++)
2696 		continue;
2697 	q = p;
2698 	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2699 		p++;
2700 	if (*p == '\0')
2701 	{
2702 		printf("No address!\n");
2703 		return;
2704 	}
2705 	*p = '\0';
2706 	if (invalidaddr(p + 1, NULL))
2707 		return;
2708 	do
2709 	{
2710 		register char **pvp;
2711 		char pvpbuf[PSBUFSIZE];
2712 
2713 		pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
2714 			      &delimptr, NULL);
2715 		if (pvp == NULL)
2716 			continue;
2717 		p = q;
2718 		while (*p != '\0')
2719 		{
2720 			int stat;
2721 
2722 			rs = strtorwset(p, NULL, ST_FIND);
2723 			if (rs < 0)
2724 			{
2725 				printf("Undefined ruleset %s\n", p);
2726 				break;
2727 			}
2728 			stat = rewrite(pvp, rs, 0, e);
2729 			if (stat != EX_OK)
2730 				printf("== Ruleset %s (%d) status %d\n",
2731 					p, rs, stat);
2732 			while (*p != '\0' && *p++ != ',')
2733 				continue;
2734 		}
2735 	} while (*(p = delimptr) != '\0');
2736 }
2737 
2738 
2739 void
2740 dump_class(s, id)
2741 	register STAB *s;
2742 	int id;
2743 {
2744 	if (s->s_type != ST_CLASS)
2745 		return;
2746 	if (bitnset(id & 0xff, s->s_class))
2747 		printf("%s\n", s->s_name);
2748 }
2749