Deleted Added
full compact
1/*
2 * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers.
2 * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#define _DEFINE
15#include <sendmail.h>
16#include <sm/xtrap.h>
17#include <sm/signal.h>
18
19#ifndef lint
20SM_UNUSED(static char copyright[]) =
21"@(#) Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.\n\
22 All rights reserved.\n\
23 Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\
24 Copyright (c) 1988, 1993\n\
25 The Regents of the University of California. All rights reserved.\n";
26#endif /* ! lint */
27
28SM_RCSID("@(#)$Id: main.c,v 8.942 2005/12/26 04:39:13 ca Exp $")
28SM_RCSID("@(#)$Id: main.c,v 8.944 2006/04/21 23:56:42 ca Exp $")
29
30
31#if NETINET || NETINET6
32# include <arpa/inet.h>
33#endif /* NETINET || NETINET6 */
34
35/* for getcfname() */
36#include <sendmail/pathnames.h>
37
38static SM_DEBUG_T
39DebugNoPRestart = SM_DEBUG_INITIALIZER("no_persistent_restart",
40 "@(#)$Debug: no_persistent_restart - don't restart, log only $");
41
42static void dump_class __P((STAB *, int));
43static void obsolete __P((char **));
44static void testmodeline __P((char *, ENVELOPE *));
45static char *getextenv __P((const char *));
46static void sm_printoptions __P((char **));
47static SIGFUNC_DECL intindebug __P((int));
48static SIGFUNC_DECL sighup __P((int));
49static SIGFUNC_DECL sigpipe __P((int));
50static SIGFUNC_DECL sigterm __P((int));
51#ifdef SIGUSR1
52static SIGFUNC_DECL sigusr1 __P((int));
53#endif /* SIGUSR1 */
54
55/*
56** SENDMAIL -- Post mail to a set of destinations.
57**
58** This is the basic mail router. All user mail programs should
59** call this routine to actually deliver mail. Sendmail in
60** turn calls a bunch of mail servers that do the real work of
61** delivering the mail.
62**
63** Sendmail is driven by settings read in from /etc/mail/sendmail.cf
64** (read by readcf.c).
65**
66** Usage:
67** /usr/lib/sendmail [flags] addr ...
68**
69** See the associated documentation for details.
70**
71** Authors:
72** Eric Allman, UCB/INGRES (until 10/81).
73** Britton-Lee, Inc., purveyors of fine
74** database computers (11/81 - 10/88).
75** International Computer Science Institute
76** (11/88 - 9/89).
77** UCB/Mammoth Project (10/89 - 7/95).
78** InReference, Inc. (8/95 - 1/97).
79** Sendmail, Inc. (1/98 - present).
80** The support of my employers is gratefully acknowledged.
81** Few of them (Britton-Lee in particular) have had
82** anything to gain from my involvement in this project.
83**
84** Gregory Neil Shapiro,
85** Worcester Polytechnic Institute (until 3/98).
86** Sendmail, Inc. (3/98 - present).
87**
88** Claus Assmann,
89** Sendmail, Inc. (12/98 - present).
90*/
91
92char *FullName; /* sender's full name */
93ENVELOPE BlankEnvelope; /* a "blank" envelope */
94static ENVELOPE MainEnvelope; /* the envelope around the basic letter */
95ADDRESS NullAddress = /* a null address */
96 { "", "", NULL, "" };
97char *CommandLineArgs; /* command line args for pid file */
98bool Warn_Q_option = false; /* warn about Q option use */
99static int MissingFds = 0; /* bit map of fds missing on startup */
100char *Mbdb = "pw"; /* mailbox database defaults to /etc/passwd */
101
102#ifdef NGROUPS_MAX
103GIDSET_T InitialGidSet[NGROUPS_MAX];
104#endif /* NGROUPS_MAX */
105
106#define MAXCONFIGLEVEL 10 /* highest config version level known */
107
108#if SASL
109static sasl_callback_t srvcallbacks[] =
110{
111 { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
112 { SASL_CB_PROXY_POLICY, &proxy_policy, NULL },
113 { SASL_CB_LIST_END, NULL, NULL }
114};
115#endif /* SASL */
116
117unsigned int SubmitMode;
118int SyslogPrefixLen; /* estimated length of syslog prefix */
119#define PIDLEN 6 /* pid length for computing SyslogPrefixLen */
120#ifndef SL_FUDGE
121# define SL_FUDGE 10 /* fudge offset for SyslogPrefixLen */
122#endif /* ! SL_FUDGE */
123#define SLDLL 8 /* est. length of default syslog label */
124
125
126/* Some options are dangerous to allow users to use in non-submit mode */
127#define CHECK_AGAINST_OPMODE(cmd) \
128{ \
129 if (extraprivs && \
130 OpMode != MD_DELIVER && OpMode != MD_SMTP && \
131 OpMode != MD_ARPAFTP && \
132 OpMode != MD_VERIFY && OpMode != MD_TEST) \
133 { \
134 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
135 "WARNING: Ignoring submission mode -%c option (not in submission mode)\n", \
136 (cmd)); \
137 break; \
138 } \
139 if (extraprivs && queuerun) \
140 { \
141 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
142 "WARNING: Ignoring submission mode -%c option with -q\n", \
143 (cmd)); \
144 break; \
145 } \
146}
147
148int
149main(argc, argv, envp)
150 int argc;
151 char **argv;
152 char **envp;
153{
154 register char *p;
155 char **av;
156 extern char Version[];
157 char *ep, *from;
158 STAB *st;
159 register int i;
160 int j;
161 int dp;
162 int fill_errno;
163 int qgrp = NOQGRP; /* queue group to process */
164 bool safecf = true;
165 BITMAP256 *p_flags = NULL; /* daemon flags */
166 bool warn_C_flag = false;
167 bool auth = true; /* whether to set e_auth_param */
168 char warn_f_flag = '\0';
169 bool run_in_foreground = false; /* -bD mode */
170 bool queuerun = false, debug = false;
171 struct passwd *pw;
172 struct hostent *hp;
173 char *nullserver = NULL;
174 char *authinfo = NULL;
175 char *sysloglabel = NULL; /* label for syslog */
176 char *conffile = NULL; /* name of .cf file */
177 char *queuegroup = NULL; /* queue group to process */
178 char *quarantining = NULL; /* quarantine queue items? */
179 bool extraprivs;
180 bool forged, negate;
181 bool queuepersistent = false; /* queue runner process runs forever */
182 bool foregroundqueue = false; /* queue run in foreground */
183 bool save_val; /* to save some bool var. */
184 int cftype; /* which cf file to use? */
185 SM_FILE_T *smdebug;
186 static time_t starttime = 0; /* when was process started */
187 struct stat traf_st; /* for TrafficLog FIFO check */
188 char buf[MAXLINE];
189 char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
190 static char rnamebuf[MAXNAME]; /* holds RealUserName */
191 char *emptyenviron[1];
192#if STARTTLS
193 bool tls_ok;
194#endif /* STARTTLS */
195 QUEUE_CHAR *new;
196 ENVELOPE *e;
197 extern int DtableSize;
198 extern int optind;
199 extern int opterr;
200 extern char *optarg;
201 extern char **environ;
202#if SASL
203 extern void sm_sasl_init __P((void));
204#endif /* SASL */
205
206#if USE_ENVIRON
207 envp = environ;
208#endif /* USE_ENVIRON */
209
210 /* turn off profiling */
211 SM_PROF(0);
212
213 /* install default exception handler */
214 sm_exc_newthread(fatal_error);
215
216 /* set the default in/out channel so errors reported to screen */
217 InChannel = smioin;
218 OutChannel = smioout;
219
220 /*
221 ** Check to see if we reentered.
222 ** This would normally happen if e_putheader or e_putbody
223 ** were NULL when invoked.
224 */
225
226 if (starttime != 0)
227 {
228 syserr("main: reentered!");
229 abort();
230 }
231 starttime = curtime();
232
233 /* avoid null pointer dereferences */
234 TermEscape.te_rv_on = TermEscape.te_rv_off = "";
235
236 RealUid = getuid();
237 RealGid = getgid();
238
239 /* Check if sendmail is running with extra privs */
240 extraprivs = (RealUid != 0 &&
241 (geteuid() != getuid() || getegid() != getgid()));
242
243 CurrentPid = getpid();
244
245 /* get whatever .cf file is right for the opmode */
246 cftype = SM_GET_RIGHT_CF;
247
248 /* in 4.4BSD, the table can be huge; impose a reasonable limit */
249 DtableSize = getdtsize();
250 if (DtableSize > 256)
251 DtableSize = 256;
252
253 /*
254 ** Be sure we have enough file descriptors.
255 ** But also be sure that 0, 1, & 2 are open.
256 */
257
258 /* reset errno and fill_errno; the latter is used way down below */
259 errno = fill_errno = 0;
260 fill_fd(STDIN_FILENO, NULL);
261 if (errno != 0)
262 fill_errno = errno;
263 fill_fd(STDOUT_FILENO, NULL);
264 if (errno != 0)
265 fill_errno = errno;
266 fill_fd(STDERR_FILENO, NULL);
267 if (errno != 0)
268 fill_errno = errno;
269
270 sm_closefrom(STDERR_FILENO + 1, DtableSize);
271 errno = 0;
272 smdebug = NULL;
273
274#if LOG
275# ifndef SM_LOG_STR
276# define SM_LOG_STR "sendmail"
277# endif /* ! SM_LOG_STR */
278# ifdef LOG_MAIL
279 openlog(SM_LOG_STR, LOG_PID, LOG_MAIL);
280# else /* LOG_MAIL */
281 openlog(SM_LOG_STR, LOG_PID);
282# endif /* LOG_MAIL */
283#endif /* LOG */
284
285 /*
286 ** Seed the random number generator.
287 ** Used for queue file names, picking a queue directory, and
288 ** MX randomization.
289 */
290
291 seed_random();
292
293 /* do machine-dependent initializations */
294 init_md(argc, argv);
295
296
297 SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) + SL_FUDGE + SLDLL;
298
299 /* reset status from syserr() calls for missing file descriptors */
300 Errors = 0;
301 ExitStat = EX_OK;
302
303 SubmitMode = SUBMIT_UNKNOWN;
304#if XDEBUG
305 checkfd012("after openlog");
306#endif /* XDEBUG */
307
308 tTsetup(tTdvect, sizeof tTdvect, "0-99.1,*_trace_*.1");
309
310#ifdef NGROUPS_MAX
311 /* save initial group set for future checks */
312 i = getgroups(NGROUPS_MAX, InitialGidSet);
313 if (i <= 0)
314 {
315 InitialGidSet[0] = (GID_T) -1;
316 i = 0;
317 }
318 while (i < NGROUPS_MAX)
319 InitialGidSet[i++] = InitialGidSet[0];
320#endif /* NGROUPS_MAX */
321
322 /* drop group id privileges (RunAsUser not yet set) */
323 dp = drop_privileges(false);
324 setstat(dp);
325
326#ifdef SIGUSR1
327 /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */
328 if (!extraprivs)
329 {
330 /* arrange to dump state on user-1 signal */
331 (void) sm_signal(SIGUSR1, sigusr1);
332 }
333 else
334 {
335 /* ignore user-1 signal */
336 (void) sm_signal(SIGUSR1, SIG_IGN);
337 }
338#endif /* SIGUSR1 */
339
340 /* initialize for setproctitle */
341 initsetproctitle(argc, argv, envp);
342
343 /* Handle any non-getoptable constructions. */
344 obsolete(argv);
345
346 /*
347 ** Do a quick prescan of the argument list.
348 */
349
350
351 /* find initial opMode */
352 OpMode = MD_DELIVER;
353 av = argv;
354 p = strrchr(*av, '/');
355 if (p++ == NULL)
356 p = *av;
357 if (strcmp(p, "newaliases") == 0)
358 OpMode = MD_INITALIAS;
359 else if (strcmp(p, "mailq") == 0)
360 OpMode = MD_PRINT;
361 else if (strcmp(p, "smtpd") == 0)
362 OpMode = MD_DAEMON;
363 else if (strcmp(p, "hoststat") == 0)
364 OpMode = MD_HOSTSTAT;
365 else if (strcmp(p, "purgestat") == 0)
366 OpMode = MD_PURGESTAT;
367
368#if defined(__osf__) || defined(_AIX3)
369# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:x"
370#endif /* defined(__osf__) || defined(_AIX3) */
371#if defined(sony_news)
372# define OPTIONS "A:B:b:C:cD:d:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:"
373#endif /* defined(sony_news) */
374#ifndef OPTIONS
375# define OPTIONS "A:B:b:C:cD:d:e:F:f:Gh:IiL:M:mN:nO:o:p:Q:q:R:r:sTtV:vX:"
376#endif /* ! OPTIONS */
377
378 /* Set to 0 to allow -b; need to check optarg before using it! */
379 opterr = 0;
380 while ((j = getopt(argc, argv, OPTIONS)) != -1)
381 {
382 switch (j)
383 {
384 case 'b': /* operations mode */
385 j = (optarg == NULL) ? ' ' : *optarg;
386 switch (j)
387 {
388 case MD_DAEMON:
389 case MD_FGDAEMON:
390 case MD_SMTP:
391 case MD_INITALIAS:
392 case MD_DELIVER:
393 case MD_VERIFY:
394 case MD_TEST:
395 case MD_PRINT:
396 case MD_PRINTNQE:
397 case MD_HOSTSTAT:
398 case MD_PURGESTAT:
399 case MD_ARPAFTP:
400 OpMode = j;
401 break;
402
403 case MD_FREEZE:
404 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
405 "Frozen configurations unsupported\n");
406 return EX_USAGE;
407
408 default:
409 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
410 "Invalid operation mode %c\n",
411 j);
412 return EX_USAGE;
413 }
414 break;
415
416 case 'D':
417 if (debug)
418 {
419 errno = 0;
420 syserr("-D file must be before -d");
421 ExitStat = EX_USAGE;
422 break;
423 }
424 dp = drop_privileges(true);
425 setstat(dp);
426 smdebug = sm_io_open(SmFtStdio, SM_TIME_DEFAULT,
427 optarg, SM_IO_APPEND, NULL);
428 if (smdebug == NULL)
429 {
430 syserr("cannot open %s", optarg);
431 ExitStat = EX_CANTCREAT;
432 break;
433 }
434 sm_debug_setfile(smdebug);
435 break;
436
437 case 'd':
438 debug = true;
439 tTflag(optarg);
440 (void) sm_io_setvbuf(sm_debug_file(), SM_TIME_DEFAULT,
441 (char *) NULL, SM_IO_NBF,
442 SM_IO_BUFSIZ);
443 break;
444
445 case 'G': /* relay (gateway) submission */
446 SubmitMode = SUBMIT_MTA;
447 break;
448
449 case 'L':
450 if (optarg == NULL)
451 {
452 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
453 "option requires an argument -- '%c'",
454 (char) j);
455 return EX_USAGE;
456 }
457 j = SM_MIN(strlen(optarg), 32) + 1;
458 sysloglabel = xalloc(j);
459 (void) sm_strlcpy(sysloglabel, optarg, j);
460 SyslogPrefixLen = PIDLEN + (MAXQFNAME - 3) +
461 SL_FUDGE + j;
462 break;
463
464 case 'Q':
465 case 'q':
466 /* just check if it is there */
467 queuerun = true;
468 break;
469 }
470 }
471 opterr = 1;
472
473 /* Don't leak queue information via debug flags */
474 if (extraprivs && queuerun && debug)
475 {
476 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
477 "WARNING: Can not use -d with -q. Disabling debugging.\n");
478 sm_debug_close();
479 sm_debug_setfile(NULL);
480 (void) memset(tTdvect, '\0', sizeof tTdvect);
481 }
482
483#if LOG
484 if (sysloglabel != NULL)
485 {
486 /* Sanitize the string */
487 for (p = sysloglabel; *p != '\0'; p++)
488 {
489 if (!isascii(*p) || !isprint(*p) || *p == '%')
490 *p = '*';
491 }
492 closelog();
493# ifdef LOG_MAIL
494 openlog(sysloglabel, LOG_PID, LOG_MAIL);
495# else /* LOG_MAIL */
496 openlog(sysloglabel, LOG_PID);
497# endif /* LOG_MAIL */
498 }
499#endif /* LOG */
500
501 /* set up the blank envelope */
502 BlankEnvelope.e_puthdr = putheader;
503 BlankEnvelope.e_putbody = putbody;
504 BlankEnvelope.e_xfp = NULL;
505 STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
506 CurEnv = &BlankEnvelope;
507 STRUCTCOPY(NullAddress, MainEnvelope.e_from);
508
509 /*
510 ** Set default values for variables.
511 ** These cannot be in initialized data space.
512 */
513
514 setdefaults(&BlankEnvelope);
515 initmacros(&BlankEnvelope);
516
517 /* reset macro */
518 set_op_mode(OpMode);
519 if (OpMode == MD_DAEMON)
520 DaemonPid = CurrentPid; /* needed for finis() to work */
521
522 pw = sm_getpwuid(RealUid);
523 if (pw != NULL)
524 (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
525 else
526 (void) sm_snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
527 (int) RealUid);
528
529 RealUserName = rnamebuf;
530
531 if (tTd(0, 101))
532 {
533 sm_dprintf("Version %s\n", Version);
534 finis(false, true, EX_OK);
535 /* NOTREACHED */
536 }
537
538 /*
539 ** if running non-set-user-ID binary as non-root, pretend
540 ** we are the RunAsUid
541 */
542
543 if (RealUid != 0 && geteuid() == RealUid)
544 {
545 if (tTd(47, 1))
546 sm_dprintf("Non-set-user-ID binary: RunAsUid = RealUid = %d\n",
547 (int) RealUid);
548 RunAsUid = RealUid;
549 }
550 else if (geteuid() != 0)
551 RunAsUid = geteuid();
552
553 EffGid = getegid();
554 if (RealUid != 0 && EffGid == RealGid)
555 RunAsGid = RealGid;
556
557 if (tTd(47, 5))
558 {
559 sm_dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n",
560 (int) geteuid(), (int) getuid(),
561 (int) getegid(), (int) getgid());
562 sm_dprintf("main: RunAsUser = %d:%d\n",
563 (int) RunAsUid, (int) RunAsGid);
564 }
565
566 /* save command line arguments */
567 j = 0;
568 for (av = argv; *av != NULL; )
569 j += strlen(*av++) + 1;
570 SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1));
571 CommandLineArgs = xalloc(j);
572 p = CommandLineArgs;
573 for (av = argv, i = 0; *av != NULL; )
574 {
575 int h;
576
577 SaveArgv[i++] = newstr(*av);
578 if (av != argv)
579 *p++ = ' ';
580 (void) sm_strlcpy(p, *av++, j);
581 h = strlen(p);
582 p += h;
583 j -= h + 1;
584 }
585 SaveArgv[i] = NULL;
586
587 if (tTd(0, 1))
588 {
589 extern char *CompileOptions[];
590
591 sm_dprintf("Version %s\n Compiled with:", Version);
592 sm_printoptions(CompileOptions);
593 }
594 if (tTd(0, 10))
595 {
596 extern char *OsCompileOptions[];
597
598 sm_dprintf(" OS Defines:");
599 sm_printoptions(OsCompileOptions);
600#ifdef _PATH_UNIX
601 sm_dprintf("Kernel symbols:\t%s\n", _PATH_UNIX);
602#endif /* _PATH_UNIX */
603
604 sm_dprintf(" Conf file:\t%s (default for MSP)\n",
605 getcfname(OpMode, SubmitMode, SM_GET_SUBMIT_CF,
606 conffile));
607 sm_dprintf(" Conf file:\t%s (default for MTA)\n",
608 getcfname(OpMode, SubmitMode, SM_GET_SENDMAIL_CF,
609 conffile));
610 sm_dprintf(" Pid file:\t%s (default)\n", PidFile);
611 }
612
613 if (tTd(0, 12))
614 {
615 extern char *SmCompileOptions[];
616
617 sm_dprintf(" libsm Defines:");
618 sm_printoptions(SmCompileOptions);
619 }
620
621 if (tTd(0, 13))
622 {
623 extern char *FFRCompileOptions[];
624
625 sm_dprintf(" FFR Defines:");
626 sm_printoptions(FFRCompileOptions);
627 }
628
629 /* clear sendmail's environment */
630 ExternalEnviron = environ;
631 emptyenviron[0] = NULL;
632 environ = emptyenviron;
633
634 /*
635 ** restore any original TZ setting until TimeZoneSpec has been
636 ** determined - or early log messages may get bogus time stamps
637 */
638
639 if ((p = getextenv("TZ")) != NULL)
640 {
641 char *tz;
642 int tzlen;
643
644 /* XXX check for reasonable length? */
645 tzlen = strlen(p) + 4;
646 tz = xalloc(tzlen);
647 (void) sm_strlcpyn(tz, tzlen, 2, "TZ=", p);
648
649 /* XXX check return code? */
650 (void) putenv(tz);
651 }
652
653 /* prime the child environment */
654 sm_setuserenv("AGENT", "sendmail");
655
656 (void) sm_signal(SIGPIPE, SIG_IGN);
657 OldUmask = umask(022);
658 FullName = getextenv("NAME");
659 if (FullName != NULL)
660 FullName = newstr(FullName);
661
662 /*
663 ** Initialize name server if it is going to be used.
664 */
665
666#if NAMED_BIND
667 if (!bitset(RES_INIT, _res.options))
668 (void) res_init();
669 if (tTd(8, 8))
670 _res.options |= RES_DEBUG;
671 else
672 _res.options &= ~RES_DEBUG;
673# ifdef RES_NOALIASES
674 _res.options |= RES_NOALIASES;
675# endif /* RES_NOALIASES */
676 TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry;
677 TimeOuts.res_retry[RES_TO_FIRST] = _res.retry;
678 TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry;
679 TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans;
680 TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans;
681 TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans;
682#endif /* NAMED_BIND */
683
684 errno = 0;
685 from = NULL;
686
687 /* initialize some macros, etc. */
688 init_vendor_macros(&BlankEnvelope);
689
690 /* version */
691 macdefine(&BlankEnvelope.e_macro, A_PERM, 'v', Version);
692
693 /* hostname */
694 hp = myhostname(jbuf, sizeof jbuf);
695 if (jbuf[0] != '\0')
696 {
697 struct utsname utsname;
698
699 if (tTd(0, 4))
700 sm_dprintf("Canonical name: %s\n", jbuf);
701 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'w', jbuf);
702 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'j', jbuf);
703 setclass('w', jbuf);
704
705 p = strchr(jbuf, '.');
706 if (p != NULL && p[1] != '\0')
707 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'm', &p[1]);
708
709 if (uname(&utsname) >= 0)
710 p = utsname.nodename;
711 else
712 {
713 if (tTd(0, 22))
714 sm_dprintf("uname failed (%s)\n",
715 sm_errstring(errno));
716 makelower(jbuf);
717 p = jbuf;
718 }
719 if (tTd(0, 4))
720 sm_dprintf(" UUCP nodename: %s\n", p);
721 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'k', p);
722 setclass('k', p);
723 setclass('w', p);
724 }
725 if (hp != NULL)
726 {
727 for (av = hp->h_aliases; av != NULL && *av != NULL; av++)
728 {
729 if (tTd(0, 4))
730 sm_dprintf("\ta.k.a.: %s\n", *av);
731 setclass('w', *av);
732 }
733#if NETINET || NETINET6
734 for (i = 0; i >= 0 && hp->h_addr_list[i] != NULL; i++)
735 {
736# if NETINET6
737 char *addr;
738 char buf6[INET6_ADDRSTRLEN];
739 struct in6_addr ia6;
740# endif /* NETINET6 */
741# if NETINET
742 struct in_addr ia;
743# endif /* NETINET */
744 char ipbuf[103];
745
746 ipbuf[0] = '\0';
747 switch (hp->h_addrtype)
748 {
749# if NETINET
750 case AF_INET:
751 if (hp->h_length != INADDRSZ)
752 break;
753
754 memmove(&ia, hp->h_addr_list[i], INADDRSZ);
755 (void) sm_snprintf(ipbuf, sizeof ipbuf,
756 "[%.100s]", inet_ntoa(ia));
757 break;
758# endif /* NETINET */
759
760# if NETINET6
761 case AF_INET6:
762 if (hp->h_length != IN6ADDRSZ)
763 break;
764
765 memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ);
766 addr = anynet_ntop(&ia6, buf6, sizeof buf6);
767 if (addr != NULL)
768 (void) sm_snprintf(ipbuf, sizeof ipbuf,
769 "[%.100s]", addr);
770 break;
771# endif /* NETINET6 */
772 }
773 if (ipbuf[0] == '\0')
774 break;
775
776 if (tTd(0, 4))
777 sm_dprintf("\ta.k.a.: %s\n", ipbuf);
778 setclass('w', ipbuf);
779 }
780#endif /* NETINET || NETINET6 */
781#if NETINET6
782 freehostent(hp);
783 hp = NULL;
784#endif /* NETINET6 */
785 }
786
787 /* current time */
788 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'b', arpadate((char *) NULL));
789
790 /* current load average */
791 sm_getla();
792
793 QueueLimitRecipient = (QUEUE_CHAR *) NULL;
794 QueueLimitSender = (QUEUE_CHAR *) NULL;
795 QueueLimitId = (QUEUE_CHAR *) NULL;
796 QueueLimitQuarantine = (QUEUE_CHAR *) NULL;
797
798 /*
799 ** Crack argv.
800 */
801
802 optind = 1;
803 while ((j = getopt(argc, argv, OPTIONS)) != -1)
804 {
805 switch (j)
806 {
807 case 'b': /* operations mode */
808 /* already done */
809 break;
810
811 case 'A': /* use Alternate sendmail/submit.cf */
812 cftype = optarg[0] == 'c' ? SM_GET_SUBMIT_CF
813 : SM_GET_SENDMAIL_CF;
814 break;
815
816 case 'B': /* body type */
817 CHECK_AGAINST_OPMODE(j);
818 BlankEnvelope.e_bodytype = newstr(optarg);
819 break;
820
821 case 'C': /* select configuration file (already done) */
822 if (RealUid != 0)
823 warn_C_flag = true;
824 conffile = newstr(optarg);
825 dp = drop_privileges(true);
826 setstat(dp);
827 safecf = false;
828 break;
829
830 case 'D':
831 case 'd': /* debugging */
832 /* already done */
833 break;
834
835 case 'f': /* from address */
836 case 'r': /* obsolete -f flag */
837 CHECK_AGAINST_OPMODE(j);
838 if (from != NULL)
839 {
840 usrerr("More than one \"from\" person");
841 ExitStat = EX_USAGE;
842 break;
843 }
844 if (optarg[0] == '\0')
845 from = newstr("<>");
846 else
847 from = newstr(denlstring(optarg, true, true));
848 if (strcmp(RealUserName, from) != 0)
849 warn_f_flag = j;
850 break;
851
852 case 'F': /* set full name */
853 CHECK_AGAINST_OPMODE(j);
854 FullName = newstr(optarg);
855 break;
856
857 case 'G': /* relay (gateway) submission */
858 /* already set */
859 CHECK_AGAINST_OPMODE(j);
860 break;
861
862 case 'h': /* hop count */
863 CHECK_AGAINST_OPMODE(j);
864 BlankEnvelope.e_hopcount = (short) strtol(optarg, &ep,
865 10);
866 (void) sm_snprintf(buf, sizeof buf, "%d",
867 BlankEnvelope.e_hopcount);
868 macdefine(&BlankEnvelope.e_macro, A_TEMP, 'c', buf);
869
870 if (*ep)
871 {
872 usrerr("Bad hop count (%s)", optarg);
873 ExitStat = EX_USAGE;
874 }
875 break;
876
877 case 'L': /* program label */
878 /* already set */
879 break;
880
881 case 'n': /* don't alias */
882 CHECK_AGAINST_OPMODE(j);
883 NoAlias = true;
884 break;
885
886 case 'N': /* delivery status notifications */
887 CHECK_AGAINST_OPMODE(j);
888 DefaultNotify |= QHASNOTIFY;
889 macdefine(&BlankEnvelope.e_macro, A_TEMP,
890 macid("{dsn_notify}"), optarg);
891 if (sm_strcasecmp(optarg, "never") == 0)
892 break;
893 for (p = optarg; p != NULL; optarg = p)
894 {
895 p = strchr(p, ',');
896 if (p != NULL)
897 *p++ = '\0';
898 if (sm_strcasecmp(optarg, "success") == 0)
899 DefaultNotify |= QPINGONSUCCESS;
900 else if (sm_strcasecmp(optarg, "failure") == 0)
901 DefaultNotify |= QPINGONFAILURE;
902 else if (sm_strcasecmp(optarg, "delay") == 0)
903 DefaultNotify |= QPINGONDELAY;
904 else
905 {
906 usrerr("Invalid -N argument");
907 ExitStat = EX_USAGE;
908 }
909 }
910 break;
911
912 case 'o': /* set option */
913 setoption(*optarg, optarg + 1, false, true,
914 &BlankEnvelope);
915 break;
916
917 case 'O': /* set option (long form) */
918 setoption(' ', optarg, false, true, &BlankEnvelope);
919 break;
920
921 case 'p': /* set protocol */
922 CHECK_AGAINST_OPMODE(j);
923 p = strchr(optarg, ':');
924 if (p != NULL)
925 {
926 *p++ = '\0';
927 if (*p != '\0')
928 {
929 i = strlen(p) + 1;
930 ep = sm_malloc_x(i);
931 cleanstrcpy(ep, p, i);
932 macdefine(&BlankEnvelope.e_macro,
933 A_HEAP, 's', ep);
934 }
935 }
936 if (*optarg != '\0')
937 {
938 i = strlen(optarg) + 1;
939 ep = sm_malloc_x(i);
940 cleanstrcpy(ep, optarg, i);
941 macdefine(&BlankEnvelope.e_macro, A_HEAP,
942 'r', ep);
943 }
944 break;
945
946 case 'Q': /* change quarantining on queued items */
947 /* sanity check */
948 if (OpMode != MD_DELIVER &&
949 OpMode != MD_QUEUERUN)
950 {
951 usrerr("Can not use -Q with -b%c", OpMode);
952 ExitStat = EX_USAGE;
953 break;
954 }
955
956 if (OpMode == MD_DELIVER)
957 set_op_mode(MD_QUEUERUN);
958
959 FullName = NULL;
960
961 quarantining = newstr(optarg);
962 break;
963
964 case 'q': /* run queue files at intervals */
965 /* sanity check */
966 if (OpMode != MD_DELIVER &&
967 OpMode != MD_DAEMON &&
968 OpMode != MD_FGDAEMON &&
969 OpMode != MD_PRINT &&
970 OpMode != MD_PRINTNQE &&
971 OpMode != MD_QUEUERUN)
972 {
973 usrerr("Can not use -q with -b%c", OpMode);
974 ExitStat = EX_USAGE;
975 break;
976 }
977
978 /* don't override -bd, -bD or -bp */
979 if (OpMode == MD_DELIVER)
980 set_op_mode(MD_QUEUERUN);
981
982 FullName = NULL;
983 negate = optarg[0] == '!';
984 if (negate)
985 {
986 /* negate meaning of pattern match */
987 optarg++; /* skip '!' for next switch */
988 }
989
990 switch (optarg[0])
991 {
992 case 'G': /* Limit by queue group name */
993 if (negate)
994 {
995 usrerr("Can not use -q!G");
996 ExitStat = EX_USAGE;
997 break;
998 }
999 if (queuegroup != NULL)
1000 {
1001 usrerr("Can not use multiple -qG options");
1002 ExitStat = EX_USAGE;
1003 break;
1004 }
1005 queuegroup = newstr(&optarg[1]);
1006 break;
1007
1008 case 'I': /* Limit by ID */
1009 new = (QUEUE_CHAR *) xalloc(sizeof *new);
1010 new->queue_match = newstr(&optarg[1]);
1011 new->queue_negate = negate;
1012 new->queue_next = QueueLimitId;
1013 QueueLimitId = new;
1014 break;
1015
1016 case 'R': /* Limit by recipient */
1017 new = (QUEUE_CHAR *) xalloc(sizeof *new);
1018 new->queue_match = newstr(&optarg[1]);
1019 new->queue_negate = negate;
1020 new->queue_next = QueueLimitRecipient;
1021 QueueLimitRecipient = new;
1022 break;
1023
1024 case 'S': /* Limit by sender */
1025 new = (QUEUE_CHAR *) xalloc(sizeof *new);
1026 new->queue_match = newstr(&optarg[1]);
1027 new->queue_negate = negate;
1028 new->queue_next = QueueLimitSender;
1029 QueueLimitSender = new;
1030 break;
1031
1032 case 'f': /* foreground queue run */
1033 foregroundqueue = true;
1034 break;
1035
1036 case 'Q': /* Limit by quarantine message */
1037 if (optarg[1] != '\0')
1038 {
1039 new = (QUEUE_CHAR *) xalloc(sizeof *new);
1040 new->queue_match = newstr(&optarg[1]);
1041 new->queue_negate = negate;
1042 new->queue_next = QueueLimitQuarantine;
1043 QueueLimitQuarantine = new;
1044 }
1045 QueueMode = QM_QUARANTINE;
1046 break;
1047
1048 case 'L': /* act on lost items */
1049 QueueMode = QM_LOST;
1050 break;
1051
1052 case 'p': /* Persistent queue */
1053 queuepersistent = true;
1054 if (QueueIntvl == 0)
1055 QueueIntvl = 1;
1056 if (optarg[1] == '\0')
1057 break;
1058 ++optarg;
1059 /* FALLTHROUGH */
1060
1061 default:
1062 i = Errors;
1063 QueueIntvl = convtime(optarg, 'm');
1064 if (QueueIntvl < 0)
1065 {
1066 usrerr("Invalid -q value");
1067 ExitStat = EX_USAGE;
1068 }
1069
1070 /* check for bad conversion */
1071 if (i < Errors)
1072 ExitStat = EX_USAGE;
1073 break;
1074 }
1075 break;
1076
1077 case 'R': /* DSN RET: what to return */
1078 CHECK_AGAINST_OPMODE(j);
1079 if (bitset(EF_RET_PARAM, BlankEnvelope.e_flags))
1080 {
1081 usrerr("Duplicate -R flag");
1082 ExitStat = EX_USAGE;
1083 break;
1084 }
1085 BlankEnvelope.e_flags |= EF_RET_PARAM;
1086 if (sm_strcasecmp(optarg, "hdrs") == 0)
1087 BlankEnvelope.e_flags |= EF_NO_BODY_RETN;
1088 else if (sm_strcasecmp(optarg, "full") != 0)
1089 {
1090 usrerr("Invalid -R value");
1091 ExitStat = EX_USAGE;
1092 }
1093 macdefine(&BlankEnvelope.e_macro, A_TEMP,
1094 macid("{dsn_ret}"), optarg);
1095 break;
1096
1097 case 't': /* read recipients from message */
1098 CHECK_AGAINST_OPMODE(j);
1099 GrabTo = true;
1100 break;
1101
1102 case 'V': /* DSN ENVID: set "original" envelope id */
1103 CHECK_AGAINST_OPMODE(j);
1104 if (!xtextok(optarg))
1105 {
1106 usrerr("Invalid syntax in -V flag");
1107 ExitStat = EX_USAGE;
1108 }
1109 else
1110 {
1111 BlankEnvelope.e_envid = newstr(optarg);
1112 macdefine(&BlankEnvelope.e_macro, A_TEMP,
1113 macid("{dsn_envid}"), optarg);
1114 }
1115 break;
1116
1117 case 'X': /* traffic log file */
1118 dp = drop_privileges(true);
1119 setstat(dp);
1120 if (stat(optarg, &traf_st) == 0 &&
1121 S_ISFIFO(traf_st.st_mode))
1122 TrafficLogFile = sm_io_open(SmFtStdio,
1123 SM_TIME_DEFAULT,
1124 optarg,
1125 SM_IO_WRONLY, NULL);
1126 else
1127 TrafficLogFile = sm_io_open(SmFtStdio,
1128 SM_TIME_DEFAULT,
1129 optarg,
1130 SM_IO_APPEND, NULL);
1131 if (TrafficLogFile == NULL)
1132 {
1133 syserr("cannot open %s", optarg);
1134 ExitStat = EX_CANTCREAT;
1135 break;
1136 }
1137 (void) sm_io_setvbuf(TrafficLogFile, SM_TIME_DEFAULT,
1138 NULL, SM_IO_LBF, 0);
1139 break;
1140
1141 /* compatibility flags */
1142 case 'c': /* connect to non-local mailers */
1143 case 'i': /* don't let dot stop me */
1144 case 'm': /* send to me too */
1145 case 'T': /* set timeout interval */
1146 case 'v': /* give blow-by-blow description */
1147 setoption(j, "T", false, true, &BlankEnvelope);
1148 break;
1149
1150 case 'e': /* error message disposition */
1151 case 'M': /* define macro */
1152 setoption(j, optarg, false, true, &BlankEnvelope);
1153 break;
1154
1155 case 's': /* save From lines in headers */
1156 setoption('f', "T", false, true, &BlankEnvelope);
1157 break;
1158
1159#ifdef DBM
1160 case 'I': /* initialize alias DBM file */
1161 set_op_mode(MD_INITALIAS);
1162 break;
1163#endif /* DBM */
1164
1165#if defined(__osf__) || defined(_AIX3)
1166 case 'x': /* random flag that OSF/1 & AIX mailx passes */
1167 break;
1168#endif /* defined(__osf__) || defined(_AIX3) */
1169#if defined(sony_news)
1170 case 'E':
1171 case 'J': /* ignore flags for Japanese code conversion
1172 implemented on Sony NEWS */
1173 break;
1174#endif /* defined(sony_news) */
1175
1176 default:
1177 finis(true, true, EX_USAGE);
1178 /* NOTREACHED */
1179 break;
1180 }
1181 }
1182
1183 /* if we've had errors so far, exit now */
1184 if ((ExitStat != EX_OK && OpMode != MD_TEST) ||
1185 ExitStat == EX_OSERR)
1186 {
1187 finis(false, true, ExitStat);
1188 /* NOTREACHED */
1189 }
1190
1191 if (bitset(SUBMIT_MTA, SubmitMode))
1192 {
1193 /* If set daemon_flags on command line, don't reset it */
1194 if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
1195 macdefine(&BlankEnvelope.e_macro, A_PERM,
1196 macid("{daemon_flags}"), "CC f");
1197 }
1198 else if (OpMode == MD_DELIVER || OpMode == MD_SMTP)
1199 {
1200 SubmitMode = SUBMIT_MSA;
1201
1202 /* If set daemon_flags on command line, don't reset it */
1203 if (macvalue(macid("{daemon_flags}"), &BlankEnvelope) == NULL)
1204 macdefine(&BlankEnvelope.e_macro, A_PERM,
1205 macid("{daemon_flags}"), "c u");
1206 }
1207
1208 /*
1209 ** Do basic initialization.
1210 ** Read system control file.
1211 ** Extract special fields for local use.
1212 */
1213
1214#if XDEBUG
1215 checkfd012("before readcf");
1216#endif /* XDEBUG */
1217 vendor_pre_defaults(&BlankEnvelope);
1218
1219 readcf(getcfname(OpMode, SubmitMode, cftype, conffile),
1220 safecf, &BlankEnvelope);
1221#if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
1222 ConfigFileRead = true;
1223#endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
1224 vendor_post_defaults(&BlankEnvelope);
1225
1226 /* now we can complain about missing fds */
1227 if (MissingFds != 0 && LogLevel > 8)
1228 {
1229 char mbuf[MAXLINE];
1230
1231 mbuf[0] = '\0';
1232 if (bitset(1 << STDIN_FILENO, MissingFds))
1233 (void) sm_strlcat(mbuf, ", stdin", sizeof mbuf);
1234 if (bitset(1 << STDOUT_FILENO, MissingFds))
1235 (void) sm_strlcat(mbuf, ", stdout", sizeof mbuf);
1236 if (bitset(1 << STDERR_FILENO, MissingFds))
1237 (void) sm_strlcat(mbuf, ", stderr", sizeof mbuf);
1238
1239 /* Notice: fill_errno is from high above: fill_fd() */
1240 sm_syslog(LOG_WARNING, NOQID,
1241 "File descriptors missing on startup: %s; %s",
1242 &mbuf[2], sm_errstring(fill_errno));
1243 }
1244
1245 /* Remove the ability for a normal user to send signals */
1246 if (RealUid != 0 && RealUid != geteuid())
1247 {
1248 uid_t new_uid = geteuid();
1249
1250#if HASSETREUID
1251 /*
1252 ** Since we can differentiate between uid and euid,
1253 ** make the uid a different user so the real user
1254 ** can't send signals. However, it doesn't need to be
1255 ** root (euid has root).
1256 */
1257
1258 if (new_uid == 0)
1259 new_uid = DefUid;
1260 if (tTd(47, 5))
1261 sm_dprintf("Changing real uid to %d\n", (int) new_uid);
1262 if (setreuid(new_uid, geteuid()) < 0)
1263 {
1264 syserr("main: setreuid(%d, %d) failed",
1265 (int) new_uid, (int) geteuid());
1266 finis(false, true, EX_OSERR);
1267 /* NOTREACHED */
1268 }
1269 if (tTd(47, 10))
1270 sm_dprintf("Now running as e/ruid %d:%d\n",
1271 (int) geteuid(), (int) getuid());
1272#else /* HASSETREUID */
1273 /*
1274 ** Have to change both effective and real so need to
1275 ** change them both to effective to keep privs.
1276 */
1277
1278 if (tTd(47, 5))
1279 sm_dprintf("Changing uid to %d\n", (int) new_uid);
1280 if (setuid(new_uid) < 0)
1281 {
1282 syserr("main: setuid(%d) failed", (int) new_uid);
1283 finis(false, true, EX_OSERR);
1284 /* NOTREACHED */
1285 }
1286 if (tTd(47, 10))
1287 sm_dprintf("Now running as e/ruid %d:%d\n",
1288 (int) geteuid(), (int) getuid());
1289#endif /* HASSETREUID */
1290 }
1291
1292#if NAMED_BIND
1293 if (FallbackMX != NULL)
1294 (void) getfallbackmxrr(FallbackMX);
1295#endif /* NAMED_BIND */
1296
1297 if (SuperSafe == SAFE_INTERACTIVE && CurEnv->e_sendmode != SM_DELIVER)
1298 {
1299 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1300 "WARNING: SuperSafe=interactive should only be used with\n DeliveryMode=interactive\n");
1301 }
1302
1303 if (UseMSP && (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON))
1304 {
1305 usrerr("Mail submission program cannot be used as daemon");
1306 finis(false, true, EX_USAGE);
1307 }
1308
1309 if (OpMode == MD_DELIVER || OpMode == MD_SMTP ||
1310 OpMode == MD_QUEUERUN || OpMode == MD_ARPAFTP ||
1311 OpMode == MD_DAEMON || OpMode == MD_FGDAEMON)
1312 makeworkgroups();
1313
1314 /* set up the basic signal handlers */
1315 if (sm_signal(SIGINT, SIG_IGN) != SIG_IGN)
1316 (void) sm_signal(SIGINT, intsig);
1317 (void) sm_signal(SIGTERM, intsig);
1318
1319 /* Enforce use of local time (null string overrides this) */
1320 if (TimeZoneSpec == NULL)
1321 unsetenv("TZ");
1322 else if (TimeZoneSpec[0] != '\0')
1323 sm_setuserenv("TZ", TimeZoneSpec);
1324 else
1325 sm_setuserenv("TZ", NULL);
1326 tzset();
1327
1328 /* initialize mailbox database */
1329 i = sm_mbdb_initialize(Mbdb);
1330 if (i != EX_OK)
1331 {
1332 usrerr("Can't initialize mailbox database \"%s\": %s",
1333 Mbdb, sm_strexit(i));
1334 ExitStat = i;
1335 }
1336
1337 /* avoid denial-of-service attacks */
1338 resetlimits();
1339
1340 if (OpMode == MD_TEST)
1341 {
1342 /* can't be done after readcf if RunAs* is used */
1343 dp = drop_privileges(true);
1344 if (dp != EX_OK)
1345 {
1346 finis(false, true, dp);
1347 /* NOTREACHED */
1348 }
1349 }
1350 else if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON)
1351 {
1352 /* drop privileges -- daemon mode done after socket/bind */
1353 dp = drop_privileges(false);
1354 setstat(dp);
1355 if (dp == EX_OK && UseMSP && (geteuid() == 0 || getuid() == 0))
1356 {
1357 usrerr("Mail submission program must have RunAsUser set to non root user");
1358 finis(false, true, EX_CONFIG);
1359 /* NOTREACHED */
1360 }
1361 }
1362
1363#if NAMED_BIND
1364 _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT];
1365 _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT];
1366#endif /* NAMED_BIND */
1367
1368 /*
1369 ** Find our real host name for future logging.
1370 */
1371
1372 authinfo = getauthinfo(STDIN_FILENO, &forged);
1373 macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
1374
1375 /* suppress error printing if errors mailed back or whatever */
1376 if (BlankEnvelope.e_errormode != EM_PRINT)
1377 HoldErrs = true;
1378
1379 /* set up the $=m class now, after .cf has a chance to redefine $m */
1380 expand("\201m", jbuf, sizeof jbuf, &BlankEnvelope);
1381 if (jbuf[0] != '\0')
1382 setclass('m', jbuf);
1383
1384 /* probe interfaces and locate any additional names */
1385 if (DontProbeInterfaces != DPI_PROBENONE)
1386 load_if_names();
1387
1388 if (tTd(0, 10))
1389 {
1390 char pidpath[MAXPATHLEN];
1391
1392 /* Now we know which .cf file we use */
1393 sm_dprintf(" Conf file:\t%s (selected)\n",
1394 getcfname(OpMode, SubmitMode, cftype, conffile));
1395 expand(PidFile, pidpath, sizeof pidpath, &BlankEnvelope);
1396 sm_dprintf(" Pid file:\t%s (selected)\n", pidpath);
1397 }
1398
1399 if (tTd(0, 1))
1400 {
1401 sm_dprintf("\n============ SYSTEM IDENTITY (after readcf) ============");
1402 sm_dprintf("\n (short domain name) $w = ");
1403 xputs(sm_debug_file(), macvalue('w', &BlankEnvelope));
1404 sm_dprintf("\n (canonical domain name) $j = ");
1405 xputs(sm_debug_file(), macvalue('j', &BlankEnvelope));
1406 sm_dprintf("\n (subdomain name) $m = ");
1407 xputs(sm_debug_file(), macvalue('m', &BlankEnvelope));
1408 sm_dprintf("\n (node name) $k = ");
1409 xputs(sm_debug_file(), macvalue('k', &BlankEnvelope));
1410 sm_dprintf("\n========================================================\n\n");
1411 }
1412
1413 /*
1414 ** Do more command line checking -- these are things that
1415 ** have to modify the results of reading the config file.
1416 */
1417
1418 /* process authorization warnings from command line */
1419 if (warn_C_flag)
1420 auth_warning(&BlankEnvelope, "Processed by %s with -C %s",
1421 RealUserName, conffile);
1422 if (Warn_Q_option && !wordinclass(RealUserName, 't'))
1423 auth_warning(&BlankEnvelope, "Processed from queue %s",
1424 QueueDir);
1425 if (sysloglabel != NULL && !wordinclass(RealUserName, 't') &&
1426 RealUid != 0 && RealUid != TrustedUid && LogLevel > 1)
1427 sm_syslog(LOG_WARNING, NOQID, "user %d changed syslog label",
1428 (int) RealUid);
1429
1430 /* check body type for legality */
1431 i = check_bodytype(BlankEnvelope.e_bodytype);
1432 if (i == BODYTYPE_ILLEGAL)
1433 {
1434 usrerr("Illegal body type %s", BlankEnvelope.e_bodytype);
1435 BlankEnvelope.e_bodytype = NULL;
1436 }
1437 else if (i != BODYTYPE_NONE)
1438 SevenBitInput = (i == BODYTYPE_7BIT);
1439
1440 /* tweak default DSN notifications */
1441 if (DefaultNotify == 0)
1442 DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
1443
1444 /* check for sane configuration level */
1445 if (ConfigLevel > MAXCONFIGLEVEL)
1446 {
1447 syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)",
1448 ConfigLevel, Version, MAXCONFIGLEVEL);
1449 }
1450
1451 /* need MCI cache to have persistence */
1452 if (HostStatDir != NULL && MaxMciCache == 0)
1453 {
1454 HostStatDir = NULL;
1455 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1456 "Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n");
1457 }
1458
1459 /* need HostStatusDir in order to have SingleThreadDelivery */
1460 if (SingleThreadDelivery && HostStatDir == NULL)
1461 {
1462 SingleThreadDelivery = false;
1463 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1464 "Warning: HostStatusDirectory required for SingleThreadDelivery\n");
1465 }
1466
1467#if _FFR_MEMSTAT
1468 j = sm_memstat_open();
1469 if (j < 0 && (RefuseLowMem > 0 || QueueLowMem > 0) && LogLevel > 4)
1470 {
1471 sm_syslog(LOG_WARNING, NOQID,
1472 "cannot get memory statistics, settings ignored, error=%d"
1473 , j);
1474 }
1475#endif /* _FFR_MEMSTAT */
1476
1477 /* check for permissions */
1478 if (RealUid != 0 &&
1479 RealUid != TrustedUid)
1480 {
1481 char *action = NULL;
1482
1483 switch (OpMode)
1484 {
1485 case MD_QUEUERUN:
1486 if (quarantining != NULL)
1487 action = "quarantine jobs";
1488 else
1489 {
1490 /* Normal users can do a single queue run */
1491 if (QueueIntvl == 0)
1492 break;
1493 }
1494
1495 /* but not persistent queue runners */
1496 if (action == NULL)
1497 action = "start a queue runner daemon";
1498 /* FALLTHROUGH */
1499
1500 case MD_PURGESTAT:
1501 if (action == NULL)
1502 action = "purge host status";
1503 /* FALLTHROUGH */
1504
1505 case MD_DAEMON:
1506 case MD_FGDAEMON:
1507 if (action == NULL)
1508 action = "run daemon";
1509
1510 if (tTd(65, 1))
1511 sm_dprintf("Deny user %d attempt to %s\n",
1512 (int) RealUid, action);
1513
1514 if (LogLevel > 1)
1515 sm_syslog(LOG_ALERT, NOQID,
1516 "user %d attempted to %s",
1517 (int) RealUid, action);
1518 HoldErrs = false;
1519 usrerr("Permission denied (real uid not trusted)");
1520 finis(false, true, EX_USAGE);
1521 /* NOTREACHED */
1522 break;
1523
1524 case MD_VERIFY:
1525 if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags))
1526 {
1527 /*
1528 ** If -bv and RestrictExpand,
1529 ** drop privs to prevent normal
1530 ** users from reading private
1531 ** aliases/forwards/:include:s
1532 */
1533
1534 if (tTd(65, 1))
1535 sm_dprintf("Drop privs for user %d attempt to expand (RestrictExpand)\n",
1536 (int) RealUid);
1537
1538 dp = drop_privileges(true);
1539
1540 /* Fake address safety */
1541 if (tTd(65, 1))
1542 sm_dprintf("Faking DontBlameSendmail=NonRootSafeAddr\n");
1543 setbitn(DBS_NONROOTSAFEADDR, DontBlameSendmail);
1544
1545 if (dp != EX_OK)
1546 {
1547 if (tTd(65, 1))
1548 sm_dprintf("Failed to drop privs for user %d attempt to expand, exiting\n",
1549 (int) RealUid);
1550 CurEnv->e_id = NULL;
1551 finis(true, true, dp);
1552 /* NOTREACHED */
1553 }
1554 }
1555 break;
1556
1557 case MD_TEST:
1558 case MD_PRINT:
1559 case MD_PRINTNQE:
1560 case MD_FREEZE:
1561 case MD_HOSTSTAT:
1562 /* Nothing special to check */
1563 break;
1564
1565 case MD_INITALIAS:
1566 if (!wordinclass(RealUserName, 't'))
1567 {
1568 if (tTd(65, 1))
1569 sm_dprintf("Deny user %d attempt to rebuild the alias map\n",
1570 (int) RealUid);
1571 if (LogLevel > 1)
1572 sm_syslog(LOG_ALERT, NOQID,
1573 "user %d attempted to rebuild the alias map",
1574 (int) RealUid);
1575 HoldErrs = false;
1576 usrerr("Permission denied (real uid not trusted)");
1577 finis(false, true, EX_USAGE);
1578 /* NOTREACHED */
1579 }
1580 if (UseMSP)
1581 {
1582 HoldErrs = false;
1583 usrerr("User %d cannot rebuild aliases in mail submission program",
1584 (int) RealUid);
1585 finis(false, true, EX_USAGE);
1586 /* NOTREACHED */
1587 }
1588 /* FALLTHROUGH */
1589
1590 default:
1591 if (bitset(PRIV_RESTRICTEXPAND, PrivacyFlags) &&
1592 Verbose != 0)
1593 {
1594 /*
1595 ** If -v and RestrictExpand, reset
1596 ** Verbose to prevent normal users
1597 ** from seeing the expansion of
1598 ** aliases/forwards/:include:s
1599 */
1600
1601 if (tTd(65, 1))
1602 sm_dprintf("Dropping verbosity for user %d (RestrictExpand)\n",
1603 (int) RealUid);
1604 Verbose = 0;
1605 }
1606 break;
1607 }
1608 }
1609
1610 if (MeToo)
1611 BlankEnvelope.e_flags |= EF_METOO;
1612
1613 switch (OpMode)
1614 {
1615 case MD_TEST:
1616 /* don't have persistent host status in test mode */
1617 HostStatDir = NULL;
1618 if (Verbose == 0)
1619 Verbose = 2;
1620 BlankEnvelope.e_errormode = EM_PRINT;
1621 HoldErrs = false;
1622 break;
1623
1624 case MD_VERIFY:
1625 BlankEnvelope.e_errormode = EM_PRINT;
1626 HoldErrs = false;
1627 /* arrange to exit cleanly on hangup signal */
1628 if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1629 (void) sm_signal(SIGHUP, intsig);
1630 if (geteuid() != 0)
1631 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1632 "Notice: -bv may give misleading output for non-privileged user\n");
1633 break;
1634
1635 case MD_FGDAEMON:
1636 run_in_foreground = true;
1637 set_op_mode(MD_DAEMON);
1638 /* FALLTHROUGH */
1639
1640 case MD_DAEMON:
1641 vendor_daemon_setup(&BlankEnvelope);
1642
1643 /* remove things that don't make sense in daemon mode */
1644 FullName = NULL;
1645 GrabTo = false;
1646
1647 /* arrange to restart on hangup signal */
1648 if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/')
1649 sm_syslog(LOG_WARNING, NOQID,
1650 "daemon invoked without full pathname; kill -1 won't work");
1651 break;
1652
1653 case MD_INITALIAS:
1654 Verbose = 2;
1655 BlankEnvelope.e_errormode = EM_PRINT;
1656 HoldErrs = false;
1657 /* FALLTHROUGH */
1658
1659 default:
1660 /* arrange to exit cleanly on hangup signal */
1661 if (sm_signal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL)
1662 (void) sm_signal(SIGHUP, intsig);
1663 break;
1664 }
1665
1666 /* special considerations for FullName */
1667 if (FullName != NULL)
1668 {
1669 char *full = NULL;
1670
1671 /* full names can't have newlines */
1672 if (strchr(FullName, '\n') != NULL)
1673 {
1674 full = newstr(denlstring(FullName, true, true));
1675 FullName = full;
1676 }
1677
1678 /* check for characters that may have to be quoted */
1679 if (!rfc822_string(FullName))
1680 {
1681 /*
1682 ** Quote a full name with special characters
1683 ** as a comment so crackaddr() doesn't destroy
1684 ** the name portion of the address.
1685 */
1686
1687 FullName = addquotes(FullName, NULL);
1688 if (full != NULL)
1689 sm_free(full); /* XXX */
1690 }
1691 }
1692
1693 /* do heuristic mode adjustment */
1694 if (Verbose)
1695 {
1696 /* turn off noconnect option */
1697 setoption('c', "F", true, false, &BlankEnvelope);
1698
1699 /* turn on interactive delivery */
1700 setoption('d', "", true, false, &BlankEnvelope);
1701 }
1702
1703#ifdef VENDOR_CODE
1704 /* check for vendor mismatch */
1705 if (VendorCode != VENDOR_CODE)
1706 {
1707 message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s",
1708 getvendor(VENDOR_CODE), getvendor(VendorCode));
1709 }
1710#endif /* VENDOR_CODE */
1711
1712 /* check for out of date configuration level */
1713 if (ConfigLevel < MAXCONFIGLEVEL)
1714 {
1715 message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d",
1716 Version, MAXCONFIGLEVEL, ConfigLevel);
1717 }
1718
1719 if (ConfigLevel < 3)
1720 UseErrorsTo = true;
1721
1722 /* set options that were previous macros */
1723 if (SmtpGreeting == NULL)
1724 {
1725 if (ConfigLevel < 7 &&
1726 (p = macvalue('e', &BlankEnvelope)) != NULL)
1727 SmtpGreeting = newstr(p);
1728 else
1729 SmtpGreeting = "\201j Sendmail \201v ready at \201b";
1730 }
1731 if (UnixFromLine == NULL)
1732 {
1733 if (ConfigLevel < 7 &&
1734 (p = macvalue('l', &BlankEnvelope)) != NULL)
1735 UnixFromLine = newstr(p);
1736 else
1737 UnixFromLine = "From \201g \201d";
1738 }
1739 SmtpError[0] = '\0';
1740
1741 /* our name for SMTP codes */
1742 expand("\201j", jbuf, sizeof jbuf, &BlankEnvelope);
1743 if (jbuf[0] == '\0')
1744 PSTRSET(MyHostName, "localhost");
1745 else
1746 PSTRSET(MyHostName, jbuf);
1747 if (strchr(MyHostName, '.') == NULL)
1748 message("WARNING: local host name (%s) is not qualified; see cf/README: WHO AM I?",
1749 MyHostName);
1750
1751 /* make certain that this name is part of the $=w class */
1752 setclass('w', MyHostName);
1753
1754 /* fill in the structure of the *default* queue */
1755 st = stab("mqueue", ST_QUEUE, ST_FIND);
1756 if (st == NULL)
1757 syserr("No default queue (mqueue) defined");
1758 else
1759 set_def_queueval(st->s_quegrp, true);
1760
1761 /* the indices of built-in mailers */
1762 st = stab("local", ST_MAILER, ST_FIND);
1763 if (st != NULL)
1764 LocalMailer = st->s_mailer;
1765 else if (OpMode != MD_TEST || !warn_C_flag)
1766 syserr("No local mailer defined");
1767
1768 st = stab("prog", ST_MAILER, ST_FIND);
1769 if (st == NULL)
1770 syserr("No prog mailer defined");
1771 else
1772 {
1773 ProgMailer = st->s_mailer;
1774 clrbitn(M_MUSER, ProgMailer->m_flags);
1775 }
1776
1777 st = stab("*file*", ST_MAILER, ST_FIND);
1778 if (st == NULL)
1779 syserr("No *file* mailer defined");
1780 else
1781 {
1782 FileMailer = st->s_mailer;
1783 clrbitn(M_MUSER, FileMailer->m_flags);
1784 }
1785
1786 st = stab("*include*", ST_MAILER, ST_FIND);
1787 if (st == NULL)
1788 syserr("No *include* mailer defined");
1789 else
1790 InclMailer = st->s_mailer;
1791
1792 if (ConfigLevel < 6)
1793 {
1794 /* heuristic tweaking of local mailer for back compat */
1795 if (LocalMailer != NULL)
1796 {
1797 setbitn(M_ALIASABLE, LocalMailer->m_flags);
1798 setbitn(M_HASPWENT, LocalMailer->m_flags);
1799 setbitn(M_TRYRULESET5, LocalMailer->m_flags);
1800 setbitn(M_CHECKINCLUDE, LocalMailer->m_flags);
1801 setbitn(M_CHECKPROG, LocalMailer->m_flags);
1802 setbitn(M_CHECKFILE, LocalMailer->m_flags);
1803 setbitn(M_CHECKUDB, LocalMailer->m_flags);
1804 }
1805 if (ProgMailer != NULL)
1806 setbitn(M_RUNASRCPT, ProgMailer->m_flags);
1807 if (FileMailer != NULL)
1808 setbitn(M_RUNASRCPT, FileMailer->m_flags);
1809 }
1810 if (ConfigLevel < 7)
1811 {
1812 if (LocalMailer != NULL)
1813 setbitn(M_VRFY250, LocalMailer->m_flags);
1814 if (ProgMailer != NULL)
1815 setbitn(M_VRFY250, ProgMailer->m_flags);
1816 if (FileMailer != NULL)
1817 setbitn(M_VRFY250, FileMailer->m_flags);
1818 }
1819
1820 /* MIME Content-Types that cannot be transfer encoded */
1821 setclass('n', "multipart/signed");
1822
1823 /* MIME message/xxx subtypes that can be treated as messages */
1824 setclass('s', "rfc822");
1825
1826 /* MIME Content-Transfer-Encodings that can be encoded */
1827 setclass('e', "7bit");
1828 setclass('e', "8bit");
1829 setclass('e', "binary");
1830
1831#ifdef USE_B_CLASS
1832 /* MIME Content-Types that should be treated as binary */
1833 setclass('b', "image");
1834 setclass('b', "audio");
1835 setclass('b', "video");
1836 setclass('b', "application/octet-stream");
1837#endif /* USE_B_CLASS */
1838
1839 /* MIME headers which have fields to check for overflow */
1840 setclass(macid("{checkMIMEFieldHeaders}"), "content-disposition");
1841 setclass(macid("{checkMIMEFieldHeaders}"), "content-type");
1842
1843 /* MIME headers to check for length overflow */
1844 setclass(macid("{checkMIMETextHeaders}"), "content-description");
1845
1846 /* MIME headers to check for overflow and rebalance */
1847 setclass(macid("{checkMIMEHeaders}"), "content-disposition");
1848 setclass(macid("{checkMIMEHeaders}"), "content-id");
1849 setclass(macid("{checkMIMEHeaders}"), "content-transfer-encoding");
1850 setclass(macid("{checkMIMEHeaders}"), "content-type");
1851 setclass(macid("{checkMIMEHeaders}"), "mime-version");
1852
1853 /* Macros to save in the queue file -- don't remove any */
1854 setclass(macid("{persistentMacros}"), "r");
1855 setclass(macid("{persistentMacros}"), "s");
1856 setclass(macid("{persistentMacros}"), "_");
1857 setclass(macid("{persistentMacros}"), "{if_addr}");
1858 setclass(macid("{persistentMacros}"), "{daemon_flags}");
1859
1860 /* operate in queue directory */
1861 if (QueueDir == NULL || *QueueDir == '\0')
1862 {
1863 if (OpMode != MD_TEST)
1864 {
1865 syserr("QueueDirectory (Q) option must be set");
1866 ExitStat = EX_CONFIG;
1867 }
1868 }
1869 else
1870 {
1871 if (OpMode != MD_TEST)
1872 setup_queues(OpMode == MD_DAEMON);
1873 }
1874
1875 /* check host status directory for validity */
1876 if (HostStatDir != NULL && !path_is_dir(HostStatDir, false))
1877 {
1878 /* cannot use this value */
1879 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1880 "Warning: Cannot use HostStatusDirectory = %s: %s\n",
1881 HostStatDir, sm_errstring(errno));
1882 HostStatDir = NULL;
1883 }
1884
1885 if (OpMode == MD_QUEUERUN &&
1886 RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags))
1887 {
1888 struct stat stbuf;
1889
1890 /* check to see if we own the queue directory */
1891 if (stat(".", &stbuf) < 0)
1892 syserr("main: cannot stat %s", QueueDir);
1893 if (stbuf.st_uid != RealUid)
1894 {
1895 /* nope, really a botch */
1896 HoldErrs = false;
1897 usrerr("You do not have permission to process the queue");
1898 finis(false, true, EX_NOPERM);
1899 /* NOTREACHED */
1900 }
1901 }
1902
1903#if MILTER
1904 /* sanity checks on milter filters */
1905 if (OpMode == MD_DAEMON || OpMode == MD_SMTP)
1906 {
1907 milter_config(InputFilterList, InputFilters, MAXFILTERS);
1908 setup_daemon_milters();
1909 }
1910#endif /* MILTER */
1911
1912 /* Convert queuegroup string to qgrp number */
1913 if (queuegroup != NULL)
1914 {
1915 qgrp = name2qid(queuegroup);
1916 if (qgrp == NOQGRP)
1917 {
1918 HoldErrs = false;
1919 usrerr("Queue group %s unknown", queuegroup);
1920 finis(false, true, ExitStat);
1921 /* NOTREACHED */
1922 }
1923 }
1924
1925 /* if we've had errors so far, exit now */
1926 if (ExitStat != EX_OK && OpMode != MD_TEST)
1927 {
1928 finis(false, true, ExitStat);
1929 /* NOTREACHED */
1930 }
1931
1932#if SASL
1933 /* sendmail specific SASL initialization */
1934 sm_sasl_init();
1935#endif /* SASL */
1936
1937#if XDEBUG
1938 checkfd012("before main() initmaps");
1939#endif /* XDEBUG */
1940
1941 /*
1942 ** Do operation-mode-dependent initialization.
1943 */
1944
1945 switch (OpMode)
1946 {
1947 case MD_PRINT:
1948 /* print the queue */
1949 HoldErrs = false;
1950 dropenvelope(&BlankEnvelope, true, false);
1951 (void) sm_signal(SIGPIPE, sigpipe);
1952 if (qgrp != NOQGRP)
1953 {
1954 int j;
1955
1956 /* Selecting a particular queue group to run */
1957 for (j = 0; j < Queue[qgrp]->qg_numqueues; j++)
1958 {
1959 if (StopRequest)
1960 stop_sendmail();
1961 (void) print_single_queue(qgrp, j);
1962 }
1963 finis(false, true, EX_OK);
1964 /* NOTREACHED */
1965 }
1966 printqueue();
1967 finis(false, true, EX_OK);
1968 /* NOTREACHED */
1969 break;
1970
1971 case MD_PRINTNQE:
1972 /* print number of entries in queue */
1973 dropenvelope(&BlankEnvelope, true, false);
1974 (void) sm_signal(SIGPIPE, sigpipe);
1975 printnqe(smioout, NULL);
1976 finis(false, true, EX_OK);
1977 /* NOTREACHED */
1978 break;
1979
1980 case MD_QUEUERUN:
1981 /* only handle quarantining here */
1982 if (quarantining == NULL)
1983 break;
1984
1985 if (QueueMode != QM_QUARANTINE &&
1986 QueueMode != QM_NORMAL)
1987 {
1988 HoldErrs = false;
1989 usrerr("Can not use -Q with -q%c", QueueMode);
1990 ExitStat = EX_USAGE;
1991 finis(false, true, ExitStat);
1992 /* NOTREACHED */
1993 }
1994 quarantine_queue(quarantining, qgrp);
1995 finis(false, true, EX_OK);
1996 break;
1997
1998 case MD_HOSTSTAT:
1999 (void) sm_signal(SIGPIPE, sigpipe);
2000 (void) mci_traverse_persistent(mci_print_persistent, NULL);
2001 finis(false, true, EX_OK);
2002 /* NOTREACHED */
2003 break;
2004
2005 case MD_PURGESTAT:
2006 (void) mci_traverse_persistent(mci_purge_persistent, NULL);
2007 finis(false, true, EX_OK);
2008 /* NOTREACHED */
2009 break;
2010
2011 case MD_INITALIAS:
2012 /* initialize maps */
2013 initmaps();
2014 finis(false, true, ExitStat);
2015 /* NOTREACHED */
2016 break;
2017
2018 case MD_SMTP:
2019 case MD_DAEMON:
2020 /* reset DSN parameters */
2021 DefaultNotify = QPINGONFAILURE|QPINGONDELAY;
2022 macdefine(&BlankEnvelope.e_macro, A_PERM,
2023 macid("{dsn_notify}"), NULL);
2024 BlankEnvelope.e_envid = NULL;
2025 macdefine(&BlankEnvelope.e_macro, A_PERM,
2026 macid("{dsn_envid}"), NULL);
2027 BlankEnvelope.e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
2028 macdefine(&BlankEnvelope.e_macro, A_PERM,
2029 macid("{dsn_ret}"), NULL);
2030
2031 /* don't open maps for daemon -- done below in child */
2032 break;
2033 }
2034
2035 if (tTd(0, 15))
2036 {
2037 /* print configuration table (or at least part of it) */
2038 if (tTd(0, 90))
2039 printrules();
2040 for (i = 0; i < MAXMAILERS; i++)
2041 {
2042 if (Mailer[i] != NULL)
2043 printmailer(sm_debug_file(), Mailer[i]);
2044 }
2045 }
2046
2047 /*
2048 ** Switch to the main envelope.
2049 */
2050
2051 CurEnv = newenvelope(&MainEnvelope, &BlankEnvelope,
2052 sm_rpool_new_x(NULL));
2053 MainEnvelope.e_flags = BlankEnvelope.e_flags;
2054
2055 /*
2056 ** If test mode, read addresses from stdin and process.
2057 */
2058
2059 if (OpMode == MD_TEST)
2060 {
2061 if (isatty(sm_io_getinfo(smioin, SM_IO_WHAT_FD, NULL)))
2062 Verbose = 2;
2063
2064 if (Verbose)
2065 {
2066 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2067 "ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
2068 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2069 "Enter <ruleset> <address>\n");
2070 }
2071 macdefine(&(MainEnvelope.e_macro), A_PERM,
2072 macid("{addr_type}"), "e r");
2073 for (;;)
2074 {
2075 SM_TRY
2076 {
2077 (void) sm_signal(SIGINT, intindebug);
2078 (void) sm_releasesignal(SIGINT);
2079 if (Verbose == 2)
2080 (void) sm_io_fprintf(smioout,
2081 SM_TIME_DEFAULT,
2082 "> ");
2083 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
2084 if (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf,
2085 sizeof buf) == NULL)
2086 testmodeline("/quit", &MainEnvelope);
2087 p = strchr(buf, '\n');
2088 if (p != NULL)
2089 *p = '\0';
2090 if (Verbose < 2)
2091 (void) sm_io_fprintf(smioout,
2092 SM_TIME_DEFAULT,
2093 "> %s\n", buf);
2094 testmodeline(buf, &MainEnvelope);
2095 }
2096 SM_EXCEPT(exc, "[!F]*")
2097 {
2098 /*
2099 ** 8.10 just prints \n on interrupt.
2100 ** I'm printing the exception here in case
2101 ** sendmail is extended to raise additional
2102 ** exceptions in this context.
2103 */
2104
2105 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2106 "\n");
2107 sm_exc_print(exc, smioout);
2108 }
2109 SM_END_TRY
2110 }
2111 }
2112
2113#if STARTTLS
2114 tls_ok = true;
2115 if (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER)
2116 {
2117 /* check whether STARTTLS is turned off for the client */
2118 if (chkclientmodifiers(D_NOTLS))
2119 tls_ok = false;
2120 }
2121 else if (OpMode == MD_DAEMON || OpMode == MD_FGDAEMON ||
2122 OpMode == MD_SMTP)
2123 {
2124 /* check whether STARTTLS is turned off for the server */
2125 if (chkdaemonmodifiers(D_NOTLS))
2126 tls_ok = false;
2127 }
2128 else /* other modes don't need STARTTLS */
2129 tls_ok = false;
2130
2131 if (tls_ok)
2132 {
2133 /* basic TLS initialization */
2134 tls_ok = init_tls_library();
2135 }
2136
2137 if (!tls_ok && (OpMode == MD_QUEUERUN || OpMode == MD_DELIVER))
2138 {
2139 /* disable TLS for client */
2140 setclttls(false);
2141 }
2142#endif /* STARTTLS */
2143
2144 /*
2145 ** If collecting stuff from the queue, go start doing that.
2146 */
2147
2148 if (OpMode == MD_QUEUERUN && QueueIntvl == 0)
2149 {
2150 pid_t pid = -1;
2151
2152#if STARTTLS
2153 /* init TLS for client, ignore result for now */
2154 (void) initclttls(tls_ok);
2155#endif /* STARTTLS */
2156
2157 /*
2158 ** The parent process of the caller of runqueue() needs
2159 ** to stay around for a possible SIGTERM. The SIGTERM will
2160 ** tell this process that all of the queue runners children
2161 ** need to be sent SIGTERM as well. At the same time, we
2162 ** want to return control to the command line. So we do an
2163 ** extra fork().
2164 */
2165
2166 if (Verbose || foregroundqueue || (pid = fork()) <= 0)
2167 {
2168 /*
2169 ** If the fork() failed we should still try to do
2170 ** the queue run. If it succeeded then the child
2171 ** is going to start the run and wait for all
2172 ** of the children to finish.
2173 */
2174
2175 if (pid == 0)
2176 {
2177 /* Reset global flags */
2178 RestartRequest = NULL;
2179 ShutdownRequest = NULL;
2180 PendingSignal = 0;
2181
2182 /* disconnect from terminal */
2183 disconnect(2, CurEnv);
2184 }
2185
2186 CurrentPid = getpid();
2187 if (qgrp != NOQGRP)
2188 {
2189 int rwgflags = RWG_NONE;
2190
2191 /*
2192 ** To run a specific queue group mark it to
2193 ** be run, select the work group it's in and
2194 ** increment the work counter.
2195 */
2196
2197 for (i = 0; i < NumQueue && Queue[i] != NULL;
2198 i++)
2199 Queue[i]->qg_nextrun = (time_t) -1;
2200 Queue[qgrp]->qg_nextrun = 0;
2201 if (Verbose)
2202 rwgflags |= RWG_VERBOSE;
2203 if (queuepersistent)
2204 rwgflags |= RWG_PERSISTENT;
2205 rwgflags |= RWG_FORCE;
2206 (void) run_work_group(Queue[qgrp]->qg_wgrp,
2207 rwgflags);
2208 }
2209 else
2210 (void) runqueue(false, Verbose,
2211 queuepersistent, true);
2212
2213 /* set the title to make it easier to find */
2214 sm_setproctitle(true, CurEnv, "Queue control");
2215 (void) sm_signal(SIGCHLD, SIG_DFL);
2216 while (CurChildren > 0)
2217 {
2218 int status;
2219 pid_t ret;
2220
2221 errno = 0;
2222 while ((ret = sm_wait(&status)) <= 0)
2223 {
2224 if (errno == ECHILD)
2225 {
2226 /*
2227 ** Oops... something got messed
2228 ** up really bad. Waiting for
2229 ** non-existent children
2230 ** shouldn't happen. Let's get
2231 ** out of here.
2232 */
2233
2234 CurChildren = 0;
2235 break;
2236 }
2237 continue;
2238 }
2239
2240 /* something is really really wrong */
2241 if (errno == ECHILD)
2242 {
2243 sm_syslog(LOG_ERR, NOQID,
2244 "queue control process: lost all children: wait returned ECHILD");
2245 break;
2246 }
2247
2248 /* Only drop when a child gives status */
2249 if (WIFSTOPPED(status))
2250 continue;
2251
2252 proc_list_drop(ret, status, NULL);
2253 }
2254 }
2255 finis(true, true, ExitStat);
2256 /* NOTREACHED */
2257 }
2258
2259# if SASL
2260 if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2261 {
2262 /* check whether AUTH is turned off for the server */
2263 if (!chkdaemonmodifiers(D_NOAUTH) &&
2264 (i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK)
2265 syserr("!sasl_server_init failed! [%s]",
2266 sasl_errstring(i, NULL, NULL));
2267 }
2268# endif /* SASL */
2269
2270 if (OpMode == MD_SMTP)
2271 {
2272 proc_list_add(CurrentPid, "Sendmail SMTP Agent",
2273 PROC_DAEMON, 0, -1, NULL);
2274
2275 /* clean up background delivery children */
2276 (void) sm_signal(SIGCHLD, reapchild);
2277 }
2278
2279 /*
2280 ** If a daemon, wait for a request.
2281 ** getrequests will always return in a child.
2282 ** If we should also be processing the queue, start
2283 ** doing it in background.
2284 ** We check for any errors that might have happened
2285 ** during startup.
2286 */
2287
2288 if (OpMode == MD_DAEMON || QueueIntvl > 0)
2289 {
2290 char dtype[200];
2291
2292 if (!run_in_foreground && !tTd(99, 100))
2293 {
2294 /* put us in background */
2295 i = fork();
2296 if (i < 0)
2297 syserr("daemon: cannot fork");
2298 if (i != 0)
2299 {
2300 finis(false, true, EX_OK);
2301 /* NOTREACHED */
2302 }
2303
2304 /*
2305 ** Initialize exception stack and default exception
2306 ** handler for child process.
2307 */
2308
2309 /* Reset global flags */
2310 RestartRequest = NULL;
2311 RestartWorkGroup = false;
2312 ShutdownRequest = NULL;
2313 PendingSignal = 0;
2314 CurrentPid = getpid();
2315
2316 sm_exc_newthread(fatal_error);
2317
2318 /* disconnect from our controlling tty */
2319 disconnect(2, &MainEnvelope);
2320 }
2321
2322 dtype[0] = '\0';
2323 if (OpMode == MD_DAEMON)
2322 {
2324 (void) sm_strlcat(dtype, "+SMTP", sizeof dtype);
2324 DaemonPid = CurrentPid;
2325 }
2325 if (QueueIntvl > 0)
2326 {
2327 (void) sm_strlcat2(dtype,
2328 queuepersistent
2329 ? "+persistent-queueing@"
2330 : "+queueing@",
2331 pintvl(QueueIntvl, true),
2332 sizeof dtype);
2333 }
2334 if (tTd(0, 1))
2335 (void) sm_strlcat(dtype, "+debugging", sizeof dtype);
2336
2337 sm_syslog(LOG_INFO, NOQID,
2338 "starting daemon (%s): %s", Version, dtype + 1);
2339#if XLA
2340 xla_create_file();
2341#endif /* XLA */
2342
2343 /* save daemon type in a macro for possible PidFile use */
2344 macdefine(&BlankEnvelope.e_macro, A_TEMP,
2345 macid("{daemon_info}"), dtype + 1);
2346
2347 /* save queue interval in a macro for possible PidFile use */
2348 macdefine(&MainEnvelope.e_macro, A_TEMP,
2349 macid("{queue_interval}"), pintvl(QueueIntvl, true));
2350
2351 /* workaround: can't seem to release the signal in the parent */
2352 (void) sm_signal(SIGHUP, sighup);
2353 (void) sm_releasesignal(SIGHUP);
2354 (void) sm_signal(SIGTERM, sigterm);
2355
2356 if (QueueIntvl > 0)
2357 {
2358 (void) runqueue(true, false, queuepersistent, true);
2359
2360 /*
2361 ** If queuepersistent but not in daemon mode then
2362 ** we're going to do the queue runner monitoring here.
2363 ** If in daemon mode then the monitoring will happen
2364 ** elsewhere.
2365 */
2366
2367 if (OpMode != MD_DAEMON && queuepersistent)
2368 {
2369 /*
2370 ** Write the pid to file
2371 ** XXX Overwrites sendmail.pid
2372 */
2373
2374 log_sendmail_pid(&MainEnvelope);
2375
2376 /* set the title to make it easier to find */
2377 sm_setproctitle(true, CurEnv, "Queue control");
2378 (void) sm_signal(SIGCHLD, SIG_DFL);
2379 while (CurChildren > 0)
2380 {
2381 int status;
2382 pid_t ret;
2383 int group;
2384
2385 CHECK_RESTART;
2386 errno = 0;
2387 while ((ret = sm_wait(&status)) <= 0)
2388 {
2389 /*
2390 ** Waiting for non-existent
2391 ** children shouldn't happen.
2392 ** Let's get out of here if
2393 ** it occurs.
2394 */
2395
2396 if (errno == ECHILD)
2397 {
2398 CurChildren = 0;
2399 break;
2400 }
2401 continue;
2402 }
2403
2404 /* something is really really wrong */
2405 if (errno == ECHILD)
2406 {
2407 sm_syslog(LOG_ERR, NOQID,
2408 "persistent queue runner control process: lost all children: wait returned ECHILD");
2409 break;
2410 }
2411
2412 if (WIFSTOPPED(status))
2413 continue;
2414
2415 /* Probe only on a child status */
2416 proc_list_drop(ret, status, &group);
2417
2418 if (WIFSIGNALED(status))
2419 {
2420 if (WCOREDUMP(status))
2421 {
2422 sm_syslog(LOG_ERR, NOQID,
2423 "persistent queue runner=%d core dumped, signal=%d",
2424 group, WTERMSIG(status));
2425
2426 /* don't restart this */
2427 mark_work_group_restart(
2428 group, -1);
2429 continue;
2430 }
2431
2432 sm_syslog(LOG_ERR, NOQID,
2433 "persistent queue runner=%d died, signal=%d",
2434 group, WTERMSIG(status));
2435 }
2436
2437 /*
2438 ** When debugging active, don't
2439 ** restart the persistent queues.
2440 ** But do log this as info.
2441 */
2442
2443 if (sm_debug_active(&DebugNoPRestart,
2444 1))
2445 {
2446 sm_syslog(LOG_DEBUG, NOQID,
2447 "persistent queue runner=%d, exited",
2448 group);
2449 mark_work_group_restart(group,
2450 -1);
2451 }
2452 }
2453 finis(true, true, ExitStat);
2454 /* NOTREACHED */
2455 }
2456
2457 if (OpMode != MD_DAEMON)
2458 {
2459 char qtype[200];
2460
2461 /*
2462 ** Write the pid to file
2463 ** XXX Overwrites sendmail.pid
2464 */
2465
2466 log_sendmail_pid(&MainEnvelope);
2467
2468 /* set the title to make it easier to find */
2469 qtype[0] = '\0';
2470 (void) sm_strlcpyn(qtype, sizeof qtype, 4,
2471 "Queue runner@",
2472 pintvl(QueueIntvl, true),
2473 " for ",
2474 QueueDir);
2475 sm_setproctitle(true, CurEnv, qtype);
2476 for (;;)
2477 {
2478 (void) pause();
2479
2480 CHECK_RESTART;
2481
2482 if (doqueuerun())
2483 (void) runqueue(true, false,
2484 false, false);
2485 }
2486 }
2487 }
2488 dropenvelope(&MainEnvelope, true, false);
2489
2490#if STARTTLS
2491 /* init TLS for server, ignore result for now */
2492 (void) initsrvtls(tls_ok);
2493#endif /* STARTTLS */
2494
2495 nextreq:
2496 p_flags = getrequests(&MainEnvelope);
2497
2498 /* drop privileges */
2499 (void) drop_privileges(false);
2500
2501 /*
2502 ** Get authentication data
2503 ** Set _ macro in BlankEnvelope before calling newenvelope().
2504 */
2505
2506 authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
2507 NULL), &forged);
2508 macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo);
2509
2510 /* at this point we are in a child: reset state */
2511 sm_rpool_free(MainEnvelope.e_rpool);
2512 (void) newenvelope(&MainEnvelope, &MainEnvelope,
2513 sm_rpool_new_x(NULL));
2514 }
2515
2516 if (LogLevel > 9)
2517 {
2518 /* log connection information */
2519 sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo);
2520 }
2521
2522 /*
2523 ** If running SMTP protocol, start collecting and executing
2524 ** commands. This will never return.
2525 */
2526
2527 if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
2528 {
2529 char pbuf[20];
2530
2531 /*
2532 ** Save some macros for check_* rulesets.
2533 */
2534
2535 if (forged)
2536 {
2537 char ipbuf[103];
2538
2539 (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]",
2540 anynet_ntoa(&RealHostAddr));
2541 macdefine(&BlankEnvelope.e_macro, A_TEMP,
2542 macid("{client_name}"), ipbuf);
2543 }
2544 else
2545 macdefine(&BlankEnvelope.e_macro, A_PERM,
2546 macid("{client_name}"), RealHostName);
2547 macdefine(&BlankEnvelope.e_macro, A_PERM,
2548 macid("{client_ptr}"), RealHostName);
2549 macdefine(&BlankEnvelope.e_macro, A_TEMP,
2550 macid("{client_addr}"), anynet_ntoa(&RealHostAddr));
2551 sm_getla();
2552
2553 switch (RealHostAddr.sa.sa_family)
2554 {
2555#if NETINET
2556 case AF_INET:
2557 (void) sm_snprintf(pbuf, sizeof pbuf, "%d",
2558 RealHostAddr.sin.sin_port);
2559 break;
2560#endif /* NETINET */
2561#if NETINET6
2562 case AF_INET6:
2563 (void) sm_snprintf(pbuf, sizeof pbuf, "%d",
2564 RealHostAddr.sin6.sin6_port);
2565 break;
2566#endif /* NETINET6 */
2567 default:
2568 (void) sm_snprintf(pbuf, sizeof pbuf, "0");
2569 break;
2570 }
2571 macdefine(&BlankEnvelope.e_macro, A_TEMP,
2572 macid("{client_port}"), pbuf);
2573
2574 if (OpMode == MD_DAEMON)
2575 {
2576 /* validate the connection */
2577 HoldErrs = true;
2578 nullserver = validate_connection(&RealHostAddr,
2579 macvalue(macid("{client_name}"),
2580 &MainEnvelope),
2581 &MainEnvelope);
2582 HoldErrs = false;
2583 }
2584 else if (p_flags == NULL)
2585 {
2586 p_flags = (BITMAP256 *) xalloc(sizeof *p_flags);
2587 clrbitmap(p_flags);
2588 }
2589#if STARTTLS
2590 if (OpMode == MD_SMTP)
2591 (void) initsrvtls(tls_ok);
2592#endif /* STARTTLS */
2593
2594 /* turn off profiling */
2595 SM_PROF(1);
2596 smtp(nullserver, *p_flags, &MainEnvelope);
2597
2598 if (tTd(93, 100))
2599 {
2600 /* turn off profiling */
2601 SM_PROF(0);
2602 if (OpMode == MD_DAEMON)
2603 goto nextreq;
2604 }
2605 }
2606
2607 sm_rpool_free(MainEnvelope.e_rpool);
2608 clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL));
2609 if (OpMode == MD_VERIFY)
2610 {
2611 set_delivery_mode(SM_VERIFY, &MainEnvelope);
2612 PostMasterCopy = NULL;
2613 }
2614 else
2615 {
2616 /* interactive -- all errors are global */
2617 MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
2618 }
2619
2620 /*
2621 ** Do basic system initialization and set the sender
2622 */
2623
2624 initsys(&MainEnvelope);
2625 macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0");
2626 macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0");
2627 setsender(from, &MainEnvelope, NULL, '\0', false);
2628 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') &&
2629 (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) ||
2630 strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0))
2631 {
2632 auth_warning(&MainEnvelope, "%s set sender to %s using -%c",
2633 RealUserName, from, warn_f_flag);
2634#if SASL
2635 auth = false;
2636#endif /* SASL */
2637 }
2638 if (auth)
2639 {
2640 char *fv;
2641
2642 /* set the initial sender for AUTH= to $f@$j */
2643 fv = macvalue('f', &MainEnvelope);
2644 if (fv == NULL || *fv == '\0')
2645 MainEnvelope.e_auth_param = NULL;
2646 else
2647 {
2648 if (strchr(fv, '@') == NULL)
2649 {
2650 i = strlen(fv) + strlen(macvalue('j',
2651 &MainEnvelope)) + 2;
2652 p = sm_malloc_x(i);
2653 (void) sm_strlcpyn(p, i, 3, fv, "@",
2654 macvalue('j',
2655 &MainEnvelope));
2656 }
2657 else
2658 p = sm_strdup_x(fv);
2659 MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool,
2660 xtextify(p, "="));
2661 sm_free(p); /* XXX */
2662 }
2663 }
2664 if (macvalue('s', &MainEnvelope) == NULL)
2665 macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName);
2666
2667 av = argv + optind;
2668 if (*av == NULL && !GrabTo)
2669 {
2670 MainEnvelope.e_to = NULL;
2671 MainEnvelope.e_flags |= EF_GLOBALERRS;
2672 HoldErrs = false;
2673 SuperSafe = SAFE_NO;
2674 usrerr("Recipient names must be specified");
2675
2676 /* collect body for UUCP return */
2677 if (OpMode != MD_VERIFY)
2678 collect(InChannel, false, NULL, &MainEnvelope, true);
2679 finis(true, true, EX_USAGE);
2680 /* NOTREACHED */
2681 }
2682
2683 /*
2684 ** Scan argv and deliver the message to everyone.
2685 */
2686
2687 save_val = LogUsrErrs;
2688 LogUsrErrs = true;
2689 sendtoargv(av, &MainEnvelope);
2690 LogUsrErrs = save_val;
2691
2692 /* if we have had errors sofar, arrange a meaningful exit stat */
2693 if (Errors > 0 && ExitStat == EX_OK)
2694 ExitStat = EX_USAGE;
2695
2696#if _FFR_FIX_DASHT
2697 /*
2698 ** If using -t, force not sending to argv recipients, even
2699 ** if they are mentioned in the headers.
2700 */
2701
2702 if (GrabTo)
2703 {
2704 ADDRESS *q;
2705
2706 for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next)
2707 q->q_state = QS_REMOVED;
2708 }
2709#endif /* _FFR_FIX_DASHT */
2710
2711 /*
2712 ** Read the input mail.
2713 */
2714
2715 MainEnvelope.e_to = NULL;
2716 if (OpMode != MD_VERIFY || GrabTo)
2717 {
2718 int savederrors;
2719 unsigned long savedflags;
2720
2721 /*
2722 ** workaround for compiler warning on Irix:
2723 ** do not initialize variable in the definition, but
2724 ** later on:
2725 ** warning(1548): transfer of control bypasses
2726 ** initialization of:
2727 ** variable "savederrors" (declared at line 2570)
2728 ** variable "savedflags" (declared at line 2571)
2729 ** goto giveup;
2730 */
2731
2732 savederrors = Errors;
2733 savedflags = MainEnvelope.e_flags & EF_FATALERRS;
2734 MainEnvelope.e_flags |= EF_GLOBALERRS;
2735 MainEnvelope.e_flags &= ~EF_FATALERRS;
2736 Errors = 0;
2737 buffer_errors();
2738 collect(InChannel, false, NULL, &MainEnvelope, true);
2739
2740 /* header checks failed */
2741 if (Errors > 0)
2742 {
2743 giveup:
2744 if (!GrabTo)
2745 {
2746 /* Log who the mail would have gone to */
2747 logundelrcpts(&MainEnvelope,
2748 MainEnvelope.e_message,
2749 8, false);
2750 }
2751 flush_errors(true);
2752 finis(true, true, ExitStat);
2753 /* NOTREACHED */
2754 return -1;
2755 }
2756
2757 /* bail out if message too large */
2758 if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags))
2759 {
2760 finis(true, true, ExitStat != EX_OK ? ExitStat
2761 : EX_DATAERR);
2762 /* NOTREACHED */
2763 return -1;
2764 }
2765
2766 /* set message size */
2767 (void) sm_snprintf(buf, sizeof buf, "%ld",
2768 MainEnvelope.e_msgsize);
2769 macdefine(&MainEnvelope.e_macro, A_TEMP,
2770 macid("{msg_size}"), buf);
2771
2772 Errors = savederrors;
2773 MainEnvelope.e_flags |= savedflags;
2774 }
2775 errno = 0;
2776
2777 if (tTd(1, 1))
2778 sm_dprintf("From person = \"%s\"\n",
2779 MainEnvelope.e_from.q_paddr);
2780
2781 /* Check if quarantining stats should be updated */
2782 if (MainEnvelope.e_quarmsg != NULL)
2783 markstats(&MainEnvelope, NULL, STATS_QUARANTINE);
2784
2785 /*
2786 ** Actually send everything.
2787 ** If verifying, just ack.
2788 */
2789
2790 if (Errors == 0)
2791 {
2792 if (!split_by_recipient(&MainEnvelope) &&
2793 bitset(EF_FATALERRS, MainEnvelope.e_flags))
2794 goto giveup;
2795 }
2796
2797 /* make sure we deliver at least the first envelope */
2798 i = FastSplit > 0 ? 0 : -1;
2799 for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++)
2800 {
2801 ENVELOPE *next;
2802
2803 e->e_from.q_state = QS_SENDER;
2804 if (tTd(1, 5))
2805 {
2806 sm_dprintf("main[%d]: QS_SENDER ", i);
2807 printaddr(sm_debug_file(), &e->e_from, false);
2808 }
2809 e->e_to = NULL;
2810 sm_getla();
2811 GrabTo = false;
2812#if NAMED_BIND
2813 _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2814 _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2815#endif /* NAMED_BIND */
2816 next = e->e_sibling;
2817 e->e_sibling = NULL;
2818
2819 /* after FastSplit envelopes: queue up */
2820 sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT);
2821 e->e_sibling = next;
2822 }
2823
2824 /*
2825 ** All done.
2826 ** Don't send return error message if in VERIFY mode.
2827 */
2828
2829 finis(true, true, ExitStat);
2830 /* NOTREACHED */
2831 return ExitStat;
2832}
2833/*
2834** STOP_SENDMAIL -- Stop the running program
2835**
2836** Parameters:
2837** none.
2838**
2839** Returns:
2840** none.
2841**
2842** Side Effects:
2843** exits.
2844*/
2845
2846void
2847stop_sendmail()
2848{
2849 /* reset uid for process accounting */
2850 endpwent();
2851 (void) setuid(RealUid);
2852 exit(EX_OK);
2853}
2854/*
2855** FINIS -- Clean up and exit.
2856**
2857** Parameters:
2858** drop -- whether or not to drop CurEnv envelope
2859** cleanup -- call exit() or _exit()?
2860** exitstat -- exit status to use for exit() call
2861**
2862** Returns:
2863** never
2864**
2865** Side Effects:
2866** exits sendmail
2867*/
2868
2869void
2870finis(drop, cleanup, exitstat)
2871 bool drop;
2872 bool cleanup;
2873 volatile int exitstat;
2874{
2875 char pidpath[MAXPATHLEN];
2876 pid_t pid;
2877
2878 /* Still want to process new timeouts added below */
2879 sm_clear_events();
2880 (void) sm_releasesignal(SIGALRM);
2881
2882 if (tTd(2, 1))
2883 {
2884 sm_dprintf("\n====finis: stat %d e_id=%s e_flags=",
2885 exitstat,
2886 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
2887 printenvflags(CurEnv);
2888 }
2889 if (tTd(2, 9))
2890 printopenfds(false);
2891
2892 SM_TRY
2893 /*
2894 ** Clean up. This might raise E:mta.quickabort
2895 */
2896
2897 /* clean up temp files */
2898 CurEnv->e_to = NULL;
2899 if (drop)
2900 {
2901 if (CurEnv->e_id != NULL)
2902 {
2903 dropenvelope(CurEnv, true, false);
2904 sm_rpool_free(CurEnv->e_rpool);
2905 CurEnv->e_rpool = NULL;
2906 }
2907 else
2908 poststats(StatFile);
2909 }
2910
2911 /* flush any cached connections */
2912 mci_flush(true, NULL);
2913
2914 /* close maps belonging to this pid */
2915 closemaps(false);
2916
2917#if USERDB
2918 /* close UserDatabase */
2919 _udbx_close();
2920#endif /* USERDB */
2921
2922#if SASL
2923 stop_sasl_client();
2924#endif /* SASL */
2925
2926#if XLA
2927 /* clean up extended load average stuff */
2928 xla_all_end();
2929#endif /* XLA */
2930
2931 SM_FINALLY
2932 /*
2933 ** And exit.
2934 */
2935
2936 if (LogLevel > 78)
2937 sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d",
2938 (int) CurrentPid);
2939 if (exitstat == EX_TEMPFAIL ||
2940 CurEnv->e_errormode == EM_BERKNET)
2941 exitstat = EX_OK;
2942
2943 /* XXX clean up queues and related data structures */
2944 cleanup_queues();
2945 pid = getpid();
2946#if SM_CONF_SHM
2946 cleanup_shm(DaemonPid == getpid());
2947 cleanup_shm(DaemonPid == pid);
2948#endif /* SM_CONF_SHM */
2949
2950 /* close locked pid file */
2951 close_sendmail_pid();
2952
2952 if (DaemonPid == getpid() || PidFilePid == getpid())
2953 if (DaemonPid == pid || PidFilePid == pid)
2954 {
2955 /* blow away the pid file */
2956 expand(PidFile, pidpath, sizeof pidpath, CurEnv);
2957 (void) unlink(pidpath);
2958 }
2959
2960 /* reset uid for process accounting */
2961 endpwent();
2962 sm_mbdb_terminate();
2963#if _FFR_MEMSTAT
2964 (void) sm_memstat_close();
2965#endif /* _FFR_MEMSTAT */
2966 (void) setuid(RealUid);
2967#if SM_HEAP_CHECK
2968 /* dump the heap, if we are checking for memory leaks */
2969 if (sm_debug_active(&SmHeapCheck, 2))
2970 sm_heap_report(smioout,
2971 sm_debug_level(&SmHeapCheck) - 1);
2972#endif /* SM_HEAP_CHECK */
2973 if (sm_debug_active(&SmXtrapReport, 1))
2974 sm_dprintf("xtrap count = %d\n", SmXtrapCount);
2975 if (cleanup)
2976 exit(exitstat);
2977 else
2978 _exit(exitstat);
2979 SM_END_TRY
2980}
2981/*
2982** INTINDEBUG -- signal handler for SIGINT in -bt mode
2983**
2984** Parameters:
2985** sig -- incoming signal.
2986**
2987** Returns:
2988** none.
2989**
2990** Side Effects:
2991** longjmps back to test mode loop.
2992**
2993** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
2994** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2995** DOING.
2996*/
2997
2998/* Type of an exception generated on SIGINT during address test mode. */
2999static const SM_EXC_TYPE_T EtypeInterrupt =
3000{
3001 SmExcTypeMagic,
3002 "S:mta.interrupt",
3003 "",
3004 sm_etype_printf,
3005 "interrupt",
3006};
3007
3008/* ARGSUSED */
3009static SIGFUNC_DECL
3010intindebug(sig)
3011 int sig;
3012{
3013 int save_errno = errno;
3014
3015 FIX_SYSV_SIGNAL(sig, intindebug);
3016 errno = save_errno;
3017 CHECK_CRITICAL(sig);
3018 errno = save_errno;
3019 sm_exc_raisenew_x(&EtypeInterrupt);
3020 errno = save_errno;
3021 return SIGFUNC_RETURN;
3022}
3023/*
3024** SIGTERM -- SIGTERM handler for the daemon
3025**
3026** Parameters:
3027** sig -- signal number.
3028**
3029** Returns:
3030** none.
3031**
3032** Side Effects:
3033** Sets ShutdownRequest which will hopefully trigger
3034** the daemon to exit.
3035**
3036** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3037** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3038** DOING.
3039*/
3040
3041/* ARGSUSED */
3042static SIGFUNC_DECL
3043sigterm(sig)
3044 int sig;
3045{
3046 int save_errno = errno;
3047
3048 FIX_SYSV_SIGNAL(sig, sigterm);
3049 ShutdownRequest = "signal";
3050 errno = save_errno;
3051 return SIGFUNC_RETURN;
3052}
3053/*
3054** SIGHUP -- handle a SIGHUP signal
3055**
3056** Parameters:
3057** sig -- incoming signal.
3058**
3059** Returns:
3060** none.
3061**
3062** Side Effects:
3063** Sets RestartRequest which should cause the daemon
3064** to restart.
3065**
3066** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3067** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3068** DOING.
3069*/
3070
3071/* ARGSUSED */
3072static SIGFUNC_DECL
3073sighup(sig)
3074 int sig;
3075{
3076 int save_errno = errno;
3077
3078 FIX_SYSV_SIGNAL(sig, sighup);
3079 RestartRequest = "signal";
3080 errno = save_errno;
3081 return SIGFUNC_RETURN;
3082}
3083/*
3084** SIGPIPE -- signal handler for SIGPIPE
3085**
3086** Parameters:
3087** sig -- incoming signal.
3088**
3089** Returns:
3090** none.
3091**
3092** Side Effects:
3093** Sets StopRequest which should cause the mailq/hoststatus
3094** display to stop.
3095**
3096** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3097** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3098** DOING.
3099*/
3100
3101/* ARGSUSED */
3102static SIGFUNC_DECL
3103sigpipe(sig)
3104 int sig;
3105{
3106 int save_errno = errno;
3107
3108 FIX_SYSV_SIGNAL(sig, sigpipe);
3109 StopRequest = true;
3110 errno = save_errno;
3111 return SIGFUNC_RETURN;
3112}
3113/*
3114** INTSIG -- clean up on interrupt
3115**
3116** This just arranges to exit. It pessimizes in that it
3117** may resend a message.
3118**
3119** Parameters:
3120** none.
3121**
3122** Returns:
3123** none.
3124**
3125** Side Effects:
3126** Unlocks the current job.
3127**
3128** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3129** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3130** DOING.
3131**
3132** XXX: More work is needed for this signal handler.
3133*/
3134
3135/* ARGSUSED */
3136SIGFUNC_DECL
3137intsig(sig)
3138 int sig;
3139{
3140 bool drop = false;
3141 int save_errno = errno;
3142
3143 FIX_SYSV_SIGNAL(sig, intsig);
3144 errno = save_errno;
3145 CHECK_CRITICAL(sig);
3146 sm_allsignals(true);
3147
3148 if (sig != 0 && LogLevel > 79)
3149 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt");
3150 FileName = NULL;
3151
3152 /* Clean-up on aborted stdin message submission */
3153 if (CurEnv->e_id != NULL &&
3154 (OpMode == MD_SMTP ||
3155 OpMode == MD_DELIVER ||
3156 OpMode == MD_ARPAFTP))
3157 {
3158 register ADDRESS *q;
3159
3160 /* don't return an error indication */
3161 CurEnv->e_to = NULL;
3162 CurEnv->e_flags &= ~EF_FATALERRS;
3163 CurEnv->e_flags |= EF_CLRQUEUE;
3164
3165 /*
3166 ** Spin through the addresses and
3167 ** mark them dead to prevent bounces
3168 */
3169
3170 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
3171 q->q_state = QS_DONTSEND;
3172
3173 drop = true;
3174 }
3175 else if (OpMode != MD_TEST)
3176 {
3177 unlockqueue(CurEnv);
3178 }
3179
3180 finis(drop, false, EX_OK);
3181 /* NOTREACHED */
3182}
3183/*
3184** DISCONNECT -- remove our connection with any foreground process
3185**
3186** Parameters:
3187** droplev -- how "deeply" we should drop the line.
3188** 0 -- ignore signals, mail back errors, make sure
3189** output goes to stdout.
3190** 1 -- also, make stdout go to /dev/null.
3191** 2 -- also, disconnect from controlling terminal
3192** (only for daemon mode).
3193** e -- the current envelope.
3194**
3195** Returns:
3196** none
3197**
3198** Side Effects:
3199** Trys to insure that we are immune to vagaries of
3200** the controlling tty.
3201*/
3202
3203void
3204disconnect(droplev, e)
3205 int droplev;
3206 register ENVELOPE *e;
3207{
3208 int fd;
3209
3210 if (tTd(52, 1))
3211 sm_dprintf("disconnect: In %d Out %d, e=%p\n",
3212 sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL),
3213 sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e);
3214 if (tTd(52, 100))
3215 {
3216 sm_dprintf("don't\n");
3217 return;
3218 }
3219 if (LogLevel > 93)
3220 sm_syslog(LOG_DEBUG, e->e_id,
3221 "disconnect level %d",
3222 droplev);
3223
3224 /* be sure we don't get nasty signals */
3225 (void) sm_signal(SIGINT, SIG_IGN);
3226 (void) sm_signal(SIGQUIT, SIG_IGN);
3227
3228 /* we can't communicate with our caller, so.... */
3229 HoldErrs = true;
3230 CurEnv->e_errormode = EM_MAIL;
3231 Verbose = 0;
3232 DisConnected = true;
3233
3234 /* all input from /dev/null */
3235 if (InChannel != smioin)
3236 {
3237 (void) sm_io_close(InChannel, SM_TIME_DEFAULT);
3238 InChannel = smioin;
3239 }
3240 if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
3241 SM_IO_RDONLY, NULL, smioin) == NULL)
3242 sm_syslog(LOG_ERR, e->e_id,
3243 "disconnect: sm_io_reopen(\"%s\") failed: %s",
3244 SM_PATH_DEVNULL, sm_errstring(errno));
3245
3246 /*
3247 ** output to the transcript
3248 ** We also compare the fd numbers here since OutChannel
3249 ** might be a layer on top of smioout due to encryption
3250 ** (see sfsasl.c).
3251 */
3252
3253 if (OutChannel != smioout &&
3254 sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) !=
3255 sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL))
3256 {
3257 (void) sm_io_close(OutChannel, SM_TIME_DEFAULT);
3258 OutChannel = smioout;
3259
3260#if 0
3261 /*
3262 ** Has smioout been closed? Reopen it.
3263 ** This shouldn't happen anymore, the code is here
3264 ** just as a reminder.
3265 */
3266
3267 if (smioout->sm_magic == NULL &&
3268 sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
3269 SM_IO_WRONLY, NULL, smioout) == NULL)
3270 sm_syslog(LOG_ERR, e->e_id,
3271 "disconnect: sm_io_reopen(\"%s\") failed: %s",
3272 SM_PATH_DEVNULL, sm_errstring(errno));
3273#endif /* 0 */
3274 }
3275 if (droplev > 0)
3276 {
3277 fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666);
3278 if (fd == -1)
3279 {
3280 sm_syslog(LOG_ERR, e->e_id,
3281 "disconnect: open(\"%s\") failed: %s",
3282 SM_PATH_DEVNULL, sm_errstring(errno));
3283 }
3284 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
3282 (void) dup2(fd, STDOUT_FILENO);
3283 (void) dup2(fd, STDERR_FILENO);
3284 (void) close(fd);
3285 if (fd >= 0)
3286 {
3287 (void) dup2(fd, STDOUT_FILENO);
3288 (void) dup2(fd, STDERR_FILENO);
3289 (void) close(fd);
3290 }
3291 }
3292
3293 /* drop our controlling TTY completely if possible */
3294 if (droplev > 1)
3295 {
3296 (void) setsid();
3297 errno = 0;
3298 }
3299
3300#if XDEBUG
3301 checkfd012("disconnect");
3302#endif /* XDEBUG */
3303
3304 if (LogLevel > 71)
3305 sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d",
3306 (int) CurrentPid);
3307
3308 errno = 0;
3309}
3310
3311static void
3312obsolete(argv)
3313 char *argv[];
3314{
3315 register char *ap;
3316 register char *op;
3317
3318 while ((ap = *++argv) != NULL)
3319 {
3320 /* Return if "--" or not an option of any form. */
3321 if (ap[0] != '-' || ap[1] == '-')
3322 return;
3323
3324 /* Don't allow users to use "-Q." or "-Q ." */
3325 if ((ap[1] == 'Q' && ap[2] == '.') ||
3326 (ap[1] == 'Q' && argv[1] != NULL &&
3327 argv[1][0] == '.' && argv[1][1] == '\0'))
3328 {
3329 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3330 "Can not use -Q.\n");
3331 exit(EX_USAGE);
3332 }
3333
3334 /* skip over options that do have a value */
3335 op = strchr(OPTIONS, ap[1]);
3336 if (op != NULL && *++op == ':' && ap[2] == '\0' &&
3337 ap[1] != 'd' &&
3338#if defined(sony_news)
3339 ap[1] != 'E' && ap[1] != 'J' &&
3340#endif /* defined(sony_news) */
3341 argv[1] != NULL && argv[1][0] != '-')
3342 {
3343 argv++;
3344 continue;
3345 }
3346
3347 /* If -C doesn't have an argument, use sendmail.cf. */
3348#define __DEFPATH "sendmail.cf"
3349 if (ap[1] == 'C' && ap[2] == '\0')
3350 {
3351 *argv = xalloc(sizeof(__DEFPATH) + 2);
3352 (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2,
3353 "-C", __DEFPATH);
3354 }
3355
3356 /* If -q doesn't have an argument, run it once. */
3357 if (ap[1] == 'q' && ap[2] == '\0')
3358 *argv = "-q0";
3359
3360 /* If -Q doesn't have an argument, disable quarantining */
3361 if (ap[1] == 'Q' && ap[2] == '\0')
3362 *argv = "-Q.";
3363
3364 /* if -d doesn't have an argument, use 0-99.1 */
3365 if (ap[1] == 'd' && ap[2] == '\0')
3366 *argv = "-d0-99.1";
3367
3368#if defined(sony_news)
3369 /* if -E doesn't have an argument, use -EC */
3370 if (ap[1] == 'E' && ap[2] == '\0')
3371 *argv = "-EC";
3372
3373 /* if -J doesn't have an argument, use -JJ */
3374 if (ap[1] == 'J' && ap[2] == '\0')
3375 *argv = "-JJ";
3376#endif /* defined(sony_news) */
3377 }
3378}
3379/*
3380** AUTH_WARNING -- specify authorization warning
3381**
3382** Parameters:
3383** e -- the current envelope.
3384** msg -- the text of the message.
3385** args -- arguments to the message.
3386**
3387** Returns:
3388** none.
3389*/
3390
3391void
3392#ifdef __STDC__
3393auth_warning(register ENVELOPE *e, const char *msg, ...)
3394#else /* __STDC__ */
3395auth_warning(e, msg, va_alist)
3396 register ENVELOPE *e;
3397 const char *msg;
3398 va_dcl
3399#endif /* __STDC__ */
3400{
3401 char buf[MAXLINE];
3402 SM_VA_LOCAL_DECL
3403
3404 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
3405 {
3406 register char *p;
3407 static char hostbuf[48];
3408
3409 if (hostbuf[0] == '\0')
3410 {
3411 struct hostent *hp;
3412
3413 hp = myhostname(hostbuf, sizeof hostbuf);
3414#if NETINET6
3415 if (hp != NULL)
3416 {
3417 freehostent(hp);
3418 hp = NULL;
3419 }
3420#endif /* NETINET6 */
3421 }
3422
3423 (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": ");
3424 p = &buf[strlen(buf)];
3425 SM_VA_START(ap, msg);
3426 (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap);
3427 SM_VA_END(ap);
3428 addheader("X-Authentication-Warning", buf, 0, e);
3429 if (LogLevel > 3)
3430 sm_syslog(LOG_INFO, e->e_id,
3431 "Authentication-Warning: %.400s",
3432 buf);
3433 }
3434}
3435/*
3436** GETEXTENV -- get from external environment
3437**
3438** Parameters:
3439** envar -- the name of the variable to retrieve
3440**
3441** Returns:
3442** The value, if any.
3443*/
3444
3445static char *
3446getextenv(envar)
3447 const char *envar;
3448{
3449 char **envp;
3450 int l;
3451
3452 l = strlen(envar);
3453 for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++)
3454 {
3455 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=')
3456 return &(*envp)[l + 1];
3457 }
3458 return NULL;
3459}
3460/*
3461** SM_SETUSERENV -- set an environment variable in the propagated environment
3462**
3463** Parameters:
3464** envar -- the name of the environment variable.
3465** value -- the value to which it should be set. If
3466** null, this is extracted from the incoming
3467** environment. If that is not set, the call
3468** to sm_setuserenv is ignored.
3469**
3470** Returns:
3471** none.
3472*/
3473
3474void
3475sm_setuserenv(envar, value)
3476 const char *envar;
3477 const char *value;
3478{
3479 int i, l;
3480 char **evp = UserEnviron;
3481 char *p;
3482
3483 if (value == NULL)
3484 {
3485 value = getextenv(envar);
3486 if (value == NULL)
3487 return;
3488 }
3489
3490 /* XXX enforce reasonable size? */
3491 i = strlen(envar) + 1;
3492 l = strlen(value) + i + 1;
3493 p = (char *) xalloc(l);
3494 (void) sm_strlcpyn(p, l, 3, envar, "=", value);
3495
3496 while (*evp != NULL && strncmp(*evp, p, i) != 0)
3497 evp++;
3498 if (*evp != NULL)
3499 {
3500 *evp++ = p;
3501 }
3502 else if (evp < &UserEnviron[MAXUSERENVIRON])
3503 {
3504 *evp++ = p;
3505 *evp = NULL;
3506 }
3507
3508 /* make sure it is in our environment as well */
3509 if (putenv(p) < 0)
3510 syserr("sm_setuserenv: putenv(%s) failed", p);
3511}
3512/*
3513** DUMPSTATE -- dump state
3514**
3515** For debugging.
3516*/
3517
3518void
3519dumpstate(when)
3520 char *when;
3521{
3522 register char *j = macvalue('j', CurEnv);
3523 int rs;
3524 extern int NextMacroId;
3525
3526 sm_syslog(LOG_DEBUG, CurEnv->e_id,
3527 "--- dumping state on %s: $j = %s ---",
3528 when,
3529 j == NULL ? "<NULL>" : j);
3530 if (j != NULL)
3531 {
3532 if (!wordinclass(j, 'w'))
3533 sm_syslog(LOG_DEBUG, CurEnv->e_id,
3534 "*** $j not in $=w ***");
3535 }
3536 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren);
3537 sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)",
3538 NextMacroId, MAXMACROID);
3539 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---");
3540 printopenfds(true);
3541 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---");
3542 mci_dump_all(smioout, true);
3543 rs = strtorwset("debug_dumpstate", NULL, ST_FIND);
3544 if (rs > 0)
3545 {
3546 int status;
3547 register char **pvp;
3548 char *pv[MAXATOM + 1];
3549
3550 pv[0] = NULL;
3551 status = REWRITE(pv, rs, CurEnv);
3552 sm_syslog(LOG_DEBUG, CurEnv->e_id,
3553 "--- ruleset debug_dumpstate returns stat %d, pv: ---",
3554 status);
3555 for (pvp = pv; *pvp != NULL; pvp++)
3556 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp);
3557 }
3558 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---");
3559}
3560
3561#ifdef SIGUSR1
3562/*
3563** SIGUSR1 -- Signal a request to dump state.
3564**
3565** Parameters:
3566** sig -- calling signal.
3567**
3568** Returns:
3569** none.
3570**
3571** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3572** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3573** DOING.
3574**
3575** XXX: More work is needed for this signal handler.
3576*/
3577
3578/* ARGSUSED */
3579static SIGFUNC_DECL
3580sigusr1(sig)
3581 int sig;
3582{
3583 int save_errno = errno;
3584# if SM_HEAP_CHECK
3585 extern void dumpstab __P((void));
3586# endif /* SM_HEAP_CHECK */
3587
3588 FIX_SYSV_SIGNAL(sig, sigusr1);
3589 errno = save_errno;
3590 CHECK_CRITICAL(sig);
3591 dumpstate("user signal");
3592# if SM_HEAP_CHECK
3593 dumpstab();
3594# endif /* SM_HEAP_CHECK */
3595 errno = save_errno;
3596 return SIGFUNC_RETURN;
3597}
3598#endif /* SIGUSR1 */
3599
3600/*
3601** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option
3602**
3603** Parameters:
3604** to_real_uid -- if set, drop to the real uid instead
3605** of the RunAsUser.
3606**
3607** Returns:
3608** EX_OSERR if the setuid failed.
3609** EX_OK otherwise.
3610*/
3611
3612int
3613drop_privileges(to_real_uid)
3614 bool to_real_uid;
3615{
3616 int rval = EX_OK;
3617 GIDSET_T emptygidset[1];
3618
3619 if (tTd(47, 1))
3620 sm_dprintf("drop_privileges(%d): Real[UG]id=%d:%d, get[ug]id=%d:%d, gete[ug]id=%d:%d, RunAs[UG]id=%d:%d\n",
3621 (int) to_real_uid,
3622 (int) RealUid, (int) RealGid,
3623 (int) getuid(), (int) getgid(),
3624 (int) geteuid(), (int) getegid(),
3625 (int) RunAsUid, (int) RunAsGid);
3626
3627 if (to_real_uid)
3628 {
3629 RunAsUserName = RealUserName;
3630 RunAsUid = RealUid;
3631 RunAsGid = RealGid;
3632 EffGid = RunAsGid;
3633 }
3634
3635 /* make sure no one can grab open descriptors for secret files */
3636 endpwent();
3637 sm_mbdb_terminate();
3638
3639 /* reset group permissions; these can be set later */
3640 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid();
3641
3642 /*
3643 ** Notice: on some OS (Linux...) the setgroups() call causes
3644 ** a logfile entry if sendmail is not run by root.
3645 ** However, it is unclear (no POSIX standard) whether
3646 ** setgroups() can only succeed if executed by root.
3647 ** So for now we keep it as it is; if you want to change it, use
3648 ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1)
3649 */
3650
3651 if (setgroups(1, emptygidset) == -1 && geteuid() == 0)
3652 {
3653 syserr("drop_privileges: setgroups(1, %d) failed",
3654 (int) emptygidset[0]);
3655 rval = EX_OSERR;
3656 }
3657
3658 /* reset primary group id */
3659 if (to_real_uid)
3660 {
3661 /*
3662 ** Drop gid to real gid.
3663 ** On some OS we must reset the effective[/real[/saved]] gid,
3664 ** and then use setgid() to finally drop all group privileges.
3665 ** Later on we check whether we can get back the
3666 ** effective gid.
3667 */
3668
3669#if HASSETEGID
3670 if (setegid(RunAsGid) < 0)
3671 {
3672 syserr("drop_privileges: setegid(%d) failed",
3673 (int) RunAsGid);
3674 rval = EX_OSERR;
3675 }
3676#else /* HASSETEGID */
3677# if HASSETREGID
3678 if (setregid(RunAsGid, RunAsGid) < 0)
3679 {
3680 syserr("drop_privileges: setregid(%d, %d) failed",
3681 (int) RunAsGid, (int) RunAsGid);
3682 rval = EX_OSERR;
3683 }
3684# else /* HASSETREGID */
3685# if HASSETRESGID
3686 if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0)
3687 {
3688 syserr("drop_privileges: setresgid(%d, %d, %d) failed",
3689 (int) RunAsGid, (int) RunAsGid, (int) RunAsGid);
3690 rval = EX_OSERR;
3691 }
3692# endif /* HASSETRESGID */
3693# endif /* HASSETREGID */
3694#endif /* HASSETEGID */
3695 }
3696 if (rval == EX_OK && (to_real_uid || RunAsGid != 0))
3697 {
3698 if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid))
3699 {
3700 syserr("drop_privileges: setgid(%d) failed",
3701 (int) RunAsGid);
3702 rval = EX_OSERR;
3703 }
3704 errno = 0;
3705 if (rval == EX_OK && getegid() != RunAsGid)
3706 {
3707 syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d",
3708 (int) getegid(), (int) RunAsGid);
3709 rval = EX_OSERR;
3710 }
3711 }
3712
3713 /* fiddle with uid */
3714 if (to_real_uid || RunAsUid != 0)
3715 {
3716 uid_t euid;
3717
3718 /*
3719 ** Try to setuid(RunAsUid).
3720 ** euid must be RunAsUid,
3721 ** ruid must be RunAsUid unless (e|r)uid wasn't 0
3722 ** and we didn't have to drop privileges to the real uid.
3723 */
3724
3725 if (setuid(RunAsUid) < 0 ||
3726 geteuid() != RunAsUid ||
3727 (getuid() != RunAsUid &&
3728 (to_real_uid || geteuid() == 0 || getuid() == 0)))
3729 {
3730#if HASSETREUID
3731 /*
3732 ** if ruid != RunAsUid, euid == RunAsUid, then
3733 ** try resetting just the real uid, then using
3734 ** setuid() to drop the saved-uid as well.
3735 */
3736
3737 if (geteuid() == RunAsUid)
3738 {
3739 if (setreuid(RunAsUid, -1) < 0)
3740 {
3741 syserr("drop_privileges: setreuid(%d, -1) failed",
3742 (int) RunAsUid);
3743 rval = EX_OSERR;
3744 }
3745 if (setuid(RunAsUid) < 0)
3746 {
3747 syserr("drop_privileges: second setuid(%d) attempt failed",
3748 (int) RunAsUid);
3749 rval = EX_OSERR;
3750 }
3751 }
3752 else
3753#endif /* HASSETREUID */
3754 {
3755 syserr("drop_privileges: setuid(%d) failed",
3756 (int) RunAsUid);
3757 rval = EX_OSERR;
3758 }
3759 }
3760 euid = geteuid();
3761 if (RunAsUid != 0 && setuid(0) == 0)
3762 {
3763 /*
3764 ** Believe it or not, the Linux capability model
3765 ** allows a non-root process to override setuid()
3766 ** on a process running as root and prevent that
3767 ** process from dropping privileges.
3768 */
3769
3770 syserr("drop_privileges: setuid(0) succeeded (when it should not)");
3771 rval = EX_OSERR;
3772 }
3773 else if (RunAsUid != euid && setuid(euid) == 0)
3774 {
3775 /*
3776 ** Some operating systems will keep the saved-uid
3777 ** if a non-root effective-uid calls setuid(real-uid)
3778 ** making it possible to set it back again later.
3779 */
3780
3781 syserr("drop_privileges: Unable to drop non-root set-user-ID privileges");
3782 rval = EX_OSERR;
3783 }
3784 }
3785
3786 if ((to_real_uid || RunAsGid != 0) &&
3787 rval == EX_OK && RunAsGid != EffGid &&
3788 getuid() != 0 && geteuid() != 0)
3789 {
3790 errno = 0;
3791 if (setgid(EffGid) == 0)
3792 {
3793 syserr("drop_privileges: setgid(%d) succeeded (when it should not)",
3794 (int) EffGid);
3795 rval = EX_OSERR;
3796 }
3797 }
3798
3799 if (tTd(47, 5))
3800 {
3801 sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n",
3802 (int) geteuid(), (int) getuid(),
3803 (int) getegid(), (int) getgid());
3804 sm_dprintf("drop_privileges: RunAsUser = %d:%d\n",
3805 (int) RunAsUid, (int) RunAsGid);
3806 if (tTd(47, 10))
3807 sm_dprintf("drop_privileges: rval = %d\n", rval);
3808 }
3809 return rval;
3810}
3811/*
3812** FILL_FD -- make sure a file descriptor has been properly allocated
3813**
3814** Used to make sure that stdin/out/err are allocated on startup
3815**
3816** Parameters:
3817** fd -- the file descriptor to be filled.
3818** where -- a string used for logging. If NULL, this is
3819** being called on startup, and logging should
3820** not be done.
3821**
3822** Returns:
3823** none
3824**
3825** Side Effects:
3826** possibly changes MissingFds
3827*/
3828
3829void
3830fill_fd(fd, where)
3831 int fd;
3832 char *where;
3833{
3834 int i;
3835 struct stat stbuf;
3836
3837 if (fstat(fd, &stbuf) >= 0 || errno != EBADF)
3838 return;
3839
3840 if (where != NULL)
3841 syserr("fill_fd: %s: fd %d not open", where, fd);
3842 else
3843 MissingFds |= 1 << fd;
3844 i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666);
3845 if (i < 0)
3846 {
3847 syserr("!fill_fd: %s: cannot open %s",
3848 where == NULL ? "startup" : where, SM_PATH_DEVNULL);
3849 }
3850 if (fd != i)
3851 {
3852 (void) dup2(i, fd);
3853 (void) close(i);
3854 }
3855}
3856/*
3857** SM_PRINTOPTIONS -- print options
3858**
3859** Parameters:
3860** options -- array of options.
3861**
3862** Returns:
3863** none.
3864*/
3865
3866static void
3867sm_printoptions(options)
3868 char **options;
3869{
3870 int ll;
3871 char **av;
3872
3873 av = options;
3874 ll = 7;
3875 while (*av != NULL)
3876 {
3877 if (ll + strlen(*av) > 63)
3878 {
3879 sm_dprintf("\n");
3880 ll = 0;
3881 }
3882 if (ll == 0)
3883 sm_dprintf("\t\t");
3884 else
3885 sm_dprintf(" ");
3886 sm_dprintf("%s", *av);
3887 ll += strlen(*av++) + 1;
3888 }
3889 sm_dprintf("\n");
3890}
3891/*
3892** TESTMODELINE -- process a test mode input line
3893**
3894** Parameters:
3895** line -- the input line.
3896** e -- the current environment.
3897** Syntax:
3898** # a comment
3899** .X process X as a configuration line
3900** =X dump a configuration item (such as mailers)
3901** $X dump a macro or class
3902** /X try an activity
3903** X normal process through rule set X
3904*/
3905
3906static void
3907testmodeline(line, e)
3908 char *line;
3909 ENVELOPE *e;
3910{
3911 register char *p;
3912 char *q;
3913 auto char *delimptr;
3914 int mid;
3915 int i, rs;
3916 STAB *map;
3917 char **s;
3918 struct rewrite *rw;
3919 ADDRESS a;
3920 static int tryflags = RF_COPYNONE;
3921 char exbuf[MAXLINE];
3922 extern unsigned char TokTypeNoC[];
3923
3924 /* skip leading spaces */
3925 while (*line == ' ')
3926 line++;
3927
3928 switch (line[0])
3929 {
3930 case '#':
3931 case '\0':
3932 return;
3933
3934 case '?':
3935 help("-bt", e);
3936 return;
3937
3938 case '.': /* config-style settings */
3939 switch (line[1])
3940 {
3941 case 'D':
3942 mid = macid_parse(&line[2], &delimptr);
3943 if (mid == 0)
3944 return;
3945 translate_dollars(delimptr);
3946 macdefine(&e->e_macro, A_TEMP, mid, delimptr);
3947 break;
3948
3949 case 'C':
3950 if (line[2] == '\0') /* not to call syserr() */
3951 return;
3952
3953 mid = macid_parse(&line[2], &delimptr);
3954 if (mid == 0)
3955 return;
3956 translate_dollars(delimptr);
3957 expand(delimptr, exbuf, sizeof exbuf, e);
3958 p = exbuf;
3959 while (*p != '\0')
3960 {
3961 register char *wd;
3962 char delim;
3963
3964 while (*p != '\0' && isascii(*p) && isspace(*p))
3965 p++;
3966 wd = p;
3967 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
3968 p++;
3969 delim = *p;
3970 *p = '\0';
3971 if (wd[0] != '\0')
3972 setclass(mid, wd);
3973 *p = delim;
3974 }
3975 break;
3976
3977 case '\0':
3978 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3979 "Usage: .[DC]macro value(s)\n");
3980 break;
3981
3982 default:
3983 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3984 "Unknown \".\" command %s\n", line);
3985 break;
3986 }
3987 return;
3988
3989 case '=': /* config-style settings */
3990 switch (line[1])
3991 {
3992 case 'S': /* dump rule set */
3993 rs = strtorwset(&line[2], NULL, ST_FIND);
3994 if (rs < 0)
3995 {
3996 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3997 "Undefined ruleset %s\n", &line[2]);
3998 return;
3999 }
4000 rw = RewriteRules[rs];
4001 if (rw == NULL)
4002 return;
4003 do
4004 {
4005 (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4006 'R');
4007 s = rw->r_lhs;
4008 while (*s != NULL)
4009 {
4010 xputs(smioout, *s++);
4011 (void) sm_io_putc(smioout,
4012 SM_TIME_DEFAULT, ' ');
4013 }
4014 (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4015 '\t');
4016 (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4017 '\t');
4018 s = rw->r_rhs;
4019 while (*s != NULL)
4020 {
4021 xputs(smioout, *s++);
4022 (void) sm_io_putc(smioout,
4023 SM_TIME_DEFAULT, ' ');
4024 }
4025 (void) sm_io_putc(smioout, SM_TIME_DEFAULT,
4026 '\n');
4027 } while ((rw = rw->r_next) != NULL);
4028 break;
4029
4030 case 'M':
4031 for (i = 0; i < MAXMAILERS; i++)
4032 {
4033 if (Mailer[i] != NULL)
4034 printmailer(smioout, Mailer[i]);
4035 }
4036 break;
4037
4038 case '\0':
4039 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4040 "Usage: =Sruleset or =M\n");
4041 break;
4042
4043 default:
4044 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4045 "Unknown \"=\" command %s\n", line);
4046 break;
4047 }
4048 return;
4049
4050 case '-': /* set command-line-like opts */
4051 switch (line[1])
4052 {
4053 case 'd':
4054 tTflag(&line[2]);
4055 break;
4056
4057 case '\0':
4058 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4059 "Usage: -d{debug arguments}\n");
4060 break;
4061
4062 default:
4063 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4064 "Unknown \"-\" command %s\n", line);
4065 break;
4066 }
4067 return;
4068
4069 case '$':
4070 if (line[1] == '=')
4071 {
4072 mid = macid(&line[2]);
4073 if (mid != 0)
4074 stabapply(dump_class, mid);
4075 return;
4076 }
4077 mid = macid(&line[1]);
4078 if (mid == 0)
4079 return;
4080 p = macvalue(mid, e);
4081 if (p == NULL)
4082 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4083 "Undefined\n");
4084 else
4085 {
4086 xputs(smioout, p);
4087 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4088 "\n");
4089 }
4090 return;
4091
4092 case '/': /* miscellaneous commands */
4093 p = &line[strlen(line)];
4094 while (--p >= line && isascii(*p) && isspace(*p))
4095 *p = '\0';
4096 p = strpbrk(line, " \t");
4097 if (p != NULL)
4098 {
4099 while (isascii(*p) && isspace(*p))
4100 *p++ = '\0';
4101 }
4102 else
4103 p = "";
4104 if (line[1] == '\0')
4105 {
4106 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4107 "Usage: /[canon|map|mx|parse|try|tryflags]\n");
4108 return;
4109 }
4110 if (sm_strcasecmp(&line[1], "quit") == 0)
4111 {
4112 CurEnv->e_id = NULL;
4113 finis(true, true, ExitStat);
4114 /* NOTREACHED */
4115 }
4116 if (sm_strcasecmp(&line[1], "mx") == 0)
4117 {
4118#if NAMED_BIND
4119 /* look up MX records */
4120 int nmx;
4121 auto int rcode;
4122 char *mxhosts[MAXMXHOSTS + 1];
4123
4124 if (*p == '\0')
4125 {
4126 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4127 "Usage: /mx address\n");
4128 return;
4129 }
4130 nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true,
4131 NULL);
4132 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4133 "getmxrr(%s) returns %d value(s):\n",
4134 p, nmx);
4135 for (i = 0; i < nmx; i++)
4136 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4137 "\t%s\n", mxhosts[i]);
4138#else /* NAMED_BIND */
4139 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4140 "No MX code compiled in\n");
4141#endif /* NAMED_BIND */
4142 }
4143 else if (sm_strcasecmp(&line[1], "canon") == 0)
4144 {
4145 char host[MAXHOSTNAMELEN];
4146
4147 if (*p == '\0')
4148 {
4149 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4150 "Usage: /canon address\n");
4151 return;
4152 }
4153 else if (sm_strlcpy(host, p, sizeof host) >= sizeof host)
4154 {
4155 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4156 "Name too long\n");
4157 return;
4158 }
4159 (void) getcanonname(host, sizeof host, !HasWildcardMX,
4160 NULL);
4161 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4162 "getcanonname(%s) returns %s\n",
4163 p, host);
4164 }
4165 else if (sm_strcasecmp(&line[1], "map") == 0)
4166 {
4167 auto int rcode = EX_OK;
4168 char *av[2];
4169
4170 if (*p == '\0')
4171 {
4172 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4173 "Usage: /map mapname key\n");
4174 return;
4175 }
4176 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++)
4177 continue;
4178 if (*q == '\0')
4179 {
4180 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4181 "No key specified\n");
4182 return;
4183 }
4184 *q++ = '\0';
4185 map = stab(p, ST_MAP, ST_FIND);
4186 if (map == NULL)
4187 {
4188 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4189 "Map named \"%s\" not found\n", p);
4190 return;
4191 }
4192 if (!bitset(MF_OPEN, map->s_map.map_mflags) &&
4193 !openmap(&(map->s_map)))
4194 {
4195 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4196 "Map named \"%s\" not open\n", p);
4197 return;
4198 }
4199 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4200 "map_lookup: %s (%s) ", p, q);
4201 av[0] = q;
4202 av[1] = NULL;
4203 p = (*map->s_map.map_class->map_lookup)
4204 (&map->s_map, q, av, &rcode);
4205 if (p == NULL)
4206 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4207 "no match (%d)\n",
4208 rcode);
4209 else
4210 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4211 "returns %s (%d)\n", p,
4212 rcode);
4213 }
4214 else if (sm_strcasecmp(&line[1], "try") == 0)
4215 {
4216 MAILER *m;
4217 STAB *st;
4218 auto int rcode = EX_OK;
4219
4220 q = strpbrk(p, " \t");
4221 if (q != NULL)
4222 {
4223 while (isascii(*q) && isspace(*q))
4224 *q++ = '\0';
4225 }
4226 if (q == NULL || *q == '\0')
4227 {
4228 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4229 "Usage: /try mailer address\n");
4230 return;
4231 }
4232 st = stab(p, ST_MAILER, ST_FIND);
4233 if (st == NULL)
4234 {
4235 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4236 "Unknown mailer %s\n", p);
4237 return;
4238 }
4239 m = st->s_mailer;
4240 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4241 "Trying %s %s address %s for mailer %s\n",
4242 bitset(RF_HEADERADDR, tryflags) ? "header"
4243 : "envelope",
4244 bitset(RF_SENDERADDR, tryflags) ? "sender"
4245 : "recipient", q, p);
4246 p = remotename(q, m, tryflags, &rcode, CurEnv);
4247 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4248 "Rcode = %d, addr = %s\n",
4249 rcode, p == NULL ? "<NULL>" : p);
4250 e->e_to = NULL;
4251 }
4252 else if (sm_strcasecmp(&line[1], "tryflags") == 0)
4253 {
4254 if (*p == '\0')
4255 {
4256 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4257 "Usage: /tryflags [Hh|Ee][Ss|Rr]\n");
4258 return;
4259 }
4260 for (; *p != '\0'; p++)
4261 {
4262 switch (*p)
4263 {
4264 case 'H':
4265 case 'h':
4266 tryflags |= RF_HEADERADDR;
4267 break;
4268
4269 case 'E':
4270 case 'e':
4271 tryflags &= ~RF_HEADERADDR;
4272 break;
4273
4274 case 'S':
4275 case 's':
4276 tryflags |= RF_SENDERADDR;
4277 break;
4278
4279 case 'R':
4280 case 'r':
4281 tryflags &= ~RF_SENDERADDR;
4282 break;
4283 }
4284 }
4285 exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e';
4286 exbuf[1] = ' ';
4287 exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r';
4288 exbuf[3] = '\0';
4289 macdefine(&e->e_macro, A_TEMP,
4290 macid("{addr_type}"), exbuf);
4291 }
4292 else if (sm_strcasecmp(&line[1], "parse") == 0)
4293 {
4294 if (*p == '\0')
4295 {
4296 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4297 "Usage: /parse address\n");
4298 return;
4299 }
4300 q = crackaddr(p, e);
4301 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4302 "Cracked address = ");
4303 xputs(smioout, q);
4304 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4305 "\nParsing %s %s address\n",
4306 bitset(RF_HEADERADDR, tryflags) ?
4307 "header" : "envelope",
4308 bitset(RF_SENDERADDR, tryflags) ?
4309 "sender" : "recipient");
4310 if (parseaddr(p, &a, tryflags, '\0', NULL, e, true)
4311 == NULL)
4312 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4313 "Cannot parse\n");
4314 else if (a.q_host != NULL && a.q_host[0] != '\0')
4315 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4316 "mailer %s, host %s, user %s\n",
4317 a.q_mailer->m_name,
4318 a.q_host,
4319 a.q_user);
4320 else
4321 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4322 "mailer %s, user %s\n",
4323 a.q_mailer->m_name,
4324 a.q_user);
4325 e->e_to = NULL;
4326 }
4327 else
4328 {
4329 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4330 "Unknown \"/\" command %s\n",
4331 line);
4332 }
4333 return;
4334 }
4335
4336 for (p = line; isascii(*p) && isspace(*p); p++)
4337 continue;
4338 q = p;
4339 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4340 p++;
4341 if (*p == '\0')
4342 {
4343 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4344 "No address!\n");
4345 return;
4346 }
4347 *p = '\0';
4348 if (invalidaddr(p + 1, NULL, true))
4349 return;
4350 do
4351 {
4352 register char **pvp;
4353 char pvpbuf[PSBUFSIZE];
4354
4355 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, &delimptr,
4356 ConfigLevel >= 9 ? TokTypeNoC : NULL, false);
4357 if (pvp == NULL)
4358 continue;
4359 p = q;
4360 while (*p != '\0')
4361 {
4362 int status;
4363
4364 rs = strtorwset(p, NULL, ST_FIND);
4365 if (rs < 0)
4366 {
4367 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4368 "Undefined ruleset %s\n",
4369 p);
4370 break;
4371 }
4372 status = REWRITE(pvp, rs, e);
4373 if (status != EX_OK)
4374 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4375 "== Ruleset %s (%d) status %d\n",
4376 p, rs, status);
4377 while (*p != '\0' && *p++ != ',')
4378 continue;
4379 }
4380 } while (*(p = delimptr) != '\0');
4381}
4382
4383static void
4384dump_class(s, id)
4385 register STAB *s;
4386 int id;
4387{
4388 if (s->s_symtype != ST_CLASS)
4389 return;
4390 if (bitnset(bitidx(id), s->s_class))
4391 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4392 "%s\n", s->s_name);
4393}
4394
4395/*
4396** An exception type used to create QuickAbort exceptions.
4397** This is my first cut at converting QuickAbort from longjmp to exceptions.
4398** These exceptions have a single integer argument, which is the argument
4399** to longjmp in the original code (either 1 or 2). I don't know the
4400** significance of 1 vs 2: the calls to setjmp don't care.
4401*/
4402
4403const SM_EXC_TYPE_T EtypeQuickAbort =
4404{
4405 SmExcTypeMagic,
4406 "E:mta.quickabort",
4407 "i",
4408 sm_etype_printf,
4409 "quick abort %0",
4410};