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