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