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