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