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