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