|
|
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.