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