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