portability
[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
319b1ec0 16static char sccsid[] = "@(#)main.c 6.47 (Berkeley) %G%";
bee79b64 17#endif /* not lint */
aeb2545d 18
137c2d1f
KB
19#define _DEFINE
20
f8a31c8e 21#include "sendmail.h"
f2e44ded 22#include <sys/stat.h>
137c2d1f
KB
23#include <signal.h>
24#include <sgtty.h>
6feb509e 25#ifdef NAMED_BIND
137c2d1f
KB
26#include <arpa/nameser.h>
27#include <resolv.h>
6feb509e 28#endif
94bc039a 29#include <pwd.h>
b3cbe40f 30
17a67c62 31# ifdef lint
2e3062fe 32char edata, end;
17a67c62
EA
33# endif lint
34
b3cbe40f 35/*
96faada8 36** SENDMAIL -- Post mail to a set of destinations.
b3cbe40f
EA
37**
38** This is the basic mail router. All user mail programs should
96faada8 39** call this routine to actually deliver mail. Sendmail in
b3cbe40f
EA
40** turn calls a bunch of mail servers that do the real work of
41** delivering the mail.
42**
3199e4f3
EA
43** Sendmail is driven by tables read in from /usr/lib/sendmail.cf
44** (read by readcf.c). Some more static configuration info,
45** including some code that you may want to tailor for your
46** installation, is in conf.c. You may also want to touch
47** daemon.c (if you have some other IPC mechanism), acct.c
48** (to change your accounting), names.c (to adjust the name
49** server mechanism).
b3cbe40f
EA
50**
51** Usage:
7338e3d4 52** /usr/lib/sendmail [flags] addr ...
b3cbe40f 53**
7338e3d4 54** See the associated documentation for details.
b3cbe40f 55**
b3cbe40f 56** Author:
7338e3d4
EA
57** Eric Allman, UCB/INGRES (until 10/81)
58** Britton-Lee, Inc., purveyors of fine
59** database computers (from 11/81)
ce46a48a 60** Now back at UCB at the Mammoth project.
7338e3d4
EA
61** The support of the INGRES Project and Britton-Lee is
62** gratefully acknowledged. Britton-Lee in
63** particular had absolutely nothing to gain from
64** my involvement in this project.
b3cbe40f
EA
65*/
66
67
83f674d8 68int NextMailer; /* "free" index into Mailer struct */
912acb74 69char *FullName; /* sender's full name */
be2fcca9 70ENVELOPE BlankEnvelope; /* a "blank" envelope */
2654b031 71ENVELOPE MainEnvelope; /* the envelope around the basic letter */
2e3062fe 72ADDRESS NullAddress = /* a null address */
599d88d0 73 { "", "", NULL, "" };
6e99f903
EA
74char *UserEnviron[MAXUSERENVIRON + 1];
75 /* saved user environment */
2e3062fe
EA
76
77/*
78** Pointers for setproctitle.
79** This allows "ps" listings to give more useful information.
80** These must be kept out of BSS for frozen configuration files
81** to work.
82*/
83
84# ifdef SETPROCTITLE
85char **Argv = NULL; /* pointer to argument vector */
86char *LastArgv = NULL; /* end of argv */
f3d8f6d6 87# endif /* SETPROCTITLE */
b3cbe40f 88
f96fa7de
EA
89static void obsolete();
90
4aebfe5d
EA
91#ifdef DAEMON
92#ifndef SMTP
93ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR
f3d8f6d6
EA
94#endif /* SMTP */
95#endif /* DAEMON */
4aebfe5d 96
a5bf555b 97#define MAXCONFIGLEVEL 4 /* highest config version level known */
2281a453 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;
af04f6e4 105 register char *q;
acae5a9d 106 char **av;
17df0fcb 107 char *locname;
b3cbe40f 108 extern int finis();
b3cbe40f 109 extern char Version[];
b2d4b27a 110 char *ep, *from;
b3cbe40f 111 typedef int (*fnptr)();
be2fcca9 112 STAB *st;
9e3c0a28 113 register int i;
d0a69620 114 int j;
4388720d 115 bool readconfig = TRUE;
aba51985 116 bool queuemode = FALSE; /* process queue requests */
43e0af62 117 bool nothaw;
66391bf0 118 bool safecf = TRUE;
be2fcca9 119 static bool reenter = FALSE;
4b26318e 120 char *argv0 = argv[0];
94bc039a 121 struct passwd *pw;
e0539260 122 struct stat stb;
94bc039a 123 char realuser[256];
b2d4b27a 124 char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */
f96fa7de
EA
125 extern int DtableSize;
126 extern int optind;
ed45aae1 127 extern time_t convtime();
dd1fe05b 128 extern putheader(), putbody();
be2fcca9 129 extern ENVELOPE *newenvelope();
0df908a9 130 extern void intsig();
1dbda134 131 extern char **myhostname();
22e6d6b8 132 extern char *arpadate();
5973222c 133 extern char *getrealhostname();
f96fa7de 134 extern char *optarg;
6e99f903 135 extern char **environ;
b72377c6 136
22659072
EA
137 /*
138 ** Check to see if we reentered.
139 ** This would normally happen if e_putheader or e_putbody
140 ** were NULL when invoked.
141 */
142
b72377c6
EA
143 if (reenter)
144 {
145 syserr("main: reentered!");
146 abort();
147 }
148 reenter = TRUE;
abae7b2d 149 extern ADDRESS *recipient();
17df0fcb 150 bool canrename;
b3cbe40f 151
07c63e56 152#ifndef SYS5TZ
140717b5
EA
153 /* enforce use of kernel-supplied time zone information */
154 unsetenv("TZ");
155#endif
60c0b7b2 156
3eb4fac4
EA
157 /* in 4.4BSD, the table can be huge; impose a reasonable limit */
158 DtableSize = getdtablesize();
159 if (DtableSize > 256)
160 DtableSize = 256;
161
d15bd559
EA
162 /*
163 ** Be sure we have enough file descriptors.
59b65d0f 164 ** But also be sure that 0, 1, & 2 are open.
d15bd559
EA
165 */
166
e1098041 167 i = open("/dev/null", O_RDWR);
e0539260
EA
168 if (fstat(STDIN_FILENO, &stb) < 0)
169 (void) dup2(i, STDIN_FILENO);
170 if (fstat(STDOUT_FILENO, &stb) < 0)
171 (void) dup2(i, STDOUT_FILENO);
172 if (fstat(STDERR_FILENO, &stb) < 0)
173 (void) dup2(i, STDERR_FILENO);
174 (void) close(i);
66391bf0 175
3eb4fac4 176 i = DtableSize;
1627a785
EA
177 while (--i > 0)
178 {
179 if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
180 (void) close(i);
181 }
d15bd559
EA
182 errno = 0;
183
07adc4f5
RA
184#ifdef LOG_MAIL
185 openlog("sendmail", LOG_PID, LOG_MAIL);
186#else
187 openlog("sendmail", LOG_PID);
188#endif
189
bb09c502
EA
190 /* set up the blank envelope */
191 BlankEnvelope.e_puthdr = putheader;
192 BlankEnvelope.e_putbody = putbody;
193 BlankEnvelope.e_xfp = NULL;
2e3062fe 194 STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
bd575ea9
EA
195 STRUCTCOPY(BlankEnvelope, MainEnvelope);
196 CurEnv = &MainEnvelope;
bb09c502 197
8c8e8e94
EA
198 /*
199 ** Set default values for variables.
200 ** These cannot be in initialized data space.
201 */
202
203 setdefaults(&BlankEnvelope);
204
ca708b8e
EA
205 RealUid = getuid();
206 RealGid = getgid();
207
94bc039a
EA
208 pw = getpwuid(RealUid);
209 if (pw != NULL)
210 (void) strcpy(realuser, pw->pw_name);
211 else
212 (void) sprintf(realuser, "Unknown UID %d", RealUid);
213
b2d4b27a
KB
214 /* Handle any non-getoptable constructions. */
215 obsolete(argv);
216
22659072
EA
217 /*
218 ** Do a quick prescan of the argument list.
219 ** We do this to find out if we can potentially thaw the
220 ** configuration file. If not, we do the thaw now so that
221 ** the argument processing applies to this run rather than
222 ** to the run that froze the configuration.
223 */
43e0af62 224 nothaw = FALSE;
94bc039a 225#ifdef __osf__
97030b8b
EA
226#define OPTIONS "b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvx"
227#else
cbcd7b22 228#define OPTIONS "b:C:cd:e:F:f:h:Iimno:p:q:r:sTtv"
97030b8b 229#endif
a0431b8d 230 while ((j = getopt(argc, argv, OPTIONS)) != EOF)
f96fa7de
EA
231 {
232 switch (j)
560a80d9 233 {
b2d4b27a
KB
234 case 'b':
235 if (optarg[0] == 'z' && optarg[1] == '\0')
236 nothaw = TRUE;
237 break;
238
239 case 'C':
240 ConfFile = optarg;
0e306e7f
EA
241 (void) setgid(getrgid());
242 (void) setuid(getruid());
66391bf0 243 safecf = FALSE;
43e0af62 244 nothaw = TRUE;
b2d4b27a
KB
245 break;
246
247 case 'd':
43e0af62 248 tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
b2d4b27a 249 tTflag(optarg);
43e0af62
EA
250 setbuf(stdout, (char *) NULL);
251 printf("Version %s\n", Version);
b2d4b27a 252 break;
43e0af62 253 }
f96fa7de 254 }
2bc15c4e
KB
255
256 InChannel = stdin;
257 OutChannel = stdout;
258
ca708b8e 259# ifdef FROZENCONFIG
43e0af62 260 if (!nothaw)
4b26318e 261 readconfig = !thaw(FreezeFile, argv0);
ca708b8e
EA
262# else
263 readconfig = TRUE;
264# endif
22659072 265
42bbf376 266# ifdef SETPROCTITLE
6e99f903
EA
267 /*
268 ** Move the environment so setproctitle can use the space at
269 ** the top of memory.
270 */
271
272 for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++)
273 {
274 if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0)
275 continue;
276 UserEnviron[j++] = newstr(p);
277 }
278 UserEnviron[j] = NULL;
279 environ = UserEnviron;
280
42bbf376
EA
281 /*
282 ** Save start and extent of argv for setproctitle.
283 */
284
285 Argv = argv;
6e99f903 286 if (i > 0)
577bce94
EA
287 LastArgv = envp[i - 1] + strlen(envp[i - 1]);
288 else
289 LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
f3d8f6d6 290# endif /* SETPROCTITLE */
e36705df 291
b3cbe40f 292 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
6e2f38be 293 (void) signal(SIGINT, intsig);
eb211e2c 294 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
6e2f38be
EA
295 (void) signal(SIGHUP, intsig);
296 (void) signal(SIGTERM, intsig);
ed7382d3 297 (void) signal(SIGPIPE, SIG_IGN);
9a62d249 298 OldUmask = umask(022);
75f95954 299 OpMode = MD_DELIVER;
561c7c50 300 FullName = getenv("NAME");
dd1fe05b 301
b3cbe40f
EA
302 errno = 0;
303 from = NULL;
378e8da7 304
4388720d 305 if (readconfig)
1dbda134 306 {
4388720d
EA
307 /* initialize some macros, etc. */
308 initmacros();
309
94bc039a
EA
310 /* version */
311 define('v', Version, CurEnv);
312 }
dec0d30e 313
94bc039a
EA
314 /* hostname */
315 av = myhostname(jbuf, sizeof jbuf);
316 if (jbuf[0] != '\0')
317 {
318 struct utsname utsname;
319 extern char *strchr();
dec0d30e 320
94bc039a
EA
321 if (tTd(0, 4))
322 printf("canonical name: %s\n", jbuf);
323 p = newstr(jbuf);
324 define('w', p, CurEnv);
72364bac 325 setclass('w', p);
422bed79 326
94bc039a
EA
327 q = strchr(jbuf, '.');
328 if (q != NULL)
43e0af62 329 {
94bc039a 330 *q++ = '\0';
94bc039a 331 define('m', q, CurEnv);
72364bac
EA
332 p = newstr(jbuf);
333 setclass('w', p);
43e0af62 334 }
4388720d 335
94bc039a
EA
336 if (uname(&utsname) >= 0)
337 p = utsname.nodename;
338 else
339 {
340 makelower(jbuf);
341 p = jbuf;
342 }
343 if (tTd(0, 4))
344 printf("UUCP nodename: %s\n", p);
345 p = newstr(p);
346 define('k', p, CurEnv);
347 setclass('w', p);
348 }
349 while (av != NULL && *av != NULL)
350 {
351 if (tTd(0, 4))
352 printf("\ta.k.a.: %s\n", *av);
353 setclass('w', *av++);
1dbda134 354 }
378e8da7
EA
355
356 /* current time */
22e6d6b8 357 define('b', arpadate((char *) NULL), CurEnv);
378e8da7 358
94bc039a
EA
359 /*
360 ** Find our real host name for future logging.
361 */
362
363 p = getrealhostname(STDIN_FILENO);
364 if (p != NULL)
365 RealHostName = newstr(p);
366 else
367 RealHostName = "localhost";
368
a691a4a6 369 /*
c1e24818 370 ** Crack argv.
a691a4a6
EA
371 */
372
acae5a9d 373 av = argv;
f3d8f6d6 374 p = strrchr(*av, '/');
26a3626c
EA
375 if (p++ == NULL)
376 p = *av;
377 if (strcmp(p, "newaliases") == 0)
75f95954 378 OpMode = MD_INITALIAS;
26a3626c 379 else if (strcmp(p, "mailq") == 0)
75f95954 380 OpMode = MD_PRINT;
34fe0a9b
EA
381 else if (strcmp(p, "smtpd") == 0)
382 OpMode = MD_DAEMON;
b2d4b27a
KB
383
384 optind = 1;
a0431b8d 385 while ((j = getopt(argc, argv, OPTIONS)) != EOF)
f96fa7de
EA
386 {
387 switch (j)
a691a4a6 388 {
75f95954 389 case 'b': /* operations mode */
f96fa7de 390 switch (j = *optarg)
c1e24818 391 {
75f95954 392 case MD_DAEMON:
908dc8db
MK
393# ifdef DAEMON
394 if (getuid() != 0) {
395 usrerr("Permission denied");
396 exit (EX_USAGE);
397 }
398 (void) unsetenv("HOSTALIASES");
399# else
2e15a2d8
MK
400 usrerr("Daemon mode not implemented");
401 ExitStat = EX_USAGE;
75f95954 402 break;
f3d8f6d6 403# endif /* DAEMON */
75f95954
EA
404 case MD_SMTP:
405# ifndef SMTP
2e15a2d8
MK
406 usrerr("I don't speak SMTP");
407 ExitStat = EX_USAGE;
75f95954 408 break;
f3d8f6d6 409# endif /* SMTP */
75f95954
EA
410 case MD_DELIVER:
411 case MD_VERIFY:
412 case MD_TEST:
413 case MD_INITALIAS:
414 case MD_PRINT:
ca708b8e 415#ifdef FROZENCONFIG
75f95954 416 case MD_FREEZE:
ca708b8e 417#endif
b2d4b27a 418 OpMode = j;
75f95954
EA
419 break;
420
ca708b8e
EA
421#ifndef FROZENCONFIG
422 case MD_FREEZE:
423 usrerr("Frozen configurations unsupported");
424 ExitStat = EX_USAGE;
425 break;
426#endif
427
75f95954 428 default:
b2d4b27a 429 usrerr("Invalid operation mode %c", j);
2e15a2d8 430 ExitStat = EX_USAGE;
75f95954 431 break;
c1e24818
EA
432 }
433 break;
434
560a80d9 435 case 'C': /* select configuration file (already done) */
94bc039a
EA
436 if (getuid() != 0)
437 auth_warning(CurEnv,
438 "Processed by %s with -C %s",
439 realuser, optarg);
c1e24818 440 break;
a691a4a6 441
43e0af62 442 case 'd': /* debugging -- redo in case frozen */
c1e24818 443 tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
b2d4b27a 444 tTflag(optarg);
c1e24818 445 setbuf(stdout, (char *) NULL);
c1e24818 446 break;
b3cbe40f 447
b3cbe40f 448 case 'f': /* from address */
c1e24818 449 case 'r': /* obsolete -f flag */
22659072 450 if (from != NULL)
b3cbe40f 451 {
2e15a2d8
MK
452 usrerr("More than one \"from\" person");
453 ExitStat = EX_USAGE;
b3cbe40f
EA
454 break;
455 }
b2d4b27a 456 from = newstr(optarg);
94bc039a
EA
457 auth_warning(CurEnv,
458 "%s set sender to %s using -%c",
459 realuser, from, j);
b3cbe40f
EA
460 break;
461
6da7b890 462 case 'F': /* set full name */
b2d4b27a 463 FullName = newstr(optarg);
6da7b890
EA
464 break;
465
b3cbe40f 466 case 'h': /* hop count */
b2d4b27a
KB
467 CurEnv->e_hopcount = strtol(optarg, &ep, 10);
468 if (*ep)
b3cbe40f 469 {
b2d4b27a 470 usrerr("Bad hop count (%s)", optarg);
2e15a2d8 471 ExitStat = EX_USAGE;
3110074f 472 break;
b3cbe40f 473 }
b3cbe40f 474 break;
b3cbe40f 475
c1e24818
EA
476 case 'n': /* don't alias */
477 NoAlias = TRUE;
d59b067a
EA
478 break;
479
c1e24818 480 case 'o': /* set option */
8c8e8e94 481 setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv);
14a39063 482 break;
cbdb7357 483
b1e36c23 484 case 'p': /* set protocol */
b2d4b27a 485 q = strchr(optarg, ':');
af04f6e4
EA
486 if (q != NULL)
487 *q++ = '\0';
b2d4b27a
KB
488 if (*optarg != '\0')
489 define('r', newstr(optarg), CurEnv);
5d41b806 490 if (q != NULL && *q != '\0')
af04f6e4 491 define('s', newstr(q), CurEnv);
b1e36c23
EA
492 break;
493
ed45aae1 494 case 'q': /* run queue files at intervals */
884a20cb 495# ifdef QUEUE
908dc8db 496 (void) unsetenv("HOSTALIASES");
d0a69620 497 FullName = NULL;
aba51985 498 queuemode = TRUE;
d6c28d1a
EA
499 switch (optarg[0])
500 {
501 case 'I':
502 QueueLimitId = newstr(&optarg[1]);
503 break;
504
505 case 'R':
506 QueueLimitRecipient = newstr(&optarg[1]);
507 break;
508
509 case 'S':
510 QueueLimitSender = newstr(&optarg[1]);
511 break;
512
513 default:
1d136a1f 514 QueueIntvl = convtime(optarg, 'm');
d6c28d1a
EA
515 break;
516 }
f3d8f6d6 517# else /* QUEUE */
2e15a2d8
MK
518 usrerr("I don't know about queues");
519 ExitStat = EX_USAGE;
f3d8f6d6 520# endif /* QUEUE */
ed45aae1
EA
521 break;
522
c1e24818
EA
523 case 't': /* read recipients from message */
524 GrabTo = TRUE;
525 break;
526
527 /* compatibility flags */
c1e24818 528 case 'c': /* connect to non-local mailers */
c1e24818
EA
529 case 'i': /* don't let dot stop me */
530 case 'm': /* send to me too */
531 case 'T': /* set timeout interval */
532 case 'v': /* give blow-by-blow description */
8c8e8e94 533 setoption(j, "T", FALSE, TRUE, CurEnv);
35cc3fad
EA
534 break;
535
5b80e275 536 case 'e': /* error message disposition */
8c8e8e94 537 setoption(j, optarg, FALSE, TRUE, CurEnv);
5b80e275
EA
538 break;
539
c1e24818 540 case 's': /* save From lines in headers */
8c8e8e94 541 setoption('f', "T", FALSE, TRUE, CurEnv);
b3cbe40f 542 break;
26a3626c
EA
543
544# ifdef DBM
545 case 'I': /* initialize alias DBM file */
75f95954 546 OpMode = MD_INITALIAS;
26a3626c 547 break;
ce46a48a
EA
548# endif /* DBM */
549
94bc039a 550# ifdef __osf__
97030b8b
EA
551 case 'x': /* random flag that DEC OSF/1 mailx passes */
552 break;
553# endif
554
b2d4b27a
KB
555 default:
556 ExitStat = EX_USAGE;
557 finis();
ce46a48a 558 break;
b3cbe40f 559 }
f96fa7de 560 }
b2d4b27a 561 av += optind;
b3cbe40f 562
836a1487 563#ifdef NAMED_BIND
322eceee 564 if (tTd(8, 8))
836a1487
EA
565 _res.options |= RES_DEBUG;
566#endif
567
9e3c0a28 568 /*
2cce0c26
EA
569 ** Do basic initialization.
570 ** Read system control file.
179c1218 571 ** Extract special fields for local use.
9e3c0a28
EA
572 */
573
46f6ec52 574 if (OpMode == MD_FREEZE || readconfig)
a4076aed 575 readcf(ConfFile, safecf, CurEnv);
22659072 576
07c63e56 577#ifdef SYS5TZ
ca4d0c0b
EA
578 /* Enforce use of local time (null string overrides this) */
579 if (TimeZoneSpec == NULL)
580 unsetenv("TZ");
581 else if (TimeZoneSpec[0] != '\0')
582 {
583 p = xalloc(strlen(TimeZoneSpec) + 4);
584 (void) strcpy(p, "TZ=");
585 (void) strcat(p, TimeZoneSpec);
586 putenv(p);
587 }
588#endif
589
2281a453
EA
590 if (ConfigLevel > MAXCONFIGLEVEL)
591 {
592 syserr("Warning: .cf version level (%d) exceeds program functionality (%d)",
593 ConfigLevel, MAXCONFIGLEVEL);
594 }
322eceee
EA
595# ifdef QUEUE
596 if (queuemode && getuid() != 0)
597 {
598 struct stat stbuf;
599
600 /* check to see if we own the queue directory */
601 if (stat(QueueDir, &stbuf) < 0)
602 syserr("main: cannot stat %s", QueueDir);
603 if (stbuf.st_uid != getuid())
604 {
605 /* nope, really a botch */
606 usrerr("Permission denied");
607 exit (EX_NOPERM);
608 }
609 }
610# endif /* QUEUE */
3fb35974 611
75f95954 612 switch (OpMode)
acae5a9d 613 {
ca708b8e 614# ifdef FROZENCONFIG
26a3626c 615 case MD_FREEZE:
a9621daf 616 /* this is critical to avoid forgeries of the frozen config */
0e306e7f
EA
617 (void) setgid(getgid());
618 (void) setuid(getuid());
a9621daf
EA
619
620 /* freeze the configuration */
8fe4fb9b 621 freeze(FreezeFile);
acae5a9d 622 exit(EX_OK);
ca708b8e 623# endif
26a3626c
EA
624
625 case MD_INITALIAS:
626 Verbose = TRUE;
627 break;
13dfebea
EA
628
629 case MD_DAEMON:
630 /* remove things that don't make sense in daemon mode */
631 FullName = NULL;
632 break;
3fb35974 633
94bc039a
EA
634 case MD_SMTP:
635 if (RealUid != 0)
636 auth_warning(CurEnv,
637 "%s owned process doing -bs",
638 realuser);
639 break;
640 }
3fb35974 641
6130649c
EA
642 /* do heuristic mode adjustment */
643 if (Verbose)
75f95954
EA
644 {
645 /* turn off noconnect option */
8c8e8e94 646 setoption('c', "F", TRUE, FALSE, CurEnv);
75f95954
EA
647
648 /* turn on interactive delivery */
8c8e8e94 649 setoption('d', "", TRUE, FALSE, CurEnv);
75f95954 650 }
6130649c 651
179c1218 652 /* our name for SMTP codes */
63323725 653 expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
57c97d4a 654 MyHostName = jbuf;
d6a28dd8 655
98e5062b 656 /* the indices of built-in mailers */
179c1218
EA
657 st = stab("local", ST_MAILER, ST_FIND);
658 if (st == NULL)
659 syserr("No local mailer defined");
660 else
661 LocalMailer = st->s_mailer;
98e5062b 662
179c1218
EA
663 st = stab("prog", ST_MAILER, ST_FIND);
664 if (st == NULL)
665 syserr("No prog mailer defined");
666 else
667 ProgMailer = st->s_mailer;
668
98e5062b
EA
669 st = stab("*file*", ST_MAILER, ST_FIND);
670 if (st == NULL)
671 syserr("No *file* mailer defined");
672 else
673 FileMailer = st->s_mailer;
674
675 st = stab("*include*", ST_MAILER, ST_FIND);
676 if (st == NULL)
677 syserr("No *include* mailer defined");
678 else
679 InclMailer = st->s_mailer;
680
681
6bbaf971
EA
682 /* operate in queue directory */
683 if (chdir(QueueDir) < 0)
684 {
685 syserr("cannot chdir(%s)", QueueDir);
686 exit(EX_SOFTWARE);
687 }
688
876fc43b
EA
689 /* if we've had errors so far, exit now */
690 if (ExitStat != EX_OK)
691 exit(ExitStat);
692
64912e7e 693 /*
55f0da62 694 ** Do operation-mode-dependent initialization.
64912e7e
EA
695 */
696
55f0da62 697 switch (OpMode)
64912e7e 698 {
55f0da62
EA
699 case MD_PRINT:
700 /* print the queue */
74f37936 701#ifdef QUEUE
64912e7e
EA
702 dropenvelope(CurEnv);
703 printqueue();
704 exit(EX_OK);
f3d8f6d6 705#else /* QUEUE */
74f37936
EA
706 usrerr("No queue to print");
707 finis();
f3d8f6d6 708#endif /* QUEUE */
8acb5142 709
55f0da62
EA
710 case MD_INITALIAS:
711 /* initialize alias database */
a4076aed 712 initaliases(AliasFile, TRUE, CurEnv);
f4dbf345 713 exit(EX_OK);
cdb17311 714
55f0da62
EA
715 case MD_DAEMON:
716 /* don't open alias database -- done in srvrsmtp */
717 break;
718
719 default:
720 /* open the alias database */
a4076aed 721 initaliases(AliasFile, FALSE, CurEnv);
55f0da62
EA
722 break;
723 }
724
9678c96d 725 if (tTd(0, 15))
9c6d4c70 726 {
f6a0cc15 727 /* print configuration table (or at least part of it) */
9c6d4c70
EA
728 printrules();
729 for (i = 0; i < MAXMAILERS; i++)
730 {
731 register struct mailer *m = Mailer[i];
1dbda134 732 int j;
9c6d4c70
EA
733
734 if (m == NULL)
735 continue;
68f7099c
EA
736 printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i, m->m_name,
737 m->m_mailer, m->m_se_rwset, m->m_sh_rwset,
738 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize);
1dbda134
EA
739 for (j = '\0'; j <= '\177'; j++)
740 if (bitnset(j, m->m_flags))
0e306e7f 741 (void) putchar(j);
1dbda134 742 printf(" E=");
b3ef02a2 743 xputs(m->m_eol);
72f91c2e
EA
744 if (m->m_argv != NULL)
745 {
746 char **a = m->m_argv;
747
748 printf(" A=");
749 while (*a != NULL)
750 {
751 if (a != m->m_argv)
752 printf(" ");
753 xputs(*a++);
754 }
755 }
b3ef02a2 756 printf("\n");
9c6d4c70
EA
757 }
758 }
9c6d4c70 759
be2fcca9
EA
760 /*
761 ** Switch to the main envelope.
762 */
763
fda58daa 764 CurEnv = newenvelope(&MainEnvelope, CurEnv);
e6f08ab1 765 MainEnvelope.e_flags = BlankEnvelope.e_flags;
be2fcca9 766
cf69a203
EA
767 /*
768 ** If test mode, read addresses from stdin and process.
769 */
770
75f95954 771 if (OpMode == MD_TEST)
cf69a203
EA
772 {
773 char buf[MAXLINE];
774
6ae7224f
EA
775 if (isatty(fileno(stdin)))
776 Verbose = TRUE;
777
778 if (Verbose)
dab2b390
EA
779 {
780 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
781 printf("Enter <ruleset> <address>\n");
782 }
cf69a203
EA
783 for (;;)
784 {
785 register char **pvp;
50435450 786 char *q;
9e2cf26f 787 auto char *delimptr;
2ee7e9e0 788 extern bool invalidaddr();
cf69a203 789
6ae7224f 790 if (Verbose)
dab2b390 791 printf("> ");
0e306e7f 792 (void) fflush(stdout);
cf69a203
EA
793 if (fgets(buf, sizeof buf, stdin) == NULL)
794 finis();
6ae7224f 795 if (!Verbose)
dab2b390
EA
796 printf("> %s", buf);
797 if (buf[0] == '#')
798 continue;
2bee003d 799 for (p = buf; isascii(*p) && isspace(*p); p++)
cf69a203 800 continue;
ecfd2c8e 801 q = p;
2bee003d 802 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
ecfd2c8e 803 p++;
cf69a203 804 if (*p == '\0')
2ee7e9e0
EA
805 {
806 printf("No address!\n");
cf69a203 807 continue;
2ee7e9e0 808 }
50435450 809 *p = '\0';
2ee7e9e0 810 if (invalidaddr(p + 1))
2ee7e9e0 811 continue;
50435450 812 do
ecfd2c8e 813 {
217a0102
EA
814 extern char **prescan();
815 char pvpbuf[PSBUFSIZE];
816
9e2cf26f 817 pvp = prescan(++p, ',', pvpbuf, &delimptr);
50435450 818 if (pvp == NULL)
ecfd2c8e 819 continue;
50435450
EA
820 p = q;
821 while (*p != '\0')
822 {
823 rewrite(pvp, atoi(p));
824 while (*p != '\0' && *p++ != ',')
825 continue;
826 }
9e2cf26f 827 } while (*(p = delimptr) != '\0');
cf69a203
EA
828 }
829 }
830
e3cd595c
EA
831# ifdef QUEUE
832 /*
833 ** If collecting stuff from the queue, go start doing that.
834 */
835
7b21425b 836 if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
e3cd595c 837 {
ca4d0c0b 838 runqueue(FALSE);
e3cd595c
EA
839 finis();
840 }
f3d8f6d6 841# endif /* QUEUE */
e3cd595c 842
f6a0cc15
EA
843 /*
844 ** If a daemon, wait for a request.
845 ** getrequests will always return in a child.
25b9d645 846 ** If we should also be processing the queue, start
19147b2d
EA
847 ** doing it in background.
848 ** We check for any errors that might have happened
849 ** during startup.
f6a0cc15
EA
850 */
851
75f95954 852 if (OpMode == MD_DAEMON || QueueIntvl != 0)
25b9d645 853 {
d0421a85
EA
854 char dtype[200];
855
9678c96d 856 if (!tTd(0, 1))
58b27aa4 857 {
fcdf8200 858 /* put us in background */
58b27aa4
EA
859 i = fork();
860 if (i < 0)
861 syserr("daemon: cannot fork");
862 if (i != 0)
863 exit(0);
fcdf8200 864
fcdf8200 865 /* disconnect from our controlling tty */
58edf3ec 866 disconnect(TRUE, CurEnv);
58b27aa4 867 }
7338e3d4 868
d0421a85
EA
869 dtype[0] = '\0';
870 if (OpMode == MD_DAEMON)
871 strcat(dtype, "+SMTP");
872 if (QueueIntvl != 0)
873 {
874 extern char *pintvl();
875
876 strcat(dtype, "+queueing@");
877 strcat(dtype, pintvl(QueueIntvl, TRUE));
878 }
879 if (tTd(0, 1))
880 strcat(dtype, "+debugging");
881
6d791734 882 syslog(LOG_INFO, "starting daemon: %s", dtype + 1);
d0421a85 883
25b9d645
EA
884# ifdef QUEUE
885 if (queuemode)
f309127e 886 {
ca4d0c0b 887 runqueue(TRUE);
75f95954 888 if (OpMode != MD_DAEMON)
f309127e
EA
889 for (;;)
890 pause();
891 }
f3d8f6d6 892# endif /* QUEUE */
7338e3d4
EA
893 dropenvelope(CurEnv);
894
895#ifdef DAEMON
f6a0cc15 896 getrequests();
2a16bae3
EA
897
898 /* at this point we are in a child: reset state */
75f95954 899 OpMode = MD_SMTP;
fda58daa 900 (void) newenvelope(CurEnv, CurEnv);
f3d8f6d6 901#endif /* DAEMON */
7338e3d4 902 }
88039044
EA
903
904# ifdef SMTP
905 /*
906 ** If running SMTP protocol, start collecting and executing
907 ** commands. This will never return.
908 */
909
75f95954 910 if (OpMode == MD_SMTP)
a4076aed 911 smtp(CurEnv);
f3d8f6d6 912# endif /* SMTP */
88039044 913
f6a0cc15 914 /*
e6f08ab1 915 ** Do basic system initialization and set the sender
f6a0cc15
EA
916 */
917
f8a31c8e 918# ifndef SYSTEM5
6f910017
EA
919 /* make sendmail immune from process group signals */
920 (void) setpgrp(0, getpid());
f8a31c8e 921# endif
6f910017 922
a4076aed 923 initsys(CurEnv);
4a2da288 924 setsender(from, CurEnv, NULL, FALSE);
a9e0e597 925
0e1aa71e 926 if (*av == NULL && !GrabTo)
e863b1fa 927 {
2e3062fe
EA
928 usrerr("Recipient names must be specified");
929
930 /* collect body for UUCP return */
931 if (OpMode != MD_VERIFY)
a4076aed 932 collect(FALSE, CurEnv);
e863b1fa
EA
933 finis();
934 }
75f95954 935 if (OpMode == MD_VERIFY)
8c8e8e94 936 CurEnv->e_sendmode = SM_VERIFY;
b3cbe40f 937
b3cbe40f 938 /*
d6b27179 939 ** Scan argv and deliver the message to everyone.
b3cbe40f
EA
940 */
941
a4076aed 942 sendtoargv(av, CurEnv);
b3cbe40f 943
72e9b3cc 944 /* if we have had errors sofar, arrange a meaningful exit stat */
d916f0ca 945 if (Errors > 0 && ExitStat == EX_OK)
a4b004a6 946 ExitStat = EX_USAGE;
a4b004a6 947
dc39c568
EA
948 /*
949 ** Read the input mail.
950 */
951
2654b031 952 CurEnv->e_to = NULL;
75f95954 953 if (OpMode != MD_VERIFY || GrabTo)
a4076aed 954 collect(FALSE, CurEnv);
d829793b 955 errno = 0;
35cc3fad 956
4e1f4d4b 957 /* collect statistics */
7338e3d4
EA
958 if (OpMode != MD_VERIFY)
959 markstats(CurEnv, (ADDRESS *) NULL);
b3cbe40f 960
9678c96d 961 if (tTd(1, 1))
2654b031 962 printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
d6b27179 963
b3cbe40f
EA
964 /*
965 ** Actually send everything.
d6b27179 966 ** If verifying, just ack.
b3cbe40f
EA
967 */
968
7338e3d4 969 CurEnv->e_from.q_flags |= QDONTSEND;
78bbbc48
EA
970 if (tTd(1, 5))
971 {
972 printf("main: QDONTSEND ");
973 printaddr(&CurEnv->e_from, FALSE);
974 }
7338e3d4 975 CurEnv->e_to = NULL;
f7e74083 976 sendall(CurEnv, SM_DEFAULT);
b3cbe40f
EA
977
978 /*
979 ** All done.
980 */
981
982 finis();
983}
984\f/*
985** FINIS -- Clean up and exit.
986**
b3cbe40f
EA
987** Parameters:
988** none
989**
990** Returns:
991** never
992**
993** Side Effects:
96faada8 994** exits sendmail
b3cbe40f
EA
995*/
996
997finis()
998{
9678c96d 999 if (tTd(2, 1))
e6f08ab1 1000 printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
aba51985 1001
7338e3d4 1002 /* clean up temp files */
912acb74 1003 CurEnv->e_to = NULL;
e6f08ab1 1004 dropenvelope(CurEnv);
b3cbe40f 1005
f2e44ded 1006 /* flush any cached connections */
1c7897ef 1007 mci_flush(TRUE, NULL);
f2e44ded 1008
7338e3d4
EA
1009 /* post statistics */
1010 poststats(StatFile);
68f0b54c 1011
7338e3d4 1012 /* and exit */
36a4e219 1013# ifdef LOG
68f7099c 1014 if (LogLevel > 78)
36a4e219 1015 syslog(LOG_DEBUG, "finis, pid=%d", getpid());
f3d8f6d6 1016# endif /* LOG */
c8ec8736
EA
1017 if (ExitStat == EX_TEMPFAIL)
1018 ExitStat = EX_OK;
b3cbe40f
EA
1019 exit(ExitStat);
1020}
1021\f/*
6e2f38be
EA
1022** INTSIG -- clean up on interrupt
1023**
7338e3d4
EA
1024** This just arranges to exit. It pessimises in that it
1025** may resend a message.
6e2f38be
EA
1026**
1027** Parameters:
1028** none.
1029**
1030** Returns:
1031** none.
1032**
1033** Side Effects:
7338e3d4 1034** Unlocks the current job.
6e2f38be
EA
1035*/
1036
0df908a9 1037void
6e2f38be
EA
1038intsig()
1039{
7338e3d4
EA
1040 FileName = NULL;
1041 unlockqueue(CurEnv);
1042 exit(EX_OK);
6e2f38be
EA
1043}
1044\f/*
721fad23
EA
1045** INITMACROS -- initialize the macro system
1046**
1047** This just involves defining some macros that are actually
1048** used internally as metasymbols to be themselves.
1049**
1050** Parameters:
1051** none.
1052**
1053** Returns:
1054** none.
1055**
1056** Side Effects:
1057** initializes several macros to be themselves.
1058*/
1059
9dbc8d99
EA
1060struct metamac MetaMacros[] =
1061{
eca244ca 1062 /* LHS pattern matching characters */
42fa5d67
EA
1063 '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE,
1064 '=', MATCHCLASS, '~', MATCHNCLASS,
721fad23
EA
1065
1066 /* these are RHS metasymbols */
42fa5d67
EA
1067 '#', CANONNET, '@', CANONHOST, ':', CANONUSER,
1068 '>', CALLSUBR,
41173b8f 1069 '{', MATCHLOOKUP, '}', MATCHELOOKUP,
721fad23 1070
eca244ca 1071 /* the conditional operations */
42fa5d67 1072 '?', CONDIF, '|', CONDELSE, '.', CONDFI,
9dbc8d99 1073
eca244ca 1074 /* and finally the hostname lookup characters */
42fa5d67
EA
1075 '[', HOSTBEGIN, ']', HOSTEND,
1076 '(', LOOKUPBEGIN, ')', LOOKUPEND,
eca244ca 1077
9dbc8d99 1078 '\0'
721fad23
EA
1079};
1080
1081initmacros()
1082{
9dbc8d99
EA
1083 register struct metamac *m;
1084 char buf[5];
1085 register int c;
721fad23 1086
9dbc8d99
EA
1087 for (m = MetaMacros; m->metaname != '\0'; m++)
1088 {
1089 buf[0] = m->metaval;
1090 buf[1] = '\0';
7338e3d4 1091 define(m->metaname, newstr(buf), CurEnv);
9dbc8d99
EA
1092 }
1093 buf[0] = MATCHREPL;
1094 buf[2] = '\0';
1095 for (c = '0'; c <= '9'; c++)
1096 {
1097 buf[1] = c;
7338e3d4 1098 define(c, newstr(buf), CurEnv);
9dbc8d99 1099 }
721fad23 1100}
dd1fe05b 1101\f/*
acae5a9d
EA
1102** FREEZE -- freeze BSS & allocated memory
1103**
1104** This will be used to efficiently load the configuration file.
1105**
1106** Parameters:
8fe4fb9b 1107** freezefile -- the name of the file to freeze to.
acae5a9d
EA
1108**
1109** Returns:
1110** none.
1111**
1112** Side Effects:
8fe4fb9b 1113** Writes BSS and malloc'ed memory to freezefile
acae5a9d
EA
1114*/
1115
ca708b8e
EA
1116# ifdef FROZENCONFIG
1117
7338e3d4 1118union frz
acae5a9d 1119{
7338e3d4
EA
1120 char frzpad[BUFSIZ]; /* insure we are on a BUFSIZ boundary */
1121 struct
1122 {
1123 time_t frzstamp; /* timestamp on this freeze */
1124 char *frzbrk; /* the current break */
2e3062fe
EA
1125 char *frzedata; /* address of edata */
1126 char *frzend; /* address of end */
7338e3d4
EA
1127 char frzver[252]; /* sendmail version */
1128 } frzinfo;
acae5a9d
EA
1129};
1130
97030b8b 1131#if defined(__hpux) || defined(__alpha)
aa102c71
EA
1132#define BRK_TYPE int
1133#define SBRK_TYPE void *
1134#else
1135#define BRK_TYPE char *
1136#define SBRK_TYPE char *
1137#endif
1138
8fe4fb9b
EA
1139freeze(freezefile)
1140 char *freezefile;
acae5a9d
EA
1141{
1142 int f;
7338e3d4 1143 union frz fhdr;
aa102c71 1144 extern SBRK_TYPE sbrk();
2e3062fe 1145 extern char edata, end;
912acb74 1146 extern char Version[];
acae5a9d 1147
8fe4fb9b 1148 if (freezefile == NULL)
acae5a9d
EA
1149 return;
1150
1151 /* try to open the freeze file */
8fe4fb9b 1152 f = creat(freezefile, FileMode);
acae5a9d
EA
1153 if (f < 0)
1154 {
2e15a2d8 1155 syserr("Cannot freeze %s", freezefile);
acae5a9d
EA
1156 errno = 0;
1157 return;
1158 }
1159
1160 /* build the freeze header */
7338e3d4
EA
1161 fhdr.frzinfo.frzstamp = curtime();
1162 fhdr.frzinfo.frzbrk = sbrk(0);
2e3062fe
EA
1163 fhdr.frzinfo.frzedata = &edata;
1164 fhdr.frzinfo.frzend = &end;
0e306e7f 1165 (void) strcpy(fhdr.frzinfo.frzver, Version);
acae5a9d
EA
1166
1167 /* write out the freeze header */
611b763d 1168 if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
34fe0a9b
EA
1169 write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
1170 (int) (fhdr.frzinfo.frzbrk - &edata))
7338e3d4 1171 {
2e15a2d8 1172 syserr("Cannot freeze %s", freezefile);
7338e3d4 1173 }
acae5a9d
EA
1174
1175 /* fine, clean up */
1176 (void) close(f);
1177}
1178\f/*
1179** THAW -- read in the frozen configuration file.
1180**
1181** Parameters:
8fe4fb9b 1182** freezefile -- the name of the file to thaw from.
4b26318e 1183** binfile -- the name of the sendmail binary (ok to guess).
acae5a9d
EA
1184**
1185** Returns:
1186** TRUE if it successfully read the freeze file.
1187** FALSE otherwise.
1188**
1189** Side Effects:
8fe4fb9b 1190** reads freezefile in to BSS area.
acae5a9d
EA
1191*/
1192
4b26318e 1193thaw(freezefile, binfile)
8fe4fb9b 1194 char *freezefile;
4b26318e 1195 char *binfile;
acae5a9d
EA
1196{
1197 int f;
ccfed53c 1198 register char *p;
7338e3d4 1199 union frz fhdr;
ccfed53c 1200 char hbuf[60];
4b26318e 1201 struct stat fst, sst;
a59237a4 1202 extern char edata, end;
912acb74 1203 extern char Version[];
ccfed53c
EA
1204 extern char **myhostname();
1205 extern char *macvalue();
aa102c71 1206 extern BRK_TYPE brk();
acae5a9d 1207
8fe4fb9b 1208 if (freezefile == NULL)
acae5a9d
EA
1209 return (FALSE);
1210
1211 /* open the freeze file */
8fe4fb9b 1212 f = open(freezefile, 0);
acae5a9d
EA
1213 if (f < 0)
1214 {
1215 errno = 0;
1216 return (FALSE);
1217 }
1218
4b26318e
EA
1219 if (fstat(f, &fst) < 0 || stat(ConfFile, &sst) < 0 ||
1220 fst.st_mtime < sst.st_mtime)
1221 {
1222 syslog(LOG_WARNING, "Freeze file older than config file");
1223 (void) close(f);
1224 return (FALSE);
1225 }
1226
1227 if (strchr(binfile, '/') != NULL && stat(binfile, &sst) == 0 &&
1228 fst.st_mtime < sst.st_mtime)
1229 {
1230 syslog(LOG_WARNING, "Freeze file older than binary file");
1231 (void) close(f);
1232 return (FALSE);
1233 }
1234
acae5a9d 1235 /* read in the header */
07adc4f5
RA
1236 if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr)
1237 {
db281fbf 1238 syslog(LOG_WARNING, "Cannot read frozen config file");
07adc4f5
RA
1239 (void) close(f);
1240 return (FALSE);
1241 }
db281fbf 1242 if (fhdr.frzinfo.frzedata != &edata ||
2e3062fe 1243 fhdr.frzinfo.frzend != &end ||
7338e3d4 1244 strcmp(fhdr.frzinfo.frzver, Version) != 0)
acae5a9d 1245 {
1d136a1f 1246 fprintf(stderr, "Wrong version of frozen config file\n");
07adc4f5 1247 syslog(LOG_WARNING, "Wrong version of frozen config file");
acae5a9d
EA
1248 (void) close(f);
1249 return (FALSE);
1250 }
1251
1252 /* arrange to have enough space */
97030b8b 1253 if (brk(fhdr.frzinfo.frzbrk) == (BRK_TYPE) -1)
acae5a9d 1254 {
7338e3d4 1255 syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
acae5a9d
EA
1256 (void) close(f);
1257 return (FALSE);
1258 }
1259
1260 /* now read in the freeze file */
34fe0a9b
EA
1261 if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - &edata)) !=
1262 (int) (fhdr.frzinfo.frzbrk - &edata))
acae5a9d 1263 {
07adc4f5 1264 syserr("Cannot read frozen config file");
acae5a9d 1265 /* oops! we have trashed memory..... */
0e306e7f 1266 (void) write(2, "Cannot read freeze file\n", 24);
7338e3d4 1267 _exit(EX_SOFTWARE);
acae5a9d
EA
1268 }
1269
1270 (void) close(f);
ccfed53c
EA
1271
1272 /* verify that the host name was correct on the freeze */
1273 (void) myhostname(hbuf, sizeof hbuf);
1274 p = macvalue('w', CurEnv);
1275 if (p == NULL)
1276 p = "";
1277 if (strcmp(hbuf, macvalue('w', CurEnv)) == 0)
1278 return (TRUE);
1279 syslog(LOG_WARNING, "Hostname changed since freeze (%s => %s)",
1280 p, hbuf);
1281 return (FALSE);
acae5a9d 1282}
ca708b8e
EA
1283
1284# endif /* FROZENCONFIG */
813d8709
EA
1285\f/*
1286** DISCONNECT -- remove our connection with any foreground process
1287**
1288** Parameters:
d188728a
EA
1289** fulldrop -- if set, we should also drop the controlling
1290** TTY if possible -- this should only be done when
1291** setting up the daemon since otherwise UUCP can
1292** leave us trying to open a dialin, and we will
1293** wait for the carrier.
813d8709
EA
1294**
1295** Returns:
1296** none
1297**
1298** Side Effects:
1299** Trys to insure that we are immune to vagaries of
1300** the controlling tty.
1301*/
1302
58edf3ec 1303disconnect(fulldrop, e)
d188728a 1304 bool fulldrop;
58edf3ec 1305 register ENVELOPE *e;
813d8709
EA
1306{
1307 int fd;
1308
e6f08ab1 1309 if (tTd(52, 1))
58edf3ec
EA
1310 printf("disconnect: In %d Out %d, e=%x\n",
1311 fileno(InChannel), fileno(OutChannel), e);
e6f08ab1 1312 if (tTd(52, 5))
813d8709 1313 {
e6f08ab1
EA
1314 printf("don't\n");
1315 return;
813d8709 1316 }
813d8709
EA
1317
1318 /* be sure we don't get nasty signals */
0e306e7f
EA
1319 (void) signal(SIGHUP, SIG_IGN);
1320 (void) signal(SIGINT, SIG_IGN);
1321 (void) signal(SIGQUIT, SIG_IGN);
813d8709
EA
1322
1323 /* we can't communicate with our caller, so.... */
7338e3d4 1324 HoldErrs = TRUE;
8c8e8e94 1325 CurEnv->e_errormode = EM_MAIL;
813d8709
EA
1326 Verbose = FALSE;
1327
1328 /* all input from /dev/null */
813d8709 1329 if (InChannel != stdin)
b9accadd
EA
1330 {
1331 (void) fclose(InChannel);
1332 InChannel = stdin;
1333 }
1334 (void) freopen("/dev/null", "r", stdin);
813d8709
EA
1335
1336 /* output to the transcript */
b9accadd 1337 if (OutChannel != stdout)
813d8709 1338 {
b9accadd
EA
1339 (void) fclose(OutChannel);
1340 OutChannel = stdout;
813d8709 1341 }
58edf3ec
EA
1342 if (e->e_xfp == NULL)
1343 fd = open("/dev/null", O_WRONLY, 0666);
1344 else
1345 fd = fileno(e->e_xfp);
b9accadd 1346 (void) fflush(stdout);
58edf3ec
EA
1347 dup2(fd, STDOUT_FILENO);
1348 dup2(fd, STDERR_FILENO);
1349 if (e->e_xfp == NULL)
1350 close(fd);
813d8709 1351
e6f08ab1 1352 /* drop our controlling TTY completely if possible */
d188728a 1353 if (fulldrop)
e6f08ab1 1354 {
6feb509e
EA
1355#ifdef SYSTEM5
1356 (void) setpgrp();
1357#else
5229f34d 1358 (void) setsid();
6feb509e 1359#endif
afe907a4 1360#ifdef TIOCNOTTY
d188728a
EA
1361 fd = open("/dev/tty", 2);
1362 if (fd >= 0)
1363 {
17a67c62 1364 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
d188728a
EA
1365 (void) close(fd);
1366 }
17a67c62 1367 (void) setpgrp(0, 0);
afe907a4 1368#endif /* TIOCNOTTY */
70faa7c8 1369 errno = 0;
e6f08ab1 1370 }
e6f08ab1 1371
813d8709 1372# ifdef LOG
68f7099c 1373 if (LogLevel > 71)
813d8709 1374 syslog(LOG_DEBUG, "in background, pid=%d", getpid());
f3d8f6d6 1375# endif /* LOG */
813d8709
EA
1376
1377 errno = 0;
1378}
b2d4b27a
KB
1379
1380static void
1381obsolete(argv)
1382 char *argv[];
1383{
1384 char *ap;
1385
1386 while (ap = *++argv)
1387 {
1388 /* Return if "--" or not an option of any form. */
1389 if (ap[0] != '-' || ap[1] == '-')
1390 return;
1391
1392 /* If -C doesn't have an argument, use sendmail.cf. */
1393#define __DEFPATH "sendmail.cf"
f96fa7de
EA
1394 if (ap[1] == 'C' && ap[2] == '\0' &&
1395 (argv[1] == NULL || argv[1][0] == '-'))
b2d4b27a
KB
1396 {
1397 *argv = xalloc(sizeof(__DEFPATH) + 2);
1398 argv[0][0] = '-';
1399 argv[0][1] = 'C';
1400 (void)strcpy(&argv[0][2], __DEFPATH);
1401 }
f96fa7de
EA
1402
1403 /* If -q doesn't have an argument, run it once. */
1404 if (ap[1] == 'q' && ap[2] == '\0' &&
1405 (argv[1] == NULL || argv[1][0] == '-'))
1406 *argv = "-q0";
a0431b8d
EA
1407
1408 /* if -d doesn't have an argument, use 0-99.1 */
1409 if (ap[1] == 'd' && ap[2] == '\0' &&
1410 (argv[1] == NULL || argv[1][0] == '-'))
1411 *argv = "-d0-99.1";
b2d4b27a
KB
1412 }
1413}
94bc039a
EA
1414\f/*
1415** AUTH_WARNING -- specify authorization warning
1416**
1417** Parameters:
1418** e -- the current envelope.
1419** msg -- the text of the message.
1420** args -- arguments to the message.
1421**
1422** Returns:
1423** none.
1424*/
1425
94bc039a 1426void
319b1ec0 1427#ifdef __STDC__
94bc039a
EA
1428auth_warning(register ENVELOPE *e, char *msg, ...)
1429#else
1430auth_warning(e, msg, va_alist)
1431 register ENVELOPE *e;
1432 char *msg;
1433 va_dcl
1434#endif
1435{
1436 char buf[MAXLINE];
1437 VA_LOCAL_DECL
1438
1439 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
1440 {
1441 register char *p;
1442 static char hostbuf[48];
1443 extern char **myhostname();
1444
1445 if (hostbuf[0] == '\0')
1446 (void) myhostname(hostbuf, sizeof hostbuf);
1447
1448 (void) sprintf(buf, "from %s: ", hostbuf);
1449 p = &buf[strlen(buf)];
1450 VA_START(msg);
1451 vsprintf(p, msg, ap);
1452 VA_END;
1453 addheader("x-authentication-warning", buf, e);
1454 }
1455}