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