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