|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted provided ! 7: * that: (1) source distributions retain this entire copyright notice and ! 8: * comment, and (2) distributions including binaries display the following ! 9: * acknowledgement: ``This product includes software developed by the ! 10: * University of California, Berkeley and its contributors'' in the ! 11: * documentation or other materials provided with the distribution and in ! 12: * all advertising materials mentioning features or use of this software. ! 13: * Neither the name of the University nor the names of its contributors may ! 14: * be used to endorse or promote products derived from this software without ! 15: * specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: */ ! 20: ! 21: #ifndef lint ! 22: char copyright[] = ! 23: "@(#) Copyright (c) 1988 Regents of the University of California.\n\ ! 24: All rights reserved.\n"; ! 25: #endif /* not lint */ ! 26: ! 27: #ifndef lint ! 28: static char sccsid[] = "@(#)main.c 5.30 (Berkeley) 6/29/90"; ! 29: #endif /* not lint */ ! 30: ! 31: #define _DEFINE ! 32: ! 33: #include <sys/param.h> ! 34: #include <sys/file.h> ! 35: #include <signal.h> ! 36: #include <sgtty.h> ! 37: #include "sendmail.h" ! 38: #include <arpa/nameser.h> ! 39: #include <resolv.h> ! 40: ! 41: # ifdef lint ! 42: char edata, end; ! 43: # endif lint ! 44: ! 45: /* ! 46: ** SENDMAIL -- Post mail to a set of destinations. ! 47: ** ! 48: ** This is the basic mail router. All user mail programs should ! 49: ** call this routine to actually deliver mail. Sendmail in ! 50: ** turn calls a bunch of mail servers that do the real work of ! 51: ** delivering the mail. ! 52: ** ! 53: ** Sendmail is driven by tables read in from /usr/lib/sendmail.cf ! 54: ** (read by readcf.c). Some more static configuration info, ! 55: ** including some code that you may want to tailor for your ! 56: ** installation, is in conf.c. You may also want to touch ! 57: ** daemon.c (if you have some other IPC mechanism), acct.c ! 58: ** (to change your accounting), names.c (to adjust the name ! 59: ** server mechanism). ! 60: ** ! 61: ** Usage: ! 62: ** /usr/lib/sendmail [flags] addr ... ! 63: ** ! 64: ** See the associated documentation for details. ! 65: ** ! 66: ** Author: ! 67: ** Eric Allman, UCB/INGRES (until 10/81) ! 68: ** Britton-Lee, Inc., purveyors of fine ! 69: ** database computers (from 11/81) ! 70: ** The support of the INGRES Project and Britton-Lee is ! 71: ** gratefully acknowledged. Britton-Lee in ! 72: ** particular had absolutely nothing to gain from ! 73: ** my involvement in this project. ! 74: */ ! 75: ! 76: ! 77: int NextMailer; /* "free" index into Mailer struct */ ! 78: char *FullName; /* sender's full name */ ! 79: ENVELOPE BlankEnvelope; /* a "blank" envelope */ ! 80: ENVELOPE MainEnvelope; /* the envelope around the basic letter */ ! 81: ADDRESS NullAddress = /* a null address */ ! 82: { "", "", "" }; ! 83: ! 84: /* ! 85: ** Pointers for setproctitle. ! 86: ** This allows "ps" listings to give more useful information. ! 87: ** These must be kept out of BSS for frozen configuration files ! 88: ** to work. ! 89: */ ! 90: ! 91: # ifdef SETPROCTITLE ! 92: char **Argv = NULL; /* pointer to argument vector */ ! 93: char *LastArgv = NULL; /* end of argv */ ! 94: # endif SETPROCTITLE ! 95: ! 96: #ifdef DAEMON ! 97: #ifndef SMTP ! 98: ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR ! 99: #endif SMTP ! 100: #endif DAEMON ! 101: ! 102: main(argc, argv, envp) ! 103: int argc; ! 104: char **argv; ! 105: char **envp; ! 106: { ! 107: register char *p; ! 108: char **av; ! 109: extern int finis(); ! 110: extern char Version[]; ! 111: char *from; ! 112: typedef int (*fnptr)(); ! 113: STAB *st; ! 114: register int i; ! 115: bool readconfig = TRUE; ! 116: bool queuemode = FALSE; /* process queue requests */ ! 117: bool nothaw; ! 118: static bool reenter = FALSE; ! 119: char jbuf[30]; /* holds MyHostName */ ! 120: extern bool safefile(); ! 121: extern time_t convtime(); ! 122: extern putheader(), putbody(); ! 123: extern ENVELOPE *newenvelope(); ! 124: extern intsig(); ! 125: extern char **myhostname(); ! 126: extern char *arpadate(); ! 127: extern char **environ; ! 128: ! 129: /* ! 130: ** Check to see if we reentered. ! 131: ** This would normally happen if e_putheader or e_putbody ! 132: ** were NULL when invoked. ! 133: */ ! 134: ! 135: if (reenter) ! 136: { ! 137: syserr("main: reentered!"); ! 138: abort(); ! 139: } ! 140: reenter = TRUE; ! 141: ! 142: /* Enforce use of local time */ ! 143: unsetenv("TZ"); ! 144: ! 145: /* ! 146: ** Be sure we have enough file descriptors. ! 147: ** But also be sure that 0, 1, & 2 are open. ! 148: */ ! 149: ! 150: i = open("/dev/null", O_RDWR); ! 151: while (i >= 0 && i < 2) ! 152: i = dup(i); ! 153: for (i = getdtablesize(); i > 2; --i) ! 154: (void) close(i); ! 155: errno = 0; ! 156: ! 157: #ifdef LOG_MAIL ! 158: openlog("sendmail", LOG_PID, LOG_MAIL); ! 159: #else ! 160: openlog("sendmail", LOG_PID); ! 161: #endif ! 162: ! 163: /* ! 164: ** Set default values for variables. ! 165: ** These cannot be in initialized data space. ! 166: */ ! 167: ! 168: setdefaults(); ! 169: ! 170: /* set up the blank envelope */ ! 171: BlankEnvelope.e_puthdr = putheader; ! 172: BlankEnvelope.e_putbody = putbody; ! 173: BlankEnvelope.e_xfp = NULL; ! 174: STRUCTCOPY(NullAddress, BlankEnvelope.e_from); ! 175: CurEnv = &BlankEnvelope; ! 176: STRUCTCOPY(NullAddress, MainEnvelope.e_from); ! 177: ! 178: /* ! 179: ** Do a quick prescan of the argument list. ! 180: ** We do this to find out if we can potentially thaw the ! 181: ** configuration file. If not, we do the thaw now so that ! 182: ** the argument processing applies to this run rather than ! 183: ** to the run that froze the configuration. ! 184: */ ! 185: ! 186: argv[argc] = NULL; ! 187: av = argv; ! 188: nothaw = FALSE; ! 189: while ((p = *++av) != NULL) ! 190: { ! 191: if (strncmp(p, "-C", 2) == 0) ! 192: { ! 193: ConfFile = &p[2]; ! 194: if (ConfFile[0] == '\0') ! 195: ConfFile = "sendmail.cf"; ! 196: (void) setgid(getrgid()); ! 197: (void) setuid(getruid()); ! 198: nothaw = TRUE; ! 199: } ! 200: else if (strncmp(p, "-bz", 3) == 0) ! 201: nothaw = TRUE; ! 202: else if (strncmp(p, "-d", 2) == 0) ! 203: { ! 204: tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); ! 205: tTflag(&p[2]); ! 206: setbuf(stdout, (char *) NULL); ! 207: printf("Version %s\n", Version); ! 208: } ! 209: } ! 210: ! 211: InChannel = stdin; ! 212: OutChannel = stdout; ! 213: ! 214: if (!nothaw) ! 215: readconfig = !thaw(FreezeFile); ! 216: ! 217: /* reset the environment after the thaw */ ! 218: for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++) ! 219: UserEnviron[i] = newstr(envp[i]); ! 220: UserEnviron[i] = NULL; ! 221: environ = UserEnviron; ! 222: ! 223: # ifdef SETPROCTITLE ! 224: /* ! 225: ** Save start and extent of argv for setproctitle. ! 226: */ ! 227: ! 228: Argv = argv; ! 229: if (i > 0) ! 230: LastArgv = envp[i - 1] + strlen(envp[i - 1]); ! 231: else ! 232: LastArgv = argv[argc - 1] + strlen(argv[argc - 1]); ! 233: # endif SETPROCTITLE ! 234: ! 235: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 236: (void) signal(SIGINT, intsig); ! 237: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) ! 238: (void) signal(SIGHUP, intsig); ! 239: (void) signal(SIGTERM, intsig); ! 240: (void) signal(SIGPIPE, SIG_IGN); ! 241: OldUmask = umask(0); ! 242: OpMode = MD_DELIVER; ! 243: MotherPid = getpid(); ! 244: FullName = getenv("NAME"); ! 245: ! 246: errno = 0; ! 247: from = NULL; ! 248: ! 249: if (readconfig) ! 250: { ! 251: /* initialize some macros, etc. */ ! 252: initmacros(); ! 253: ! 254: /* hostname */ ! 255: av = myhostname(jbuf, sizeof jbuf); ! 256: if (jbuf[0] != '\0') ! 257: { ! 258: if (tTd(0, 4)) ! 259: printf("canonical name: %s\n", jbuf); ! 260: p = newstr(jbuf); ! 261: define('w', p, CurEnv); ! 262: setclass('w', p); ! 263: } ! 264: while (av != NULL && *av != NULL) ! 265: { ! 266: if (tTd(0, 4)) ! 267: printf("\ta.k.a.: %s\n", *av); ! 268: setclass('w', *av++); ! 269: } ! 270: ! 271: /* version */ ! 272: define('v', Version, CurEnv); ! 273: } ! 274: ! 275: /* current time */ ! 276: define('b', arpadate((char *) NULL), CurEnv); ! 277: ! 278: /* ! 279: ** Crack argv. ! 280: */ ! 281: ! 282: av = argv; ! 283: p = rindex(*av, '/'); ! 284: if (p++ == NULL) ! 285: p = *av; ! 286: if (strcmp(p, "newaliases") == 0) ! 287: OpMode = MD_INITALIAS; ! 288: else if (strcmp(p, "mailq") == 0) ! 289: OpMode = MD_PRINT; ! 290: else if (strcmp(p, "smtpd") == 0) ! 291: OpMode = MD_DAEMON; ! 292: while ((p = *++av) != NULL && p[0] == '-') ! 293: { ! 294: switch (p[1]) ! 295: { ! 296: case 'b': /* operations mode */ ! 297: switch (p[2]) ! 298: { ! 299: case MD_DAEMON: ! 300: # ifdef DAEMON ! 301: if (getuid() != 0) { ! 302: usrerr("Permission denied"); ! 303: exit (EX_USAGE); ! 304: } ! 305: (void) unsetenv("HOSTALIASES"); ! 306: # else ! 307: usrerr("Daemon mode not implemented"); ! 308: ExitStat = EX_USAGE; ! 309: break; ! 310: # endif DAEMON ! 311: case MD_SMTP: ! 312: # ifndef SMTP ! 313: usrerr("I don't speak SMTP"); ! 314: ExitStat = EX_USAGE; ! 315: break; ! 316: # endif SMTP ! 317: case MD_ARPAFTP: ! 318: case MD_DELIVER: ! 319: case MD_VERIFY: ! 320: case MD_TEST: ! 321: case MD_INITALIAS: ! 322: case MD_PRINT: ! 323: case MD_FREEZE: ! 324: OpMode = p[2]; ! 325: break; ! 326: ! 327: default: ! 328: usrerr("Invalid operation mode %c", p[2]); ! 329: ExitStat = EX_USAGE; ! 330: break; ! 331: } ! 332: break; ! 333: ! 334: case 'C': /* select configuration file (already done) */ ! 335: break; ! 336: ! 337: case 'd': /* debugging -- redo in case frozen */ ! 338: tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); ! 339: tTflag(&p[2]); ! 340: setbuf(stdout, (char *) NULL); ! 341: #ifdef NAMED_BIND ! 342: _res.options |= RES_DEBUG; ! 343: #endif ! 344: break; ! 345: ! 346: case 'f': /* from address */ ! 347: case 'r': /* obsolete -f flag */ ! 348: p += 2; ! 349: if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) ! 350: { ! 351: p = *++av; ! 352: if (p == NULL || *p == '-') ! 353: { ! 354: usrerr("No \"from\" person"); ! 355: ExitStat = EX_USAGE; ! 356: av--; ! 357: break; ! 358: } ! 359: } ! 360: if (from != NULL) ! 361: { ! 362: usrerr("More than one \"from\" person"); ! 363: ExitStat = EX_USAGE; ! 364: break; ! 365: } ! 366: from = newstr(p); ! 367: break; ! 368: ! 369: case 'F': /* set full name */ ! 370: p += 2; ! 371: if (*p == '\0' && ((p = *++av) == NULL || *p == '-')) ! 372: { ! 373: usrerr("Bad -F flag"); ! 374: ExitStat = EX_USAGE; ! 375: av--; ! 376: break; ! 377: } ! 378: FullName = newstr(p); ! 379: break; ! 380: ! 381: case 'h': /* hop count */ ! 382: p += 2; ! 383: if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p))) ! 384: { ! 385: usrerr("Bad hop count (%s)", p); ! 386: ExitStat = EX_USAGE; ! 387: av--; ! 388: break; ! 389: } ! 390: CurEnv->e_hopcount = atoi(p); ! 391: break; ! 392: ! 393: case 'n': /* don't alias */ ! 394: NoAlias = TRUE; ! 395: break; ! 396: ! 397: case 'o': /* set option */ ! 398: setoption(p[2], &p[3], FALSE, TRUE); ! 399: break; ! 400: ! 401: case 'q': /* run queue files at intervals */ ! 402: # ifdef QUEUE ! 403: if (getuid() != 0) { ! 404: usrerr("Permission denied"); ! 405: exit (EX_USAGE); ! 406: } ! 407: (void) unsetenv("HOSTALIASES"); ! 408: queuemode = TRUE; ! 409: QueueIntvl = convtime(&p[2]); ! 410: # else QUEUE ! 411: usrerr("I don't know about queues"); ! 412: ExitStat = EX_USAGE; ! 413: # endif QUEUE ! 414: break; ! 415: ! 416: case 't': /* read recipients from message */ ! 417: GrabTo = TRUE; ! 418: break; ! 419: ! 420: /* compatibility flags */ ! 421: case 'c': /* connect to non-local mailers */ ! 422: case 'e': /* error message disposition */ ! 423: case 'i': /* don't let dot stop me */ ! 424: case 'm': /* send to me too */ ! 425: case 'T': /* set timeout interval */ ! 426: case 'v': /* give blow-by-blow description */ ! 427: setoption(p[1], &p[2], FALSE, TRUE); ! 428: break; ! 429: ! 430: case 's': /* save From lines in headers */ ! 431: setoption('f', &p[2], FALSE, TRUE); ! 432: break; ! 433: ! 434: # ifdef DBM ! 435: case 'I': /* initialize alias DBM file */ ! 436: OpMode = MD_INITALIAS; ! 437: break; ! 438: # endif DBM ! 439: } ! 440: } ! 441: ! 442: /* ! 443: ** Do basic initialization. ! 444: ** Read system control file. ! 445: ** Extract special fields for local use. ! 446: */ ! 447: ! 448: if (OpMode == MD_FREEZE || readconfig) ! 449: readcf(ConfFile); ! 450: ! 451: switch (OpMode) ! 452: { ! 453: case MD_FREEZE: ! 454: /* this is critical to avoid forgeries of the frozen config */ ! 455: (void) setgid(getgid()); ! 456: (void) setuid(getuid()); ! 457: ! 458: /* freeze the configuration */ ! 459: freeze(FreezeFile); ! 460: exit(EX_OK); ! 461: ! 462: case MD_INITALIAS: ! 463: Verbose = TRUE; ! 464: break; ! 465: } ! 466: ! 467: /* do heuristic mode adjustment */ ! 468: if (Verbose) ! 469: { ! 470: /* turn off noconnect option */ ! 471: setoption('c', "F", TRUE, FALSE); ! 472: ! 473: /* turn on interactive delivery */ ! 474: setoption('d', "", TRUE, FALSE); ! 475: } ! 476: ! 477: /* our name for SMTP codes */ ! 478: expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); ! 479: MyHostName = jbuf; ! 480: ! 481: /* the indices of local and program mailers */ ! 482: st = stab("local", ST_MAILER, ST_FIND); ! 483: if (st == NULL) ! 484: syserr("No local mailer defined"); ! 485: else ! 486: LocalMailer = st->s_mailer; ! 487: st = stab("prog", ST_MAILER, ST_FIND); ! 488: if (st == NULL) ! 489: syserr("No prog mailer defined"); ! 490: else ! 491: ProgMailer = st->s_mailer; ! 492: ! 493: /* operate in queue directory */ ! 494: if (chdir(QueueDir) < 0) ! 495: { ! 496: syserr("cannot chdir(%s)", QueueDir); ! 497: exit(EX_SOFTWARE); ! 498: } ! 499: ! 500: /* ! 501: ** Do operation-mode-dependent initialization. ! 502: */ ! 503: ! 504: switch (OpMode) ! 505: { ! 506: case MD_PRINT: ! 507: /* print the queue */ ! 508: #ifdef QUEUE ! 509: dropenvelope(CurEnv); ! 510: printqueue(); ! 511: exit(EX_OK); ! 512: #else QUEUE ! 513: usrerr("No queue to print"); ! 514: finis(); ! 515: #endif QUEUE ! 516: ! 517: case MD_INITALIAS: ! 518: /* initialize alias database */ ! 519: initaliases(AliasFile, TRUE); ! 520: exit(EX_OK); ! 521: ! 522: case MD_DAEMON: ! 523: /* don't open alias database -- done in srvrsmtp */ ! 524: break; ! 525: ! 526: default: ! 527: /* open the alias database */ ! 528: initaliases(AliasFile, FALSE); ! 529: break; ! 530: } ! 531: ! 532: if (tTd(0, 15)) ! 533: { ! 534: /* print configuration table (or at least part of it) */ ! 535: printrules(); ! 536: for (i = 0; i < MAXMAILERS; i++) ! 537: { ! 538: register struct mailer *m = Mailer[i]; ! 539: int j; ! 540: ! 541: if (m == NULL) ! 542: continue; ! 543: printf("mailer %d (%s): P=%s S=%d R=%d M=%ld F=", i, m->m_name, ! 544: m->m_mailer, m->m_s_rwset, m->m_r_rwset, ! 545: m->m_maxsize); ! 546: for (j = '\0'; j <= '\177'; j++) ! 547: if (bitnset(j, m->m_flags)) ! 548: (void) putchar(j); ! 549: printf(" E="); ! 550: xputs(m->m_eol); ! 551: printf("\n"); ! 552: } ! 553: } ! 554: ! 555: /* ! 556: ** Switch to the main envelope. ! 557: */ ! 558: ! 559: CurEnv = newenvelope(&MainEnvelope); ! 560: MainEnvelope.e_flags = BlankEnvelope.e_flags; ! 561: ! 562: /* ! 563: ** If test mode, read addresses from stdin and process. ! 564: */ ! 565: ! 566: if (OpMode == MD_TEST) ! 567: { ! 568: char buf[MAXLINE]; ! 569: ! 570: printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n"); ! 571: for (;;) ! 572: { ! 573: register char **pvp; ! 574: char *q; ! 575: extern char *DelimChar; ! 576: ! 577: printf("> "); ! 578: (void) fflush(stdout); ! 579: if (fgets(buf, sizeof buf, stdin) == NULL) ! 580: finis(); ! 581: for (p = buf; isspace(*p); p++) ! 582: continue; ! 583: q = p; ! 584: while (*p != '\0' && !isspace(*p)) ! 585: p++; ! 586: if (*p == '\0') ! 587: continue; ! 588: *p = '\0'; ! 589: do ! 590: { ! 591: extern char **prescan(); ! 592: char pvpbuf[PSBUFSIZE]; ! 593: ! 594: pvp = prescan(++p, ',', pvpbuf); ! 595: if (pvp == NULL) ! 596: continue; ! 597: rewrite(pvp, 3); ! 598: p = q; ! 599: while (*p != '\0') ! 600: { ! 601: rewrite(pvp, atoi(p)); ! 602: while (*p != '\0' && *p++ != ',') ! 603: continue; ! 604: } ! 605: } while (*(p = DelimChar) != '\0'); ! 606: } ! 607: } ! 608: ! 609: # ifdef QUEUE ! 610: /* ! 611: ** If collecting stuff from the queue, go start doing that. ! 612: */ ! 613: ! 614: if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) ! 615: { ! 616: runqueue(FALSE); ! 617: finis(); ! 618: } ! 619: # endif QUEUE ! 620: ! 621: /* ! 622: ** If a daemon, wait for a request. ! 623: ** getrequests will always return in a child. ! 624: ** If we should also be processing the queue, start ! 625: ** doing it in background. ! 626: ** We check for any errors that might have happened ! 627: ** during startup. ! 628: */ ! 629: ! 630: if (OpMode == MD_DAEMON || QueueIntvl != 0) ! 631: { ! 632: if (!tTd(0, 1)) ! 633: { ! 634: /* put us in background */ ! 635: i = fork(); ! 636: if (i < 0) ! 637: syserr("daemon: cannot fork"); ! 638: if (i != 0) ! 639: exit(0); ! 640: ! 641: /* get our pid right */ ! 642: MotherPid = getpid(); ! 643: ! 644: /* disconnect from our controlling tty */ ! 645: disconnect(TRUE); ! 646: } ! 647: ! 648: # ifdef QUEUE ! 649: if (queuemode) ! 650: { ! 651: runqueue(TRUE); ! 652: if (OpMode != MD_DAEMON) ! 653: for (;;) ! 654: pause(); ! 655: } ! 656: # endif QUEUE ! 657: dropenvelope(CurEnv); ! 658: ! 659: #ifdef DAEMON ! 660: getrequests(); ! 661: ! 662: /* at this point we are in a child: reset state */ ! 663: OpMode = MD_SMTP; ! 664: (void) newenvelope(CurEnv); ! 665: openxscript(CurEnv); ! 666: #endif DAEMON ! 667: } ! 668: ! 669: # ifdef SMTP ! 670: /* ! 671: ** If running SMTP protocol, start collecting and executing ! 672: ** commands. This will never return. ! 673: */ ! 674: ! 675: if (OpMode == MD_SMTP) ! 676: smtp(); ! 677: # endif SMTP ! 678: ! 679: /* ! 680: ** Do basic system initialization and set the sender ! 681: */ ! 682: ! 683: initsys(); ! 684: setsender(from); ! 685: ! 686: if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo) ! 687: { ! 688: usrerr("Recipient names must be specified"); ! 689: ! 690: /* collect body for UUCP return */ ! 691: if (OpMode != MD_VERIFY) ! 692: collect(FALSE); ! 693: finis(); ! 694: } ! 695: if (OpMode == MD_VERIFY) ! 696: SendMode = SM_VERIFY; ! 697: ! 698: /* ! 699: ** Scan argv and deliver the message to everyone. ! 700: */ ! 701: ! 702: sendtoargv(av); ! 703: ! 704: /* if we have had errors sofar, arrange a meaningful exit stat */ ! 705: if (Errors > 0 && ExitStat == EX_OK) ! 706: ExitStat = EX_USAGE; ! 707: ! 708: /* ! 709: ** Read the input mail. ! 710: */ ! 711: ! 712: CurEnv->e_to = NULL; ! 713: if (OpMode != MD_VERIFY || GrabTo) ! 714: collect(FALSE); ! 715: errno = 0; ! 716: ! 717: /* collect statistics */ ! 718: if (OpMode != MD_VERIFY) ! 719: markstats(CurEnv, (ADDRESS *) NULL); ! 720: ! 721: if (tTd(1, 1)) ! 722: printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); ! 723: ! 724: /* ! 725: ** Actually send everything. ! 726: ** If verifying, just ack. ! 727: */ ! 728: ! 729: CurEnv->e_from.q_flags |= QDONTSEND; ! 730: CurEnv->e_to = NULL; ! 731: sendall(CurEnv, SM_DEFAULT); ! 732: ! 733: /* ! 734: ** All done. ! 735: */ ! 736: ! 737: finis(); ! 738: } ! 739: /* ! 740: ** FINIS -- Clean up and exit. ! 741: ** ! 742: ** Parameters: ! 743: ** none ! 744: ** ! 745: ** Returns: ! 746: ** never ! 747: ** ! 748: ** Side Effects: ! 749: ** exits sendmail ! 750: */ ! 751: ! 752: finis() ! 753: { ! 754: if (tTd(2, 1)) ! 755: printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags); ! 756: ! 757: /* clean up temp files */ ! 758: CurEnv->e_to = NULL; ! 759: dropenvelope(CurEnv); ! 760: ! 761: /* post statistics */ ! 762: poststats(StatFile); ! 763: ! 764: /* and exit */ ! 765: # ifdef LOG ! 766: if (LogLevel > 11) ! 767: syslog(LOG_DEBUG, "finis, pid=%d", getpid()); ! 768: # endif LOG ! 769: if (ExitStat == EX_TEMPFAIL) ! 770: ExitStat = EX_OK; ! 771: exit(ExitStat); ! 772: } ! 773: /* ! 774: ** INTSIG -- clean up on interrupt ! 775: ** ! 776: ** This just arranges to exit. It pessimises in that it ! 777: ** may resend a message. ! 778: ** ! 779: ** Parameters: ! 780: ** none. ! 781: ** ! 782: ** Returns: ! 783: ** none. ! 784: ** ! 785: ** Side Effects: ! 786: ** Unlocks the current job. ! 787: */ ! 788: ! 789: intsig() ! 790: { ! 791: FileName = NULL; ! 792: unlockqueue(CurEnv); ! 793: exit(EX_OK); ! 794: } ! 795: /* ! 796: ** INITMACROS -- initialize the macro system ! 797: ** ! 798: ** This just involves defining some macros that are actually ! 799: ** used internally as metasymbols to be themselves. ! 800: ** ! 801: ** Parameters: ! 802: ** none. ! 803: ** ! 804: ** Returns: ! 805: ** none. ! 806: ** ! 807: ** Side Effects: ! 808: ** initializes several macros to be themselves. ! 809: */ ! 810: ! 811: struct metamac ! 812: { ! 813: char metaname; ! 814: char metaval; ! 815: }; ! 816: ! 817: struct metamac MetaMacros[] = ! 818: { ! 819: /* LHS pattern matching characters */ ! 820: '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, '=', MATCHCLASS, ! 821: '~', MATCHNCLASS, ! 822: ! 823: /* these are RHS metasymbols */ ! 824: '#', CANONNET, '@', CANONHOST, ':', CANONUSER, '>', CALLSUBR, ! 825: ! 826: /* the conditional operations */ ! 827: '?', CONDIF, '|', CONDELSE, '.', CONDFI, ! 828: ! 829: /* and finally the hostname lookup characters */ ! 830: '[', HOSTBEGIN, ']', HOSTEND, ! 831: ! 832: '\0' ! 833: }; ! 834: ! 835: initmacros() ! 836: { ! 837: register struct metamac *m; ! 838: char buf[5]; ! 839: register int c; ! 840: ! 841: for (m = MetaMacros; m->metaname != '\0'; m++) ! 842: { ! 843: buf[0] = m->metaval; ! 844: buf[1] = '\0'; ! 845: define(m->metaname, newstr(buf), CurEnv); ! 846: } ! 847: buf[0] = MATCHREPL; ! 848: buf[2] = '\0'; ! 849: for (c = '0'; c <= '9'; c++) ! 850: { ! 851: buf[1] = c; ! 852: define(c, newstr(buf), CurEnv); ! 853: } ! 854: } ! 855: /* ! 856: ** FREEZE -- freeze BSS & allocated memory ! 857: ** ! 858: ** This will be used to efficiently load the configuration file. ! 859: ** ! 860: ** Parameters: ! 861: ** freezefile -- the name of the file to freeze to. ! 862: ** ! 863: ** Returns: ! 864: ** none. ! 865: ** ! 866: ** Side Effects: ! 867: ** Writes BSS and malloc'ed memory to freezefile ! 868: */ ! 869: ! 870: union frz ! 871: { ! 872: char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */ ! 873: struct ! 874: { ! 875: time_t frzstamp; /* timestamp on this freeze */ ! 876: char *frzbrk; /* the current break */ ! 877: char *frzedata; /* address of edata */ ! 878: char *frzend; /* address of end */ ! 879: char frzver[252]; /* sendmail version */ ! 880: } frzinfo; ! 881: }; ! 882: ! 883: freeze(freezefile) ! 884: char *freezefile; ! 885: { ! 886: int f; ! 887: union frz fhdr; ! 888: extern char edata, end; ! 889: extern char *sbrk(); ! 890: extern char Version[]; ! 891: ! 892: if (freezefile == NULL) ! 893: return; ! 894: ! 895: /* try to open the freeze file */ ! 896: f = creat(freezefile, FileMode); ! 897: if (f < 0) ! 898: { ! 899: syserr("Cannot freeze %s", freezefile); ! 900: errno = 0; ! 901: return; ! 902: } ! 903: ! 904: /* build the freeze header */ ! 905: fhdr.frzinfo.frzstamp = curtime(); ! 906: fhdr.frzinfo.frzbrk = sbrk(0); ! 907: fhdr.frzinfo.frzedata = &edata; ! 908: fhdr.frzinfo.frzend = &end; ! 909: (void) strcpy(fhdr.frzinfo.frzver, Version); ! 910: ! 911: /* write out the freeze header */ ! 912: if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr || ! 913: write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != ! 914: (int) (fhdr.frzinfo.frzbrk - &edata)) ! 915: { ! 916: syserr("Cannot freeze %s", freezefile); ! 917: } ! 918: ! 919: /* fine, clean up */ ! 920: (void) close(f); ! 921: } ! 922: /* ! 923: ** THAW -- read in the frozen configuration file. ! 924: ** ! 925: ** Parameters: ! 926: ** freezefile -- the name of the file to thaw from. ! 927: ** ! 928: ** Returns: ! 929: ** TRUE if it successfully read the freeze file. ! 930: ** FALSE otherwise. ! 931: ** ! 932: ** Side Effects: ! 933: ** reads freezefile in to BSS area. ! 934: */ ! 935: ! 936: thaw(freezefile) ! 937: char *freezefile; ! 938: { ! 939: int f; ! 940: union frz fhdr; ! 941: extern char edata, end; ! 942: extern char Version[]; ! 943: extern caddr_t brk(); ! 944: ! 945: if (freezefile == NULL) ! 946: return (FALSE); ! 947: ! 948: /* open the freeze file */ ! 949: f = open(freezefile, 0); ! 950: if (f < 0) ! 951: { ! 952: syslog(LOG_WARNING, "Cannot open frozen config file %s: %m", ! 953: freezefile); ! 954: errno = 0; ! 955: return (FALSE); ! 956: } ! 957: ! 958: /* read in the header */ ! 959: if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr) ! 960: { ! 961: syserr("Cannot read frozen config file"); ! 962: (void) close(f); ! 963: return (FALSE); ! 964: } ! 965: if ( fhdr.frzinfo.frzedata != &edata || ! 966: fhdr.frzinfo.frzend != &end || ! 967: strcmp(fhdr.frzinfo.frzver, Version) != 0) ! 968: { ! 969: syslog(LOG_WARNING, "Wrong version of frozen config file"); ! 970: (void) close(f); ! 971: return (FALSE); ! 972: } ! 973: ! 974: /* arrange to have enough space */ ! 975: if (brk(fhdr.frzinfo.frzbrk) == (caddr_t) -1) ! 976: { ! 977: syserr("Cannot break to %x", fhdr.frzinfo.frzbrk); ! 978: (void) close(f); ! 979: return (FALSE); ! 980: } ! 981: ! 982: /* now read in the freeze file */ ! 983: if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) != ! 984: (int) (fhdr.frzinfo.frzbrk - &edata)) ! 985: { ! 986: syserr("Cannot read frozen config file"); ! 987: /* oops! we have trashed memory..... */ ! 988: (void) write(2, "Cannot read freeze file\n", 24); ! 989: _exit(EX_SOFTWARE); ! 990: } ! 991: ! 992: (void) close(f); ! 993: return (TRUE); ! 994: } ! 995: /* ! 996: ** DISCONNECT -- remove our connection with any foreground process ! 997: ** ! 998: ** Parameters: ! 999: ** fulldrop -- if set, we should also drop the controlling ! 1000: ** TTY if possible -- this should only be done when ! 1001: ** setting up the daemon since otherwise UUCP can ! 1002: ** leave us trying to open a dialin, and we will ! 1003: ** wait for the carrier. ! 1004: ** ! 1005: ** Returns: ! 1006: ** none ! 1007: ** ! 1008: ** Side Effects: ! 1009: ** Trys to insure that we are immune to vagaries of ! 1010: ** the controlling tty. ! 1011: */ ! 1012: ! 1013: disconnect(fulldrop) ! 1014: bool fulldrop; ! 1015: { ! 1016: int fd; ! 1017: ! 1018: if (tTd(52, 1)) ! 1019: printf("disconnect: In %d Out %d\n", fileno(InChannel), ! 1020: fileno(OutChannel)); ! 1021: if (tTd(52, 5)) ! 1022: { ! 1023: printf("don't\n"); ! 1024: return; ! 1025: } ! 1026: ! 1027: /* be sure we don't get nasty signals */ ! 1028: (void) signal(SIGHUP, SIG_IGN); ! 1029: (void) signal(SIGINT, SIG_IGN); ! 1030: (void) signal(SIGQUIT, SIG_IGN); ! 1031: ! 1032: /* we can't communicate with our caller, so.... */ ! 1033: HoldErrs = TRUE; ! 1034: ErrorMode = EM_MAIL; ! 1035: Verbose = FALSE; ! 1036: ! 1037: /* all input from /dev/null */ ! 1038: if (InChannel != stdin) ! 1039: { ! 1040: (void) fclose(InChannel); ! 1041: InChannel = stdin; ! 1042: } ! 1043: (void) freopen("/dev/null", "r", stdin); ! 1044: ! 1045: /* output to the transcript */ ! 1046: if (OutChannel != stdout) ! 1047: { ! 1048: (void) fclose(OutChannel); ! 1049: OutChannel = stdout; ! 1050: } ! 1051: if (CurEnv->e_xfp == NULL) ! 1052: CurEnv->e_xfp = fopen("/dev/null", "w"); ! 1053: (void) fflush(stdout); ! 1054: (void) close(1); ! 1055: (void) close(2); ! 1056: while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0) ! 1057: continue; ! 1058: ! 1059: /* drop our controlling TTY completely if possible */ ! 1060: if (fulldrop) ! 1061: { ! 1062: #if BSD > 43 ! 1063: daemon(1, 1); ! 1064: #else ! 1065: #ifdef TIOCNOTTY ! 1066: fd = open("/dev/tty", 2); ! 1067: if (fd >= 0) ! 1068: { ! 1069: (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); ! 1070: (void) close(fd); ! 1071: } ! 1072: (void) setpgrp(0, 0); ! 1073: #endif /* TIOCNOTTY */ ! 1074: #endif /* BSD */ ! 1075: errno = 0; ! 1076: } ! 1077: ! 1078: # ifdef LOG ! 1079: if (LogLevel > 11) ! 1080: syslog(LOG_DEBUG, "in background, pid=%d", getpid()); ! 1081: # endif LOG ! 1082: ! 1083: errno = 0; ! 1084: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.