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