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