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