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