1 /* 2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #ifndef lint 15 static char copyright[] = 16 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ 17 All rights reserved.\n\ 18 Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ 19 Copyright (c) 1988, 1993\n\ 20 The Regents of the University of California. All rights reserved.\n"; 21 #endif /* ! lint */ 22 23 #ifndef lint 24 static char id[] = "@(#)$Id: main.c,v 8.485.4.60 2001/05/27 22:00:26 gshapiro Exp $"; 25 #endif /* ! lint */ 26 27 #define _DEFINE 28 29 #include <sendmail.h> 30 31 32 #if NETINET || NETINET6 33 # include <arpa/inet.h> 34 #endif /* NETINET || NETINET6 */ 35 36 static SIGFUNC_DECL intindebug __P((int)); 37 static SIGFUNC_DECL quiesce __P((int)); 38 static SIGFUNC_DECL sigusr1 __P((int)); 39 static SIGFUNC_DECL term_daemon __P((int)); 40 static void dump_class __P((STAB *, int)); 41 static void obsolete __P((char **)); 42 static void testmodeline __P((char *, ENVELOPE *)); 43 44 /* 45 ** SENDMAIL -- Post mail to a set of destinations. 46 ** 47 ** This is the basic mail router. All user mail programs should 48 ** call this routine to actually deliver mail. Sendmail in 49 ** turn calls a bunch of mail servers that do the real work of 50 ** delivering the mail. 51 ** 52 ** Sendmail is driven by settings read in from /etc/mail/sendmail.cf 53 ** (read by readcf.c). 54 ** 55 ** Usage: 56 ** /usr/lib/sendmail [flags] addr ... 57 ** 58 ** See the associated documentation for details. 59 ** 60 ** Author: 61 ** Eric Allman, UCB/INGRES (until 10/81). 62 ** Britton-Lee, Inc., purveyors of fine 63 ** database computers (11/81 - 10/88). 64 ** International Computer Science Institute 65 ** (11/88 - 9/89). 66 ** UCB/Mammoth Project (10/89 - 7/95). 67 ** InReference, Inc. (8/95 - 1/97). 68 ** Sendmail, Inc. (1/98 - present). 69 ** The support of the my employers is gratefully acknowledged. 70 ** Few of them (Britton-Lee in particular) have had 71 ** anything to gain from my involvement in this project. 72 */ 73 74 75 int NextMailer; /* "free" index into Mailer struct */ 76 char *FullName; /* sender's full name */ 77 ENVELOPE BlankEnvelope; /* a "blank" envelope */ 78 static ENVELOPE MainEnvelope; /* the envelope around the basic letter */ 79 ADDRESS NullAddress = /* a null address */ 80 { "", "", NULL, "" }; 81 char *CommandLineArgs; /* command line args for pid file */ 82 bool Warn_Q_option = FALSE; /* warn about Q option use */ 83 static int MissingFds = 0; /* bit map of fds missing on startup */ 84 85 #ifdef NGROUPS_MAX 86 GIDSET_T InitialGidSet[NGROUPS_MAX]; 87 #endif /* NGROUPS_MAX */ 88 89 #if DAEMON && !SMTP 90 ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR 91 #endif /* DAEMON && !SMTP */ 92 #if SMTP && !QUEUE 93 ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR 94 #endif /* SMTP && !QUEUE */ 95 96 #define MAXCONFIGLEVEL 9 /* highest config version level known */ 97 98 #if SASL 99 static sasl_callback_t srvcallbacks[] = 100 { 101 { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, 102 { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, 103 { SASL_CB_LIST_END, NULL, NULL } 104 }; 105 106 #endif /* SASL */ 107 108 int SubmitMode; 109 110 int 111 main(argc, argv, envp) 112 int argc; 113 char **argv; 114 char **envp; 115 { 116 register char *p; 117 char **av; 118 extern char Version[]; 119 char *ep, *from; 120 STAB *st; 121 register int i; 122 int j; 123 int dp; 124 bool safecf = TRUE; 125 BITMAP256 *p_flags = NULL; /* daemon flags */ 126 bool warn_C_flag = FALSE; 127 bool auth = TRUE; /* whether to set e_auth_param */ 128 char warn_f_flag = '\0'; 129 bool run_in_foreground = FALSE; /* -bD mode */ 130 static bool reenter = FALSE; 131 struct passwd *pw; 132 struct hostent *hp; 133 char *nullserver = NULL; 134 char *authinfo = NULL; 135 char *sysloglabel = NULL; /* label for syslog */ 136 bool forged; 137 struct stat traf_st; /* for TrafficLog FIFO check */ 138 char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ 139 static char rnamebuf[MAXNAME]; /* holds RealUserName */ 140 char *emptyenviron[1]; 141 # if STARTTLS 142 bool tls_ok; 143 # endif /* STARTTLS */ 144 QUEUE_CHAR *new; 145 extern int DtableSize; 146 extern int optind; 147 extern int opterr; 148 extern char *optarg; 149 extern char **environ; 150 151 /* 152 ** Check to see if we reentered. 153 ** This would normally happen if e_putheader or e_putbody 154 ** were NULL when invoked. 155 */ 156 157 if (reenter) 158 { 159 syserr("main: reentered!"); 160 abort(); 161 } 162 reenter = TRUE; 163 164 /* avoid null pointer dereferences */ 165 TermEscape.te_rv_on = TermEscape.te_rv_off = ""; 166 167 /* 168 ** Seed the random number generator. 169 ** Used for queue file names, picking a queue directory, and 170 ** MX randomization. 171 */ 172 173 seed_random(); 174 175 /* do machine-dependent initializations */ 176 init_md(argc, argv); 177 178 179 /* in 4.4BSD, the table can be huge; impose a reasonable limit */ 180 DtableSize = getdtsize(); 181 if (DtableSize > 256) 182 DtableSize = 256; 183 184 /* 185 ** Be sure we have enough file descriptors. 186 ** But also be sure that 0, 1, & 2 are open. 187 */ 188 189 fill_fd(STDIN_FILENO, NULL); 190 fill_fd(STDOUT_FILENO, NULL); 191 fill_fd(STDERR_FILENO, NULL); 192 193 i = DtableSize; 194 while (--i > 0) 195 { 196 if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) 197 (void) close(i); 198 } 199 errno = 0; 200 201 #if LOG 202 # ifdef LOG_MAIL 203 openlog("sendmail", LOG_PID, LOG_MAIL); 204 # else /* LOG_MAIL */ 205 openlog("sendmail", LOG_PID); 206 # endif /* LOG_MAIL */ 207 #endif /* LOG */ 208 209 if (MissingFds != 0) 210 { 211 char mbuf[MAXLINE]; 212 213 mbuf[0] = '\0'; 214 if (bitset(1 << STDIN_FILENO, MissingFds)) 215 (void) strlcat(mbuf, ", stdin", sizeof mbuf); 216 if (bitset(1 << STDOUT_FILENO, MissingFds)) 217 (void) strlcat(mbuf, ", stdout", sizeof mbuf); 218 if (bitset(1 << STDERR_FILENO, MissingFds)) 219 (void) strlcat(mbuf, ", stderr", sizeof mbuf); 220 syserr("File descriptors missing on startup: %s", &mbuf[2]); 221 } 222 223 /* reset status from syserr() calls for missing file descriptors */ 224 Errors = 0; 225 ExitStat = EX_OK; 226 227 SubmitMode = SUBMIT_UNKNOWN; 228 #if XDEBUG 229 checkfd012("after openlog"); 230 #endif /* XDEBUG */ 231 232 tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 233 234 #ifdef NGROUPS_MAX 235 /* save initial group set for future checks */ 236 i = getgroups(NGROUPS_MAX, InitialGidSet); 237 if (i == 0) 238 InitialGidSet[0] = (GID_T) -1; 239 while (i < NGROUPS_MAX) 240 InitialGidSet[i++] = InitialGidSet[0]; 241 #endif /* NGROUPS_MAX */ 242 243 /* drop group id privileges (RunAsUser not yet set) */ 244 dp = drop_privileges(FALSE); 245 setstat(dp); 246 247 # ifdef SIGUSR1 248 /* Only allow root (or non-set-*-ID binaries) to use SIGUSR1 */ 249 if (getuid() == 0 || 250 (getuid() == geteuid() && getgid() == getegid())) 251 { 252 /* arrange to dump state on user-1 signal */ 253 (void) setsignal(SIGUSR1, sigusr1); 254 } 255 # endif /* SIGUSR1 */ 256 257 /* initialize for setproctitle */ 258 initsetproctitle(argc, argv, envp); 259 260 /* Handle any non-getoptable constructions. */ 261 obsolete(argv); 262 263 /* 264 ** Do a quick prescan of the argument list. 265 */ 266 267 268 #if defined(__osf__) || defined(_AIX3) 269 # define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:x" 270 #endif /* defined(__osf__) || defined(_AIX3) */ 271 #if defined(sony_news) 272 # define OPTIONS "B:b:C:cd:E:e:F:f:Gh:IiJ:L:M:mN:nO:o:p:q:R:r:sTtUV:vX:" 273 #endif /* defined(sony_news) */ 274 #ifndef OPTIONS 275 # define OPTIONS "B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtUV:vX:" 276 #endif /* ! OPTIONS */ 277 opterr = 0; 278 while ((j = getopt(argc, argv, OPTIONS)) != -1) 279 { 280 switch (j) 281 { 282 case 'd': 283 /* hack attack -- see if should use ANSI mode */ 284 if (strcmp(optarg, "ANSI") == 0) 285 { 286 TermEscape.te_rv_on = "\033[7m"; 287 TermEscape.te_rv_off = "\033[0m"; 288 break; 289 } 290 tTflag(optarg); 291 setbuf(stdout, (char *) NULL); 292 break; 293 294 case 'G': /* relay (gateway) submission */ 295 SubmitMode |= SUBMIT_MTA; 296 break; 297 298 case 'L': 299 j = min(strlen(optarg), 24) + 1; 300 sysloglabel = xalloc(j); 301 (void) strlcpy(sysloglabel, optarg, j); 302 break; 303 304 case 'U': /* initial (user) submission */ 305 SubmitMode |= SUBMIT_MSA; 306 break; 307 } 308 } 309 opterr = 1; 310 311 #if LOG 312 if (sysloglabel != NULL) 313 { 314 /* Sanitize the string */ 315 for (p = sysloglabel; *p != '\0'; p++) 316 { 317 if (!isascii(*p) || !isprint(*p) || *p == '%') 318 *p = '*'; 319 } 320 closelog(); 321 # ifdef LOG_MAIL 322 openlog(sysloglabel, LOG_PID, LOG_MAIL); 323 # else /* LOG_MAIL */ 324 openlog(sysloglabel, LOG_PID); 325 # endif /* LOG_MAIL */ 326 } 327 #endif /* LOG */ 328 329 /* set up the blank envelope */ 330 BlankEnvelope.e_puthdr = putheader; 331 BlankEnvelope.e_putbody = putbody; 332 BlankEnvelope.e_xfp = NULL; 333 STRUCTCOPY(NullAddress, BlankEnvelope.e_from); 334 CurEnv = &BlankEnvelope; 335 STRUCTCOPY(NullAddress, MainEnvelope.e_from); 336 337 /* 338 ** Set default values for variables. 339 ** These cannot be in initialized data space. 340 */ 341 342 setdefaults(&BlankEnvelope); 343 344 RealUid = getuid(); 345 RealGid = getgid(); 346 347 pw = sm_getpwuid(RealUid); 348 if (pw != NULL) 349 (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 350 else 351 (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", 352 (int) RealUid); 353 354 RealUserName = rnamebuf; 355 356 if (tTd(0, 101)) 357 { 358 dprintf("Version %s\n", Version); 359 finis(FALSE, EX_OK); 360 } 361 362 /* 363 ** if running non-setuid binary as non-root, pretend 364 ** we are the RunAsUid 365 */ 366 367 if (RealUid != 0 && geteuid() == RealUid) 368 { 369 if (tTd(47, 1)) 370 dprintf("Non-setuid binary: RunAsUid = RealUid = %d\n", 371 (int)RealUid); 372 RunAsUid = RealUid; 373 } 374 else if (geteuid() != 0) 375 RunAsUid = geteuid(); 376 377 if (RealUid != 0 && getegid() == RealGid) 378 RunAsGid = RealGid; 379 380 if (tTd(47, 5)) 381 { 382 dprintf("main: e/ruid = %d/%d e/rgid = %d/%d\n", 383 (int)geteuid(), (int)getuid(), 384 (int)getegid(), (int)getgid()); 385 dprintf("main: RunAsUser = %d:%d\n", 386 (int)RunAsUid, (int)RunAsGid); 387 } 388 389 /* save command line arguments */ 390 j = 0; 391 for (av = argv; *av != NULL; ) 392 j += strlen(*av++) + 1; 393 SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); 394 CommandLineArgs = xalloc(j); 395 p = CommandLineArgs; 396 for (av = argv, i = 0; *av != NULL; ) 397 { 398 int h; 399 400 SaveArgv[i++] = newstr(*av); 401 if (av != argv) 402 *p++ = ' '; 403 (void) strlcpy(p, *av++, j); 404 h = strlen(p); 405 p += h; 406 j -= h + 1; 407 } 408 SaveArgv[i] = NULL; 409 410 if (tTd(0, 1)) 411 { 412 int ll; 413 extern char *CompileOptions[]; 414 415 dprintf("Version %s\n Compiled with:", Version); 416 av = CompileOptions; 417 ll = 7; 418 while (*av != NULL) 419 { 420 if (ll + strlen(*av) > 63) 421 { 422 dprintf("\n"); 423 ll = 0; 424 } 425 if (ll == 0) 426 dprintf("\t\t"); 427 else 428 dprintf(" "); 429 dprintf("%s", *av); 430 ll += strlen(*av++) + 1; 431 } 432 dprintf("\n"); 433 } 434 if (tTd(0, 10)) 435 { 436 int ll; 437 extern char *OsCompileOptions[]; 438 439 dprintf(" OS Defines:"); 440 av = OsCompileOptions; 441 ll = 7; 442 while (*av != NULL) 443 { 444 if (ll + strlen(*av) > 63) 445 { 446 dprintf("\n"); 447 ll = 0; 448 } 449 if (ll == 0) 450 dprintf("\t\t"); 451 else 452 dprintf(" "); 453 dprintf("%s", *av); 454 ll += strlen(*av++) + 1; 455 } 456 dprintf("\n"); 457 #ifdef _PATH_UNIX 458 dprintf("Kernel symbols:\t%s\n", _PATH_UNIX); 459 #endif /* _PATH_UNIX */ 460 dprintf(" Def Conf file:\t%s\n", getcfname()); 461 dprintf(" Def Pid file:\t%s\n", PidFile); 462 } 463 464 InChannel = stdin; 465 OutChannel = stdout; 466 467 /* clear sendmail's environment */ 468 ExternalEnviron = environ; 469 emptyenviron[0] = NULL; 470 environ = emptyenviron; 471 472 /* 473 ** restore any original TZ setting until TimeZoneSpec has been 474 ** determined - or early log messages may get bogus time stamps 475 */ 476 if ((p = getextenv("TZ")) != NULL) 477 { 478 char *tz; 479 int tzlen; 480 481 tzlen = strlen(p) + 4; 482 tz = xalloc(tzlen); 483 (void) snprintf(tz, tzlen, "TZ=%s", p); 484 (void) putenv(tz); 485 } 486 487 /* prime the child environment */ 488 setuserenv("AGENT", "sendmail"); 489 (void) setsignal(SIGPIPE, SIG_IGN); 490 491 OldUmask = umask(022); 492 OpMode = MD_DELIVER; 493 FullName = getextenv("NAME"); 494 495 /* 496 ** Initialize name server if it is going to be used. 497 */ 498 499 #if NAMED_BIND 500 if (!bitset(RES_INIT, _res.options)) 501 (void) res_init(); 502 503 /* 504 ** hack to avoid crashes when debugging for the resolver is 505 ** turned on and sfio is used 506 */ 507 if (tTd(8, 8)) 508 # if !SFIO || SFIO_STDIO_COMPAT 509 _res.options |= RES_DEBUG; 510 # else /* !SFIO || SFIO_STDIO_COMPAT */ 511 dprintf("RES_DEBUG not available due to SFIO\n"); 512 # endif /* !SFIO || SFIO_STDIO_COMPAT */ 513 else 514 _res.options &= ~RES_DEBUG; 515 # ifdef RES_NOALIASES 516 _res.options |= RES_NOALIASES; 517 # endif /* RES_NOALIASES */ 518 TimeOuts.res_retry[RES_TO_DEFAULT] = _res.retry; 519 TimeOuts.res_retry[RES_TO_FIRST] = _res.retry; 520 TimeOuts.res_retry[RES_TO_NORMAL] = _res.retry; 521 TimeOuts.res_retrans[RES_TO_DEFAULT] = _res.retrans; 522 TimeOuts.res_retrans[RES_TO_FIRST] = _res.retrans; 523 TimeOuts.res_retrans[RES_TO_NORMAL] = _res.retrans; 524 #endif /* NAMED_BIND */ 525 526 errno = 0; 527 from = NULL; 528 529 /* initialize some macros, etc. */ 530 initmacros(CurEnv); 531 init_vendor_macros(CurEnv); 532 533 /* version */ 534 define('v', Version, CurEnv); 535 536 /* hostname */ 537 hp = myhostname(jbuf, sizeof jbuf); 538 if (jbuf[0] != '\0') 539 { 540 struct utsname utsname; 541 542 if (tTd(0, 4)) 543 dprintf("canonical name: %s\n", jbuf); 544 define('w', newstr(jbuf), CurEnv); /* must be new string */ 545 define('j', newstr(jbuf), CurEnv); 546 setclass('w', jbuf); 547 548 p = strchr(jbuf, '.'); 549 if (p != NULL) 550 { 551 if (p[1] != '\0') 552 { 553 define('m', newstr(&p[1]), CurEnv); 554 } 555 while (p != NULL && strchr(&p[1], '.') != NULL) 556 { 557 *p = '\0'; 558 if (tTd(0, 4)) 559 dprintf("\ta.k.a.: %s\n", jbuf); 560 setclass('w', jbuf); 561 *p++ = '.'; 562 p = strchr(p, '.'); 563 } 564 } 565 566 if (uname(&utsname) >= 0) 567 p = utsname.nodename; 568 else 569 { 570 if (tTd(0, 22)) 571 dprintf("uname failed (%s)\n", 572 errstring(errno)); 573 makelower(jbuf); 574 p = jbuf; 575 } 576 if (tTd(0, 4)) 577 dprintf(" UUCP nodename: %s\n", p); 578 p = newstr(p); 579 define('k', p, CurEnv); 580 setclass('k', p); 581 setclass('w', p); 582 } 583 if (hp != NULL) 584 { 585 for (av = hp->h_aliases; av != NULL && *av != NULL; av++) 586 { 587 if (tTd(0, 4)) 588 dprintf("\ta.k.a.: %s\n", *av); 589 setclass('w', *av); 590 } 591 #if NETINET || NETINET6 592 for (i = 0; hp->h_addr_list[i] != NULL; i++) 593 { 594 # if NETINET6 595 char *addr; 596 char buf6[INET6_ADDRSTRLEN]; 597 struct in6_addr ia6; 598 # endif /* NETINET6 */ 599 # if NETINET 600 struct in_addr ia; 601 # endif /* NETINET */ 602 char ipbuf[103]; 603 604 ipbuf[0] = '\0'; 605 switch (hp->h_addrtype) 606 { 607 # if NETINET 608 case AF_INET: 609 if (hp->h_length != INADDRSZ) 610 break; 611 612 memmove(&ia, hp->h_addr_list[i], INADDRSZ); 613 (void) snprintf(ipbuf, sizeof ipbuf, 614 "[%.100s]", inet_ntoa(ia)); 615 break; 616 # endif /* NETINET */ 617 618 # if NETINET6 619 case AF_INET6: 620 if (hp->h_length != IN6ADDRSZ) 621 break; 622 623 memmove(&ia6, hp->h_addr_list[i], IN6ADDRSZ); 624 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 625 if (addr != NULL) 626 (void) snprintf(ipbuf, sizeof ipbuf, 627 "[%.100s]", addr); 628 break; 629 # endif /* NETINET6 */ 630 } 631 if (ipbuf[0] == '\0') 632 break; 633 634 if (tTd(0, 4)) 635 dprintf("\ta.k.a.: %s\n", ipbuf); 636 setclass('w', ipbuf); 637 } 638 #endif /* NETINET || NETINET6 */ 639 #if _FFR_FREEHOSTENT && NETINET6 640 freehostent(hp); 641 hp = NULL; 642 #endif /* _FFR_FREEHOSTENT && NETINET6 */ 643 } 644 645 /* current time */ 646 define('b', arpadate((char *) NULL), CurEnv); 647 /* current load average */ 648 CurrentLA = sm_getla(CurEnv); 649 650 QueueLimitRecipient = (QUEUE_CHAR *) NULL; 651 QueueLimitSender = (QUEUE_CHAR *) NULL; 652 QueueLimitId = (QUEUE_CHAR *) NULL; 653 654 /* 655 ** Crack argv. 656 */ 657 658 av = argv; 659 p = strrchr(*av, '/'); 660 if (p++ == NULL) 661 p = *av; 662 if (strcmp(p, "newaliases") == 0) 663 OpMode = MD_INITALIAS; 664 else if (strcmp(p, "mailq") == 0) 665 OpMode = MD_PRINT; 666 else if (strcmp(p, "smtpd") == 0) 667 OpMode = MD_DAEMON; 668 else if (strcmp(p, "hoststat") == 0) 669 OpMode = MD_HOSTSTAT; 670 else if (strcmp(p, "purgestat") == 0) 671 OpMode = MD_PURGESTAT; 672 673 optind = 1; 674 while ((j = getopt(argc, argv, OPTIONS)) != -1) 675 { 676 switch (j) 677 { 678 case 'b': /* operations mode */ 679 switch (j = *optarg) 680 { 681 case MD_DAEMON: 682 case MD_FGDAEMON: 683 #if !DAEMON 684 usrerr("Daemon mode not implemented"); 685 ExitStat = EX_USAGE; 686 break; 687 #endif /* !DAEMON */ 688 case MD_SMTP: 689 #if !SMTP 690 usrerr("I don't speak SMTP"); 691 ExitStat = EX_USAGE; 692 break; 693 #endif /* !SMTP */ 694 695 case MD_INITALIAS: 696 case MD_DELIVER: 697 case MD_VERIFY: 698 case MD_TEST: 699 case MD_PRINT: 700 case MD_HOSTSTAT: 701 case MD_PURGESTAT: 702 case MD_ARPAFTP: 703 OpMode = j; 704 break; 705 706 case MD_FREEZE: 707 usrerr("Frozen configurations unsupported"); 708 ExitStat = EX_USAGE; 709 break; 710 711 default: 712 usrerr("Invalid operation mode %c", j); 713 ExitStat = EX_USAGE; 714 break; 715 } 716 break; 717 718 case 'B': /* body type */ 719 CurEnv->e_bodytype = newstr(optarg); 720 break; 721 722 case 'C': /* select configuration file (already done) */ 723 if (RealUid != 0) 724 warn_C_flag = TRUE; 725 ConfFile = newstr(optarg); 726 dp = drop_privileges(TRUE); 727 setstat(dp); 728 safecf = FALSE; 729 break; 730 731 case 'd': /* debugging -- already done */ 732 break; 733 734 case 'f': /* from address */ 735 case 'r': /* obsolete -f flag */ 736 if (from != NULL) 737 { 738 usrerr("More than one \"from\" person"); 739 ExitStat = EX_USAGE; 740 break; 741 } 742 from = newstr(denlstring(optarg, TRUE, TRUE)); 743 if (strcmp(RealUserName, from) != 0) 744 warn_f_flag = j; 745 break; 746 747 case 'F': /* set full name */ 748 FullName = newstr(optarg); 749 break; 750 751 case 'G': /* relay (gateway) submission */ 752 /* already set */ 753 break; 754 755 case 'h': /* hop count */ 756 CurEnv->e_hopcount = (short) strtol(optarg, &ep, 10); 757 if (*ep) 758 { 759 usrerr("Bad hop count (%s)", optarg); 760 ExitStat = EX_USAGE; 761 } 762 break; 763 764 case 'L': /* program label */ 765 /* already set */ 766 break; 767 768 case 'n': /* don't alias */ 769 NoAlias = TRUE; 770 break; 771 772 case 'N': /* delivery status notifications */ 773 DefaultNotify |= QHASNOTIFY; 774 define(macid("{dsn_notify}", NULL), 775 newstr(optarg), CurEnv); 776 if (strcasecmp(optarg, "never") == 0) 777 break; 778 for (p = optarg; p != NULL; optarg = p) 779 { 780 p = strchr(p, ','); 781 if (p != NULL) 782 *p++ = '\0'; 783 if (strcasecmp(optarg, "success") == 0) 784 DefaultNotify |= QPINGONSUCCESS; 785 else if (strcasecmp(optarg, "failure") == 0) 786 DefaultNotify |= QPINGONFAILURE; 787 else if (strcasecmp(optarg, "delay") == 0) 788 DefaultNotify |= QPINGONDELAY; 789 else 790 { 791 usrerr("Invalid -N argument"); 792 ExitStat = EX_USAGE; 793 } 794 } 795 break; 796 797 case 'o': /* set option */ 798 setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv); 799 break; 800 801 case 'O': /* set option (long form) */ 802 setoption(' ', optarg, FALSE, TRUE, CurEnv); 803 break; 804 805 case 'p': /* set protocol */ 806 p = strchr(optarg, ':'); 807 if (p != NULL) 808 { 809 *p++ = '\0'; 810 if (*p != '\0') 811 { 812 ep = xalloc(strlen(p) + 1); 813 cleanstrcpy(ep, p, MAXNAME); 814 define('s', ep, CurEnv); 815 } 816 } 817 if (*optarg != '\0') 818 { 819 ep = xalloc(strlen(optarg) + 1); 820 cleanstrcpy(ep, optarg, MAXNAME); 821 define('r', ep, CurEnv); 822 } 823 break; 824 825 case 'q': /* run queue files at intervals */ 826 #if QUEUE 827 /* sanity check */ 828 if (OpMode != MD_DELIVER && 829 OpMode != MD_DAEMON && 830 OpMode != MD_FGDAEMON && 831 OpMode != MD_PRINT && 832 OpMode != MD_QUEUERUN) 833 { 834 usrerr("Can not use -q with -b%c", OpMode); 835 ExitStat = EX_USAGE; 836 break; 837 } 838 839 /* don't override -bd, -bD or -bp */ 840 if (OpMode == MD_DELIVER) 841 OpMode = MD_QUEUERUN; 842 843 FullName = NULL; 844 845 switch (optarg[0]) 846 { 847 case 'I': 848 new = (QUEUE_CHAR *) xalloc(sizeof *new); 849 new->queue_match = newstr(&optarg[1]); 850 new->queue_next = QueueLimitId; 851 QueueLimitId = new; 852 break; 853 854 case 'R': 855 new = (QUEUE_CHAR *) xalloc(sizeof *new); 856 new->queue_match = newstr(&optarg[1]); 857 new->queue_next = QueueLimitRecipient; 858 QueueLimitRecipient = new; 859 break; 860 861 case 'S': 862 new = (QUEUE_CHAR *) xalloc(sizeof *new); 863 new->queue_match = newstr(&optarg[1]); 864 new->queue_next = QueueLimitSender; 865 QueueLimitSender = new; 866 break; 867 868 default: 869 i = Errors; 870 QueueIntvl = convtime(optarg, 'm'); 871 872 /* check for bad conversion */ 873 if (i < Errors) 874 ExitStat = EX_USAGE; 875 break; 876 } 877 #else /* QUEUE */ 878 usrerr("I don't know about queues"); 879 ExitStat = EX_USAGE; 880 #endif /* QUEUE */ 881 break; 882 883 case 'R': /* DSN RET: what to return */ 884 if (bitset(EF_RET_PARAM, CurEnv->e_flags)) 885 { 886 usrerr("Duplicate -R flag"); 887 ExitStat = EX_USAGE; 888 break; 889 } 890 CurEnv->e_flags |= EF_RET_PARAM; 891 if (strcasecmp(optarg, "hdrs") == 0) 892 CurEnv->e_flags |= EF_NO_BODY_RETN; 893 else if (strcasecmp(optarg, "full") != 0) 894 { 895 usrerr("Invalid -R value"); 896 ExitStat = EX_USAGE; 897 } 898 define(macid("{dsn_ret}", NULL), 899 newstr(optarg), CurEnv); 900 break; 901 902 case 't': /* read recipients from message */ 903 GrabTo = TRUE; 904 break; 905 906 case 'U': /* initial (user) submission */ 907 /* already set */ 908 break; 909 910 case 'V': /* DSN ENVID: set "original" envelope id */ 911 if (!xtextok(optarg)) 912 { 913 usrerr("Invalid syntax in -V flag"); 914 ExitStat = EX_USAGE; 915 } 916 else 917 { 918 CurEnv->e_envid = newstr(optarg); 919 define(macid("{dsn_envid}", NULL), 920 newstr(optarg), CurEnv); 921 } 922 break; 923 924 case 'X': /* traffic log file */ 925 dp = drop_privileges(TRUE); 926 setstat(dp); 927 if (stat(optarg, &traf_st) == 0 && 928 S_ISFIFO(traf_st.st_mode)) 929 TrafficLogFile = fopen(optarg, "w"); 930 else 931 TrafficLogFile = fopen(optarg, "a"); 932 if (TrafficLogFile == NULL) 933 { 934 syserr("cannot open %s", optarg); 935 ExitStat = EX_CANTCREAT; 936 break; 937 } 938 #if HASSETVBUF 939 (void) setvbuf(TrafficLogFile, NULL, _IOLBF, 0); 940 #else /* HASSETVBUF */ 941 (void) setlinebuf(TrafficLogFile); 942 #endif /* HASSETVBUF */ 943 break; 944 945 /* compatibility flags */ 946 case 'c': /* connect to non-local mailers */ 947 case 'i': /* don't let dot stop me */ 948 case 'm': /* send to me too */ 949 case 'T': /* set timeout interval */ 950 case 'v': /* give blow-by-blow description */ 951 setoption(j, "T", FALSE, TRUE, CurEnv); 952 break; 953 954 case 'e': /* error message disposition */ 955 case 'M': /* define macro */ 956 setoption(j, optarg, FALSE, TRUE, CurEnv); 957 break; 958 959 case 's': /* save From lines in headers */ 960 setoption('f', "T", FALSE, TRUE, CurEnv); 961 break; 962 963 #ifdef DBM 964 case 'I': /* initialize alias DBM file */ 965 OpMode = MD_INITALIAS; 966 break; 967 #endif /* DBM */ 968 969 #if defined(__osf__) || defined(_AIX3) 970 case 'x': /* random flag that OSF/1 & AIX mailx passes */ 971 break; 972 #endif /* defined(__osf__) || defined(_AIX3) */ 973 #if defined(sony_news) 974 case 'E': 975 case 'J': /* ignore flags for Japanese code conversion 976 implemented on Sony NEWS */ 977 break; 978 #endif /* defined(sony_news) */ 979 980 default: 981 finis(TRUE, EX_USAGE); 982 break; 983 } 984 } 985 av += optind; 986 987 if (bitset(SUBMIT_MTA, SubmitMode) && 988 bitset(SUBMIT_MSA, SubmitMode)) 989 { 990 /* sanity check */ 991 errno = 0; /* reset to avoid bogus error messages */ 992 syserr("Cannot use both -G and -U together"); 993 } 994 else if (bitset(SUBMIT_MTA, SubmitMode)) 995 define(macid("{daemon_flags}", NULL), "CC f", CurEnv); 996 else if (bitset(SUBMIT_MSA, SubmitMode)) 997 { 998 define(macid("{daemon_flags}", NULL), "c u", CurEnv); 999 1000 /* check for wrong OpMode */ 1001 if (OpMode != MD_DELIVER && OpMode != MD_SMTP) 1002 { 1003 errno = 0; /* reset to avoid bogus error msgs */ 1004 syserr("Cannot use -U and -b%c", OpMode); 1005 } 1006 } 1007 else 1008 { 1009 #if _FFR_DEFAULT_SUBMIT_TO_MSA 1010 define(macid("{daemon_flags}", NULL), "c u", CurEnv); 1011 #else /* _FFR_DEFAULT_SUBMIT_TO_MSA */ 1012 /* EMPTY */ 1013 #endif /* _FFR_DEFAULT_SUBMIT_TO_MSA */ 1014 } 1015 1016 /* 1017 ** Do basic initialization. 1018 ** Read system control file. 1019 ** Extract special fields for local use. 1020 */ 1021 1022 /* set up ${opMode} for use in config file */ 1023 { 1024 char mbuf[2]; 1025 1026 mbuf[0] = OpMode; 1027 mbuf[1] = '\0'; 1028 define(MID_OPMODE, newstr(mbuf), CurEnv); 1029 } 1030 1031 #if XDEBUG 1032 checkfd012("before readcf"); 1033 #endif /* XDEBUG */ 1034 vendor_pre_defaults(CurEnv); 1035 1036 readcf(getcfname(), safecf, CurEnv); 1037 ConfigFileRead = TRUE; 1038 vendor_post_defaults(CurEnv); 1039 1040 /* Remove the ability for a normal user to send signals */ 1041 if (RealUid != 0 && 1042 RealUid != geteuid()) 1043 { 1044 uid_t new_uid = geteuid(); 1045 1046 #if HASSETREUID 1047 /* 1048 ** Since we can differentiate between uid and euid, 1049 ** make the uid a different user so the real user 1050 ** can't send signals. However, it doesn't need to be 1051 ** root (euid has root). 1052 */ 1053 1054 if (new_uid == 0) 1055 new_uid = DefUid; 1056 if (tTd(47, 5)) 1057 dprintf("Changing real uid to %d\n", (int) new_uid); 1058 if (setreuid(new_uid, geteuid()) < 0) 1059 { 1060 syserr("main: setreuid(%d, %d) failed", 1061 (int) new_uid, (int) geteuid()); 1062 finis(FALSE, EX_OSERR); 1063 /* NOTREACHED */ 1064 } 1065 if (tTd(47, 10)) 1066 dprintf("Now running as e/ruid %d:%d\n", 1067 (int) geteuid(), (int) getuid()); 1068 #else /* HASSETREUID */ 1069 /* 1070 ** Have to change both effective and real so need to 1071 ** change them both to effective to keep privs. 1072 */ 1073 1074 if (tTd(47, 5)) 1075 dprintf("Changing uid to %d\n", (int) new_uid); 1076 if (setuid(new_uid) < 0) 1077 { 1078 syserr("main: setuid(%d) failed", (int) new_uid); 1079 finis(FALSE, EX_OSERR); 1080 /* NOTREACHED */ 1081 } 1082 if (tTd(47, 10)) 1083 dprintf("Now running as e/ruid %d:%d\n", 1084 (int) geteuid(), (int) getuid()); 1085 #endif /* HASSETREUID */ 1086 } 1087 1088 /* set up the basic signal handlers */ 1089 if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) 1090 (void) setsignal(SIGINT, intsig); 1091 (void) setsignal(SIGTERM, intsig); 1092 1093 /* Enforce use of local time (null string overrides this) */ 1094 if (TimeZoneSpec == NULL) 1095 unsetenv("TZ"); 1096 else if (TimeZoneSpec[0] != '\0') 1097 setuserenv("TZ", TimeZoneSpec); 1098 else 1099 setuserenv("TZ", NULL); 1100 tzset(); 1101 1102 /* avoid denial-of-service attacks */ 1103 resetlimits(); 1104 1105 if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) 1106 { 1107 /* drop privileges -- daemon mode done after socket/bind */ 1108 dp = drop_privileges(FALSE); 1109 setstat(dp); 1110 } 1111 1112 #if NAMED_BIND 1113 _res.retry = TimeOuts.res_retry[RES_TO_DEFAULT]; 1114 _res.retrans = TimeOuts.res_retrans[RES_TO_DEFAULT]; 1115 #endif /* NAMED_BIND */ 1116 1117 /* 1118 ** Find our real host name for future logging. 1119 */ 1120 1121 authinfo = getauthinfo(STDIN_FILENO, &forged); 1122 define('_', authinfo, CurEnv); 1123 1124 /* suppress error printing if errors mailed back or whatever */ 1125 if (CurEnv->e_errormode != EM_PRINT) 1126 HoldErrs = TRUE; 1127 1128 /* set up the $=m class now, after .cf has a chance to redefine $m */ 1129 expand("\201m", jbuf, sizeof jbuf, CurEnv); 1130 if (jbuf[0] != '\0') 1131 setclass('m', jbuf); 1132 1133 /* probe interfaces and locate any additional names */ 1134 if (!DontProbeInterfaces) 1135 load_if_names(); 1136 1137 if (tTd(0, 1)) 1138 { 1139 dprintf("\n============ SYSTEM IDENTITY (after readcf) ============"); 1140 dprintf("\n (short domain name) $w = "); 1141 xputs(macvalue('w', CurEnv)); 1142 dprintf("\n (canonical domain name) $j = "); 1143 xputs(macvalue('j', CurEnv)); 1144 dprintf("\n (subdomain name) $m = "); 1145 xputs(macvalue('m', CurEnv)); 1146 dprintf("\n (node name) $k = "); 1147 xputs(macvalue('k', CurEnv)); 1148 dprintf("\n========================================================\n\n"); 1149 } 1150 1151 /* 1152 ** Do more command line checking -- these are things that 1153 ** have to modify the results of reading the config file. 1154 */ 1155 1156 /* process authorization warnings from command line */ 1157 if (warn_C_flag) 1158 auth_warning(CurEnv, "Processed by %s with -C %s", 1159 RealUserName, ConfFile); 1160 if (Warn_Q_option && !wordinclass(RealUserName, 't')) 1161 auth_warning(CurEnv, "Processed from queue %s", QueueDir); 1162 1163 /* check body type for legality */ 1164 if (CurEnv->e_bodytype == NULL) 1165 /* EMPTY */ 1166 /* nothing */ ; 1167 else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0) 1168 SevenBitInput = TRUE; 1169 else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0) 1170 SevenBitInput = FALSE; 1171 else 1172 { 1173 usrerr("Illegal body type %s", CurEnv->e_bodytype); 1174 CurEnv->e_bodytype = NULL; 1175 } 1176 1177 /* tweak default DSN notifications */ 1178 if (DefaultNotify == 0) 1179 DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 1180 1181 /* be sure we don't pick up bogus HOSTALIASES environment variable */ 1182 if (OpMode == MD_QUEUERUN && RealUid != 0) 1183 (void) unsetenv("HOSTALIASES"); 1184 1185 /* check for sane configuration level */ 1186 if (ConfigLevel > MAXCONFIGLEVEL) 1187 { 1188 syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", 1189 ConfigLevel, Version, MAXCONFIGLEVEL); 1190 } 1191 1192 /* need MCI cache to have persistence */ 1193 if (HostStatDir != NULL && MaxMciCache == 0) 1194 { 1195 HostStatDir = NULL; 1196 printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); 1197 } 1198 1199 /* need HostStatusDir in order to have SingleThreadDelivery */ 1200 if (SingleThreadDelivery && HostStatDir == NULL) 1201 { 1202 SingleThreadDelivery = FALSE; 1203 printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n"); 1204 } 1205 1206 /* check for permissions */ 1207 if ((OpMode == MD_DAEMON || 1208 OpMode == MD_FGDAEMON || 1209 OpMode == MD_PURGESTAT) && 1210 RealUid != 0 && 1211 RealUid != TrustedUid) 1212 { 1213 if (LogLevel > 1) 1214 sm_syslog(LOG_ALERT, NOQID, 1215 "user %d attempted to %s", 1216 RealUid, 1217 OpMode != MD_PURGESTAT ? "run daemon" 1218 : "purge host status"); 1219 usrerr("Permission denied"); 1220 finis(FALSE, EX_USAGE); 1221 } 1222 if (OpMode == MD_INITALIAS && 1223 RealUid != 0 && 1224 RealUid != TrustedUid && 1225 !wordinclass(RealUserName, 't')) 1226 { 1227 if (LogLevel > 1) 1228 sm_syslog(LOG_ALERT, NOQID, 1229 "user %d attempted to rebuild the alias map", 1230 RealUid); 1231 usrerr("Permission denied"); 1232 finis(FALSE, EX_USAGE); 1233 } 1234 1235 if (MeToo) 1236 BlankEnvelope.e_flags |= EF_METOO; 1237 1238 switch (OpMode) 1239 { 1240 case MD_TEST: 1241 /* don't have persistent host status in test mode */ 1242 HostStatDir = NULL; 1243 if (Verbose == 0) 1244 Verbose = 2; 1245 CurEnv->e_errormode = EM_PRINT; 1246 HoldErrs = FALSE; 1247 break; 1248 1249 case MD_VERIFY: 1250 CurEnv->e_errormode = EM_PRINT; 1251 HoldErrs = FALSE; 1252 1253 /* arrange to exit cleanly on hangup signal */ 1254 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1255 (void) setsignal(SIGHUP, intsig); 1256 break; 1257 1258 case MD_FGDAEMON: 1259 run_in_foreground = TRUE; 1260 OpMode = MD_DAEMON; 1261 /* FALLTHROUGH */ 1262 1263 case MD_DAEMON: 1264 vendor_daemon_setup(CurEnv); 1265 1266 /* remove things that don't make sense in daemon mode */ 1267 FullName = NULL; 1268 GrabTo = FALSE; 1269 1270 /* arrange to restart on hangup signal */ 1271 if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 1272 sm_syslog(LOG_WARNING, NOQID, 1273 "daemon invoked without full pathname; kill -1 won't work"); 1274 (void) setsignal(SIGTERM, term_daemon); 1275 break; 1276 1277 case MD_INITALIAS: 1278 Verbose = 2; 1279 CurEnv->e_errormode = EM_PRINT; 1280 HoldErrs = FALSE; 1281 /* FALLTHROUGH */ 1282 1283 default: 1284 /* arrange to exit cleanly on hangup signal */ 1285 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1286 (void) setsignal(SIGHUP, intsig); 1287 break; 1288 } 1289 1290 /* special considerations for FullName */ 1291 if (FullName != NULL) 1292 { 1293 char *full = NULL; 1294 1295 /* full names can't have newlines */ 1296 if (strchr(FullName, '\n') != NULL) 1297 { 1298 full = newstr(denlstring(FullName, TRUE, TRUE)); 1299 FullName = full; 1300 } 1301 1302 /* check for characters that may have to be quoted */ 1303 if (!rfc822_string(FullName)) 1304 { 1305 /* 1306 ** Quote a full name with special characters 1307 ** as a comment so crackaddr() doesn't destroy 1308 ** the name portion of the address. 1309 */ 1310 1311 FullName = addquotes(FullName); 1312 if (full != NULL) 1313 sm_free(full); 1314 } 1315 } 1316 1317 /* do heuristic mode adjustment */ 1318 if (Verbose) 1319 { 1320 /* turn off noconnect option */ 1321 setoption('c', "F", TRUE, FALSE, CurEnv); 1322 1323 /* turn on interactive delivery */ 1324 setoption('d', "", TRUE, FALSE, CurEnv); 1325 } 1326 1327 #ifdef VENDOR_CODE 1328 /* check for vendor mismatch */ 1329 if (VendorCode != VENDOR_CODE) 1330 { 1331 message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 1332 getvendor(VENDOR_CODE), getvendor(VendorCode)); 1333 } 1334 #endif /* VENDOR_CODE */ 1335 1336 /* check for out of date configuration level */ 1337 if (ConfigLevel < MAXCONFIGLEVEL) 1338 { 1339 message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 1340 Version, MAXCONFIGLEVEL, ConfigLevel); 1341 } 1342 1343 if (ConfigLevel < 3) 1344 UseErrorsTo = TRUE; 1345 1346 /* set options that were previous macros */ 1347 if (SmtpGreeting == NULL) 1348 { 1349 if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL) 1350 SmtpGreeting = newstr(p); 1351 else 1352 SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 1353 } 1354 if (UnixFromLine == NULL) 1355 { 1356 if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL) 1357 UnixFromLine = newstr(p); 1358 else 1359 UnixFromLine = "From \201g \201d"; 1360 } 1361 SmtpError[0] = '\0'; 1362 1363 /* our name for SMTP codes */ 1364 expand("\201j", jbuf, sizeof jbuf, CurEnv); 1365 if (jbuf[0] == '\0') 1366 MyHostName = newstr("localhost"); 1367 else 1368 MyHostName = jbuf; 1369 if (strchr(MyHostName, '.') == NULL) 1370 message("WARNING: local host name (%s) is not qualified; fix $j in config file", 1371 MyHostName); 1372 1373 /* make certain that this name is part of the $=w class */ 1374 setclass('w', MyHostName); 1375 1376 /* the indices of built-in mailers */ 1377 st = stab("local", ST_MAILER, ST_FIND); 1378 if (st != NULL) 1379 LocalMailer = st->s_mailer; 1380 else if (OpMode != MD_TEST || !warn_C_flag) 1381 syserr("No local mailer defined"); 1382 1383 st = stab("prog", ST_MAILER, ST_FIND); 1384 if (st == NULL) 1385 syserr("No prog mailer defined"); 1386 else 1387 { 1388 ProgMailer = st->s_mailer; 1389 clrbitn(M_MUSER, ProgMailer->m_flags); 1390 } 1391 1392 st = stab("*file*", ST_MAILER, ST_FIND); 1393 if (st == NULL) 1394 syserr("No *file* mailer defined"); 1395 else 1396 { 1397 FileMailer = st->s_mailer; 1398 clrbitn(M_MUSER, FileMailer->m_flags); 1399 } 1400 1401 st = stab("*include*", ST_MAILER, ST_FIND); 1402 if (st == NULL) 1403 syserr("No *include* mailer defined"); 1404 else 1405 InclMailer = st->s_mailer; 1406 1407 if (ConfigLevel < 6) 1408 { 1409 /* heuristic tweaking of local mailer for back compat */ 1410 if (LocalMailer != NULL) 1411 { 1412 setbitn(M_ALIASABLE, LocalMailer->m_flags); 1413 setbitn(M_HASPWENT, LocalMailer->m_flags); 1414 setbitn(M_TRYRULESET5, LocalMailer->m_flags); 1415 setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 1416 setbitn(M_CHECKPROG, LocalMailer->m_flags); 1417 setbitn(M_CHECKFILE, LocalMailer->m_flags); 1418 setbitn(M_CHECKUDB, LocalMailer->m_flags); 1419 } 1420 if (ProgMailer != NULL) 1421 setbitn(M_RUNASRCPT, ProgMailer->m_flags); 1422 if (FileMailer != NULL) 1423 setbitn(M_RUNASRCPT, FileMailer->m_flags); 1424 } 1425 if (ConfigLevel < 7) 1426 { 1427 if (LocalMailer != NULL) 1428 setbitn(M_VRFY250, LocalMailer->m_flags); 1429 if (ProgMailer != NULL) 1430 setbitn(M_VRFY250, ProgMailer->m_flags); 1431 if (FileMailer != NULL) 1432 setbitn(M_VRFY250, FileMailer->m_flags); 1433 } 1434 1435 /* MIME Content-Types that cannot be transfer encoded */ 1436 setclass('n', "multipart/signed"); 1437 1438 /* MIME message/xxx subtypes that can be treated as messages */ 1439 setclass('s', "rfc822"); 1440 1441 /* MIME Content-Transfer-Encodings that can be encoded */ 1442 setclass('e', "7bit"); 1443 setclass('e', "8bit"); 1444 setclass('e', "binary"); 1445 1446 #ifdef USE_B_CLASS 1447 /* MIME Content-Types that should be treated as binary */ 1448 setclass('b', "image"); 1449 setclass('b', "audio"); 1450 setclass('b', "video"); 1451 setclass('b', "application/octet-stream"); 1452 #endif /* USE_B_CLASS */ 1453 1454 /* MIME headers which have fields to check for overflow */ 1455 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition"); 1456 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type"); 1457 1458 /* MIME headers to check for length overflow */ 1459 setclass(macid("{checkMIMETextHeaders}", NULL), "content-description"); 1460 1461 /* MIME headers to check for overflow and rebalance */ 1462 setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition"); 1463 setclass(macid("{checkMIMEHeaders}", NULL), "content-id"); 1464 setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding"); 1465 setclass(macid("{checkMIMEHeaders}", NULL), "content-type"); 1466 setclass(macid("{checkMIMEHeaders}", NULL), "mime-version"); 1467 1468 /* Macros to save in the qf file -- don't remove any */ 1469 setclass(macid("{persistentMacros}", NULL), "r"); 1470 setclass(macid("{persistentMacros}", NULL), "s"); 1471 setclass(macid("{persistentMacros}", NULL), "_"); 1472 setclass(macid("{persistentMacros}", NULL), "{if_addr}"); 1473 setclass(macid("{persistentMacros}", NULL), "{daemon_flags}"); 1474 setclass(macid("{persistentMacros}", NULL), "{client_flags}"); 1475 1476 /* operate in queue directory */ 1477 if (QueueDir == NULL) 1478 { 1479 if (OpMode != MD_TEST) 1480 { 1481 syserr("QueueDirectory (Q) option must be set"); 1482 ExitStat = EX_CONFIG; 1483 } 1484 } 1485 else 1486 { 1487 /* 1488 ** If multiple queues wildcarded, use one for 1489 ** the daemon's home. Note that this preconditions 1490 ** a wildcarded QueueDir to a real pathname. 1491 */ 1492 1493 if (OpMode != MD_TEST) 1494 multiqueue_cache(); 1495 } 1496 1497 /* check host status directory for validity */ 1498 if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE)) 1499 { 1500 /* cannot use this value */ 1501 if (tTd(0, 2)) 1502 dprintf("Cannot use HostStatusDirectory = %s: %s\n", 1503 HostStatDir, errstring(errno)); 1504 HostStatDir = NULL; 1505 } 1506 1507 #if QUEUE 1508 if (OpMode == MD_QUEUERUN && RealUid != 0 && 1509 bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 1510 { 1511 struct stat stbuf; 1512 1513 /* check to see if we own the queue directory */ 1514 if (stat(".", &stbuf) < 0) 1515 syserr("main: cannot stat %s", QueueDir); 1516 if (stbuf.st_uid != RealUid) 1517 { 1518 /* nope, really a botch */ 1519 usrerr("You do not have permission to process the queue"); 1520 finis(FALSE, EX_NOPERM); 1521 } 1522 } 1523 #endif /* QUEUE */ 1524 1525 #if _FFR_MILTER 1526 /* sanity checks on milter filters */ 1527 if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 1528 milter_parse_list(InputFilterList, InputFilters, MAXFILTERS); 1529 #endif /* _FFR_MILTER */ 1530 1531 1532 /* if we've had errors so far, exit now */ 1533 if (ExitStat != EX_OK && OpMode != MD_TEST) 1534 finis(FALSE, ExitStat); 1535 1536 #if XDEBUG 1537 checkfd012("before main() initmaps"); 1538 #endif /* XDEBUG */ 1539 1540 /* 1541 ** Do operation-mode-dependent initialization. 1542 */ 1543 1544 switch (OpMode) 1545 { 1546 case MD_PRINT: 1547 /* print the queue */ 1548 #if QUEUE 1549 dropenvelope(CurEnv, TRUE); 1550 (void) setsignal(SIGPIPE, quiesce); 1551 printqueue(); 1552 finis(FALSE, EX_OK); 1553 #else /* QUEUE */ 1554 usrerr("No queue to print"); 1555 finis(FALSE, EX_UNAVAILABLE); 1556 #endif /* QUEUE */ 1557 break; 1558 1559 case MD_HOSTSTAT: 1560 (void) setsignal(SIGPIPE, quiesce); 1561 (void) mci_traverse_persistent(mci_print_persistent, NULL); 1562 finis(FALSE, EX_OK); 1563 break; 1564 1565 case MD_PURGESTAT: 1566 (void) mci_traverse_persistent(mci_purge_persistent, NULL); 1567 finis(FALSE, EX_OK); 1568 break; 1569 1570 case MD_INITALIAS: 1571 /* initialize maps */ 1572 initmaps(); 1573 finis(FALSE, ExitStat); 1574 break; 1575 1576 case MD_SMTP: 1577 case MD_DAEMON: 1578 /* reset DSN parameters */ 1579 DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 1580 define(macid("{dsn_notify}", NULL), NULL, CurEnv); 1581 CurEnv->e_envid = NULL; 1582 define(macid("{dsn_envid}", NULL), NULL, CurEnv); 1583 CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 1584 define(macid("{dsn_ret}", NULL), NULL, CurEnv); 1585 1586 /* don't open maps for daemon -- done below in child */ 1587 break; 1588 } 1589 1590 if (tTd(0, 15)) 1591 { 1592 /* print configuration table (or at least part of it) */ 1593 if (tTd(0, 90)) 1594 printrules(); 1595 for (i = 0; i < MAXMAILERS; i++) 1596 { 1597 if (Mailer[i] != NULL) 1598 printmailer(Mailer[i]); 1599 } 1600 } 1601 1602 /* 1603 ** Switch to the main envelope. 1604 */ 1605 1606 CurEnv = newenvelope(&MainEnvelope, CurEnv); 1607 MainEnvelope.e_flags = BlankEnvelope.e_flags; 1608 1609 /* 1610 ** If test mode, read addresses from stdin and process. 1611 */ 1612 1613 if (OpMode == MD_TEST) 1614 { 1615 char buf[MAXLINE]; 1616 1617 #if _FFR_TESTMODE_DROP_PRIVS 1618 dp = drop_privileges(TRUE); 1619 if (dp != EX_OK) 1620 { 1621 CurEnv->e_id = NULL; 1622 finis(TRUE, dp); 1623 } 1624 #endif /* _FFR_TESTMODE_DROP_PRIVS */ 1625 1626 if (isatty(fileno(stdin))) 1627 Verbose = 2; 1628 1629 if (Verbose) 1630 { 1631 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 1632 printf("Enter <ruleset> <address>\n"); 1633 } 1634 if (setjmp(TopFrame) > 0) 1635 printf("\n"); 1636 (void) setsignal(SIGINT, intindebug); 1637 for (;;) 1638 { 1639 if (Verbose == 2) 1640 printf("> "); 1641 (void) fflush(stdout); 1642 if (fgets(buf, sizeof buf, stdin) == NULL) 1643 testmodeline("/quit", CurEnv); 1644 p = strchr(buf, '\n'); 1645 if (p != NULL) 1646 *p = '\0'; 1647 if (Verbose < 2) 1648 printf("> %s\n", buf); 1649 testmodeline(buf, CurEnv); 1650 } 1651 } 1652 1653 #if SMTP 1654 # if STARTTLS 1655 tls_ok = init_tls_library(); 1656 # endif /* STARTTLS */ 1657 #endif /* SMTP */ 1658 1659 #if QUEUE 1660 /* 1661 ** If collecting stuff from the queue, go start doing that. 1662 */ 1663 1664 if (OpMode == MD_QUEUERUN && QueueIntvl == 0) 1665 { 1666 # if SMTP 1667 # if STARTTLS 1668 if (tls_ok 1669 ) 1670 { 1671 /* init TLS for client, ignore result for now */ 1672 (void) initclttls(); 1673 } 1674 # endif /* STARTTLS */ 1675 # endif /* SMTP */ 1676 (void) runqueue(FALSE, Verbose); 1677 finis(TRUE, ExitStat); 1678 } 1679 #endif /* QUEUE */ 1680 1681 # if SASL 1682 if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 1683 { 1684 /* give a syserr or just disable AUTH ? */ 1685 if ((i = sasl_server_init(srvcallbacks, "Sendmail")) != SASL_OK) 1686 syserr("!sasl_server_init failed! [%s]", 1687 sasl_errstring(i, NULL, NULL)); 1688 } 1689 # endif /* SASL */ 1690 1691 /* 1692 ** If a daemon, wait for a request. 1693 ** getrequests will always return in a child. 1694 ** If we should also be processing the queue, start 1695 ** doing it in background. 1696 ** We check for any errors that might have happened 1697 ** during startup. 1698 */ 1699 1700 if (OpMode == MD_DAEMON || QueueIntvl != 0) 1701 { 1702 char dtype[200]; 1703 1704 if (!run_in_foreground && !tTd(99, 100)) 1705 { 1706 /* put us in background */ 1707 i = fork(); 1708 if (i < 0) 1709 syserr("daemon: cannot fork"); 1710 if (i != 0) 1711 finis(FALSE, EX_OK); 1712 1713 /* disconnect from our controlling tty */ 1714 disconnect(2, CurEnv); 1715 } 1716 1717 dtype[0] = '\0'; 1718 if (OpMode == MD_DAEMON) 1719 (void) strlcat(dtype, "+SMTP", sizeof dtype); 1720 if (QueueIntvl != 0) 1721 { 1722 (void) strlcat(dtype, "+queueing@", sizeof dtype); 1723 (void) strlcat(dtype, pintvl(QueueIntvl, TRUE), 1724 sizeof dtype); 1725 } 1726 if (tTd(0, 1)) 1727 (void) strlcat(dtype, "+debugging", sizeof dtype); 1728 1729 sm_syslog(LOG_INFO, NOQID, 1730 "starting daemon (%s): %s", Version, dtype + 1); 1731 #ifdef XLA 1732 xla_create_file(); 1733 #endif /* XLA */ 1734 1735 /* save daemon type in a macro for possible PidFile use */ 1736 define(macid("{daemon_info}", NULL), 1737 newstr(dtype + 1), &BlankEnvelope); 1738 1739 /* save queue interval in a macro for possible PidFile use */ 1740 define(macid("{queue_interval}", NULL), 1741 newstr(pintvl(QueueIntvl, TRUE)), CurEnv); 1742 1743 #if QUEUE 1744 if (QueueIntvl != 0) 1745 { 1746 (void) runqueue(TRUE, FALSE); 1747 if (OpMode != MD_DAEMON) 1748 { 1749 /* write the pid to file */ 1750 log_sendmail_pid(CurEnv); 1751 (void) setsignal(SIGTERM, term_daemon); 1752 for (;;) 1753 { 1754 (void) pause(); 1755 if (ShutdownRequest != NULL) 1756 shutdown_daemon(); 1757 else if (DoQueueRun) 1758 (void) runqueue(TRUE, FALSE); 1759 } 1760 } 1761 } 1762 #endif /* QUEUE */ 1763 dropenvelope(CurEnv, TRUE); 1764 1765 #if DAEMON 1766 # if STARTTLS 1767 /* init TLS for server, ignore result for now */ 1768 (void) initsrvtls(); 1769 # endif /* STARTTLS */ 1770 p_flags = getrequests(CurEnv); 1771 1772 /* drop privileges */ 1773 (void) drop_privileges(FALSE); 1774 1775 /* at this point we are in a child: reset state */ 1776 (void) newenvelope(CurEnv, CurEnv); 1777 1778 /* 1779 ** Get authentication data 1780 */ 1781 1782 authinfo = getauthinfo(fileno(InChannel), &forged); 1783 define('_', authinfo, &BlankEnvelope); 1784 #endif /* DAEMON */ 1785 } 1786 1787 if (LogLevel > 9) 1788 { 1789 /* log connection information */ 1790 sm_syslog(LOG_INFO, NULL, "connect from %.100s", authinfo); 1791 } 1792 1793 #if SMTP 1794 /* 1795 ** If running SMTP protocol, start collecting and executing 1796 ** commands. This will never return. 1797 */ 1798 1799 if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 1800 { 1801 char pbuf[20]; 1802 1803 /* 1804 ** Save some macros for check_* rulesets. 1805 */ 1806 1807 if (forged) 1808 { 1809 char ipbuf[103]; 1810 1811 (void) snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 1812 anynet_ntoa(&RealHostAddr)); 1813 define(macid("{client_name}", NULL), 1814 newstr(ipbuf), &BlankEnvelope); 1815 define(macid("{client_resolve}", NULL), 1816 "FORGED", &BlankEnvelope); 1817 } 1818 else 1819 define(macid("{client_name}", NULL), RealHostName, 1820 &BlankEnvelope); 1821 define(macid("{client_addr}", NULL), 1822 newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); 1823 (void)sm_getla(&BlankEnvelope); 1824 1825 switch(RealHostAddr.sa.sa_family) 1826 { 1827 # if NETINET 1828 case AF_INET: 1829 (void) snprintf(pbuf, sizeof pbuf, "%d", 1830 RealHostAddr.sin.sin_port); 1831 break; 1832 # endif /* NETINET */ 1833 # if NETINET6 1834 case AF_INET6: 1835 (void) snprintf(pbuf, sizeof pbuf, "%d", 1836 RealHostAddr.sin6.sin6_port); 1837 break; 1838 # endif /* NETINET6 */ 1839 default: 1840 (void) snprintf(pbuf, sizeof pbuf, "0"); 1841 break; 1842 } 1843 define(macid("{client_port}", NULL), 1844 newstr(pbuf), &BlankEnvelope); 1845 1846 if (OpMode == MD_DAEMON) 1847 { 1848 /* validate the connection */ 1849 HoldErrs = TRUE; 1850 nullserver = validate_connection(&RealHostAddr, 1851 RealHostName, CurEnv); 1852 HoldErrs = FALSE; 1853 } 1854 else if (p_flags == NULL) 1855 { 1856 p_flags = (BITMAP256 *) xalloc(sizeof *p_flags); 1857 clrbitmap(p_flags); 1858 } 1859 # if STARTTLS 1860 if (OpMode == MD_SMTP) 1861 (void) initsrvtls(); 1862 # endif /* STARTTLS */ 1863 1864 1865 smtp(nullserver, *p_flags, CurEnv); 1866 } 1867 #endif /* SMTP */ 1868 1869 clearenvelope(CurEnv, FALSE); 1870 if (OpMode == MD_VERIFY) 1871 { 1872 set_delivery_mode(SM_VERIFY, CurEnv); 1873 PostMasterCopy = NULL; 1874 } 1875 else 1876 { 1877 /* interactive -- all errors are global */ 1878 CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 1879 } 1880 1881 /* 1882 ** Do basic system initialization and set the sender 1883 */ 1884 1885 initsys(CurEnv); 1886 define(macid("{ntries}", NULL), "0", CurEnv); 1887 setsender(from, CurEnv, NULL, '\0', FALSE); 1888 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't') && 1889 (!bitnset(M_LOCALMAILER, CurEnv->e_from.q_mailer->m_flags) || 1890 strcmp(CurEnv->e_from.q_user, RealUserName) != 0)) 1891 { 1892 auth_warning(CurEnv, "%s set sender to %s using -%c", 1893 RealUserName, from, warn_f_flag); 1894 #if SASL 1895 auth = FALSE; 1896 #endif /* SASL */ 1897 } 1898 if (auth) 1899 { 1900 char *fv; 1901 1902 /* set the initial sender for AUTH= to $f@$j */ 1903 fv = macvalue('f', CurEnv); 1904 if (fv == NULL || *fv == '\0') 1905 CurEnv->e_auth_param = NULL; 1906 else 1907 { 1908 if (strchr(fv, '@') == NULL) 1909 { 1910 i = strlen(fv) + strlen(macvalue('j', CurEnv)) 1911 + 2; 1912 p = xalloc(i); 1913 (void) snprintf(p, i, "%s@%s", fv, 1914 macvalue('j', CurEnv)); 1915 } 1916 else 1917 p = newstr(fv); 1918 CurEnv->e_auth_param = newstr(xtextify(p, "=")); 1919 } 1920 } 1921 if (macvalue('s', CurEnv) == NULL) 1922 define('s', RealHostName, CurEnv); 1923 1924 if (*av == NULL && !GrabTo) 1925 { 1926 CurEnv->e_to = NULL; 1927 CurEnv->e_flags |= EF_GLOBALERRS; 1928 HoldErrs = FALSE; 1929 SuperSafe = FALSE; 1930 usrerr("Recipient names must be specified"); 1931 1932 /* collect body for UUCP return */ 1933 if (OpMode != MD_VERIFY) 1934 collect(InChannel, FALSE, NULL, CurEnv); 1935 finis(TRUE, EX_USAGE); 1936 } 1937 1938 /* 1939 ** Scan argv and deliver the message to everyone. 1940 */ 1941 1942 sendtoargv(av, CurEnv); 1943 1944 /* if we have had errors sofar, arrange a meaningful exit stat */ 1945 if (Errors > 0 && ExitStat == EX_OK) 1946 ExitStat = EX_USAGE; 1947 1948 #if _FFR_FIX_DASHT 1949 /* 1950 ** If using -t, force not sending to argv recipients, even 1951 ** if they are mentioned in the headers. 1952 */ 1953 1954 if (GrabTo) 1955 { 1956 ADDRESS *q; 1957 1958 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 1959 q->q_state = QS_REMOVED; 1960 } 1961 #endif /* _FFR_FIX_DASHT */ 1962 1963 /* 1964 ** Read the input mail. 1965 */ 1966 1967 CurEnv->e_to = NULL; 1968 if (OpMode != MD_VERIFY || GrabTo) 1969 { 1970 int savederrors = Errors; 1971 long savedflags = CurEnv->e_flags & EF_FATALERRS; 1972 1973 CurEnv->e_flags |= EF_GLOBALERRS; 1974 CurEnv->e_flags &= ~EF_FATALERRS; 1975 Errors = 0; 1976 buffer_errors(); 1977 collect(InChannel, FALSE, NULL, CurEnv); 1978 1979 /* header checks failed */ 1980 if (Errors > 0) 1981 { 1982 /* Log who the mail would have gone to */ 1983 if (LogLevel > 8 && CurEnv->e_message != NULL && 1984 !GrabTo) 1985 { 1986 ADDRESS *a; 1987 1988 for (a = CurEnv->e_sendqueue; 1989 a != NULL; 1990 a = a->q_next) 1991 { 1992 if (!QS_IS_UNDELIVERED(a->q_state)) 1993 continue; 1994 1995 CurEnv->e_to = a->q_paddr; 1996 logdelivery(NULL, NULL, NULL, 1997 CurEnv->e_message, 1998 NULL, (time_t) 0, CurEnv); 1999 } 2000 CurEnv->e_to = NULL; 2001 } 2002 flush_errors(TRUE); 2003 finis(TRUE, ExitStat); 2004 /* NOTREACHED */ 2005 return -1; 2006 } 2007 2008 /* bail out if message too large */ 2009 if (bitset(EF_CLRQUEUE, CurEnv->e_flags)) 2010 { 2011 finis(TRUE, ExitStat != EX_OK ? ExitStat : EX_DATAERR); 2012 /* NOTREACHED */ 2013 return -1; 2014 } 2015 Errors = savederrors; 2016 CurEnv->e_flags |= savedflags; 2017 } 2018 errno = 0; 2019 2020 if (tTd(1, 1)) 2021 dprintf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); 2022 2023 /* 2024 ** Actually send everything. 2025 ** If verifying, just ack. 2026 */ 2027 2028 CurEnv->e_from.q_state = QS_SENDER; 2029 if (tTd(1, 5)) 2030 { 2031 dprintf("main: QS_SENDER "); 2032 printaddr(&CurEnv->e_from, FALSE); 2033 } 2034 CurEnv->e_to = NULL; 2035 CurrentLA = sm_getla(CurEnv); 2036 GrabTo = FALSE; 2037 #if NAMED_BIND 2038 _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 2039 _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 2040 #endif /* NAMED_BIND */ 2041 sendall(CurEnv, SM_DEFAULT); 2042 2043 /* 2044 ** All done. 2045 ** Don't send return error message if in VERIFY mode. 2046 */ 2047 2048 finis(TRUE, ExitStat); 2049 /* NOTREACHED */ 2050 return ExitStat; 2051 } 2052 /* 2053 ** QUIESCE -- signal handler for SIGPIPE 2054 ** 2055 ** Parameters: 2056 ** sig -- incoming signal. 2057 ** 2058 ** Returns: 2059 ** none. 2060 ** 2061 ** Side Effects: 2062 ** Sets StopRequest which should cause the mailq/hoststatus 2063 ** display to stop. 2064 ** 2065 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2066 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2067 ** DOING. 2068 */ 2069 2070 /* ARGSUSED */ 2071 static SIGFUNC_DECL 2072 quiesce(sig) 2073 int sig; 2074 { 2075 int save_errno = errno; 2076 2077 FIX_SYSV_SIGNAL(sig, quiesce); 2078 StopRequest = TRUE; 2079 errno = save_errno; 2080 return SIGFUNC_RETURN; 2081 } 2082 /* 2083 ** STOP_SENDMAIL -- Stop the running program 2084 ** 2085 ** Parameters: 2086 ** none. 2087 ** 2088 ** Returns: 2089 ** none. 2090 ** 2091 ** Side Effects: 2092 ** exits. 2093 */ 2094 2095 void 2096 stop_sendmail() 2097 { 2098 /* reset uid for process accounting */ 2099 endpwent(); 2100 (void) setuid(RealUid); 2101 exit(EX_OK); 2102 } 2103 2104 /* 2105 ** INTINDEBUG -- signal handler for SIGINT in -bt mode 2106 ** 2107 ** Parameters: 2108 ** sig -- incoming signal. 2109 ** 2110 ** Returns: 2111 ** none. 2112 ** 2113 ** Side Effects: 2114 ** longjmps back to test mode loop. 2115 ** 2116 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2117 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2118 ** DOING. 2119 ** 2120 ** XXX: More work is needed for this signal handler. 2121 */ 2122 2123 /* ARGSUSED */ 2124 static SIGFUNC_DECL 2125 intindebug(sig) 2126 int sig; 2127 { 2128 int save_errno = errno; 2129 2130 FIX_SYSV_SIGNAL(sig, intindebug); 2131 errno = save_errno; 2132 CHECK_CRITICAL(sig); 2133 2134 errno = save_errno; 2135 longjmp(TopFrame, 1); 2136 return SIGFUNC_RETURN; 2137 } 2138 /* 2139 ** FINIS -- Clean up and exit. 2140 ** 2141 ** Parameters: 2142 ** drop -- whether or not to drop CurEnv envelope 2143 ** exitstat -- exit status to use for exit() call 2144 ** 2145 ** Returns: 2146 ** never 2147 ** 2148 ** Side Effects: 2149 ** exits sendmail 2150 */ 2151 2152 void 2153 finis(drop, exitstat) 2154 bool drop; 2155 volatile int exitstat; 2156 { 2157 /* Still want to process new timeouts added below */ 2158 clear_events(); 2159 releasesignal(SIGALRM); 2160 2161 if (tTd(2, 1)) 2162 { 2163 dprintf("\n====finis: stat %d e_id=%s e_flags=", 2164 exitstat, 2165 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 2166 printenvflags(CurEnv); 2167 } 2168 if (tTd(2, 9)) 2169 printopenfds(FALSE); 2170 2171 /* if we fail in finis(), just exit */ 2172 if (setjmp(TopFrame) != 0) 2173 { 2174 /* failed -- just give it up */ 2175 goto forceexit; 2176 } 2177 2178 /* clean up temp files */ 2179 CurEnv->e_to = NULL; 2180 if (drop) 2181 { 2182 if (CurEnv->e_id != NULL) 2183 dropenvelope(CurEnv, TRUE); 2184 else 2185 poststats(StatFile); 2186 } 2187 2188 /* flush any cached connections */ 2189 mci_flush(TRUE, NULL); 2190 2191 /* close maps belonging to this pid */ 2192 closemaps(); 2193 2194 #if USERDB 2195 /* close UserDatabase */ 2196 _udbx_close(); 2197 #endif /* USERDB */ 2198 2199 #ifdef XLA 2200 /* clean up extended load average stuff */ 2201 xla_all_end(); 2202 #endif /* XLA */ 2203 2204 /* and exit */ 2205 forceexit: 2206 if (LogLevel > 78) 2207 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2208 "finis, pid=%d", 2209 (int) getpid()); 2210 if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) 2211 exitstat = EX_OK; 2212 2213 sync_queue_time(); 2214 2215 /* reset uid for process accounting */ 2216 endpwent(); 2217 (void) setuid(RealUid); 2218 exit(exitstat); 2219 } 2220 /* 2221 ** TERM_DEAMON -- SIGTERM handler for the daemon 2222 ** 2223 ** Parameters: 2224 ** sig -- signal number. 2225 ** 2226 ** Returns: 2227 ** none. 2228 ** 2229 ** Side Effects: 2230 ** Sets ShutdownRequest which will hopefully trigger 2231 ** the daemon to exit. 2232 ** 2233 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2234 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2235 ** DOING. 2236 */ 2237 2238 /* ARGSUSED */ 2239 static SIGFUNC_DECL 2240 term_daemon(sig) 2241 int sig; 2242 { 2243 int save_errno = errno; 2244 2245 FIX_SYSV_SIGNAL(sig, term_daemon); 2246 ShutdownRequest = "signal"; 2247 errno = save_errno; 2248 return SIGFUNC_RETURN; 2249 } 2250 /* 2251 ** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 2252 ** 2253 ** Parameters: 2254 ** none. 2255 ** 2256 ** Returns: 2257 ** none. 2258 ** 2259 ** Side Effects: 2260 ** closes control socket, exits. 2261 */ 2262 2263 void 2264 shutdown_daemon() 2265 { 2266 char *reason; 2267 2268 allsignals(TRUE); 2269 2270 reason = ShutdownRequest; 2271 ShutdownRequest = NULL; 2272 PendingSignal = 0; 2273 2274 if (LogLevel > 79) 2275 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 2276 2277 FileName = NULL; 2278 closecontrolsocket(TRUE); 2279 #ifdef XLA 2280 xla_all_end(); 2281 #endif /* XLA */ 2282 2283 finis(FALSE, EX_OK); 2284 } 2285 /* 2286 ** INTSIG -- clean up on interrupt 2287 ** 2288 ** This just arranges to exit. It pessimizes in that it 2289 ** may resend a message. 2290 ** 2291 ** Parameters: 2292 ** none. 2293 ** 2294 ** Returns: 2295 ** none. 2296 ** 2297 ** Side Effects: 2298 ** Unlocks the current job. 2299 ** 2300 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2301 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2302 ** DOING. 2303 ** 2304 ** XXX: More work is needed for this signal handler. 2305 */ 2306 2307 /* ARGSUSED */ 2308 SIGFUNC_DECL 2309 intsig(sig) 2310 int sig; 2311 { 2312 bool drop = FALSE; 2313 int save_errno = errno; 2314 2315 FIX_SYSV_SIGNAL(sig, intsig); 2316 errno = save_errno; 2317 CHECK_CRITICAL(sig); 2318 allsignals(TRUE); 2319 if (sig != 0 && LogLevel > 79) 2320 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 2321 FileName = NULL; 2322 2323 /* Clean-up on aborted stdin message submission */ 2324 if (CurEnv->e_id != NULL && 2325 (OpMode == MD_SMTP || 2326 OpMode == MD_DELIVER || 2327 OpMode == MD_ARPAFTP)) 2328 { 2329 register ADDRESS *q; 2330 2331 /* don't return an error indication */ 2332 CurEnv->e_to = NULL; 2333 CurEnv->e_flags &= ~EF_FATALERRS; 2334 CurEnv->e_flags |= EF_CLRQUEUE; 2335 2336 /* 2337 ** Spin through the addresses and 2338 ** mark them dead to prevent bounces 2339 */ 2340 2341 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 2342 q->q_state = QS_DONTSEND; 2343 2344 /* and don't try to deliver the partial message either */ 2345 if (InChild) 2346 ExitStat = EX_QUIT; 2347 2348 drop = TRUE; 2349 } 2350 else 2351 unlockqueue(CurEnv); 2352 2353 finis(drop, EX_OK); 2354 } 2355 /* 2356 ** INITMACROS -- initialize the macro system 2357 ** 2358 ** This just involves defining some macros that are actually 2359 ** used internally as metasymbols to be themselves. 2360 ** 2361 ** Parameters: 2362 ** none. 2363 ** 2364 ** Returns: 2365 ** none. 2366 ** 2367 ** Side Effects: 2368 ** initializes several macros to be themselves. 2369 */ 2370 2371 struct metamac MetaMacros[] = 2372 { 2373 /* LHS pattern matching characters */ 2374 { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE }, 2375 { '=', MATCHCLASS }, { '~', MATCHNCLASS }, 2376 2377 /* these are RHS metasymbols */ 2378 { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER }, 2379 { '>', CALLSUBR }, 2380 2381 /* the conditional operations */ 2382 { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI }, 2383 2384 /* the hostname lookup characters */ 2385 { '[', HOSTBEGIN }, { ']', HOSTEND }, 2386 { '(', LOOKUPBEGIN }, { ')', LOOKUPEND }, 2387 2388 /* miscellaneous control characters */ 2389 { '&', MACRODEXPAND }, 2390 2391 { '\0', '\0' } 2392 }; 2393 2394 #define MACBINDING(name, mid) \ 2395 stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \ 2396 MacroName[mid] = name; 2397 2398 void 2399 initmacros(e) 2400 register ENVELOPE *e; 2401 { 2402 register struct metamac *m; 2403 register int c; 2404 char buf[5]; 2405 extern char *MacroName[MAXMACROID + 1]; 2406 2407 for (m = MetaMacros; m->metaname != '\0'; m++) 2408 { 2409 buf[0] = m->metaval; 2410 buf[1] = '\0'; 2411 define(m->metaname, newstr(buf), e); 2412 } 2413 buf[0] = MATCHREPL; 2414 buf[2] = '\0'; 2415 for (c = '0'; c <= '9'; c++) 2416 { 2417 buf[1] = c; 2418 define(c, newstr(buf), e); 2419 } 2420 2421 /* set defaults for some macros sendmail will use later */ 2422 define('n', "MAILER-DAEMON", e); 2423 2424 /* set up external names for some internal macros */ 2425 MACBINDING("opMode", MID_OPMODE); 2426 /*XXX should probably add equivalents for all short macros here XXX*/ 2427 } 2428 /* 2429 ** DISCONNECT -- remove our connection with any foreground process 2430 ** 2431 ** Parameters: 2432 ** droplev -- how "deeply" we should drop the line. 2433 ** 0 -- ignore signals, mail back errors, make sure 2434 ** output goes to stdout. 2435 ** 1 -- also, make stdout go to /dev/null. 2436 ** 2 -- also, disconnect from controlling terminal 2437 ** (only for daemon mode). 2438 ** e -- the current envelope. 2439 ** 2440 ** Returns: 2441 ** none 2442 ** 2443 ** Side Effects: 2444 ** Trys to insure that we are immune to vagaries of 2445 ** the controlling tty. 2446 */ 2447 2448 void 2449 disconnect(droplev, e) 2450 int droplev; 2451 register ENVELOPE *e; 2452 { 2453 int fd; 2454 2455 if (tTd(52, 1)) 2456 dprintf("disconnect: In %d Out %d, e=%lx\n", 2457 fileno(InChannel), fileno(OutChannel), (u_long) e); 2458 if (tTd(52, 100)) 2459 { 2460 dprintf("don't\n"); 2461 return; 2462 } 2463 if (LogLevel > 93) 2464 sm_syslog(LOG_DEBUG, e->e_id, 2465 "disconnect level %d", 2466 droplev); 2467 2468 /* be sure we don't get nasty signals */ 2469 (void) setsignal(SIGINT, SIG_IGN); 2470 (void) setsignal(SIGQUIT, SIG_IGN); 2471 2472 /* we can't communicate with our caller, so.... */ 2473 HoldErrs = TRUE; 2474 CurEnv->e_errormode = EM_MAIL; 2475 Verbose = 0; 2476 DisConnected = TRUE; 2477 2478 /* all input from /dev/null */ 2479 if (InChannel != stdin) 2480 { 2481 (void) fclose(InChannel); 2482 InChannel = stdin; 2483 } 2484 if (freopen("/dev/null", "r", stdin) == NULL) 2485 sm_syslog(LOG_ERR, e->e_id, 2486 "disconnect: freopen(\"/dev/null\") failed: %s", 2487 errstring(errno)); 2488 2489 /* output to the transcript */ 2490 if (OutChannel != stdout) 2491 { 2492 (void) fclose(OutChannel); 2493 OutChannel = stdout; 2494 } 2495 if (droplev > 0) 2496 { 2497 fd = open("/dev/null", O_WRONLY, 0666); 2498 if (fd == -1) 2499 sm_syslog(LOG_ERR, e->e_id, 2500 "disconnect: open(\"/dev/null\") failed: %s", 2501 errstring(errno)); 2502 (void) fflush(stdout); 2503 (void) dup2(fd, STDOUT_FILENO); 2504 (void) dup2(fd, STDERR_FILENO); 2505 (void) close(fd); 2506 } 2507 2508 /* drop our controlling TTY completely if possible */ 2509 if (droplev > 1) 2510 { 2511 (void) setsid(); 2512 errno = 0; 2513 } 2514 2515 #if XDEBUG 2516 checkfd012("disconnect"); 2517 #endif /* XDEBUG */ 2518 2519 if (LogLevel > 71) 2520 sm_syslog(LOG_DEBUG, e->e_id, 2521 "in background, pid=%d", 2522 (int) getpid()); 2523 2524 errno = 0; 2525 } 2526 2527 static void 2528 obsolete(argv) 2529 char *argv[]; 2530 { 2531 register char *ap; 2532 register char *op; 2533 2534 while ((ap = *++argv) != NULL) 2535 { 2536 /* Return if "--" or not an option of any form. */ 2537 if (ap[0] != '-' || ap[1] == '-') 2538 return; 2539 2540 /* skip over options that do have a value */ 2541 op = strchr(OPTIONS, ap[1]); 2542 if (op != NULL && *++op == ':' && ap[2] == '\0' && 2543 ap[1] != 'd' && 2544 #if defined(sony_news) 2545 ap[1] != 'E' && ap[1] != 'J' && 2546 #endif /* defined(sony_news) */ 2547 argv[1] != NULL && argv[1][0] != '-') 2548 { 2549 argv++; 2550 continue; 2551 } 2552 2553 /* If -C doesn't have an argument, use sendmail.cf. */ 2554 #define __DEFPATH "sendmail.cf" 2555 if (ap[1] == 'C' && ap[2] == '\0') 2556 { 2557 *argv = xalloc(sizeof(__DEFPATH) + 2); 2558 (void) snprintf(argv[0], sizeof(__DEFPATH) + 2, "-C%s", 2559 __DEFPATH); 2560 } 2561 2562 /* If -q doesn't have an argument, run it once. */ 2563 if (ap[1] == 'q' && ap[2] == '\0') 2564 *argv = "-q0"; 2565 2566 /* if -d doesn't have an argument, use 0-99.1 */ 2567 if (ap[1] == 'd' && ap[2] == '\0') 2568 *argv = "-d0-99.1"; 2569 2570 #if defined(sony_news) 2571 /* if -E doesn't have an argument, use -EC */ 2572 if (ap[1] == 'E' && ap[2] == '\0') 2573 *argv = "-EC"; 2574 2575 /* if -J doesn't have an argument, use -JJ */ 2576 if (ap[1] == 'J' && ap[2] == '\0') 2577 *argv = "-JJ"; 2578 #endif /* defined(sony_news) */ 2579 } 2580 } 2581 /* 2582 ** AUTH_WARNING -- specify authorization warning 2583 ** 2584 ** Parameters: 2585 ** e -- the current envelope. 2586 ** msg -- the text of the message. 2587 ** args -- arguments to the message. 2588 ** 2589 ** Returns: 2590 ** none. 2591 */ 2592 2593 void 2594 #ifdef __STDC__ 2595 auth_warning(register ENVELOPE *e, const char *msg, ...) 2596 #else /* __STDC__ */ 2597 auth_warning(e, msg, va_alist) 2598 register ENVELOPE *e; 2599 const char *msg; 2600 va_dcl 2601 #endif /* __STDC__ */ 2602 { 2603 char buf[MAXLINE]; 2604 VA_LOCAL_DECL 2605 2606 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 2607 { 2608 register char *p; 2609 static char hostbuf[48]; 2610 2611 if (hostbuf[0] == '\0') 2612 { 2613 struct hostent *hp; 2614 2615 hp = myhostname(hostbuf, sizeof hostbuf); 2616 #if _FFR_FREEHOSTENT && NETINET6 2617 if (hp != NULL) 2618 { 2619 freehostent(hp); 2620 hp = NULL; 2621 } 2622 #endif /* _FFR_FREEHOSTENT && NETINET6 */ 2623 } 2624 2625 (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); 2626 p = &buf[strlen(buf)]; 2627 VA_START(msg); 2628 vsnprintf(p, SPACELEFT(buf, p), msg, ap); 2629 VA_END; 2630 addheader("X-Authentication-Warning", buf, 0, &e->e_header); 2631 if (LogLevel > 3) 2632 sm_syslog(LOG_INFO, e->e_id, 2633 "Authentication-Warning: %.400s", 2634 buf); 2635 } 2636 } 2637 /* 2638 ** GETEXTENV -- get from external environment 2639 ** 2640 ** Parameters: 2641 ** envar -- the name of the variable to retrieve 2642 ** 2643 ** Returns: 2644 ** The value, if any. 2645 */ 2646 2647 char * 2648 getextenv(envar) 2649 const char *envar; 2650 { 2651 char **envp; 2652 int l; 2653 2654 l = strlen(envar); 2655 for (envp = ExternalEnviron; *envp != NULL; envp++) 2656 { 2657 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 2658 return &(*envp)[l + 1]; 2659 } 2660 return NULL; 2661 } 2662 /* 2663 ** SETUSERENV -- set an environment in the propogated environment 2664 ** 2665 ** Parameters: 2666 ** envar -- the name of the environment variable. 2667 ** value -- the value to which it should be set. If 2668 ** null, this is extracted from the incoming 2669 ** environment. If that is not set, the call 2670 ** to setuserenv is ignored. 2671 ** 2672 ** Returns: 2673 ** none. 2674 */ 2675 2676 void 2677 setuserenv(envar, value) 2678 const char *envar; 2679 const char *value; 2680 { 2681 int i, l; 2682 char **evp = UserEnviron; 2683 char *p; 2684 2685 if (value == NULL) 2686 { 2687 value = getextenv(envar); 2688 if (value == NULL) 2689 return; 2690 } 2691 2692 i = strlen(envar) + 1; 2693 l = strlen(value) + i + 1; 2694 p = (char *) xalloc(l); 2695 (void) snprintf(p, l, "%s=%s", envar, value); 2696 2697 while (*evp != NULL && strncmp(*evp, p, i) != 0) 2698 evp++; 2699 if (*evp != NULL) 2700 { 2701 *evp++ = p; 2702 } 2703 else if (evp < &UserEnviron[MAXUSERENVIRON]) 2704 { 2705 *evp++ = p; 2706 *evp = NULL; 2707 } 2708 2709 /* make sure it is in our environment as well */ 2710 if (putenv(p) < 0) 2711 syserr("setuserenv: putenv(%s) failed", p); 2712 } 2713 /* 2714 ** DUMPSTATE -- dump state 2715 ** 2716 ** For debugging. 2717 */ 2718 2719 void 2720 dumpstate(when) 2721 char *when; 2722 { 2723 register char *j = macvalue('j', CurEnv); 2724 int rs; 2725 extern int NextMacroId; 2726 2727 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2728 "--- dumping state on %s: $j = %s ---", 2729 when, 2730 j == NULL ? "<NULL>" : j); 2731 if (j != NULL) 2732 { 2733 if (!wordinclass(j, 'w')) 2734 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2735 "*** $j not in $=w ***"); 2736 } 2737 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 2738 sm_syslog(LOG_DEBUG, CurEnv->e_id, "NextMacroId = %d (Max %d)\n", 2739 NextMacroId, MAXMACROID); 2740 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 2741 printopenfds(TRUE); 2742 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 2743 mci_dump_all(TRUE); 2744 rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 2745 if (rs > 0) 2746 { 2747 int status; 2748 register char **pvp; 2749 char *pv[MAXATOM + 1]; 2750 2751 pv[0] = NULL; 2752 status = rewrite(pv, rs, 0, CurEnv); 2753 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2754 "--- ruleset debug_dumpstate returns stat %d, pv: ---", 2755 status); 2756 for (pvp = pv; *pvp != NULL; pvp++) 2757 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 2758 } 2759 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 2760 } 2761 /* 2762 ** SIGUSR1 -- Signal a request to dump state. 2763 ** 2764 ** Parameters: 2765 ** sig -- calling signal. 2766 ** 2767 ** Returns: 2768 ** none. 2769 ** 2770 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2771 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2772 ** DOING. 2773 ** 2774 ** XXX: More work is needed for this signal handler. 2775 */ 2776 2777 /* ARGSUSED */ 2778 static SIGFUNC_DECL 2779 sigusr1(sig) 2780 int sig; 2781 { 2782 int save_errno = errno; 2783 2784 FIX_SYSV_SIGNAL(sig, sigusr1); 2785 errno = save_errno; 2786 CHECK_CRITICAL(sig); 2787 dumpstate("user signal"); 2788 errno = save_errno; 2789 return SIGFUNC_RETURN; 2790 } 2791 /* 2792 ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 2793 ** 2794 ** Parameters: 2795 ** to_real_uid -- if set, drop to the real uid instead 2796 ** of the RunAsUser. 2797 ** 2798 ** Returns: 2799 ** EX_OSERR if the setuid failed. 2800 ** EX_OK otherwise. 2801 */ 2802 2803 int 2804 drop_privileges(to_real_uid) 2805 bool to_real_uid; 2806 { 2807 int rval = EX_OK; 2808 GIDSET_T emptygidset[1]; 2809 2810 if (tTd(47, 1)) 2811 dprintf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", 2812 (int)to_real_uid, (int)RealUid, 2813 (int)RealGid, (int)RunAsUid, (int)RunAsGid); 2814 2815 if (to_real_uid) 2816 { 2817 RunAsUserName = RealUserName; 2818 RunAsUid = RealUid; 2819 RunAsGid = RealGid; 2820 } 2821 2822 /* make sure no one can grab open descriptors for secret files */ 2823 endpwent(); 2824 2825 /* reset group permissions; these can be set later */ 2826 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 2827 if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 2828 { 2829 syserr("drop_privileges: setgroups(1, %d) failed", 2830 (int)emptygidset[0]); 2831 rval = EX_OSERR; 2832 } 2833 2834 /* reset primary group and user id */ 2835 if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0) 2836 { 2837 syserr("drop_privileges: setgid(%d) failed", (int)RunAsGid); 2838 rval = EX_OSERR; 2839 } 2840 if (to_real_uid || RunAsUid != 0) 2841 { 2842 uid_t euid = geteuid(); 2843 2844 if (setuid(RunAsUid) < 0) 2845 { 2846 syserr("drop_privileges: setuid(%d) failed", 2847 (int)RunAsUid); 2848 rval = EX_OSERR; 2849 } 2850 else if (RunAsUid != 0 && setuid(0) == 0) 2851 { 2852 /* 2853 ** Believe it or not, the Linux capability model 2854 ** allows a non-root process to override setuid() 2855 ** on a process running as root and prevent that 2856 ** process from dropping privileges. 2857 */ 2858 2859 syserr("drop_privileges: setuid(0) succeeded (when it should not)"); 2860 rval = EX_OSERR; 2861 } 2862 else if (RunAsUid != euid && setuid(euid) == 0) 2863 { 2864 /* 2865 ** Some operating systems will keep the saved-uid 2866 ** if a non-root effective-uid calls setuid(real-uid) 2867 ** making it possible to set it back again later. 2868 */ 2869 2870 syserr("drop_privileges: Unable to drop non-root set-user-id privileges"); 2871 rval = EX_OSERR; 2872 } 2873 } 2874 if (tTd(47, 5)) 2875 { 2876 dprintf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 2877 (int)geteuid(), (int)getuid(), 2878 (int)getegid(), (int)getgid()); 2879 dprintf("drop_privileges: RunAsUser = %d:%d\n", 2880 (int)RunAsUid, (int)RunAsGid); 2881 if (tTd(47, 10)) 2882 dprintf("drop_privileges: rval = %d\n", rval); 2883 } 2884 return rval; 2885 } 2886 /* 2887 ** FILL_FD -- make sure a file descriptor has been properly allocated 2888 ** 2889 ** Used to make sure that stdin/out/err are allocated on startup 2890 ** 2891 ** Parameters: 2892 ** fd -- the file descriptor to be filled. 2893 ** where -- a string used for logging. If NULL, this is 2894 ** being called on startup, and logging should 2895 ** not be done. 2896 ** 2897 ** Returns: 2898 ** none 2899 */ 2900 2901 void 2902 fill_fd(fd, where) 2903 int fd; 2904 char *where; 2905 { 2906 int i; 2907 struct stat stbuf; 2908 2909 if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 2910 return; 2911 2912 if (where != NULL) 2913 syserr("fill_fd: %s: fd %d not open", where, fd); 2914 else 2915 MissingFds |= 1 << fd; 2916 i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666); 2917 if (i < 0) 2918 { 2919 syserr("!fill_fd: %s: cannot open /dev/null", 2920 where == NULL ? "startup" : where); 2921 } 2922 if (fd != i) 2923 { 2924 (void) dup2(i, fd); 2925 (void) close(i); 2926 } 2927 } 2928 /* 2929 ** TESTMODELINE -- process a test mode input line 2930 ** 2931 ** Parameters: 2932 ** line -- the input line. 2933 ** e -- the current environment. 2934 ** Syntax: 2935 ** # a comment 2936 ** .X process X as a configuration line 2937 ** =X dump a configuration item (such as mailers) 2938 ** $X dump a macro or class 2939 ** /X try an activity 2940 ** X normal process through rule set X 2941 */ 2942 2943 static void 2944 testmodeline(line, e) 2945 char *line; 2946 ENVELOPE *e; 2947 { 2948 register char *p; 2949 char *q; 2950 auto char *delimptr; 2951 int mid; 2952 int i, rs; 2953 STAB *map; 2954 char **s; 2955 struct rewrite *rw; 2956 ADDRESS a; 2957 static int tryflags = RF_COPYNONE; 2958 char exbuf[MAXLINE]; 2959 extern u_char TokTypeNoC[]; 2960 2961 #if _FFR_ADDR_TYPE 2962 define(macid("{addr_type}", NULL), "e r", e); 2963 #endif /* _FFR_ADDR_TYPE */ 2964 2965 /* skip leading spaces */ 2966 while (*line == ' ') 2967 line++; 2968 2969 switch (line[0]) 2970 { 2971 case '#': 2972 case '\0': 2973 return; 2974 2975 case '?': 2976 help("-bt", e); 2977 return; 2978 2979 case '.': /* config-style settings */ 2980 switch (line[1]) 2981 { 2982 case 'D': 2983 mid = macid(&line[2], &delimptr); 2984 if (mid == 0) 2985 return; 2986 translate_dollars(delimptr); 2987 define(mid, newstr(delimptr), e); 2988 break; 2989 2990 case 'C': 2991 if (line[2] == '\0') /* not to call syserr() */ 2992 return; 2993 2994 mid = macid(&line[2], &delimptr); 2995 if (mid == 0) 2996 return; 2997 translate_dollars(delimptr); 2998 expand(delimptr, exbuf, sizeof exbuf, e); 2999 p = exbuf; 3000 while (*p != '\0') 3001 { 3002 register char *wd; 3003 char delim; 3004 3005 while (*p != '\0' && isascii(*p) && isspace(*p)) 3006 p++; 3007 wd = p; 3008 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3009 p++; 3010 delim = *p; 3011 *p = '\0'; 3012 if (wd[0] != '\0') 3013 setclass(mid, wd); 3014 *p = delim; 3015 } 3016 break; 3017 3018 case '\0': 3019 printf("Usage: .[DC]macro value(s)\n"); 3020 break; 3021 3022 default: 3023 printf("Unknown \".\" command %s\n", line); 3024 break; 3025 } 3026 return; 3027 3028 case '=': /* config-style settings */ 3029 switch (line[1]) 3030 { 3031 case 'S': /* dump rule set */ 3032 rs = strtorwset(&line[2], NULL, ST_FIND); 3033 if (rs < 0) 3034 { 3035 printf("Undefined ruleset %s\n", &line[2]); 3036 return; 3037 } 3038 rw = RewriteRules[rs]; 3039 if (rw == NULL) 3040 return; 3041 do 3042 { 3043 (void) putchar('R'); 3044 s = rw->r_lhs; 3045 while (*s != NULL) 3046 { 3047 xputs(*s++); 3048 (void) putchar(' '); 3049 } 3050 (void) putchar('\t'); 3051 (void) putchar('\t'); 3052 s = rw->r_rhs; 3053 while (*s != NULL) 3054 { 3055 xputs(*s++); 3056 (void) putchar(' '); 3057 } 3058 (void) putchar('\n'); 3059 } while ((rw = rw->r_next) != NULL); 3060 break; 3061 3062 case 'M': 3063 for (i = 0; i < MAXMAILERS; i++) 3064 { 3065 if (Mailer[i] != NULL) 3066 printmailer(Mailer[i]); 3067 } 3068 break; 3069 3070 case '\0': 3071 printf("Usage: =Sruleset or =M\n"); 3072 break; 3073 3074 default: 3075 printf("Unknown \"=\" command %s\n", line); 3076 break; 3077 } 3078 return; 3079 3080 case '-': /* set command-line-like opts */ 3081 switch (line[1]) 3082 { 3083 case 'd': 3084 tTflag(&line[2]); 3085 break; 3086 3087 case '\0': 3088 printf("Usage: -d{debug arguments}\n"); 3089 break; 3090 3091 default: 3092 printf("Unknown \"-\" command %s\n", line); 3093 break; 3094 } 3095 return; 3096 3097 case '$': 3098 if (line[1] == '=') 3099 { 3100 mid = macid(&line[2], NULL); 3101 if (mid != 0) 3102 stabapply(dump_class, mid); 3103 return; 3104 } 3105 mid = macid(&line[1], NULL); 3106 if (mid == 0) 3107 return; 3108 p = macvalue(mid, e); 3109 if (p == NULL) 3110 printf("Undefined\n"); 3111 else 3112 { 3113 xputs(p); 3114 printf("\n"); 3115 } 3116 return; 3117 3118 case '/': /* miscellaneous commands */ 3119 p = &line[strlen(line)]; 3120 while (--p >= line && isascii(*p) && isspace(*p)) 3121 *p = '\0'; 3122 p = strpbrk(line, " \t"); 3123 if (p != NULL) 3124 { 3125 while (isascii(*p) && isspace(*p)) 3126 *p++ = '\0'; 3127 } 3128 else 3129 p = ""; 3130 if (line[1] == '\0') 3131 { 3132 printf("Usage: /[canon|map|mx|parse|try|tryflags]\n"); 3133 return; 3134 } 3135 if (strcasecmp(&line[1], "quit") == 0) 3136 { 3137 CurEnv->e_id = NULL; 3138 finis(TRUE, ExitStat); 3139 } 3140 if (strcasecmp(&line[1], "mx") == 0) 3141 { 3142 #if NAMED_BIND 3143 /* look up MX records */ 3144 int nmx; 3145 auto int rcode; 3146 char *mxhosts[MAXMXHOSTS + 1]; 3147 3148 if (*p == '\0') 3149 { 3150 printf("Usage: /mx address\n"); 3151 return; 3152 } 3153 nmx = getmxrr(p, mxhosts, NULL, FALSE, &rcode); 3154 printf("getmxrr(%s) returns %d value(s):\n", p, nmx); 3155 for (i = 0; i < nmx; i++) 3156 printf("\t%s\n", mxhosts[i]); 3157 #else /* NAMED_BIND */ 3158 printf("No MX code compiled in\n"); 3159 #endif /* NAMED_BIND */ 3160 } 3161 else if (strcasecmp(&line[1], "canon") == 0) 3162 { 3163 char host[MAXHOSTNAMELEN]; 3164 3165 if (*p == '\0') 3166 { 3167 printf("Usage: /canon address\n"); 3168 return; 3169 } 3170 else if (strlcpy(host, p, sizeof host) >= sizeof host) 3171 { 3172 printf("Name too long\n"); 3173 return; 3174 } 3175 (void) getcanonname(host, sizeof host, HasWildcardMX); 3176 printf("getcanonname(%s) returns %s\n", p, host); 3177 } 3178 else if (strcasecmp(&line[1], "map") == 0) 3179 { 3180 auto int rcode = EX_OK; 3181 char *av[2]; 3182 3183 if (*p == '\0') 3184 { 3185 printf("Usage: /map mapname key\n"); 3186 return; 3187 } 3188 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 3189 continue; 3190 if (*q == '\0') 3191 { 3192 printf("No key specified\n"); 3193 return; 3194 } 3195 *q++ = '\0'; 3196 map = stab(p, ST_MAP, ST_FIND); 3197 if (map == NULL) 3198 { 3199 printf("Map named \"%s\" not found\n", p); 3200 return; 3201 } 3202 if (!bitset(MF_OPEN, map->s_map.map_mflags) && 3203 !openmap(&(map->s_map))) 3204 { 3205 printf("Map named \"%s\" not open\n", p); 3206 return; 3207 } 3208 printf("map_lookup: %s (%s) ", p, q); 3209 av[0] = q; 3210 av[1] = NULL; 3211 p = (*map->s_map.map_class->map_lookup) 3212 (&map->s_map, q, av, &rcode); 3213 if (p == NULL) 3214 printf("no match (%d)\n", rcode); 3215 else 3216 printf("returns %s (%d)\n", p, rcode); 3217 } 3218 else if (strcasecmp(&line[1], "try") == 0) 3219 { 3220 MAILER *m; 3221 STAB *st; 3222 auto int rcode = EX_OK; 3223 3224 q = strpbrk(p, " \t"); 3225 if (q != NULL) 3226 { 3227 while (isascii(*q) && isspace(*q)) 3228 *q++ = '\0'; 3229 } 3230 if (q == NULL || *q == '\0') 3231 { 3232 printf("Usage: /try mailer address\n"); 3233 return; 3234 } 3235 st = stab(p, ST_MAILER, ST_FIND); 3236 if (st == NULL) 3237 { 3238 printf("Unknown mailer %s\n", p); 3239 return; 3240 } 3241 m = st->s_mailer; 3242 printf("Trying %s %s address %s for mailer %s\n", 3243 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", 3244 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient", 3245 q, p); 3246 p = remotename(q, m, tryflags, &rcode, CurEnv); 3247 printf("Rcode = %d, addr = %s\n", 3248 rcode, p == NULL ? "<NULL>" : p); 3249 e->e_to = NULL; 3250 } 3251 else if (strcasecmp(&line[1], "tryflags") == 0) 3252 { 3253 if (*p == '\0') 3254 { 3255 printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 3256 return; 3257 } 3258 for (; *p != '\0'; p++) 3259 { 3260 switch (*p) 3261 { 3262 case 'H': 3263 case 'h': 3264 tryflags |= RF_HEADERADDR; 3265 break; 3266 3267 case 'E': 3268 case 'e': 3269 tryflags &= ~RF_HEADERADDR; 3270 break; 3271 3272 case 'S': 3273 case 's': 3274 tryflags |= RF_SENDERADDR; 3275 break; 3276 3277 case 'R': 3278 case 'r': 3279 tryflags &= ~RF_SENDERADDR; 3280 break; 3281 } 3282 } 3283 #if _FFR_ADDR_TYPE 3284 exbuf[0] = bitset(RF_HEADERADDR, tryflags) ? 'h' : 'e'; 3285 exbuf[1] = ' '; 3286 exbuf[2] = bitset(RF_SENDERADDR, tryflags) ? 's' : 'r'; 3287 exbuf[3] = '\0'; 3288 define(macid("{addr_type}", NULL), newstr(exbuf), e); 3289 #endif /* _FFR_ADDR_TYPE */ 3290 } 3291 else if (strcasecmp(&line[1], "parse") == 0) 3292 { 3293 if (*p == '\0') 3294 { 3295 printf("Usage: /parse address\n"); 3296 return; 3297 } 3298 q = crackaddr(p); 3299 printf("Cracked address = "); 3300 xputs(q); 3301 printf("\nParsing %s %s address\n", 3302 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", 3303 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient"); 3304 if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL) 3305 printf("Cannot parse\n"); 3306 else if (a.q_host != NULL && a.q_host[0] != '\0') 3307 printf("mailer %s, host %s, user %s\n", 3308 a.q_mailer->m_name, a.q_host, a.q_user); 3309 else 3310 printf("mailer %s, user %s\n", 3311 a.q_mailer->m_name, a.q_user); 3312 e->e_to = NULL; 3313 } 3314 else 3315 { 3316 printf("Unknown \"/\" command %s\n", line); 3317 } 3318 return; 3319 } 3320 3321 for (p = line; isascii(*p) && isspace(*p); p++) 3322 continue; 3323 q = p; 3324 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3325 p++; 3326 if (*p == '\0') 3327 { 3328 printf("No address!\n"); 3329 return; 3330 } 3331 *p = '\0'; 3332 if (invalidaddr(p + 1, NULL)) 3333 return; 3334 do 3335 { 3336 register char **pvp; 3337 char pvpbuf[PSBUFSIZE]; 3338 3339 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, 3340 &delimptr, ConfigLevel >= 9 ? TokTypeNoC : NULL); 3341 if (pvp == NULL) 3342 continue; 3343 p = q; 3344 while (*p != '\0') 3345 { 3346 int status; 3347 3348 rs = strtorwset(p, NULL, ST_FIND); 3349 if (rs < 0) 3350 { 3351 printf("Undefined ruleset %s\n", p); 3352 break; 3353 } 3354 status = rewrite(pvp, rs, 0, e); 3355 if (status != EX_OK) 3356 printf("== Ruleset %s (%d) status %d\n", 3357 p, rs, status); 3358 while (*p != '\0' && *p++ != ',') 3359 continue; 3360 } 3361 } while (*(p = delimptr) != '\0'); 3362 } 3363 3364 static void 3365 dump_class(s, id) 3366 register STAB *s; 3367 int id; 3368 { 3369 if (s->s_type != ST_CLASS) 3370 return; 3371 if (bitnset(bitidx(id), s->s_class)) 3372 printf("%s\n", s->s_name); 3373 } 3374