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