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