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