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