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