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 if (OpMode == MD_INITALIAS && 988 RealUid != 0 && 989 RealUid != TrustedUid && 990 !wordinclass(RealUserName, 't')) 991 { 992 if (LogLevel > 1) 993 sm_syslog(LOG_ALERT, NOQID, 994 "user %d attempted to rebuild the alias map", 995 RealUid); 996 usrerr("Permission denied"); 997 finis(FALSE, EX_USAGE); 998 } 999 1000 if (MeToo) 1001 BlankEnvelope.e_flags |= EF_METOO; 1002 1003 switch (OpMode) 1004 { 1005 case MD_TEST: 1006 /* don't have persistent host status in test mode */ 1007 HostStatDir = NULL; 1008 if (Verbose == 0) 1009 Verbose = 2; 1010 CurEnv->e_errormode = EM_PRINT; 1011 HoldErrs = FALSE; 1012 break; 1013 1014 case MD_VERIFY: 1015 CurEnv->e_errormode = EM_PRINT; 1016 HoldErrs = FALSE; 1017 /* arrange to exit cleanly on hangup signal */ 1018 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1019 setsignal(SIGHUP, intsig); 1020 break; 1021 1022 case MD_FGDAEMON: 1023 run_in_foreground = TRUE; 1024 OpMode = MD_DAEMON; 1025 /* fall through ... */ 1026 1027 case MD_DAEMON: 1028 vendor_daemon_setup(CurEnv); 1029 1030 /* remove things that don't make sense in daemon mode */ 1031 FullName = NULL; 1032 GrabTo = FALSE; 1033 1034 /* arrange to restart on hangup signal */ 1035 if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') 1036 sm_syslog(LOG_WARNING, NOQID, 1037 "daemon invoked without full pathname; kill -1 won't work"); 1038 setsignal(SIGHUP, sighup); 1039 1040 /* workaround: can't seem to release the signal in the parent */ 1041 releasesignal(SIGHUP); 1042 break; 1043 1044 case MD_INITALIAS: 1045 Verbose = 2; 1046 CurEnv->e_errormode = EM_PRINT; 1047 HoldErrs = FALSE; 1048 /* fall through... */ 1049 1050 case MD_PRINT: 1051 /* to handle sendmail -bp -qSfoobar properly */ 1052 queuemode = FALSE; 1053 /* fall through... */ 1054 1055 default: 1056 /* arrange to exit cleanly on hangup signal */ 1057 if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) 1058 setsignal(SIGHUP, intsig); 1059 break; 1060 } 1061 1062 /* special considerations for FullName */ 1063 if (FullName != NULL) 1064 { 1065 char *full = NULL; 1066 extern bool rfc822_string __P((char *)); 1067 1068 /* full names can't have newlines */ 1069 if (strchr(FullName, '\n') != NULL) 1070 { 1071 FullName = full = newstr(denlstring(FullName, TRUE, TRUE)); 1072 } 1073 /* check for characters that may have to be quoted */ 1074 if (!rfc822_string(FullName)) 1075 { 1076 extern char *addquotes __P((char *)); 1077 1078 /* 1079 ** Quote a full name with special characters 1080 ** as a comment so crackaddr() doesn't destroy 1081 ** the name portion of the address. 1082 */ 1083 FullName = addquotes(FullName); 1084 if (full != NULL) 1085 free(full); 1086 } 1087 } 1088 1089 /* do heuristic mode adjustment */ 1090 if (Verbose) 1091 { 1092 /* turn off noconnect option */ 1093 setoption('c', "F", TRUE, FALSE, CurEnv); 1094 1095 /* turn on interactive delivery */ 1096 setoption('d', "", TRUE, FALSE, CurEnv); 1097 } 1098 1099 #ifdef VENDOR_CODE 1100 /* check for vendor mismatch */ 1101 if (VendorCode != VENDOR_CODE) 1102 { 1103 extern char *getvendor __P((int)); 1104 1105 message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", 1106 getvendor(VENDOR_CODE), getvendor(VendorCode)); 1107 } 1108 #endif 1109 1110 /* check for out of date configuration level */ 1111 if (ConfigLevel < MAXCONFIGLEVEL) 1112 { 1113 message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", 1114 Version, MAXCONFIGLEVEL, ConfigLevel); 1115 } 1116 1117 if (ConfigLevel < 3) 1118 { 1119 UseErrorsTo = TRUE; 1120 } 1121 1122 /* set options that were previous macros */ 1123 if (SmtpGreeting == NULL) 1124 { 1125 if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL) 1126 SmtpGreeting = newstr(p); 1127 else 1128 SmtpGreeting = "\201j Sendmail \201v ready at \201b"; 1129 } 1130 if (UnixFromLine == NULL) 1131 { 1132 if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL) 1133 UnixFromLine = newstr(p); 1134 else 1135 UnixFromLine = "From \201g \201d"; 1136 } 1137 1138 /* our name for SMTP codes */ 1139 expand("\201j", jbuf, sizeof jbuf, CurEnv); 1140 MyHostName = jbuf; 1141 if (strchr(jbuf, '.') == NULL) 1142 message("WARNING: local host name (%s) is not qualified; fix $j in config file", 1143 jbuf); 1144 1145 /* make certain that this name is part of the $=w class */ 1146 setclass('w', MyHostName); 1147 1148 /* the indices of built-in mailers */ 1149 st = stab("local", ST_MAILER, ST_FIND); 1150 if (st != NULL) 1151 LocalMailer = st->s_mailer; 1152 else if (OpMode != MD_TEST || !warn_C_flag) 1153 syserr("No local mailer defined"); 1154 1155 st = stab("prog", ST_MAILER, ST_FIND); 1156 if (st == NULL) 1157 syserr("No prog mailer defined"); 1158 else 1159 { 1160 ProgMailer = st->s_mailer; 1161 clrbitn(M_MUSER, ProgMailer->m_flags); 1162 } 1163 1164 st = stab("*file*", ST_MAILER, ST_FIND); 1165 if (st == NULL) 1166 syserr("No *file* mailer defined"); 1167 else 1168 { 1169 FileMailer = st->s_mailer; 1170 clrbitn(M_MUSER, FileMailer->m_flags); 1171 } 1172 1173 st = stab("*include*", ST_MAILER, ST_FIND); 1174 if (st == NULL) 1175 syserr("No *include* mailer defined"); 1176 else 1177 InclMailer = st->s_mailer; 1178 1179 if (ConfigLevel < 6) 1180 { 1181 /* heuristic tweaking of local mailer for back compat */ 1182 if (LocalMailer != NULL) 1183 { 1184 setbitn(M_ALIASABLE, LocalMailer->m_flags); 1185 setbitn(M_HASPWENT, LocalMailer->m_flags); 1186 setbitn(M_TRYRULESET5, LocalMailer->m_flags); 1187 setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); 1188 setbitn(M_CHECKPROG, LocalMailer->m_flags); 1189 setbitn(M_CHECKFILE, LocalMailer->m_flags); 1190 setbitn(M_CHECKUDB, LocalMailer->m_flags); 1191 } 1192 if (ProgMailer != NULL) 1193 setbitn(M_RUNASRCPT, ProgMailer->m_flags); 1194 if (FileMailer != NULL) 1195 setbitn(M_RUNASRCPT, FileMailer->m_flags); 1196 } 1197 if (ConfigLevel < 7) 1198 { 1199 if (LocalMailer != NULL) 1200 setbitn(M_VRFY250, LocalMailer->m_flags); 1201 if (ProgMailer != NULL) 1202 setbitn(M_VRFY250, ProgMailer->m_flags); 1203 if (FileMailer != NULL) 1204 setbitn(M_VRFY250, FileMailer->m_flags); 1205 } 1206 1207 /* MIME Content-Types that cannot be transfer encoded */ 1208 setclass('n', "multipart/signed"); 1209 1210 /* MIME message/xxx subtypes that can be treated as messages */ 1211 setclass('s', "rfc822"); 1212 1213 /* MIME Content-Transfer-Encodings that can be encoded */ 1214 setclass('e', "7bit"); 1215 setclass('e', "8bit"); 1216 setclass('e', "binary"); 1217 1218 #ifdef USE_B_CLASS 1219 /* MIME Content-Types that should be treated as binary */ 1220 setclass('b', "image"); 1221 setclass('b', "audio"); 1222 setclass('b', "video"); 1223 setclass('b', "application/octet-stream"); 1224 #endif 1225 1226 #if _FFR_MAX_MIME_HEADER_LENGTH 1227 /* MIME headers which have fields to check for overflow */ 1228 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition"); 1229 setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type"); 1230 1231 /* MIME headers to check for length overflow */ 1232 setclass(macid("{checkMIMETextHeaders}", NULL), "content-description"); 1233 1234 /* MIME headers to check for overflow and rebalance */ 1235 setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition"); 1236 setclass(macid("{checkMIMEHeaders}", NULL), "content-id"); 1237 setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding"); 1238 setclass(macid("{checkMIMEHeaders}", NULL), "content-type"); 1239 setclass(macid("{checkMIMEHeaders}", NULL), "mime-version"); 1240 #endif 1241 1242 /* operate in queue directory */ 1243 if (QueueDir == NULL) 1244 { 1245 if (OpMode != MD_TEST) 1246 { 1247 syserr("QueueDirectory (Q) option must be set"); 1248 ExitStat = EX_CONFIG; 1249 } 1250 } 1251 else 1252 { 1253 /* test path to get warning messages */ 1254 (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE); 1255 if (OpMode != MD_TEST && chdir(QueueDir) < 0) 1256 { 1257 syserr("cannot chdir(%s)", QueueDir); 1258 ExitStat = EX_CONFIG; 1259 } 1260 } 1261 1262 /* check host status directory for validity */ 1263 if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE)) 1264 { 1265 /* cannot use this value */ 1266 if (tTd(0, 2)) 1267 printf("Cannot use HostStatusDirectory = %s: %s\n", 1268 HostStatDir, errstring(errno)); 1269 HostStatDir = NULL; 1270 } 1271 1272 # if QUEUE 1273 if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) 1274 { 1275 struct stat stbuf; 1276 1277 /* check to see if we own the queue directory */ 1278 if (stat(".", &stbuf) < 0) 1279 syserr("main: cannot stat %s", QueueDir); 1280 if (stbuf.st_uid != RealUid) 1281 { 1282 /* nope, really a botch */ 1283 usrerr("You do not have permission to process the queue"); 1284 finis(FALSE, EX_NOPERM); 1285 } 1286 } 1287 # endif /* QUEUE */ 1288 1289 /* if we've had errors so far, exit now */ 1290 if (ExitStat != EX_OK && OpMode != MD_TEST) 1291 finis(FALSE, ExitStat); 1292 1293 #if XDEBUG 1294 checkfd012("before main() initmaps"); 1295 #endif 1296 1297 /* 1298 ** Do operation-mode-dependent initialization. 1299 */ 1300 1301 switch (OpMode) 1302 { 1303 case MD_PRINT: 1304 /* print the queue */ 1305 #if QUEUE 1306 dropenvelope(CurEnv, TRUE); 1307 signal(SIGPIPE, quiesce); 1308 printqueue(); 1309 finis(FALSE, EX_OK); 1310 #else /* QUEUE */ 1311 usrerr("No queue to print"); 1312 finis(FALSE, ExitStat); 1313 #endif /* QUEUE */ 1314 break; 1315 1316 case MD_HOSTSTAT: 1317 signal(SIGPIPE, quiesce); 1318 mci_traverse_persistent(mci_print_persistent, NULL); 1319 finis(FALSE, EX_OK); 1320 break; 1321 1322 case MD_PURGESTAT: 1323 mci_traverse_persistent(mci_purge_persistent, NULL); 1324 finis(FALSE, EX_OK); 1325 break; 1326 1327 case MD_INITALIAS: 1328 /* initialize maps */ 1329 initmaps(TRUE, CurEnv); 1330 finis(FALSE, ExitStat); 1331 break; 1332 1333 case MD_SMTP: 1334 case MD_DAEMON: 1335 /* reset DSN parameters */ 1336 DefaultNotify = QPINGONFAILURE|QPINGONDELAY; 1337 CurEnv->e_envid = NULL; 1338 CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 1339 1340 /* don't open maps for daemon -- done below in child */ 1341 break; 1342 1343 default: 1344 /* open the maps */ 1345 initmaps(FALSE, CurEnv); 1346 break; 1347 } 1348 1349 if (tTd(0, 15)) 1350 { 1351 extern void printrules __P((void)); 1352 1353 /* print configuration table (or at least part of it) */ 1354 if (tTd(0, 90)) 1355 printrules(); 1356 for (i = 0; i < MAXMAILERS; i++) 1357 { 1358 if (Mailer[i] != NULL) 1359 printmailer(Mailer[i]); 1360 } 1361 } 1362 1363 /* 1364 ** Switch to the main envelope. 1365 */ 1366 1367 CurEnv = newenvelope(&MainEnvelope, CurEnv); 1368 MainEnvelope.e_flags = BlankEnvelope.e_flags; 1369 1370 /* 1371 ** If test mode, read addresses from stdin and process. 1372 */ 1373 1374 if (OpMode == MD_TEST) 1375 { 1376 char buf[MAXLINE]; 1377 SIGFUNC_DECL intindebug __P((int)); 1378 1379 if (isatty(fileno(stdin))) 1380 Verbose = 2; 1381 1382 if (Verbose) 1383 { 1384 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); 1385 printf("Enter <ruleset> <address>\n"); 1386 } 1387 if (setjmp(TopFrame) > 0) 1388 printf("\n"); 1389 (void) setsignal(SIGINT, intindebug); 1390 for (;;) 1391 { 1392 extern void testmodeline __P((char *, ENVELOPE *)); 1393 1394 if (Verbose == 2) 1395 printf("> "); 1396 (void) fflush(stdout); 1397 if (fgets(buf, sizeof buf, stdin) == NULL) 1398 finis(TRUE, ExitStat); 1399 p = strchr(buf, '\n'); 1400 if (p != NULL) 1401 *p = '\0'; 1402 if (Verbose < 2) 1403 printf("> %s\n", buf); 1404 testmodeline(buf, CurEnv); 1405 } 1406 } 1407 1408 # if QUEUE 1409 /* 1410 ** If collecting stuff from the queue, go start doing that. 1411 */ 1412 1413 if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) 1414 { 1415 (void) runqueue(FALSE, Verbose); 1416 finis(TRUE, ExitStat); 1417 } 1418 # endif /* QUEUE */ 1419 1420 /* 1421 ** If a daemon, wait for a request. 1422 ** getrequests will always return in a child. 1423 ** If we should also be processing the queue, start 1424 ** doing it in background. 1425 ** We check for any errors that might have happened 1426 ** during startup. 1427 */ 1428 1429 if (OpMode == MD_DAEMON || QueueIntvl != 0) 1430 { 1431 char dtype[200]; 1432 extern void getrequests __P((ENVELOPE *)); 1433 1434 if (!run_in_foreground && !tTd(99, 100)) 1435 { 1436 /* put us in background */ 1437 i = fork(); 1438 if (i < 0) 1439 syserr("daemon: cannot fork"); 1440 if (i != 0) 1441 finis(FALSE, EX_OK); 1442 1443 /* disconnect from our controlling tty */ 1444 disconnect(2, CurEnv); 1445 } 1446 1447 dtype[0] = '\0'; 1448 if (OpMode == MD_DAEMON) 1449 strcat(dtype, "+SMTP"); 1450 if (QueueIntvl != 0) 1451 { 1452 strcat(dtype, "+queueing@"); 1453 strcat(dtype, pintvl(QueueIntvl, TRUE)); 1454 } 1455 if (tTd(0, 1)) 1456 strcat(dtype, "+debugging"); 1457 1458 sm_syslog(LOG_INFO, NOQID, 1459 "starting daemon (%s): %s", Version, dtype + 1); 1460 #ifdef XLA 1461 xla_create_file(); 1462 #endif 1463 1464 # if QUEUE 1465 if (queuemode) 1466 { 1467 (void) runqueue(TRUE, FALSE); 1468 if (OpMode != MD_DAEMON) 1469 { 1470 for (;;) 1471 { 1472 pause(); 1473 if (DoQueueRun) 1474 (void) runqueue(TRUE, FALSE); 1475 } 1476 } 1477 } 1478 # endif /* QUEUE */ 1479 dropenvelope(CurEnv, TRUE); 1480 1481 #if DAEMON 1482 getrequests(CurEnv); 1483 1484 /* drop privileges */ 1485 (void) drop_privileges(FALSE); 1486 1487 /* at this point we are in a child: reset state */ 1488 (void) newenvelope(CurEnv, CurEnv); 1489 1490 /* 1491 ** Get authentication data 1492 */ 1493 1494 p = getauthinfo(fileno(InChannel), &forged); 1495 define('_', p, &BlankEnvelope); 1496 #endif /* DAEMON */ 1497 } 1498 1499 # if SMTP 1500 /* 1501 ** If running SMTP protocol, start collecting and executing 1502 ** commands. This will never return. 1503 */ 1504 1505 if (OpMode == MD_SMTP || OpMode == MD_DAEMON) 1506 { 1507 char pbuf[20]; 1508 extern void smtp __P((char *, ENVELOPE *)); 1509 1510 /* 1511 ** Save some macros for check_* rulesets. 1512 */ 1513 1514 if (forged) 1515 { 1516 char ipbuf[103]; 1517 1518 snprintf(ipbuf, sizeof ipbuf, "[%.100s]", 1519 inet_ntoa(RealHostAddr.sin.sin_addr)); 1520 1521 define(macid("{client_name}", NULL), 1522 newstr(ipbuf), &BlankEnvelope); 1523 } 1524 else 1525 define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope); 1526 define(macid("{client_addr}", NULL), 1527 newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); 1528 if (RealHostAddr.sa.sa_family == AF_INET) 1529 snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port); 1530 else 1531 snprintf(pbuf, sizeof pbuf, "0"); 1532 define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); 1533 1534 /* initialize maps now for check_relay ruleset */ 1535 initmaps(FALSE, CurEnv); 1536 1537 if (OpMode == MD_DAEMON) 1538 { 1539 /* validate the connection */ 1540 HoldErrs = TRUE; 1541 nullserver = validate_connection(&RealHostAddr, 1542 RealHostName, CurEnv); 1543 HoldErrs = FALSE; 1544 } 1545 smtp(nullserver, CurEnv); 1546 } 1547 # endif /* SMTP */ 1548 1549 clearenvelope(CurEnv, FALSE); 1550 if (OpMode == MD_VERIFY) 1551 { 1552 CurEnv->e_sendmode = SM_VERIFY; 1553 PostMasterCopy = NULL; 1554 } 1555 else 1556 { 1557 /* interactive -- all errors are global */ 1558 CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER; 1559 } 1560 1561 /* 1562 ** Do basic system initialization and set the sender 1563 */ 1564 1565 initsys(CurEnv); 1566 if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't')) 1567 auth_warning(CurEnv, "%s set sender to %s using -%c", 1568 RealUserName, from, warn_f_flag); 1569 setsender(from, CurEnv, NULL, '\0', FALSE); 1570 if (macvalue('s', CurEnv) == NULL) 1571 define('s', RealHostName, CurEnv); 1572 1573 if (*av == NULL && !GrabTo) 1574 { 1575 CurEnv->e_flags |= EF_GLOBALERRS; 1576 usrerr("Recipient names must be specified"); 1577 1578 /* collect body for UUCP return */ 1579 if (OpMode != MD_VERIFY) 1580 collect(InChannel, FALSE, NULL, CurEnv); 1581 finis(TRUE, ExitStat); 1582 } 1583 1584 /* 1585 ** Scan argv and deliver the message to everyone. 1586 */ 1587 1588 sendtoargv(av, CurEnv); 1589 1590 /* if we have had errors sofar, arrange a meaningful exit stat */ 1591 if (Errors > 0 && ExitStat == EX_OK) 1592 ExitStat = EX_USAGE; 1593 1594 #if _FFR_FIX_DASHT 1595 /* 1596 ** If using -t, force not sending to argv recipients, even 1597 ** if they are mentioned in the headers. 1598 */ 1599 1600 if (GrabTo) 1601 { 1602 ADDRESS *q; 1603 1604 for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 1605 q->q_flags |= QDONTSEND; 1606 } 1607 #endif 1608 1609 /* 1610 ** Read the input mail. 1611 */ 1612 1613 CurEnv->e_to = NULL; 1614 if (OpMode != MD_VERIFY || GrabTo) 1615 { 1616 long savedflags = CurEnv->e_flags & EF_FATALERRS; 1617 1618 CurEnv->e_flags |= EF_GLOBALERRS; 1619 CurEnv->e_flags &= ~EF_FATALERRS; 1620 collect(InChannel, FALSE, NULL, CurEnv); 1621 1622 /* bail out if message too large */ 1623 if (bitset(EF_CLRQUEUE, CurEnv->e_flags)) 1624 { 1625 finis(TRUE, ExitStat); 1626 /*NOTREACHED*/ 1627 return -1; 1628 } 1629 CurEnv->e_flags |= savedflags; 1630 } 1631 errno = 0; 1632 1633 if (tTd(1, 1)) 1634 printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); 1635 1636 /* 1637 ** Actually send everything. 1638 ** If verifying, just ack. 1639 */ 1640 1641 CurEnv->e_from.q_flags |= QDONTSEND; 1642 if (tTd(1, 5)) 1643 { 1644 printf("main: QDONTSEND "); 1645 printaddr(&CurEnv->e_from, FALSE); 1646 } 1647 CurEnv->e_to = NULL; 1648 CurrentLA = getla(); 1649 GrabTo = FALSE; 1650 sendall(CurEnv, SM_DEFAULT); 1651 1652 /* 1653 ** All done. 1654 ** Don't send return error message if in VERIFY mode. 1655 */ 1656 1657 finis(TRUE, ExitStat); 1658 /*NOTREACHED*/ 1659 return -1; 1660 } 1661 1662 /* ARGSUSED */ 1663 SIGFUNC_DECL 1664 quiesce(sig) 1665 int sig; 1666 { 1667 finis(FALSE, EX_OK); 1668 } 1669 1670 /* ARGSUSED */ 1671 SIGFUNC_DECL 1672 intindebug(sig) 1673 int sig; 1674 { 1675 longjmp(TopFrame, 1); 1676 return SIGFUNC_RETURN; 1677 } 1678 1679 1680 /* 1681 ** FINIS -- Clean up and exit. 1682 ** 1683 ** Parameters: 1684 ** drop -- whether or not to drop CurEnv envelope 1685 ** exitstat -- exit status to use for exit() call 1686 ** 1687 ** Returns: 1688 ** never 1689 ** 1690 ** Side Effects: 1691 ** exits sendmail 1692 */ 1693 1694 void 1695 finis(drop, exitstat) 1696 bool drop; 1697 volatile int exitstat; 1698 { 1699 extern void closemaps __P((void)); 1700 #ifdef USERDB 1701 extern void _udbx_close __P((void)); 1702 #endif 1703 1704 if (tTd(2, 1)) 1705 { 1706 extern void printenvflags __P((ENVELOPE *)); 1707 1708 printf("\n====finis: stat %d e_id=%s e_flags=", 1709 exitstat, 1710 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); 1711 printenvflags(CurEnv); 1712 } 1713 if (tTd(2, 9)) 1714 printopenfds(FALSE); 1715 1716 /* if we fail in finis(), just exit */ 1717 if (setjmp(TopFrame) != 0) 1718 { 1719 /* failed -- just give it up */ 1720 goto forceexit; 1721 } 1722 1723 /* clean up temp files */ 1724 CurEnv->e_to = NULL; 1725 if (drop && CurEnv->e_id != NULL) 1726 dropenvelope(CurEnv, TRUE); 1727 1728 /* flush any cached connections */ 1729 mci_flush(TRUE, NULL); 1730 1731 /* close maps belonging to this pid */ 1732 closemaps(); 1733 1734 #ifdef USERDB 1735 /* close UserDatabase */ 1736 _udbx_close(); 1737 #endif 1738 1739 # ifdef XLA 1740 /* clean up extended load average stuff */ 1741 xla_all_end(); 1742 # endif 1743 1744 /* and exit */ 1745 forceexit: 1746 if (LogLevel > 78) 1747 sm_syslog(LOG_DEBUG, CurEnv->e_id, 1748 "finis, pid=%d", 1749 getpid()); 1750 if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) 1751 exitstat = EX_OK; 1752 1753 /* reset uid for process accounting */ 1754 endpwent(); 1755 setuid(RealUid); 1756 1757 exit(exitstat); 1758 } 1759 /* 1760 ** INTSIG -- clean up on interrupt 1761 ** 1762 ** This just arranges to exit. It pessimises in that it 1763 ** may resend a message. 1764 ** 1765 ** Parameters: 1766 ** none. 1767 ** 1768 ** Returns: 1769 ** none. 1770 ** 1771 ** Side Effects: 1772 ** Unlocks the current job. 1773 */ 1774 1775 /* ARGSUSED */ 1776 SIGFUNC_DECL 1777 intsig(sig) 1778 int sig; 1779 { 1780 if (LogLevel > 79) 1781 sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); 1782 FileName = NULL; 1783 unlockqueue(CurEnv); 1784 closecontrolsocket(TRUE); 1785 #ifdef XLA 1786 xla_all_end(); 1787 #endif 1788 finis(FALSE, EX_OK); 1789 } 1790 /* 1791 ** INITMACROS -- initialize the macro system 1792 ** 1793 ** This just involves defining some macros that are actually 1794 ** used internally as metasymbols to be themselves. 1795 ** 1796 ** Parameters: 1797 ** none. 1798 ** 1799 ** Returns: 1800 ** none. 1801 ** 1802 ** Side Effects: 1803 ** initializes several macros to be themselves. 1804 */ 1805 1806 struct metamac MetaMacros[] = 1807 { 1808 /* LHS pattern matching characters */ 1809 { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE }, 1810 { '=', MATCHCLASS }, { '~', MATCHNCLASS }, 1811 1812 /* these are RHS metasymbols */ 1813 { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER }, 1814 { '>', CALLSUBR }, 1815 1816 /* the conditional operations */ 1817 { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI }, 1818 1819 /* the hostname lookup characters */ 1820 { '[', HOSTBEGIN }, { ']', HOSTEND }, 1821 { '(', LOOKUPBEGIN }, { ')', LOOKUPEND }, 1822 1823 /* miscellaneous control characters */ 1824 { '&', MACRODEXPAND }, 1825 1826 { '\0' } 1827 }; 1828 1829 #define MACBINDING(name, mid) \ 1830 stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \ 1831 MacroName[mid] = name; 1832 1833 void 1834 initmacros(e) 1835 register ENVELOPE *e; 1836 { 1837 register struct metamac *m; 1838 register int c; 1839 char buf[5]; 1840 extern char *MacroName[256]; 1841 1842 for (m = MetaMacros; m->metaname != '\0'; m++) 1843 { 1844 buf[0] = m->metaval; 1845 buf[1] = '\0'; 1846 define(m->metaname, newstr(buf), e); 1847 } 1848 buf[0] = MATCHREPL; 1849 buf[2] = '\0'; 1850 for (c = '0'; c <= '9'; c++) 1851 { 1852 buf[1] = c; 1853 define(c, newstr(buf), e); 1854 } 1855 1856 /* set defaults for some macros sendmail will use later */ 1857 define('n', "MAILER-DAEMON", e); 1858 1859 /* set up external names for some internal macros */ 1860 MACBINDING("opMode", MID_OPMODE); 1861 /*XXX should probably add equivalents for all short macros here XXX*/ 1862 } 1863 /* 1864 ** DISCONNECT -- remove our connection with any foreground process 1865 ** 1866 ** Parameters: 1867 ** droplev -- how "deeply" we should drop the line. 1868 ** 0 -- ignore signals, mail back errors, make sure 1869 ** output goes to stdout. 1870 ** 1 -- also, make stdout go to transcript. 1871 ** 2 -- also, disconnect from controlling terminal 1872 ** (only for daemon mode). 1873 ** e -- the current envelope. 1874 ** 1875 ** Returns: 1876 ** none 1877 ** 1878 ** Side Effects: 1879 ** Trys to insure that we are immune to vagaries of 1880 ** the controlling tty. 1881 */ 1882 1883 void 1884 disconnect(droplev, e) 1885 int droplev; 1886 register ENVELOPE *e; 1887 { 1888 int fd; 1889 1890 if (tTd(52, 1)) 1891 printf("disconnect: In %d Out %d, e=%lx\n", 1892 fileno(InChannel), fileno(OutChannel), (u_long) e); 1893 if (tTd(52, 100)) 1894 { 1895 printf("don't\n"); 1896 return; 1897 } 1898 if (LogLevel > 93) 1899 sm_syslog(LOG_DEBUG, e->e_id, 1900 "disconnect level %d", 1901 droplev); 1902 1903 /* be sure we don't get nasty signals */ 1904 (void) setsignal(SIGINT, SIG_IGN); 1905 (void) setsignal(SIGQUIT, SIG_IGN); 1906 1907 /* we can't communicate with our caller, so.... */ 1908 HoldErrs = TRUE; 1909 CurEnv->e_errormode = EM_MAIL; 1910 Verbose = 0; 1911 DisConnected = TRUE; 1912 1913 /* all input from /dev/null */ 1914 if (InChannel != stdin) 1915 { 1916 (void) fclose(InChannel); 1917 InChannel = stdin; 1918 } 1919 if (freopen("/dev/null", "r", stdin) == NULL) 1920 sm_syslog(LOG_ERR, e->e_id, 1921 "disconnect: freopen(\"/dev/null\") failed: %s", 1922 errstring(errno)); 1923 1924 /* output to the transcript */ 1925 if (OutChannel != stdout) 1926 { 1927 (void) fclose(OutChannel); 1928 OutChannel = stdout; 1929 } 1930 if (droplev > 0) 1931 { 1932 if (e->e_xfp == NULL) 1933 { 1934 fd = open("/dev/null", O_WRONLY, 0666); 1935 if (fd == -1) 1936 sm_syslog(LOG_ERR, e->e_id, 1937 "disconnect: open(\"/dev/null\") failed: %s", 1938 errstring(errno)); 1939 } 1940 else 1941 { 1942 fd = fileno(e->e_xfp); 1943 if (fd == -1) 1944 sm_syslog(LOG_ERR, e->e_id, 1945 "disconnect: fileno(e->e_xfp) failed: %s", 1946 errstring(errno)); 1947 } 1948 (void) fflush(stdout); 1949 dup2(fd, STDOUT_FILENO); 1950 dup2(fd, STDERR_FILENO); 1951 if (e->e_xfp == NULL) 1952 close(fd); 1953 } 1954 1955 /* drop our controlling TTY completely if possible */ 1956 if (droplev > 1) 1957 { 1958 (void) setsid(); 1959 errno = 0; 1960 } 1961 1962 #if XDEBUG 1963 checkfd012("disconnect"); 1964 #endif 1965 1966 if (LogLevel > 71) 1967 sm_syslog(LOG_DEBUG, e->e_id, 1968 "in background, pid=%d", 1969 getpid()); 1970 1971 errno = 0; 1972 } 1973 1974 static void 1975 obsolete(argv) 1976 char *argv[]; 1977 { 1978 register char *ap; 1979 register char *op; 1980 1981 while ((ap = *++argv) != NULL) 1982 { 1983 /* Return if "--" or not an option of any form. */ 1984 if (ap[0] != '-' || ap[1] == '-') 1985 return; 1986 1987 /* skip over options that do have a value */ 1988 op = strchr(OPTIONS, ap[1]); 1989 if (op != NULL && *++op == ':' && ap[2] == '\0' && 1990 ap[1] != 'd' && 1991 #if defined(sony_news) 1992 ap[1] != 'E' && ap[1] != 'J' && 1993 #endif 1994 argv[1] != NULL && argv[1][0] != '-') 1995 { 1996 argv++; 1997 continue; 1998 } 1999 2000 /* If -C doesn't have an argument, use sendmail.cf. */ 2001 #define __DEFPATH "sendmail.cf" 2002 if (ap[1] == 'C' && ap[2] == '\0') 2003 { 2004 *argv = xalloc(sizeof(__DEFPATH) + 2); 2005 argv[0][0] = '-'; 2006 argv[0][1] = 'C'; 2007 (void)strcpy(&argv[0][2], __DEFPATH); 2008 } 2009 2010 /* If -q doesn't have an argument, run it once. */ 2011 if (ap[1] == 'q' && ap[2] == '\0') 2012 *argv = "-q0"; 2013 2014 /* if -d doesn't have an argument, use 0-99.1 */ 2015 if (ap[1] == 'd' && ap[2] == '\0') 2016 *argv = "-d0-99.1"; 2017 2018 # if defined(sony_news) 2019 /* if -E doesn't have an argument, use -EC */ 2020 if (ap[1] == 'E' && ap[2] == '\0') 2021 *argv = "-EC"; 2022 2023 /* if -J doesn't have an argument, use -JJ */ 2024 if (ap[1] == 'J' && ap[2] == '\0') 2025 *argv = "-JJ"; 2026 # endif 2027 } 2028 } 2029 /* 2030 ** AUTH_WARNING -- specify authorization warning 2031 ** 2032 ** Parameters: 2033 ** e -- the current envelope. 2034 ** msg -- the text of the message. 2035 ** args -- arguments to the message. 2036 ** 2037 ** Returns: 2038 ** none. 2039 */ 2040 2041 void 2042 #ifdef __STDC__ 2043 auth_warning(register ENVELOPE *e, const char *msg, ...) 2044 #else 2045 auth_warning(e, msg, va_alist) 2046 register ENVELOPE *e; 2047 const char *msg; 2048 va_dcl 2049 #endif 2050 { 2051 char buf[MAXLINE]; 2052 VA_LOCAL_DECL 2053 2054 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) 2055 { 2056 register char *p; 2057 static char hostbuf[48]; 2058 extern struct hostent *myhostname __P((char *, int)); 2059 2060 if (hostbuf[0] == '\0') 2061 (void) myhostname(hostbuf, sizeof hostbuf); 2062 2063 (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); 2064 p = &buf[strlen(buf)]; 2065 VA_START(msg); 2066 vsnprintf(p, SPACELEFT(buf, p), msg, ap); 2067 VA_END; 2068 addheader("X-Authentication-Warning", buf, &e->e_header); 2069 if (LogLevel > 3) 2070 sm_syslog(LOG_INFO, e->e_id, 2071 "Authentication-Warning: %.400s", 2072 buf); 2073 } 2074 } 2075 /* 2076 ** GETEXTENV -- get from external environment 2077 ** 2078 ** Parameters: 2079 ** envar -- the name of the variable to retrieve 2080 ** 2081 ** Returns: 2082 ** The value, if any. 2083 */ 2084 2085 char * 2086 getextenv(envar) 2087 const char *envar; 2088 { 2089 char **envp; 2090 int l; 2091 2092 l = strlen(envar); 2093 for (envp = ExternalEnviron; *envp != NULL; envp++) 2094 { 2095 if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') 2096 return &(*envp)[l + 1]; 2097 } 2098 return NULL; 2099 } 2100 /* 2101 ** SETUSERENV -- set an environment in the propogated environment 2102 ** 2103 ** Parameters: 2104 ** envar -- the name of the environment variable. 2105 ** value -- the value to which it should be set. If 2106 ** null, this is extracted from the incoming 2107 ** environment. If that is not set, the call 2108 ** to setuserenv is ignored. 2109 ** 2110 ** Returns: 2111 ** none. 2112 */ 2113 2114 void 2115 setuserenv(envar, value) 2116 const char *envar; 2117 const char *value; 2118 { 2119 int i; 2120 char **evp = UserEnviron; 2121 char *p; 2122 2123 if (value == NULL) 2124 { 2125 value = getextenv(envar); 2126 if (value == NULL) 2127 return; 2128 } 2129 2130 i = strlen(envar); 2131 p = (char *) xalloc(strlen(value) + i + 2); 2132 strcpy(p, envar); 2133 p[i++] = '='; 2134 strcpy(&p[i], value); 2135 2136 while (*evp != NULL && strncmp(*evp, p, i) != 0) 2137 evp++; 2138 if (*evp != NULL) 2139 { 2140 *evp++ = p; 2141 } 2142 else if (evp < &UserEnviron[MAXUSERENVIRON]) 2143 { 2144 *evp++ = p; 2145 *evp = NULL; 2146 } 2147 2148 /* make sure it is in our environment as well */ 2149 if (putenv(p) < 0) 2150 syserr("setuserenv: putenv(%s) failed", p); 2151 } 2152 /* 2153 ** DUMPSTATE -- dump state 2154 ** 2155 ** For debugging. 2156 */ 2157 2158 void 2159 dumpstate(when) 2160 char *when; 2161 { 2162 register char *j = macvalue('j', CurEnv); 2163 int rs; 2164 2165 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2166 "--- dumping state on %s: $j = %s ---", 2167 when, 2168 j == NULL ? "<NULL>" : j); 2169 if (j != NULL) 2170 { 2171 if (!wordinclass(j, 'w')) 2172 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2173 "*** $j not in $=w ***"); 2174 } 2175 sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); 2176 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); 2177 printopenfds(TRUE); 2178 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); 2179 mci_dump_all(TRUE); 2180 rs = strtorwset("debug_dumpstate", NULL, ST_FIND); 2181 if (rs > 0) 2182 { 2183 int stat; 2184 register char **pvp; 2185 char *pv[MAXATOM + 1]; 2186 2187 pv[0] = NULL; 2188 stat = rewrite(pv, rs, 0, CurEnv); 2189 sm_syslog(LOG_DEBUG, CurEnv->e_id, 2190 "--- ruleset debug_dumpstate returns stat %d, pv: ---", 2191 stat); 2192 for (pvp = pv; *pvp != NULL; pvp++) 2193 sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); 2194 } 2195 sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); 2196 } 2197 2198 2199 /* ARGSUSED */ 2200 SIGFUNC_DECL 2201 sigusr1(sig) 2202 int sig; 2203 { 2204 dumpstate("user signal"); 2205 return SIGFUNC_RETURN; 2206 } 2207 2208 2209 /* ARGSUSED */ 2210 SIGFUNC_DECL 2211 sighup(sig) 2212 int sig; 2213 { 2214 if (SaveArgv[0][0] != '/') 2215 { 2216 if (LogLevel > 3) 2217 sm_syslog(LOG_INFO, NOQID, "could not restart: need full path"); 2218 finis(FALSE, EX_OSFILE); 2219 } 2220 if (LogLevel > 3) 2221 sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]); 2222 alarm(0); 2223 releasesignal(SIGHUP); 2224 closecontrolsocket(TRUE); 2225 if (drop_privileges(TRUE) != EX_OK) 2226 { 2227 if (LogLevel > 0) 2228 sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m", 2229 RunAsUid, RunAsGid); 2230 finis(FALSE, EX_OSERR); 2231 } 2232 execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 2233 if (LogLevel > 0) 2234 sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]); 2235 finis(FALSE, EX_OSFILE); 2236 } 2237 /* 2238 ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option 2239 ** 2240 ** Parameters: 2241 ** to_real_uid -- if set, drop to the real uid instead 2242 ** of the RunAsUser. 2243 ** 2244 ** Returns: 2245 ** EX_OSERR if the setuid failed. 2246 ** EX_OK otherwise. 2247 */ 2248 2249 int 2250 drop_privileges(to_real_uid) 2251 bool to_real_uid; 2252 { 2253 int rval = EX_OK; 2254 GIDSET_T emptygidset[1]; 2255 2256 if (tTd(47, 1)) 2257 printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", 2258 (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid); 2259 2260 if (to_real_uid) 2261 { 2262 RunAsUserName = RealUserName; 2263 RunAsUid = RealUid; 2264 RunAsGid = RealGid; 2265 } 2266 2267 /* make sure no one can grab open descriptors for secret files */ 2268 endpwent(); 2269 2270 /* reset group permissions; these can be set later */ 2271 emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); 2272 if (setgroups(1, emptygidset) == -1 && geteuid() == 0) 2273 rval = EX_OSERR; 2274 2275 /* reset primary group and user id */ 2276 if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0) 2277 rval = EX_OSERR; 2278 if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0) 2279 rval = EX_OSERR; 2280 if (tTd(47, 5)) 2281 { 2282 printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", 2283 (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); 2284 printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); 2285 } 2286 return rval; 2287 } 2288 /* 2289 ** FILL_FD -- make sure a file descriptor has been properly allocated 2290 ** 2291 ** Used to make sure that stdin/out/err are allocated on startup 2292 ** 2293 ** Parameters: 2294 ** fd -- the file descriptor to be filled. 2295 ** where -- a string used for logging. If NULL, this is 2296 ** being called on startup, and logging should 2297 ** not be done. 2298 ** 2299 ** Returns: 2300 ** none 2301 */ 2302 2303 void 2304 fill_fd(fd, where) 2305 int fd; 2306 char *where; 2307 { 2308 int i; 2309 struct stat stbuf; 2310 2311 if (fstat(fd, &stbuf) >= 0 || errno != EBADF) 2312 return; 2313 2314 if (where != NULL) 2315 syserr("fill_fd: %s: fd %d not open", where, fd); 2316 else 2317 MissingFds |= 1 << fd; 2318 i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666); 2319 if (i < 0) 2320 { 2321 syserr("!fill_fd: %s: cannot open /dev/null", 2322 where == NULL ? "startup" : where); 2323 } 2324 if (fd != i) 2325 { 2326 (void) dup2(i, fd); 2327 (void) close(i); 2328 } 2329 } 2330 /* 2331 ** TESTMODELINE -- process a test mode input line 2332 ** 2333 ** Parameters: 2334 ** line -- the input line. 2335 ** e -- the current environment. 2336 ** Syntax: 2337 ** # a comment 2338 ** .X process X as a configuration line 2339 ** =X dump a configuration item (such as mailers) 2340 ** $X dump a macro or class 2341 ** /X try an activity 2342 ** X normal process through rule set X 2343 */ 2344 2345 void 2346 testmodeline(line, e) 2347 char *line; 2348 ENVELOPE *e; 2349 { 2350 register char *p; 2351 char *q; 2352 auto char *delimptr; 2353 int mid; 2354 int i, rs; 2355 STAB *map; 2356 char **s; 2357 struct rewrite *rw; 2358 ADDRESS a; 2359 static int tryflags = RF_COPYNONE; 2360 char exbuf[MAXLINE]; 2361 extern bool invalidaddr __P((char *, char *)); 2362 extern char *crackaddr __P((char *)); 2363 extern void dump_class __P((STAB *, int)); 2364 extern void translate_dollars __P((char *)); 2365 extern void help __P((char *)); 2366 2367 switch (line[0]) 2368 { 2369 case '#': 2370 case 0: 2371 return; 2372 2373 case '?': 2374 help("-bt"); 2375 return; 2376 2377 case '.': /* config-style settings */ 2378 switch (line[1]) 2379 { 2380 case 'D': 2381 mid = macid(&line[2], &delimptr); 2382 if (mid == '\0') 2383 return; 2384 translate_dollars(delimptr); 2385 define(mid, newstr(delimptr), e); 2386 break; 2387 2388 case 'C': 2389 if (line[2] == '\0') /* not to call syserr() */ 2390 return; 2391 2392 mid = macid(&line[2], &delimptr); 2393 if (mid == '\0') 2394 return; 2395 translate_dollars(delimptr); 2396 expand(delimptr, exbuf, sizeof exbuf, e); 2397 p = exbuf; 2398 while (*p != '\0') 2399 { 2400 register char *wd; 2401 char delim; 2402 2403 while (*p != '\0' && isascii(*p) && isspace(*p)) 2404 p++; 2405 wd = p; 2406 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2407 p++; 2408 delim = *p; 2409 *p = '\0'; 2410 if (wd[0] != '\0') 2411 setclass(mid, wd); 2412 *p = delim; 2413 } 2414 break; 2415 2416 case '\0': 2417 printf("Usage: .[DC]macro value(s)\n"); 2418 break; 2419 2420 default: 2421 printf("Unknown \".\" command %s\n", line); 2422 break; 2423 } 2424 return; 2425 2426 case '=': /* config-style settings */ 2427 switch (line[1]) 2428 { 2429 case 'S': /* dump rule set */ 2430 rs = strtorwset(&line[2], NULL, ST_FIND); 2431 if (rs < 0) 2432 { 2433 printf("Undefined ruleset %s\n", &line[2]); 2434 return; 2435 } 2436 rw = RewriteRules[rs]; 2437 if (rw == NULL) 2438 return; 2439 do 2440 { 2441 putchar('R'); 2442 s = rw->r_lhs; 2443 while (*s != NULL) 2444 { 2445 xputs(*s++); 2446 putchar(' '); 2447 } 2448 putchar('\t'); 2449 putchar('\t'); 2450 s = rw->r_rhs; 2451 while (*s != NULL) 2452 { 2453 xputs(*s++); 2454 putchar(' '); 2455 } 2456 putchar('\n'); 2457 } while ((rw = rw->r_next) != NULL); 2458 break; 2459 2460 case 'M': 2461 for (i = 0; i < MAXMAILERS; i++) 2462 { 2463 if (Mailer[i] != NULL) 2464 printmailer(Mailer[i]); 2465 } 2466 break; 2467 2468 case '\0': 2469 printf("Usage: =Sruleset or =M\n"); 2470 break; 2471 2472 default: 2473 printf("Unknown \"=\" command %s\n", line); 2474 break; 2475 } 2476 return; 2477 2478 case '-': /* set command-line-like opts */ 2479 switch (line[1]) 2480 { 2481 case 'd': 2482 tTflag(&line[2]); 2483 break; 2484 2485 case '\0': 2486 printf("Usage: -d{debug arguments}\n"); 2487 break; 2488 2489 default: 2490 printf("Unknown \"-\" command %s\n", line); 2491 break; 2492 } 2493 return; 2494 2495 case '$': 2496 if (line[1] == '=') 2497 { 2498 mid = macid(&line[2], NULL); 2499 if (mid != '\0') 2500 stabapply(dump_class, mid); 2501 return; 2502 } 2503 mid = macid(&line[1], NULL); 2504 if (mid == '\0') 2505 return; 2506 p = macvalue(mid, e); 2507 if (p == NULL) 2508 printf("Undefined\n"); 2509 else 2510 { 2511 xputs(p); 2512 printf("\n"); 2513 } 2514 return; 2515 2516 case '/': /* miscellaneous commands */ 2517 p = &line[strlen(line)]; 2518 while (--p >= line && isascii(*p) && isspace(*p)) 2519 *p = '\0'; 2520 p = strpbrk(line, " \t"); 2521 if (p != NULL) 2522 { 2523 while (isascii(*p) && isspace(*p)) 2524 *p++ = '\0'; 2525 } 2526 else 2527 p = ""; 2528 if (line[1] == '\0') 2529 { 2530 printf("Usage: /[canon|map|mx|parse|try|tryflags]\n"); 2531 return; 2532 } 2533 if (strcasecmp(&line[1], "mx") == 0) 2534 { 2535 #if NAMED_BIND 2536 /* look up MX records */ 2537 int nmx; 2538 auto int rcode; 2539 char *mxhosts[MAXMXHOSTS + 1]; 2540 2541 if (*p == '\0') 2542 { 2543 printf("Usage: /mx address\n"); 2544 return; 2545 } 2546 nmx = getmxrr(p, mxhosts, FALSE, &rcode); 2547 printf("getmxrr(%s) returns %d value(s):\n", p, nmx); 2548 for (i = 0; i < nmx; i++) 2549 printf("\t%s\n", mxhosts[i]); 2550 #else 2551 printf("No MX code compiled in\n"); 2552 #endif 2553 } 2554 else if (strcasecmp(&line[1], "canon") == 0) 2555 { 2556 char host[MAXHOSTNAMELEN]; 2557 2558 if (*p == '\0') 2559 { 2560 printf("Usage: /canon address\n"); 2561 return; 2562 } 2563 else if (strlen(p) >= sizeof host) 2564 { 2565 printf("Name too long\n"); 2566 return; 2567 } 2568 strcpy(host, p); 2569 (void) getcanonname(host, sizeof(host), HasWildcardMX); 2570 printf("getcanonname(%s) returns %s\n", p, host); 2571 } 2572 else if (strcasecmp(&line[1], "map") == 0) 2573 { 2574 auto int rcode = EX_OK; 2575 char *av[2]; 2576 2577 if (*p == '\0') 2578 { 2579 printf("Usage: /map mapname key\n"); 2580 return; 2581 } 2582 for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) 2583 continue; 2584 if (*q == '\0') 2585 { 2586 printf("No key specified\n"); 2587 return; 2588 } 2589 *q++ = '\0'; 2590 map = stab(p, ST_MAP, ST_FIND); 2591 if (map == NULL) 2592 { 2593 printf("Map named \"%s\" not found\n", p); 2594 return; 2595 } 2596 if (!bitset(MF_OPEN, map->s_map.map_mflags)) 2597 { 2598 printf("Map named \"%s\" not open\n", p); 2599 return; 2600 } 2601 printf("map_lookup: %s (%s) ", p, q); 2602 av[0] = q; 2603 av[1] = NULL; 2604 p = (*map->s_map.map_class->map_lookup) 2605 (&map->s_map, q, av, &rcode); 2606 if (p == NULL) 2607 printf("no match (%d)\n", rcode); 2608 else 2609 printf("returns %s (%d)\n", p, rcode); 2610 } 2611 else if (strcasecmp(&line[1], "try") == 0) 2612 { 2613 MAILER *m; 2614 STAB *s; 2615 auto int rcode = EX_OK; 2616 2617 q = strpbrk(p, " \t"); 2618 if (q != NULL) 2619 { 2620 while (isascii(*q) && isspace(*q)) 2621 *q++ = '\0'; 2622 } 2623 if (q == NULL || *q == '\0') 2624 { 2625 printf("Usage: /try mailer address\n"); 2626 return; 2627 } 2628 s = stab(p, ST_MAILER, ST_FIND); 2629 if (s == NULL) 2630 { 2631 printf("Unknown mailer %s\n", p); 2632 return; 2633 } 2634 m = s->s_mailer; 2635 printf("Trying %s %s address %s for mailer %s\n", 2636 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", 2637 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient", 2638 q, p); 2639 p = remotename(q, m, tryflags, &rcode, CurEnv); 2640 printf("Rcode = %d, addr = %s\n", 2641 rcode, p == NULL ? "<NULL>" : p); 2642 e->e_to = NULL; 2643 } 2644 else if (strcasecmp(&line[1], "tryflags") == 0) 2645 { 2646 if (*p == '\0') 2647 { 2648 printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); 2649 return; 2650 } 2651 for (; *p != '\0'; p++) 2652 { 2653 switch (*p) 2654 { 2655 case 'H': 2656 case 'h': 2657 tryflags |= RF_HEADERADDR; 2658 break; 2659 2660 case 'E': 2661 case 'e': 2662 tryflags &= ~RF_HEADERADDR; 2663 break; 2664 2665 case 'S': 2666 case 's': 2667 tryflags |= RF_SENDERADDR; 2668 break; 2669 2670 case 'R': 2671 case 'r': 2672 tryflags &= ~RF_SENDERADDR; 2673 break; 2674 } 2675 } 2676 } 2677 else if (strcasecmp(&line[1], "parse") == 0) 2678 { 2679 if (*p == '\0') 2680 { 2681 printf("Usage: /parse address\n"); 2682 return; 2683 } 2684 q = crackaddr(p); 2685 printf("Cracked address = "); 2686 xputs(q); 2687 printf("\nParsing %s %s address\n", 2688 bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", 2689 bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient"); 2690 if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL) 2691 printf("Cannot parse\n"); 2692 else if (a.q_host != NULL && a.q_host[0] != '\0') 2693 printf("mailer %s, host %s, user %s\n", 2694 a.q_mailer->m_name, a.q_host, a.q_user); 2695 else 2696 printf("mailer %s, user %s\n", 2697 a.q_mailer->m_name, a.q_user); 2698 e->e_to = NULL; 2699 } 2700 else 2701 { 2702 printf("Unknown \"/\" command %s\n", line); 2703 } 2704 return; 2705 } 2706 2707 for (p = line; isascii(*p) && isspace(*p); p++) 2708 continue; 2709 q = p; 2710 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2711 p++; 2712 if (*p == '\0') 2713 { 2714 printf("No address!\n"); 2715 return; 2716 } 2717 *p = '\0'; 2718 if (invalidaddr(p + 1, NULL)) 2719 return; 2720 do 2721 { 2722 register char **pvp; 2723 char pvpbuf[PSBUFSIZE]; 2724 2725 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, 2726 &delimptr, NULL); 2727 if (pvp == NULL) 2728 continue; 2729 p = q; 2730 while (*p != '\0') 2731 { 2732 int stat; 2733 2734 rs = strtorwset(p, NULL, ST_FIND); 2735 if (rs < 0) 2736 { 2737 printf("Undefined ruleset %s\n", p); 2738 break; 2739 } 2740 stat = rewrite(pvp, rs, 0, e); 2741 if (stat != EX_OK) 2742 printf("== Ruleset %s (%d) status %d\n", 2743 p, rs, stat); 2744 while (*p != '\0' && *p++ != ',') 2745 continue; 2746 } 2747 } while (*(p = delimptr) != '\0'); 2748 } 2749 2750 2751 void 2752 dump_class(s, id) 2753 register STAB *s; 2754 int id; 2755 { 2756 if (s->s_type != ST_CLASS) 2757 return; 2758 if (bitnset(id & 0xff, s->s_class)) 2759 printf("%s\n", s->s_name); 2760 } 2761