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