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