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