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