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