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