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