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