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