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