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 2006/04/21 23:56:42 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 if (!run_in_foreground && !tTd(99, 100)) 2302 { 2303 /* put us in background */ 2304 i = fork(); 2305 if (i < 0) 2306 syserr("daemon: cannot fork"); 2307 if (i != 0) 2308 { 2309 finis(false, true, EX_OK); 2310 /* NOTREACHED */ 2311 } 2312 2313 /* 2314 ** Initialize exception stack and default exception 2315 ** handler for child process. 2316 */ 2317 2318 /* Reset global flags */ 2319 RestartRequest = NULL; 2320 RestartWorkGroup = false; 2321 ShutdownRequest = NULL; 2322 PendingSignal = 0; 2323 CurrentPid = getpid(); 2324 2325 sm_exc_newthread(fatal_error); 2326 2327 /* disconnect from our controlling tty */ 2328 disconnect(2, &MainEnvelope); 2329 } 2330 2331 dtype[0] = '\0'; 2332 if (OpMode == MD_DAEMON) 2333 (void) sm_strlcat(dtype, "+SMTP", sizeof dtype); 2334 if (QueueIntvl > 0) 2335 { 2336 (void) sm_strlcat2(dtype, 2337 queuepersistent 2338 ? "+persistent-queueing@" 2339 : "+queueing@", 2340 pintvl(QueueIntvl, true), 2341 sizeof dtype); 2342 } 2343 if (tTd(0, 1)) 2344 (void) sm_strlcat(dtype, "+debugging", sizeof dtype); 2345 2346 sm_syslog(LOG_INFO, NOQID, 2347 "starting daemon (%s): %s", Version, dtype + 1); 2348 #if XLA 2349 xla_create_file(); 2350 #endif /* XLA */ 2351 2352 /* save daemon type in a macro for possible PidFile use */ 2353 macdefine(&BlankEnvelope.e_macro, A_TEMP, 2354 macid("{daemon_info}"), dtype + 1); 2355 2356 /* save queue interval in a macro for possible PidFile use */ 2357 macdefine(&MainEnvelope.e_macro, A_TEMP, 2358 macid("{queue_interval}"), pintvl(QueueIntvl, true)); 2359 2360 /* workaround: can't seem to release the signal in the parent */ 2361 (void) sm_signal(SIGHUP, sighup); 2362 (void) sm_releasesignal(SIGHUP); 2363 (void) sm_signal(SIGTERM, sigterm); 2364 2365 if (QueueIntvl > 0) 2366 { 2367 (void) runqueue(true, false, queuepersistent, true); 2368 2369 /* 2370 ** If queuepersistent but not in daemon mode then 2371 ** we're going to do the queue runner monitoring here. 2372 ** If in daemon mode then the monitoring will happen 2373 ** elsewhere. 2374 */ 2375 2376 if (OpMode != MD_DAEMON && queuepersistent) 2377 { 2378 /* 2379 ** Write the pid to file 2380 ** XXX Overwrites sendmail.pid 2381 */ 2382 2383 log_sendmail_pid(&MainEnvelope); 2384 2385 /* set the title to make it easier to find */ 2386 sm_setproctitle(true, CurEnv, "Queue control"); 2387 (void) sm_signal(SIGCHLD, SIG_DFL); 2388 while (CurChildren > 0) 2389 { 2390 int status; 2391 pid_t ret; 2392 int group; 2393 2394 CHECK_RESTART; 2395 errno = 0; 2396 while ((ret = sm_wait(&status)) <= 0) 2397 { 2398 /* 2399 ** Waiting for non-existent 2400 ** children shouldn't happen. 2401 ** Let's get out of here if 2402 ** it occurs. 2403 */ 2404 2405 if (errno == ECHILD) 2406 { 2407 CurChildren = 0; 2408 break; 2409 } 2410 continue; 2411 } 2412 2413 /* something is really really wrong */ 2414 if (errno == ECHILD) 2415 { 2416 sm_syslog(LOG_ERR, NOQID, 2417 "persistent queue runner control process: lost all children: wait returned ECHILD"); 2418 break; 2419 } 2420 2421 if (WIFSTOPPED(status)) 2422 continue; 2423 2424 /* Probe only on a child status */ 2425 proc_list_drop(ret, status, &group); 2426 2427 if (WIFSIGNALED(status)) 2428 { 2429 if (WCOREDUMP(status)) 2430 { 2431 sm_syslog(LOG_ERR, NOQID, 2432 "persistent queue runner=%d core dumped, signal=%d", 2433 group, WTERMSIG(status)); 2434 2435 /* don't restart this */ 2436 mark_work_group_restart( 2437 group, -1); 2438 continue; 2439 } 2440 2441 sm_syslog(LOG_ERR, NOQID, 2442 "persistent queue runner=%d died, signal=%d", 2443 group, WTERMSIG(status)); 2444 } 2445 2446 /* 2447 ** When debugging active, don't 2448 ** restart the persistent queues. 2449 ** But do log this as info. 2450 */ 2451 2452 if (sm_debug_active(&DebugNoPRestart, 2453 1)) 2454 { 2455 sm_syslog(LOG_DEBUG, NOQID, 2456 "persistent queue runner=%d, exited", 2457 group); 2458 mark_work_group_restart(group, 2459 -1); 2460 } 2461 } 2462 finis(true, true, ExitStat); 2463 /* NOTREACHED */ 2464 } 2465 2466 if (OpMode != MD_DAEMON) 2467 { 2468 char qtype[200]; 2469 2470 /* 2471 ** Write the pid to file 2472 ** XXX Overwrites sendmail.pid 2473 */ 2474 2475 log_sendmail_pid(&MainEnvelope); 2476 2477 /* set the title to make it easier to find */ 2478 qtype[0] = '\0'; 2479 (void) sm_strlcpyn(qtype, sizeof qtype, 4, 2480 "Queue runner@", 2481 pintvl(QueueIntvl, true), 2482 " for ", 2483 QueueDir); 2484 sm_setproctitle(true, CurEnv, qtype); 2485 for (;;) 2486 { 2487 (void) pause(); 2488 2489 CHECK_RESTART; 2490 2491 if (doqueuerun()) 2492 (void) runqueue(true, false, 2493 false, false); 2494 } 2495 } 2496 } 2497 dropenvelope(&MainEnvelope, true, false); 2498 2499 #if STARTTLS 2500 /* init TLS for server, ignore result for now */ 2501 (void) initsrvtls(tls_ok); 2502 #endif /* STARTTLS */ 2503 2504 nextreq: 2505 p_flags = getrequests(&MainEnvelope); 2506 2507 /* drop privileges */ 2508 (void) drop_privileges(false); 2509 2510 /* 2511 ** Get authentication data 2512 ** Set _ macro in BlankEnvelope before calling newenvelope(). 2513 */ 2514 2515 authinfo = getauthinfo(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 2516 NULL), &forged); 2517 macdefine(&BlankEnvelope.e_macro, A_TEMP, '_', authinfo); 2518 2519 /* at this point we are in a child: reset state */ 2520 sm_rpool_free(MainEnvelope.e_rpool); 2521 (void) newenvelope(&MainEnvelope, &MainEnvelope, 2522 sm_rpool_new_x(NULL)); 2523 } 2524 2525 if (LogLevel > 9) 2526 { 2527 /* log connection information */ 2528 sm_syslog(LOG_INFO, NULL, "connect from %s", authinfo); 2529 } 2530 2531 /* 2532 ** If running SMTP protocol, start collecting and executing 2533 ** commands. This will never return. 2534 */ 2535 2536 if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 2537 { 2538 char pbuf[20]; 2539 2540 /* 2541 ** Save some macros for check_* rulesets. 2542 */ 2543 2544 if (forged) 2545 { 2546 char ipbuf[103]; 2547 2548 (void) sm_snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 2549 anynet_ntoa(&RealHostAddr)); 2550 macdefine(&BlankEnvelope.e_macro, A_TEMP, 2551 macid("{client_name}"), ipbuf); 2552 } 2553 else 2554 macdefine(&BlankEnvelope.e_macro, A_PERM, 2555 macid("{client_name}"), RealHostName); 2556 macdefine(&BlankEnvelope.e_macro, A_PERM, 2557 macid("{client_ptr}"), RealHostName); 2558 macdefine(&BlankEnvelope.e_macro, A_TEMP, 2559 macid("{client_addr}"), anynet_ntoa(&RealHostAddr)); 2560 sm_getla(); 2561 2562 switch (RealHostAddr.sa.sa_family) 2563 { 2564 #if NETINET 2565 case AF_INET: 2566 (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 2567 RealHostAddr.sin.sin_port); 2568 break; 2569 #endif /* NETINET */ 2570 #if NETINET6 2571 case AF_INET6: 2572 (void) sm_snprintf(pbuf, sizeof pbuf, "%d", 2573 RealHostAddr.sin6.sin6_port); 2574 break; 2575 #endif /* NETINET6 */ 2576 default: 2577 (void) sm_snprintf(pbuf, sizeof pbuf, "0"); 2578 break; 2579 } 2580 macdefine(&BlankEnvelope.e_macro, A_TEMP, 2581 macid("{client_port}"), pbuf); 2582 2583 if (OpMode == MD_DAEMON) 2584 { 2585 /* validate the connection */ 2586 HoldErrs = true; 2587 nullserver = validate_connection(&RealHostAddr, 2588 macvalue(macid("{client_name}"), 2589 &MainEnvelope), 2590 &MainEnvelope); 2591 HoldErrs = false; 2592 } 2593 else if (p_flags == NULL) 2594 { 2595 p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); 2596 clrbitmap(p_flags); 2597 } 2598 #if STARTTLS 2599 if (OpMode == MD_SMTP) 2600 (void) initsrvtls(tls_ok); 2601 #endif /* STARTTLS */ 2602 2603 /* turn off profiling */ 2604 SM_PROF(1); 2605 smtp(nullserver, *p_flags, &MainEnvelope); 2606 2607 if (tTd(93, 100)) 2608 { 2609 /* turn off profiling */ 2610 SM_PROF(0); 2611 if (OpMode == MD_DAEMON) 2612 goto nextreq; 2613 } 2614 } 2615 2616 sm_rpool_free(MainEnvelope.e_rpool); 2617 clearenvelope(&MainEnvelope, false, sm_rpool_new_x(NULL)); 2618 if (OpMode == MD_VERIFY) 2619 { 2620 set_delivery_mode(SM_VERIFY, &MainEnvelope); 2621 PostMasterCopy = NULL; 2622 } 2623 else 2624 { 2625 /* interactive -- all errors are global */ 2626 MainEnvelope.e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 2627 } 2628 2629 /* 2630 ** Do basic system initialization and set the sender 2631 */ 2632 2633 initsys(&MainEnvelope); 2634 macdefine(&MainEnvelope.e_macro, A_PERM, macid("{ntries}"), "0"); 2635 macdefine(&MainEnvelope.e_macro, A_PERM, macid("{nrcpts}"), "0"); 2636 setsender(from, &MainEnvelope, NULL, '\0', false); 2637 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 2638 (!bitnset(M_LOCALMAILER, MainEnvelope.e_from.q_mailer->m_flags) || 2639 strcmp(MainEnvelope.e_from.q_user, RealUserName) != 0)) 2640 { 2641 auth_warning(&MainEnvelope, "%s set sender to %s using -%c", 2642 RealUserName, from, warn_f_flag); 2643 #if SASL 2644 auth = false; 2645 #endif /* SASL */ 2646 } 2647 if (auth) 2648 { 2649 char *fv; 2650 2651 /* set the initial sender for AUTH= to $f@$j */ 2652 fv = macvalue('f', &MainEnvelope); 2653 if (fv == NULL || *fv == '\0') 2654 MainEnvelope.e_auth_param = NULL; 2655 else 2656 { 2657 if (strchr(fv, '@') == NULL) 2658 { 2659 i = strlen(fv) + strlen(macvalue('j', 2660 &MainEnvelope)) + 2; 2661 p = sm_malloc_x(i); 2662 (void) sm_strlcpyn(p, i, 3, fv, "@", 2663 macvalue('j', 2664 &MainEnvelope)); 2665 } 2666 else 2667 p = sm_strdup_x(fv); 2668 MainEnvelope.e_auth_param = sm_rpool_strdup_x(MainEnvelope.e_rpool, 2669 xtextify(p, "=")); 2670 sm_free(p); /* XXX */ 2671 } 2672 } 2673 if (macvalue('s', &MainEnvelope) == NULL) 2674 macdefine(&MainEnvelope.e_macro, A_PERM, 's', RealHostName); 2675 2676 av = argv + optind; 2677 if (*av == NULL && !GrabTo) 2678 { 2679 MainEnvelope.e_to = NULL; 2680 MainEnvelope.e_flags |= EF_GLOBALERRS; 2681 HoldErrs = false; 2682 SuperSafe = SAFE_NO; 2683 usrerr("Recipient names must be specified"); 2684 2685 /* collect body for UUCP return */ 2686 if (OpMode != MD_VERIFY) 2687 collect(InChannel, false, NULL, &MainEnvelope, true); 2688 finis(true, true, EX_USAGE); 2689 /* NOTREACHED */ 2690 } 2691 2692 /* 2693 ** Scan argv and deliver the message to everyone. 2694 */ 2695 2696 save_val = LogUsrErrs; 2697 LogUsrErrs = true; 2698 sendtoargv(av, &MainEnvelope); 2699 LogUsrErrs = save_val; 2700 2701 /* if we have had errors sofar, arrange a meaningful exit stat */ 2702 if (Errors > 0 && ExitStat == EX_OK) 2703 ExitStat = EX_USAGE; 2704 2705 #if _FFR_FIX_DASHT 2706 /* 2707 ** If using -t, force not sending to argv recipients, even 2708 ** if they are mentioned in the headers. 2709 */ 2710 2711 if (GrabTo) 2712 { 2713 ADDRESS *q; 2714 2715 for (q = MainEnvelope.e_sendqueue; q != NULL; q = q->q_next) 2716 q->q_state = QS_REMOVED; 2717 } 2718 #endif /* _FFR_FIX_DASHT */ 2719 2720 /* 2721 ** Read the input mail. 2722 */ 2723 2724 MainEnvelope.e_to = NULL; 2725 if (OpMode != MD_VERIFY || GrabTo) 2726 { 2727 int savederrors; 2728 unsigned long savedflags; 2729 2730 /* 2731 ** workaround for compiler warning on Irix: 2732 ** do not initialize variable in the definition, but 2733 ** later on: 2734 ** warning(1548): transfer of control bypasses 2735 ** initialization of: 2736 ** variable "savederrors" (declared at line 2570) 2737 ** variable "savedflags" (declared at line 2571) 2738 ** goto giveup; 2739 */ 2740 2741 savederrors = Errors; 2742 savedflags = MainEnvelope.e_flags & EF_FATALERRS; 2743 MainEnvelope.e_flags |= EF_GLOBALERRS; 2744 MainEnvelope.e_flags &= ~EF_FATALERRS; 2745 Errors = 0; 2746 buffer_errors(); 2747 collect(InChannel, false, NULL, &MainEnvelope, true); 2748 2749 /* header checks failed */ 2750 if (Errors > 0) 2751 { 2752 giveup: 2753 if (!GrabTo) 2754 { 2755 /* Log who the mail would have gone to */ 2756 logundelrcpts(&MainEnvelope, 2757 MainEnvelope.e_message, 2758 8, false); 2759 } 2760 flush_errors(true); 2761 finis(true, true, ExitStat); 2762 /* NOTREACHED */ 2763 return -1; 2764 } 2765 2766 /* bail out if message too large */ 2767 if (bitset(EF_CLRQUEUE, MainEnvelope.e_flags)) 2768 { 2769 finis(true, true, ExitStat != EX_OK ? ExitStat 2770 : EX_DATAERR); 2771 /* NOTREACHED */ 2772 return -1; 2773 } 2774 2775 /* set message size */ 2776 (void) sm_snprintf(buf, sizeof buf, "%ld", 2777 MainEnvelope.e_msgsize); 2778 macdefine(&MainEnvelope.e_macro, A_TEMP, 2779 macid("{msg_size}"), buf); 2780 2781 Errors = savederrors; 2782 MainEnvelope.e_flags |= savedflags; 2783 } 2784 errno = 0; 2785 2786 if (tTd(1, 1)) 2787 sm_dprintf("From person = \"%s\"\n", 2788 MainEnvelope.e_from.q_paddr); 2789 2790 /* Check if quarantining stats should be updated */ 2791 if (MainEnvelope.e_quarmsg != NULL) 2792 markstats(&MainEnvelope, NULL, STATS_QUARANTINE); 2793 2794 /* 2795 ** Actually send everything. 2796 ** If verifying, just ack. 2797 */ 2798 2799 if (Errors == 0) 2800 { 2801 if (!split_by_recipient(&MainEnvelope) && 2802 bitset(EF_FATALERRS, MainEnvelope.e_flags)) 2803 goto giveup; 2804 } 2805 2806 /* make sure we deliver at least the first envelope */ 2807 i = FastSplit > 0 ? 0 : -1; 2808 for (e = &MainEnvelope; e != NULL; e = e->e_sibling, i++) 2809 { 2810 ENVELOPE *next; 2811 2812 e->e_from.q_state = QS_SENDER; 2813 if (tTd(1, 5)) 2814 { 2815 sm_dprintf("main[%d]: QS_SENDER ", i); 2816 printaddr(sm_debug_file(), &e->e_from, false); 2817 } 2818 e->e_to = NULL; 2819 sm_getla(); 2820 GrabTo = false; 2821 #if NAMED_BIND 2822 _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 2823 _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 2824 #endif /* NAMED_BIND */ 2825 next = e->e_sibling; 2826 e->e_sibling = NULL; 2827 2828 /* after FastSplit envelopes: queue up */ 2829 sendall(e, i >= FastSplit ? SM_QUEUE : SM_DEFAULT); 2830 e->e_sibling = next; 2831 } 2832 2833 /* 2834 ** All done. 2835 ** Don't send return error message if in VERIFY mode. 2836 */ 2837 2838 finis(true, true, ExitStat); 2839 /* NOTREACHED */ 2840 return ExitStat; 2841 } 2842 /* 2843 ** STOP_SENDMAIL -- Stop the running program 2844 ** 2845 ** Parameters: 2846 ** none. 2847 ** 2848 ** Returns: 2849 ** none. 2850 ** 2851 ** Side Effects: 2852 ** exits. 2853 */ 2854 2855 void 2856 stop_sendmail() 2857 { 2858 /* reset uid for process accounting */ 2859 endpwent(); 2860 (void) setuid(RealUid); 2861 exit(EX_OK); 2862 } 2863 /* 2864 ** FINIS -- Clean up and exit. 2865 ** 2866 ** Parameters: 2867 ** drop -- whether or not to drop CurEnv envelope 2868 ** cleanup -- call exit() or _exit()? 2869 ** exitstat -- exit status to use for exit() call 2870 ** 2871 ** Returns: 2872 ** never 2873 ** 2874 ** Side Effects: 2875 ** exits sendmail 2876 */ 2877 2878 void 2879 finis(drop, cleanup, exitstat) 2880 bool drop; 2881 bool cleanup; 2882 volatile int exitstat; 2883 { 2884 char pidpath[MAXPATHLEN]; 2885 pid_t pid; 2886 2887 /* Still want to process new timeouts added below */ 2888 sm_clear_events(); 2889 (void) sm_releasesignal(SIGALRM); 2890 2891 if (tTd(2, 1)) 2892 { 2893 sm_dprintf("\n====finis: stat %d e_id=%s e_flags=", 2894 exitstat, 2895 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 2896 printenvflags(CurEnv); 2897 } 2898 if (tTd(2, 9)) 2899 printopenfds(false); 2900 2901 SM_TRY 2902 /* 2903 ** Clean up. This might raise E:mta.quickabort 2904 */ 2905 2906 /* clean up temp files */ 2907 CurEnv->e_to = NULL; 2908 if (drop) 2909 { 2910 if (CurEnv->e_id != NULL) 2911 { 2912 dropenvelope(CurEnv, true, false); 2913 sm_rpool_free(CurEnv->e_rpool); 2914 CurEnv->e_rpool = NULL; 2915 } 2916 else 2917 poststats(StatFile); 2918 } 2919 2920 /* flush any cached connections */ 2921 mci_flush(true, NULL); 2922 2923 /* close maps belonging to this pid */ 2924 closemaps(false); 2925 2926 #if USERDB 2927 /* close UserDatabase */ 2928 _udbx_close(); 2929 #endif /* USERDB */ 2930 2931 #if SASL 2932 stop_sasl_client(); 2933 #endif /* SASL */ 2934 2935 #if XLA 2936 /* clean up extended load average stuff */ 2937 xla_all_end(); 2938 #endif /* XLA */ 2939 2940 SM_FINALLY 2941 /* 2942 ** And exit. 2943 */ 2944 2945 if (LogLevel > 78) 2946 sm_syslog(LOG_DEBUG, CurEnv->e_id, "finis, pid=%d", 2947 (int) CurrentPid); 2948 if (exitstat == EX_TEMPFAIL || 2949 CurEnv->e_errormode == EM_BERKNET) 2950 exitstat = EX_OK; 2951 2952 /* XXX clean up queues and related data structures */ 2953 cleanup_queues(); 2954 pid = getpid(); 2955 #if SM_CONF_SHM 2956 cleanup_shm(DaemonPid == pid); 2957 #endif /* SM_CONF_SHM */ 2958 2959 /* close locked pid file */ 2960 close_sendmail_pid(); 2961 2962 if (DaemonPid == pid || PidFilePid == pid) 2963 { 2964 /* blow away the pid file */ 2965 expand(PidFile, pidpath, sizeof pidpath, CurEnv); 2966 (void) unlink(pidpath); 2967 } 2968 2969 /* reset uid for process accounting */ 2970 endpwent(); 2971 sm_mbdb_terminate(); 2972 #if _FFR_MEMSTAT 2973 (void) sm_memstat_close(); 2974 #endif /* _FFR_MEMSTAT */ 2975 (void) setuid(RealUid); 2976 #if SM_HEAP_CHECK 2977 /* dump the heap, if we are checking for memory leaks */ 2978 if (sm_debug_active(&SmHeapCheck, 2)) 2979 sm_heap_report(smioout, 2980 sm_debug_level(&SmHeapCheck) - 1); 2981 #endif /* SM_HEAP_CHECK */ 2982 if (sm_debug_active(&SmXtrapReport, 1)) 2983 sm_dprintf("xtrap count = %d\n", SmXtrapCount); 2984 if (cleanup) 2985 exit(exitstat); 2986 else 2987 _exit(exitstat); 2988 SM_END_TRY 2989 } 2990 /* 2991 ** INTINDEBUG -- signal handler for SIGINT in -bt mode 2992 ** 2993 ** Parameters: 2994 ** sig -- incoming signal. 2995 ** 2996 ** Returns: 2997 ** none. 2998 ** 2999 ** Side Effects: 3000 ** longjmps back to test mode loop. 3001 ** 3002 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3003 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3004 ** DOING. 3005 */ 3006 3007 /* Type of an exception generated on SIGINT during address test mode. */ 3008 static const SM_EXC_TYPE_T EtypeInterrupt = 3009 { 3010 SmExcTypeMagic, 3011 "S:mta.interrupt", 3012 "", 3013 sm_etype_printf, 3014 "interrupt", 3015 }; 3016 3017 /* ARGSUSED */ 3018 static SIGFUNC_DECL 3019 intindebug(sig) 3020 int sig; 3021 { 3022 int save_errno = errno; 3023 3024 FIX_SYSV_SIGNAL(sig, intindebug); 3025 errno = save_errno; 3026 CHECK_CRITICAL(sig); 3027 errno = save_errno; 3028 sm_exc_raisenew_x(&EtypeInterrupt); 3029 errno = save_errno; 3030 return SIGFUNC_RETURN; 3031 } 3032 /* 3033 ** SIGTERM -- SIGTERM handler for the daemon 3034 ** 3035 ** Parameters: 3036 ** sig -- signal number. 3037 ** 3038 ** Returns: 3039 ** none. 3040 ** 3041 ** Side Effects: 3042 ** Sets ShutdownRequest which will hopefully trigger 3043 ** the daemon to exit. 3044 ** 3045 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3046 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3047 ** DOING. 3048 */ 3049 3050 /* ARGSUSED */ 3051 static SIGFUNC_DECL 3052 sigterm(sig) 3053 int sig; 3054 { 3055 int save_errno = errno; 3056 3057 FIX_SYSV_SIGNAL(sig, sigterm); 3058 ShutdownRequest = "signal"; 3059 errno = save_errno; 3060 return SIGFUNC_RETURN; 3061 } 3062 /* 3063 ** SIGHUP -- handle a SIGHUP signal 3064 ** 3065 ** Parameters: 3066 ** sig -- incoming signal. 3067 ** 3068 ** Returns: 3069 ** none. 3070 ** 3071 ** Side Effects: 3072 ** Sets RestartRequest which should cause the daemon 3073 ** to restart. 3074 ** 3075 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3076 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3077 ** DOING. 3078 */ 3079 3080 /* ARGSUSED */ 3081 static SIGFUNC_DECL 3082 sighup(sig) 3083 int sig; 3084 { 3085 int save_errno = errno; 3086 3087 FIX_SYSV_SIGNAL(sig, sighup); 3088 RestartRequest = "signal"; 3089 errno = save_errno; 3090 return SIGFUNC_RETURN; 3091 } 3092 /* 3093 ** SIGPIPE -- signal handler for SIGPIPE 3094 ** 3095 ** Parameters: 3096 ** sig -- incoming signal. 3097 ** 3098 ** Returns: 3099 ** none. 3100 ** 3101 ** Side Effects: 3102 ** Sets StopRequest which should cause the mailq/hoststatus 3103 ** display to stop. 3104 ** 3105 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3106 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3107 ** DOING. 3108 */ 3109 3110 /* ARGSUSED */ 3111 static SIGFUNC_DECL 3112 sigpipe(sig) 3113 int sig; 3114 { 3115 int save_errno = errno; 3116 3117 FIX_SYSV_SIGNAL(sig, sigpipe); 3118 StopRequest = true; 3119 errno = save_errno; 3120 return SIGFUNC_RETURN; 3121 } 3122 /* 3123 ** INTSIG -- clean up on interrupt 3124 ** 3125 ** This just arranges to exit. It pessimizes in that it 3126 ** may resend a message. 3127 ** 3128 ** Parameters: 3129 ** none. 3130 ** 3131 ** Returns: 3132 ** none. 3133 ** 3134 ** Side Effects: 3135 ** Unlocks the current job. 3136 ** 3137 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3138 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3139 ** DOING. 3140 ** 3141 ** XXX: More work is needed for this signal handler. 3142 */ 3143 3144 /* ARGSUSED */ 3145 SIGFUNC_DECL 3146 intsig(sig) 3147 int sig; 3148 { 3149 bool drop = false; 3150 int save_errno = errno; 3151 3152 FIX_SYSV_SIGNAL(sig, intsig); 3153 errno = save_errno; 3154 CHECK_CRITICAL(sig); 3155 sm_allsignals(true); 3156 3157 if (sig != 0 && LogLevel > 79) 3158 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 3159 FileName = NULL; 3160 3161 /* Clean-up on aborted stdin message submission */ 3162 if (CurEnv->e_id != NULL && 3163 (OpMode == MD_SMTP || 3164 OpMode == MD_DELIVER || 3165 OpMode == MD_ARPAFTP)) 3166 { 3167 register ADDRESS *q; 3168 3169 /* don't return an error indication */ 3170 CurEnv->e_to = NULL; 3171 CurEnv->e_flags &= ~EF_FATALERRS; 3172 CurEnv->e_flags |= EF_CLRQUEUE; 3173 3174 /* 3175 ** Spin through the addresses and 3176 ** mark them dead to prevent bounces 3177 */ 3178 3179 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 3180 q->q_state = QS_DONTSEND; 3181 3182 drop = true; 3183 } 3184 else if (OpMode != MD_TEST) 3185 { 3186 unlockqueue(CurEnv); 3187 } 3188 3189 finis(drop, false, EX_OK); 3190 /* NOTREACHED */ 3191 } 3192 /* 3193 ** DISCONNECT -- remove our connection with any foreground process 3194 ** 3195 ** Parameters: 3196 ** droplev -- how "deeply" we should drop the line. 3197 ** 0 -- ignore signals, mail back errors, make sure 3198 ** output goes to stdout. 3199 ** 1 -- also, make stdout go to /dev/null. 3200 ** 2 -- also, disconnect from controlling terminal 3201 ** (only for daemon mode). 3202 ** e -- the current envelope. 3203 ** 3204 ** Returns: 3205 ** none 3206 ** 3207 ** Side Effects: 3208 ** Trys to insure that we are immune to vagaries of 3209 ** the controlling tty. 3210 */ 3211 3212 void 3213 disconnect(droplev, e) 3214 int droplev; 3215 register ENVELOPE *e; 3216 { 3217 int fd; 3218 3219 if (tTd(52, 1)) 3220 sm_dprintf("disconnect: In %d Out %d, e=%p\n", 3221 sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL), 3222 sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL), e); 3223 if (tTd(52, 100)) 3224 { 3225 sm_dprintf("don't\n"); 3226 return; 3227 } 3228 if (LogLevel > 93) 3229 sm_syslog(LOG_DEBUG, e->e_id, 3230 "disconnect level %d", 3231 droplev); 3232 3233 /* be sure we don't get nasty signals */ 3234 (void) sm_signal(SIGINT, SIG_IGN); 3235 (void) sm_signal(SIGQUIT, SIG_IGN); 3236 3237 /* we can't communicate with our caller, so.... */ 3238 HoldErrs = true; 3239 CurEnv->e_errormode = EM_MAIL; 3240 Verbose = 0; 3241 DisConnected = true; 3242 3243 /* all input from /dev/null */ 3244 if (InChannel != smioin) 3245 { 3246 (void) sm_io_close(InChannel, SM_TIME_DEFAULT); 3247 InChannel = smioin; 3248 } 3249 if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 3250 SM_IO_RDONLY, NULL, smioin) == NULL) 3251 sm_syslog(LOG_ERR, e->e_id, 3252 "disconnect: sm_io_reopen(\"%s\") failed: %s", 3253 SM_PATH_DEVNULL, sm_errstring(errno)); 3254 3255 /* 3256 ** output to the transcript 3257 ** We also compare the fd numbers here since OutChannel 3258 ** might be a layer on top of smioout due to encryption 3259 ** (see sfsasl.c). 3260 */ 3261 3262 if (OutChannel != smioout && 3263 sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL) != 3264 sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL)) 3265 { 3266 (void) sm_io_close(OutChannel, SM_TIME_DEFAULT); 3267 OutChannel = smioout; 3268 3269 #if 0 3270 /* 3271 ** Has smioout been closed? Reopen it. 3272 ** This shouldn't happen anymore, the code is here 3273 ** just as a reminder. 3274 */ 3275 3276 if (smioout->sm_magic == NULL && 3277 sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL, 3278 SM_IO_WRONLY, NULL, smioout) == NULL) 3279 sm_syslog(LOG_ERR, e->e_id, 3280 "disconnect: sm_io_reopen(\"%s\") failed: %s", 3281 SM_PATH_DEVNULL, sm_errstring(errno)); 3282 #endif /* 0 */ 3283 } 3284 if (droplev > 0) 3285 { 3286 fd = open(SM_PATH_DEVNULL, O_WRONLY, 0666); 3287 if (fd == -1) 3288 { 3289 sm_syslog(LOG_ERR, e->e_id, 3290 "disconnect: open(\"%s\") failed: %s", 3291 SM_PATH_DEVNULL, sm_errstring(errno)); 3292 } 3293 (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 3294 if (fd >= 0) 3295 { 3296 (void) dup2(fd, STDOUT_FILENO); 3297 (void) dup2(fd, STDERR_FILENO); 3298 (void) close(fd); 3299 } 3300 } 3301 3302 /* drop our controlling TTY completely if possible */ 3303 if (droplev > 1) 3304 { 3305 (void) setsid(); 3306 errno = 0; 3307 } 3308 3309 #if XDEBUG 3310 checkfd012("disconnect"); 3311 #endif /* XDEBUG */ 3312 3313 if (LogLevel > 71) 3314 sm_syslog(LOG_DEBUG, e->e_id, "in background, pid=%d", 3315 (int) CurrentPid); 3316 3317 errno = 0; 3318 } 3319 3320 static void 3321 obsolete(argv) 3322 char *argv[]; 3323 { 3324 register char *ap; 3325 register char *op; 3326 3327 while ((ap = *++argv) != NULL) 3328 { 3329 /* Return if "--" or not an option of any form. */ 3330 if (ap[0] != '-' || ap[1] == '-') 3331 return; 3332 3333 /* Don't allow users to use "-Q." or "-Q ." */ 3334 if ((ap[1] == 'Q' && ap[2] == '.') || 3335 (ap[1] == 'Q' && argv[1] != NULL && 3336 argv[1][0] == '.' && argv[1][1] == '\0')) 3337 { 3338 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3339 "Can not use -Q.\n"); 3340 exit(EX_USAGE); 3341 } 3342 3343 /* skip over options that do have a value */ 3344 op = strchr(OPTIONS, ap[1]); 3345 if (op != NULL && *++op == ':' && ap[2] == '\0' && 3346 ap[1] != 'd' && 3347 #if defined(sony_news) 3348 ap[1] != 'E' && ap[1] != 'J' && 3349 #endif /* defined(sony_news) */ 3350 argv[1] != NULL && argv[1][0] != '-') 3351 { 3352 argv++; 3353 continue; 3354 } 3355 3356 /* If -C doesn't have an argument, use sendmail.cf. */ 3357 #define __DEFPATH "sendmail.cf" 3358 if (ap[1] == 'C' && ap[2] == '\0') 3359 { 3360 *argv = xalloc(sizeof(__DEFPATH) + 2); 3361 (void) sm_strlcpyn(argv[0], sizeof(__DEFPATH) + 2, 2, 3362 "-C", __DEFPATH); 3363 } 3364 3365 /* If -q doesn't have an argument, run it once. */ 3366 if (ap[1] == 'q' && ap[2] == '\0') 3367 *argv = "-q0"; 3368 3369 /* If -Q doesn't have an argument, disable quarantining */ 3370 if (ap[1] == 'Q' && ap[2] == '\0') 3371 *argv = "-Q."; 3372 3373 /* if -d doesn't have an argument, use 0-99.1 */ 3374 if (ap[1] == 'd' && ap[2] == '\0') 3375 *argv = "-d0-99.1"; 3376 3377 #if defined(sony_news) 3378 /* if -E doesn't have an argument, use -EC */ 3379 if (ap[1] == 'E' && ap[2] == '\0') 3380 *argv = "-EC"; 3381 3382 /* if -J doesn't have an argument, use -JJ */ 3383 if (ap[1] == 'J' && ap[2] == '\0') 3384 *argv = "-JJ"; 3385 #endif /* defined(sony_news) */ 3386 } 3387 } 3388 /* 3389 ** AUTH_WARNING -- specify authorization warning 3390 ** 3391 ** Parameters: 3392 ** e -- the current envelope. 3393 ** msg -- the text of the message. 3394 ** args -- arguments to the message. 3395 ** 3396 ** Returns: 3397 ** none. 3398 */ 3399 3400 void 3401 #ifdef __STDC__ 3402 auth_warning(register ENVELOPE *e, const char *msg, ...) 3403 #else /* __STDC__ */ 3404 auth_warning(e, msg, va_alist) 3405 register ENVELOPE *e; 3406 const char *msg; 3407 va_dcl 3408 #endif /* __STDC__ */ 3409 { 3410 char buf[MAXLINE]; 3411 SM_VA_LOCAL_DECL 3412 3413 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 3414 { 3415 register char *p; 3416 static char hostbuf[48]; 3417 3418 if (hostbuf[0] == '\0') 3419 { 3420 struct hostent *hp; 3421 3422 hp = myhostname(hostbuf, sizeof hostbuf); 3423 #if NETINET6 3424 if (hp != NULL) 3425 { 3426 freehostent(hp); 3427 hp = NULL; 3428 } 3429 #endif /* NETINET6 */ 3430 } 3431 3432 (void) sm_strlcpyn(buf, sizeof buf, 2, hostbuf, ": "); 3433 p = &buf[strlen(buf)]; 3434 SM_VA_START(ap, msg); 3435 (void) sm_vsnprintf(p, SPACELEFT(buf, p), msg, ap); 3436 SM_VA_END(ap); 3437 addheader("X-Authentication-Warning", buf, 0, e); 3438 if (LogLevel > 3) 3439 sm_syslog(LOG_INFO, e->e_id, 3440 "Authentication-Warning: %.400s", 3441 buf); 3442 } 3443 } 3444 /* 3445 ** GETEXTENV -- get from external environment 3446 ** 3447 ** Parameters: 3448 ** envar -- the name of the variable to retrieve 3449 ** 3450 ** Returns: 3451 ** The value, if any. 3452 */ 3453 3454 static char * 3455 getextenv(envar) 3456 const char *envar; 3457 { 3458 char **envp; 3459 int l; 3460 3461 l = strlen(envar); 3462 for (envp = ExternalEnviron; envp != NULL && *envp != NULL; envp++) 3463 { 3464 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 3465 return &(*envp)[l + 1]; 3466 } 3467 return NULL; 3468 } 3469 /* 3470 ** SM_SETUSERENV -- set an environment variable in the propagated environment 3471 ** 3472 ** Parameters: 3473 ** envar -- the name of the environment variable. 3474 ** value -- the value to which it should be set. If 3475 ** null, this is extracted from the incoming 3476 ** environment. If that is not set, the call 3477 ** to sm_setuserenv is ignored. 3478 ** 3479 ** Returns: 3480 ** none. 3481 */ 3482 3483 void 3484 sm_setuserenv(envar, value) 3485 const char *envar; 3486 const char *value; 3487 { 3488 int i, l; 3489 char **evp = UserEnviron; 3490 char *p; 3491 3492 if (value == NULL) 3493 { 3494 value = getextenv(envar); 3495 if (value == NULL) 3496 return; 3497 } 3498 3499 /* XXX enforce reasonable size? */ 3500 i = strlen(envar) + 1; 3501 l = strlen(value) + i + 1; 3502 p = (char *) xalloc(l); 3503 (void) sm_strlcpyn(p, l, 3, envar, "=", value); 3504 3505 while (*evp != NULL && strncmp(*evp, p, i) != 0) 3506 evp++; 3507 if (*evp != NULL) 3508 { 3509 *evp++ = p; 3510 } 3511 else if (evp < &UserEnviron[MAXUSERENVIRON]) 3512 { 3513 *evp++ = p; 3514 *evp = NULL; 3515 } 3516 3517 /* make sure it is in our environment as well */ 3518 if (putenv(p) < 0) 3519 syserr("sm_setuserenv: putenv(%s) failed", p); 3520 } 3521 /* 3522 ** DUMPSTATE -- dump state 3523 ** 3524 ** For debugging. 3525 */ 3526 3527 void 3528 dumpstate(when) 3529 char *when; 3530 { 3531 register char *j = macvalue('j', CurEnv); 3532 int rs; 3533 extern int NextMacroId; 3534 3535 sm_syslog(LOG_DEBUG, CurEnv->e_id, 3536 "--- dumping state on %s: $j = %s ---", 3537 when, 3538 j == NULL ? "<NULL>" : j); 3539 if (j != NULL) 3540 { 3541 if (!wordinclass(j, 'w')) 3542 sm_syslog(LOG_DEBUG, CurEnv->e_id, 3543 "*** $j not in $=w ***"); 3544 } 3545 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 3546 sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)", 3547 NextMacroId, MAXMACROID); 3548 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 3549 printopenfds(true); 3550 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 3551 mci_dump_all(smioout, true); 3552 rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 3553 if (rs > 0) 3554 { 3555 int status; 3556 register char **pvp; 3557 char *pv[MAXATOM + 1]; 3558 3559 pv[0] = NULL; 3560 status = REWRITE(pv, rs, CurEnv); 3561 sm_syslog(LOG_DEBUG, CurEnv->e_id, 3562 "--- ruleset debug_dumpstate returns stat %d, pv: ---", 3563 status); 3564 for (pvp = pv; *pvp != NULL; pvp++) 3565 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 3566 } 3567 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 3568 } 3569 3570 #ifdef SIGUSR1 3571 /* 3572 ** SIGUSR1 -- Signal a request to dump state. 3573 ** 3574 ** Parameters: 3575 ** sig -- calling signal. 3576 ** 3577 ** Returns: 3578 ** none. 3579 ** 3580 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 3581 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 3582 ** DOING. 3583 ** 3584 ** XXX: More work is needed for this signal handler. 3585 */ 3586 3587 /* ARGSUSED */ 3588 static SIGFUNC_DECL 3589 sigusr1(sig) 3590 int sig; 3591 { 3592 int save_errno = errno; 3593 # if SM_HEAP_CHECK 3594 extern void dumpstab __P((void)); 3595 # endif /* SM_HEAP_CHECK */ 3596 3597 FIX_SYSV_SIGNAL(sig, sigusr1); 3598 errno = save_errno; 3599 CHECK_CRITICAL(sig); 3600 dumpstate("user signal"); 3601 # if SM_HEAP_CHECK 3602 dumpstab(); 3603 # endif /* SM_HEAP_CHECK */ 3604 errno = save_errno; 3605 return SIGFUNC_RETURN; 3606 } 3607 #endif /* SIGUSR1 */ 3608 3609 /* 3610 ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 3611 ** 3612 ** Parameters: 3613 ** to_real_uid -- if set, drop to the real uid instead 3614 ** of the RunAsUser. 3615 ** 3616 ** Returns: 3617 ** EX_OSERR if the setuid failed. 3618 ** EX_OK otherwise. 3619 */ 3620 3621 int 3622 drop_privileges(to_real_uid) 3623 bool to_real_uid; 3624 { 3625 int rval = EX_OK; 3626 GIDSET_T emptygidset[1]; 3627 3628 if (tTd(47, 1)) 3629 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", 3630 (int) to_real_uid, 3631 (int) RealUid, (int) RealGid, 3632 (int) getuid(), (int) getgid(), 3633 (int) geteuid(), (int) getegid(), 3634 (int) RunAsUid, (int) RunAsGid); 3635 3636 if (to_real_uid) 3637 { 3638 RunAsUserName = RealUserName; 3639 RunAsUid = RealUid; 3640 RunAsGid = RealGid; 3641 EffGid = RunAsGid; 3642 } 3643 3644 /* make sure no one can grab open descriptors for secret files */ 3645 endpwent(); 3646 sm_mbdb_terminate(); 3647 3648 /* reset group permissions; these can be set later */ 3649 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 3650 3651 /* 3652 ** Notice: on some OS (Linux...) the setgroups() call causes 3653 ** a logfile entry if sendmail is not run by root. 3654 ** However, it is unclear (no POSIX standard) whether 3655 ** setgroups() can only succeed if executed by root. 3656 ** So for now we keep it as it is; if you want to change it, use 3657 ** if (geteuid() == 0 && setgroups(1, emptygidset) == -1) 3658 */ 3659 3660 if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 3661 { 3662 syserr("drop_privileges: setgroups(1, %d) failed", 3663 (int) emptygidset[0]); 3664 rval = EX_OSERR; 3665 } 3666 3667 /* reset primary group id */ 3668 if (to_real_uid) 3669 { 3670 /* 3671 ** Drop gid to real gid. 3672 ** On some OS we must reset the effective[/real[/saved]] gid, 3673 ** and then use setgid() to finally drop all group privileges. 3674 ** Later on we check whether we can get back the 3675 ** effective gid. 3676 */ 3677 3678 #if HASSETEGID 3679 if (setegid(RunAsGid) < 0) 3680 { 3681 syserr("drop_privileges: setegid(%d) failed", 3682 (int) RunAsGid); 3683 rval = EX_OSERR; 3684 } 3685 #else /* HASSETEGID */ 3686 # if HASSETREGID 3687 if (setregid(RunAsGid, RunAsGid) < 0) 3688 { 3689 syserr("drop_privileges: setregid(%d, %d) failed", 3690 (int) RunAsGid, (int) RunAsGid); 3691 rval = EX_OSERR; 3692 } 3693 # else /* HASSETREGID */ 3694 # if HASSETRESGID 3695 if (setresgid(RunAsGid, RunAsGid, RunAsGid) < 0) 3696 { 3697 syserr("drop_privileges: setresgid(%d, %d, %d) failed", 3698 (int) RunAsGid, (int) RunAsGid, (int) RunAsGid); 3699 rval = EX_OSERR; 3700 } 3701 # endif /* HASSETRESGID */ 3702 # endif /* HASSETREGID */ 3703 #endif /* HASSETEGID */ 3704 } 3705 if (rval == EX_OK && (to_real_uid || RunAsGid != 0)) 3706 { 3707 if (setgid(RunAsGid) < 0 && (!UseMSP || getegid() != RunAsGid)) 3708 { 3709 syserr("drop_privileges: setgid(%d) failed", 3710 (int) RunAsGid); 3711 rval = EX_OSERR; 3712 } 3713 errno = 0; 3714 if (rval == EX_OK && getegid() != RunAsGid) 3715 { 3716 syserr("drop_privileges: Unable to set effective gid=%d to RunAsGid=%d", 3717 (int) getegid(), (int) RunAsGid); 3718 rval = EX_OSERR; 3719 } 3720 } 3721 3722 /* fiddle with uid */ 3723 if (to_real_uid || RunAsUid != 0) 3724 { 3725 uid_t euid; 3726 3727 /* 3728 ** Try to setuid(RunAsUid). 3729 ** euid must be RunAsUid, 3730 ** ruid must be RunAsUid unless (e|r)uid wasn't 0 3731 ** and we didn't have to drop privileges to the real uid. 3732 */ 3733 3734 if (setuid(RunAsUid) < 0 || 3735 geteuid() != RunAsUid || 3736 (getuid() != RunAsUid && 3737 (to_real_uid || geteuid() == 0 || getuid() == 0))) 3738 { 3739 #if HASSETREUID 3740 /* 3741 ** if ruid != RunAsUid, euid == RunAsUid, then 3742 ** try resetting just the real uid, then using 3743 ** setuid() to drop the saved-uid as well. 3744 */ 3745 3746 if (geteuid() == RunAsUid) 3747 { 3748 if (setreuid(RunAsUid, -1) < 0) 3749 { 3750 syserr("drop_privileges: setreuid(%d, -1) failed", 3751 (int) RunAsUid); 3752 rval = EX_OSERR; 3753 } 3754 if (setuid(RunAsUid) < 0) 3755 { 3756 syserr("drop_privileges: second setuid(%d) attempt failed", 3757 (int) RunAsUid); 3758 rval = EX_OSERR; 3759 } 3760 } 3761 else 3762 #endif /* HASSETREUID */ 3763 { 3764 syserr("drop_privileges: setuid(%d) failed", 3765 (int) RunAsUid); 3766 rval = EX_OSERR; 3767 } 3768 } 3769 euid = geteuid(); 3770 if (RunAsUid != 0 && setuid(0) == 0) 3771 { 3772 /* 3773 ** Believe it or not, the Linux capability model 3774 ** allows a non-root process to override setuid() 3775 ** on a process running as root and prevent that 3776 ** process from dropping privileges. 3777 */ 3778 3779 syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 3780 rval = EX_OSERR; 3781 } 3782 else if (RunAsUid != euid && setuid(euid) == 0) 3783 { 3784 /* 3785 ** Some operating systems will keep the saved-uid 3786 ** if a non-root effective-uid calls setuid(real-uid) 3787 ** making it possible to set it back again later. 3788 */ 3789 3790 syserr("drop_privileges: Unable to drop non-root set-user-ID privileges"); 3791 rval = EX_OSERR; 3792 } 3793 } 3794 3795 if ((to_real_uid || RunAsGid != 0) && 3796 rval == EX_OK && RunAsGid != EffGid && 3797 getuid() != 0 && geteuid() != 0) 3798 { 3799 errno = 0; 3800 if (setgid(EffGid) == 0) 3801 { 3802 syserr("drop_privileges: setgid(%d) succeeded (when it should not)", 3803 (int) EffGid); 3804 rval = EX_OSERR; 3805 } 3806 } 3807 3808 if (tTd(47, 5)) 3809 { 3810 sm_dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 3811 (int) geteuid(), (int) getuid(), 3812 (int) getegid(), (int) getgid()); 3813 sm_dprintf("drop_privileges: RunAsUser = %d:%d\n", 3814 (int) RunAsUid, (int) RunAsGid); 3815 if (tTd(47, 10)) 3816 sm_dprintf("drop_privileges: rval = %d\n", rval); 3817 } 3818 return rval; 3819 } 3820 /* 3821 ** FILL_FD -- make sure a file descriptor has been properly allocated 3822 ** 3823 ** Used to make sure that stdin/out/err are allocated on startup 3824 ** 3825 ** Parameters: 3826 ** fd -- the file descriptor to be filled. 3827 ** where -- a string used for logging. If NULL, this is 3828 ** being called on startup, and logging should 3829 ** not be done. 3830 ** 3831 ** Returns: 3832 ** none 3833 ** 3834 ** Side Effects: 3835 ** possibly changes MissingFds 3836 */ 3837 3838 void 3839 fill_fd(fd, where) 3840 int fd; 3841 char *where; 3842 { 3843 int i; 3844 struct stat stbuf; 3845 3846 if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 3847 return; 3848 3849 if (where != NULL) 3850 syserr("fill_fd: %s: fd %d not open", where, fd); 3851 else 3852 MissingFds |= 1 << fd; 3853 i = open(SM_PATH_DEVNULL, fd == 0 ? O_RDONLY : O_WRONLY, 0666); 3854 if (i < 0) 3855 { 3856 syserr("!fill_fd: %s: cannot open %s", 3857 where == NULL ? "startup" : where, SM_PATH_DEVNULL); 3858 } 3859 if (fd != i) 3860 { 3861 (void) dup2(i, fd); 3862 (void) close(i); 3863 } 3864 } 3865 /* 3866 ** SM_PRINTOPTIONS -- print options 3867 ** 3868 ** Parameters: 3869 ** options -- array of options. 3870 ** 3871 ** Returns: 3872 ** none. 3873 */ 3874 3875 static void 3876 sm_printoptions(options) 3877 char **options; 3878 { 3879 int ll; 3880 char **av; 3881 3882 av = options; 3883 ll = 7; 3884 while (*av != NULL) 3885 { 3886 if (ll + strlen(*av) > 63) 3887 { 3888 sm_dprintf("\n"); 3889 ll = 0; 3890 } 3891 if (ll == 0) 3892 sm_dprintf("\t\t"); 3893 else 3894 sm_dprintf(" "); 3895 sm_dprintf("%s", *av); 3896 ll += strlen(*av++) + 1; 3897 } 3898 sm_dprintf("\n"); 3899 } 3900 /* 3901 ** TESTMODELINE -- process a test mode input line 3902 ** 3903 ** Parameters: 3904 ** line -- the input line. 3905 ** e -- the current environment. 3906 ** Syntax: 3907 ** # a comment 3908 ** .X process X as a configuration line 3909 ** =X dump a configuration item (such as mailers) 3910 ** $X dump a macro or class 3911 ** /X try an activity 3912 ** X normal process through rule set X 3913 */ 3914 3915 static void 3916 testmodeline(line, e) 3917 char *line; 3918 ENVELOPE *e; 3919 { 3920 register char *p; 3921 char *q; 3922 auto char *delimptr; 3923 int mid; 3924 int i, rs; 3925 STAB *map; 3926 char **s; 3927 struct rewrite *rw; 3928 ADDRESS a; 3929 static int tryflags = RF_COPYNONE; 3930 char exbuf[MAXLINE]; 3931 extern unsigned char TokTypeNoC[]; 3932 3933 /* skip leading spaces */ 3934 while (*line == ' ') 3935 line++; 3936 3937 switch (line[0]) 3938 { 3939 case '#': 3940 case '\0': 3941 return; 3942 3943 case '?': 3944 help("-bt", e); 3945 return; 3946 3947 case '.': /* config-style settings */ 3948 switch (line[1]) 3949 { 3950 case 'D': 3951 mid = macid_parse(&line[2], &delimptr); 3952 if (mid == 0) 3953 return; 3954 translate_dollars(delimptr); 3955 macdefine(&e->e_macro, A_TEMP, mid, delimptr); 3956 break; 3957 3958 case 'C': 3959 if (line[2] == '\0') /* not to call syserr() */ 3960 return; 3961 3962 mid = macid_parse(&line[2], &delimptr); 3963 if (mid == 0) 3964 return; 3965 translate_dollars(delimptr); 3966 expand(delimptr, exbuf, sizeof exbuf, e); 3967 p = exbuf; 3968 while (*p != '\0') 3969 { 3970 register char *wd; 3971 char delim; 3972 3973 while (*p != '\0' && isascii(*p) && isspace(*p)) 3974 p++; 3975 wd = p; 3976 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3977 p++; 3978 delim = *p; 3979 *p = '\0'; 3980 if (wd[0] != '\0') 3981 setclass(mid, wd); 3982 *p = delim; 3983 } 3984 break; 3985 3986 case '\0': 3987 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3988 "Usage: .[DC]macro value(s)\n"); 3989 break; 3990 3991 default: 3992 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 3993 "Unknown \".\" command %s\n", line); 3994 break; 3995 } 3996 return; 3997 3998 case '=': /* config-style settings */ 3999 switch (line[1]) 4000 { 4001 case 'S': /* dump rule set */ 4002 rs = strtorwset(&line[2], NULL, ST_FIND); 4003 if (rs < 0) 4004 { 4005 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4006 "Undefined ruleset %s\n", &line[2]); 4007 return; 4008 } 4009 rw = RewriteRules[rs]; 4010 if (rw == NULL) 4011 return; 4012 do 4013 { 4014 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4015 'R'); 4016 s = rw->r_lhs; 4017 while (*s != NULL) 4018 { 4019 xputs(smioout, *s++); 4020 (void) sm_io_putc(smioout, 4021 SM_TIME_DEFAULT, ' '); 4022 } 4023 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4024 '\t'); 4025 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4026 '\t'); 4027 s = rw->r_rhs; 4028 while (*s != NULL) 4029 { 4030 xputs(smioout, *s++); 4031 (void) sm_io_putc(smioout, 4032 SM_TIME_DEFAULT, ' '); 4033 } 4034 (void) sm_io_putc(smioout, SM_TIME_DEFAULT, 4035 '\n'); 4036 } while ((rw = rw->r_next) != NULL); 4037 break; 4038 4039 case 'M': 4040 for (i = 0; i < MAXMAILERS; i++) 4041 { 4042 if (Mailer[i] != NULL) 4043 printmailer(smioout, Mailer[i]); 4044 } 4045 break; 4046 4047 case '\0': 4048 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4049 "Usage: =Sruleset or =M\n"); 4050 break; 4051 4052 default: 4053 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4054 "Unknown \"=\" command %s\n", line); 4055 break; 4056 } 4057 return; 4058 4059 case '-': /* set command-line-like opts */ 4060 switch (line[1]) 4061 { 4062 case 'd': 4063 tTflag(&line[2]); 4064 break; 4065 4066 case '\0': 4067 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4068 "Usage: -d{debug arguments}\n"); 4069 break; 4070 4071 default: 4072 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4073 "Unknown \"-\" command %s\n", line); 4074 break; 4075 } 4076 return; 4077 4078 case '$': 4079 if (line[1] == '=') 4080 { 4081 mid = macid(&line[2]); 4082 if (mid != 0) 4083 stabapply(dump_class, mid); 4084 return; 4085 } 4086 mid = macid(&line[1]); 4087 if (mid == 0) 4088 return; 4089 p = macvalue(mid, e); 4090 if (p == NULL) 4091 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4092 "Undefined\n"); 4093 else 4094 { 4095 xputs(smioout, p); 4096 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4097 "\n"); 4098 } 4099 return; 4100 4101 case '/': /* miscellaneous commands */ 4102 p = &line[strlen(line)]; 4103 while (--p >= line && isascii(*p) && isspace(*p)) 4104 *p = '\0'; 4105 p = strpbrk(line, " \t"); 4106 if (p != NULL) 4107 { 4108 while (isascii(*p) && isspace(*p)) 4109 *p++ = '\0'; 4110 } 4111 else 4112 p = ""; 4113 if (line[1] == '\0') 4114 { 4115 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4116 "Usage: /[canon|map|mx|parse|try|tryflags]\n"); 4117 return; 4118 } 4119 if (sm_strcasecmp(&line[1], "quit") == 0) 4120 { 4121 CurEnv->e_id = NULL; 4122 finis(true, true, ExitStat); 4123 /* NOTREACHED */ 4124 } 4125 if (sm_strcasecmp(&line[1], "mx") == 0) 4126 { 4127 #if NAMED_BIND 4128 /* look up MX records */ 4129 int nmx; 4130 auto int rcode; 4131 char *mxhosts[MAXMXHOSTS + 1]; 4132 4133 if (*p == '\0') 4134 { 4135 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4136 "Usage: /mx address\n"); 4137 return; 4138 } 4139 nmx = getmxrr(p, mxhosts, NULL, false, &rcode, true, 4140 NULL); 4141 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4142 "getmxrr(%s) returns %d value(s):\n", 4143 p, nmx); 4144 for (i = 0; i < nmx; i++) 4145 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4146 "\t%s\n", mxhosts[i]); 4147 #else /* NAMED_BIND */ 4148 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4149 "No MX code compiled in\n"); 4150 #endif /* NAMED_BIND */ 4151 } 4152 else if (sm_strcasecmp(&line[1], "canon") == 0) 4153 { 4154 char host[MAXHOSTNAMELEN]; 4155 4156 if (*p == '\0') 4157 { 4158 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4159 "Usage: /canon address\n"); 4160 return; 4161 } 4162 else if (sm_strlcpy(host, p, sizeof host) >= sizeof host) 4163 { 4164 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4165 "Name too long\n"); 4166 return; 4167 } 4168 (void) getcanonname(host, sizeof host, !HasWildcardMX, 4169 NULL); 4170 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4171 "getcanonname(%s) returns %s\n", 4172 p, host); 4173 } 4174 else if (sm_strcasecmp(&line[1], "map") == 0) 4175 { 4176 auto int rcode = EX_OK; 4177 char *av[2]; 4178 4179 if (*p == '\0') 4180 { 4181 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4182 "Usage: /map mapname key\n"); 4183 return; 4184 } 4185 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 4186 continue; 4187 if (*q == '\0') 4188 { 4189 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4190 "No key specified\n"); 4191 return; 4192 } 4193 *q++ = '\0'; 4194 map = stab(p, ST_MAP, ST_FIND); 4195 if (map == NULL) 4196 { 4197 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4198 "Map named \"%s\" not found\n", p); 4199 return; 4200 } 4201 if (!bitset(MF_OPEN, map->s_map.map_mflags) && 4202 !openmap(&(map->s_map))) 4203 { 4204 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4205 "Map named \"%s\" not open\n", p); 4206 return; 4207 } 4208 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4209 "map_lookup: %s (%s) ", p, q); 4210 av[0] = q; 4211 av[1] = NULL; 4212 p = (*map->s_map.map_class->map_lookup) 4213 (&map->s_map, q, av, &rcode); 4214 if (p == NULL) 4215 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4216 "no match (%d)\n", 4217 rcode); 4218 else 4219 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4220 "returns %s (%d)\n", p, 4221 rcode); 4222 } 4223 else if (sm_strcasecmp(&line[1], "try") == 0) 4224 { 4225 MAILER *m; 4226 STAB *st; 4227 auto int rcode = EX_OK; 4228 4229 q = strpbrk(p, " \t"); 4230 if (q != NULL) 4231 { 4232 while (isascii(*q) && isspace(*q)) 4233 *q++ = '\0'; 4234 } 4235 if (q == NULL || *q == '\0') 4236 { 4237 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4238 "Usage: /try mailer address\n"); 4239 return; 4240 } 4241 st = stab(p, ST_MAILER, ST_FIND); 4242 if (st == NULL) 4243 { 4244 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4245 "Unknown mailer %s\n", p); 4246 return; 4247 } 4248 m = st->s_mailer; 4249 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4250 "Trying %s %s address %s for mailer %s\n", 4251 bitset(RF_HEADERADDR, tryflags) ? "header" 4252 : "envelope", 4253 bitset(RF_SENDERADDR, tryflags) ? "sender" 4254 : "recipient", q, p); 4255 p = remotename(q, m, tryflags, &rcode, CurEnv); 4256 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4257 "Rcode = %d, addr = %s\n", 4258 rcode, p == NULL ? "<NULL>" : p); 4259 e->e_to = NULL; 4260 } 4261 else if (sm_strcasecmp(&line[1], "tryflags") == 0) 4262 { 4263 if (*p == '\0') 4264 { 4265 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4266 "Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 4267 return; 4268 } 4269 for (; *p != '\0'; p++) 4270 { 4271 switch (*p) 4272 { 4273 case 'H': 4274 case 'h': 4275 tryflags |= RF_HEADERADDR; 4276 break; 4277 4278 case 'E': 4279 case 'e': 4280 tryflags &= ~RF_HEADERADDR; 4281 break; 4282 4283 case 'S': 4284 case 's': 4285 tryflags |= RF_SENDERADDR; 4286 break; 4287 4288 case 'R': 4289 case 'r': 4290 tryflags &= ~RF_SENDERADDR; 4291 break; 4292 } 4293 } 4294 exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 4295 exbuf[1] = ' '; 4296 exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 4297 exbuf[3] = '\0'; 4298 macdefine(&e->e_macro, A_TEMP, 4299 macid("{addr_type}"), exbuf); 4300 } 4301 else if (sm_strcasecmp(&line[1], "parse") == 0) 4302 { 4303 if (*p == '\0') 4304 { 4305 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4306 "Usage: /parse address\n"); 4307 return; 4308 } 4309 q = crackaddr(p, e); 4310 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4311 "Cracked address = "); 4312 xputs(smioout, q); 4313 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4314 "\nParsing %s %s address\n", 4315 bitset(RF_HEADERADDR, tryflags) ? 4316 "header" : "envelope", 4317 bitset(RF_SENDERADDR, tryflags) ? 4318 "sender" : "recipient"); 4319 if (parseaddr(p, &a, tryflags, '\0', NULL, e, true) 4320 == NULL) 4321 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4322 "Cannot parse\n"); 4323 else if (a.q_host != NULL && a.q_host[0] != '\0') 4324 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4325 "mailer %s, host %s, user %s\n", 4326 a.q_mailer->m_name, 4327 a.q_host, 4328 a.q_user); 4329 else 4330 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4331 "mailer %s, user %s\n", 4332 a.q_mailer->m_name, 4333 a.q_user); 4334 e->e_to = NULL; 4335 } 4336 else 4337 { 4338 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4339 "Unknown \"/\" command %s\n", 4340 line); 4341 } 4342 return; 4343 } 4344 4345 for (p = line; isascii(*p) && isspace(*p); p++) 4346 continue; 4347 q = p; 4348 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4349 p++; 4350 if (*p == '\0') 4351 { 4352 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4353 "No address!\n"); 4354 return; 4355 } 4356 *p = '\0'; 4357 if (invalidaddr(p + 1, NULL, true)) 4358 return; 4359 do 4360 { 4361 register char **pvp; 4362 char pvpbuf[PSBUFSIZE]; 4363 4364 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, &delimptr, 4365 ConfigLevel >= 9 ? TokTypeNoC : NULL, false); 4366 if (pvp == NULL) 4367 continue; 4368 p = q; 4369 while (*p != '\0') 4370 { 4371 int status; 4372 4373 rs = strtorwset(p, NULL, ST_FIND); 4374 if (rs < 0) 4375 { 4376 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4377 "Undefined ruleset %s\n", 4378 p); 4379 break; 4380 } 4381 status = REWRITE(pvp, rs, e); 4382 if (status != EX_OK) 4383 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4384 "== Ruleset %s (%d) status %d\n", 4385 p, rs, status); 4386 while (*p != '\0' && *p++ != ',') 4387 continue; 4388 } 4389 } while (*(p = delimptr) != '\0'); 4390 } 4391 4392 static void 4393 dump_class(s, id) 4394 register STAB *s; 4395 int id; 4396 { 4397 if (s->s_symtype != ST_CLASS) 4398 return; 4399 if (bitnset(bitidx(id), s->s_class)) 4400 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 4401 "%s\n", s->s_name); 4402 } 4403 4404 /* 4405 ** An exception type used to create QuickAbort exceptions. 4406 ** This is my first cut at converting QuickAbort from longjmp to exceptions. 4407 ** These exceptions have a single integer argument, which is the argument 4408 ** to longjmp in the original code (either 1 or 2). I don't know the 4409 ** significance of 1 vs 2: the calls to setjmp don't care. 4410 */ 4411 4412 const SM_EXC_TYPE_T EtypeQuickAbort = 4413 { 4414 SmExcTypeMagic, 4415 "E:mta.quickabort", 4416 "i", 4417 sm_etype_printf, 4418 "quick abort %0", 4419 }; 4420