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