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