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