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