more cleanup for DSN drafts
[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
66d16835 16static char sccsid[] = "@(#)main.c 8.93 (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) */
66d16835
EA
891 if (tTd(0, 90))
892 printrules();
9c6d4c70
EA
893 for (i = 0; i < MAXMAILERS; i++)
894 {
66d16835
EA
895 if (Mailer[i] != NULL)
896 printmailer(Mailer[i]);
9c6d4c70
EA
897 }
898 }
9c6d4c70 899
be2fcca9
EA
900 /*
901 ** Switch to the main envelope.
902 */
903
fda58daa 904 CurEnv = newenvelope(&MainEnvelope, CurEnv);
e6f08ab1 905 MainEnvelope.e_flags = BlankEnvelope.e_flags;
be2fcca9 906
cf69a203
EA
907 /*
908 ** If test mode, read addresses from stdin and process.
909 */
910
75f95954 911 if (OpMode == MD_TEST)
cf69a203
EA
912 {
913 char buf[MAXLINE];
914
6ae7224f
EA
915 if (isatty(fileno(stdin)))
916 Verbose = TRUE;
917
918 if (Verbose)
dab2b390
EA
919 {
920 printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
921 printf("Enter <ruleset> <address>\n");
922 }
cf69a203
EA
923 for (;;)
924 {
925 register char **pvp;
50435450 926 char *q;
9e2cf26f 927 auto char *delimptr;
2ee7e9e0 928 extern bool invalidaddr();
b44813bc 929 extern char *crackaddr();
cf69a203 930
6ae7224f 931 if (Verbose)
dab2b390 932 printf("> ");
0e306e7f 933 (void) fflush(stdout);
cf69a203
EA
934 if (fgets(buf, sizeof buf, stdin) == NULL)
935 finis();
6ae7224f 936 if (!Verbose)
dab2b390 937 printf("> %s", buf);
b44813bc
EA
938 switch (buf[0])
939 {
940 case '#':
dab2b390 941 continue;
b44813bc 942
319564a1 943 case '?': /* try crackaddr */
b44813bc
EA
944 q = crackaddr(&buf[1]);
945 xputs(q);
946 printf("\n");
947 continue;
319564a1
EA
948
949 case '.': /* config-style settings */
950 switch (buf[1])
951 {
952 case 'D':
8a7ac87b 953 define(buf[2], newstr(&buf[3]), CurEnv);
319564a1
EA
954 break;
955
956 case 'C':
957 setclass(buf[2], &buf[3]);
958 break;
959
8a7ac87b
EA
960 case 'S': /* dump rule set */
961 {
962 int rs;
963 struct rewrite *rw;
7d330641
EA
964 char *cp;
965 STAB *s;
8a7ac87b 966
7d330641
EA
967 if ((cp = strchr(buf, '\n')) != NULL)
968 *cp = '\0';
969 if (cp == buf+2)
8a7ac87b 970 continue;
7d330641
EA
971 s = stab(buf+2, ST_RULESET, ST_FIND);
972 if (s == NULL)
973 {
974 if (!isdigit(buf[2]))
975 continue;
976 rs = atoi(buf+2);
977 }
978 else
979 rs = s->s_ruleset;
8a7ac87b
EA
980 if (rs < 0 || rs > MAXRWSETS)
981 continue;
982 if ((rw = RewriteRules[rs]) == NULL)
983 continue;
984 do
985 {
986 char **s;
987 putchar('R');
988 s = rw->r_lhs;
989 while (*s != NULL)
990 {
991 xputs(*s++);
992 putchar(' ');
993 }
994 putchar('\t');
995 putchar('\t');
996 s = rw->r_rhs;
997 while (*s != NULL)
998 {
999 xputs(*s++);
1000 putchar(' ');
1001 }
1002 putchar('\n');
1003 } while (rw = rw->r_next);
1004 }
1005 break;
1006
319564a1
EA
1007 default:
1008 printf("Unknown config command %s", buf);
1009 break;
8a7ac87b
EA
1010 }
1011 continue;
1012
1013 case '-': /* set command-line-like opts */
1014 switch (buf[1])
1015 {
1016 case 'd':
1017 if (buf[2] == '\n')
1018 tTflag("");
1019 else
1020 tTflag(&buf[2]);
1021 break;
1022
1023 default:
1024 printf("Unknown \"-\" command %s", buf);
1025 break;
1026 }
1027 continue;
b44813bc
EA
1028 }
1029
2bee003d 1030 for (p = buf; isascii(*p) && isspace(*p); p++)
cf69a203 1031 continue;
ecfd2c8e 1032 q = p;
2bee003d 1033 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
ecfd2c8e 1034 p++;
cf69a203 1035 if (*p == '\0')
2ee7e9e0
EA
1036 {
1037 printf("No address!\n");
cf69a203 1038 continue;
2ee7e9e0 1039 }
50435450 1040 *p = '\0';
b44813bc 1041 if (invalidaddr(p + 1, NULL))
2ee7e9e0 1042 continue;
50435450 1043 do
ecfd2c8e 1044 {
217a0102
EA
1045 char pvpbuf[PSBUFSIZE];
1046
148ea694
EA
1047 pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf,
1048 &delimptr);
50435450 1049 if (pvp == NULL)
ecfd2c8e 1050 continue;
50435450
EA
1051 p = q;
1052 while (*p != '\0')
1053 {
d1db7a89
EA
1054 int stat;
1055
b141a9b6 1056 stat = rewrite(pvp, atoi(p), 0, CurEnv);
d1db7a89
EA
1057 if (stat != EX_OK)
1058 printf("== Ruleset %s status %d\n",
1059 p, stat);
50435450
EA
1060 while (*p != '\0' && *p++ != ',')
1061 continue;
1062 }
9e2cf26f 1063 } while (*(p = delimptr) != '\0');
cf69a203
EA
1064 }
1065 }
1066
e3cd595c
EA
1067# ifdef QUEUE
1068 /*
1069 ** If collecting stuff from the queue, go start doing that.
1070 */
1071
7b21425b 1072 if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
e3cd595c 1073 {
ca4d0c0b 1074 runqueue(FALSE);
e3cd595c
EA
1075 finis();
1076 }
f3d8f6d6 1077# endif /* QUEUE */
e3cd595c 1078
f6a0cc15
EA
1079 /*
1080 ** If a daemon, wait for a request.
1081 ** getrequests will always return in a child.
25b9d645 1082 ** If we should also be processing the queue, start
19147b2d
EA
1083 ** doing it in background.
1084 ** We check for any errors that might have happened
1085 ** during startup.
f6a0cc15
EA
1086 */
1087
75f95954 1088 if (OpMode == MD_DAEMON || QueueIntvl != 0)
25b9d645 1089 {
d0421a85
EA
1090 char dtype[200];
1091
9678c96d 1092 if (!tTd(0, 1))
58b27aa4 1093 {
fcdf8200 1094 /* put us in background */
58b27aa4
EA
1095 i = fork();
1096 if (i < 0)
1097 syserr("daemon: cannot fork");
1098 if (i != 0)
1099 exit(0);
fcdf8200 1100
fcdf8200 1101 /* disconnect from our controlling tty */
9bc46e51 1102 disconnect(2, CurEnv);
58b27aa4 1103 }
7338e3d4 1104
d0421a85
EA
1105 dtype[0] = '\0';
1106 if (OpMode == MD_DAEMON)
1107 strcat(dtype, "+SMTP");
1108 if (QueueIntvl != 0)
1109 {
d0421a85
EA
1110 strcat(dtype, "+queueing@");
1111 strcat(dtype, pintvl(QueueIntvl, TRUE));
1112 }
1113 if (tTd(0, 1))
1114 strcat(dtype, "+debugging");
1115
8b223875 1116#ifdef LOG
ae1d509e 1117 syslog(LOG_INFO, "starting daemon (%s): %s", Version, dtype + 1);
8b223875 1118#endif
b4f81c5d
EA
1119#ifdef XLA
1120 xla_create_file();
1121#endif
d0421a85 1122
25b9d645
EA
1123# ifdef QUEUE
1124 if (queuemode)
f309127e 1125 {
ca4d0c0b 1126 runqueue(TRUE);
75f95954 1127 if (OpMode != MD_DAEMON)
f309127e
EA
1128 for (;;)
1129 pause();
1130 }
f3d8f6d6 1131# endif /* QUEUE */
7338e3d4
EA
1132 dropenvelope(CurEnv);
1133
1134#ifdef DAEMON
f6a0cc15 1135 getrequests();
2a16bae3
EA
1136
1137 /* at this point we are in a child: reset state */
fda58daa 1138 (void) newenvelope(CurEnv, CurEnv);
3f03d7a7
EA
1139
1140 /*
1141 ** Get authentication data
1142 */
1143
1144 p = getauthinfo(fileno(InChannel));
1145 define('_', p, CurEnv);
1146
f3d8f6d6 1147#endif /* DAEMON */
7338e3d4 1148 }
88039044
EA
1149
1150# ifdef SMTP
1151 /*
1152 ** If running SMTP protocol, start collecting and executing
1153 ** commands. This will never return.
1154 */
1155
198d9e9c 1156 if (OpMode == MD_SMTP || OpMode == MD_DAEMON)
a4076aed 1157 smtp(CurEnv);
f3d8f6d6 1158# endif /* SMTP */
88039044 1159
6f26749b
EA
1160 if (OpMode == MD_VERIFY)
1161 {
1162 CurEnv->e_sendmode = SM_VERIFY;
1163 CurEnv->e_errormode = EM_QUIET;
1164 }
1165 else
1166 {
1167 /* interactive -- all errors are global */
281c6540 1168 CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER;
6f26749b
EA
1169 }
1170
f6a0cc15 1171 /*
e6f08ab1 1172 ** Do basic system initialization and set the sender
f6a0cc15
EA
1173 */
1174
a4076aed 1175 initsys(CurEnv);
4a2da288 1176 setsender(from, CurEnv, NULL, FALSE);
a9bac7a9
EA
1177 if (macvalue('s', CurEnv) == NULL)
1178 define('s', RealHostName, CurEnv);
a9e0e597 1179
0e1aa71e 1180 if (*av == NULL && !GrabTo)
e863b1fa 1181 {
9bc46e51 1182 CurEnv->e_flags |= EF_GLOBALERRS;
2e3062fe
EA
1183 usrerr("Recipient names must be specified");
1184
1185 /* collect body for UUCP return */
1186 if (OpMode != MD_VERIFY)
c23930c0 1187 collect(InChannel, FALSE, FALSE, NULL, CurEnv);
e863b1fa
EA
1188 finis();
1189 }
b3cbe40f 1190
b3cbe40f 1191 /*
d6b27179 1192 ** Scan argv and deliver the message to everyone.
b3cbe40f
EA
1193 */
1194
a4076aed 1195 sendtoargv(av, CurEnv);
b3cbe40f 1196
72e9b3cc 1197 /* if we have had errors sofar, arrange a meaningful exit stat */
d916f0ca 1198 if (Errors > 0 && ExitStat == EX_OK)
a4b004a6 1199 ExitStat = EX_USAGE;
a4b004a6 1200
dc39c568
EA
1201 /*
1202 ** Read the input mail.
1203 */
1204
2654b031 1205 CurEnv->e_to = NULL;
75f95954 1206 if (OpMode != MD_VERIFY || GrabTo)
9bc46e51
EA
1207 {
1208 CurEnv->e_flags |= EF_GLOBALERRS;
c23930c0 1209 collect(InChannel, FALSE, FALSE, NULL, CurEnv);
9bc46e51 1210 }
d829793b 1211 errno = 0;
35cc3fad 1212
9678c96d 1213 if (tTd(1, 1))
2654b031 1214 printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
d6b27179 1215
b3cbe40f
EA
1216 /*
1217 ** Actually send everything.
d6b27179 1218 ** If verifying, just ack.
b3cbe40f
EA
1219 */
1220
7338e3d4 1221 CurEnv->e_from.q_flags |= QDONTSEND;
78bbbc48
EA
1222 if (tTd(1, 5))
1223 {
1224 printf("main: QDONTSEND ");
1225 printaddr(&CurEnv->e_from, FALSE);
1226 }
7338e3d4 1227 CurEnv->e_to = NULL;
f7e74083 1228 sendall(CurEnv, SM_DEFAULT);
b3cbe40f
EA
1229
1230 /*
8ed24c99
EA
1231 ** All done.
1232 ** Don't send return error message if in VERIFY mode.
b3cbe40f
EA
1233 */
1234
1235 finis();
1236}
1237\f/*
1238** FINIS -- Clean up and exit.
1239**
b3cbe40f
EA
1240** Parameters:
1241** none
1242**
1243** Returns:
1244** never
1245**
1246** Side Effects:
96faada8 1247** exits sendmail
b3cbe40f
EA
1248*/
1249
ea07b2d2 1250void
b3cbe40f
EA
1251finis()
1252{
9678c96d 1253 if (tTd(2, 1))
297f3a15
EA
1254 {
1255 extern void printenvflags();
1256
1257 printf("\n====finis: stat %d e_id=%s e_flags=",
1258 ExitStat,
3c9561b8 1259 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id);
297f3a15
EA
1260 printenvflags(CurEnv);
1261 }
c56a2245
EA
1262 if (tTd(2, 9))
1263 printopenfds(FALSE);
aba51985 1264
7338e3d4 1265 /* clean up temp files */
912acb74 1266 CurEnv->e_to = NULL;
e6f08ab1 1267 dropenvelope(CurEnv);
b3cbe40f 1268
f2e44ded 1269 /* flush any cached connections */
1c7897ef 1270 mci_flush(TRUE, NULL);
f2e44ded 1271
b4f81c5d
EA
1272# ifdef XLA
1273 /* clean up extended load average stuff */
1274 xla_all_end();
1275# endif
1276
7338e3d4 1277 /* and exit */
36a4e219 1278# ifdef LOG
68f7099c 1279 if (LogLevel > 78)
36a4e219 1280 syslog(LOG_DEBUG, "finis, pid=%d", getpid());
f3d8f6d6 1281# endif /* LOG */
c8ec8736
EA
1282 if (ExitStat == EX_TEMPFAIL)
1283 ExitStat = EX_OK;
fd57f063
EA
1284
1285 /* reset uid for process accounting */
1286 setuid(RealUid);
1287
b3cbe40f
EA
1288 exit(ExitStat);
1289}
1290\f/*
6e2f38be
EA
1291** INTSIG -- clean up on interrupt
1292**
7338e3d4
EA
1293** This just arranges to exit. It pessimises in that it
1294** may resend a message.
6e2f38be
EA
1295**
1296** Parameters:
1297** none.
1298**
1299** Returns:
1300** none.
1301**
1302** Side Effects:
7338e3d4 1303** Unlocks the current job.
6e2f38be
EA
1304*/
1305
0df908a9 1306void
6e2f38be
EA
1307intsig()
1308{
7338e3d4
EA
1309 FileName = NULL;
1310 unlockqueue(CurEnv);
b4f81c5d
EA
1311#ifdef XLA
1312 xla_all_end();
1313#endif
fd57f063
EA
1314
1315 /* reset uid for process accounting */
1316 setuid(RealUid);
1317
7338e3d4 1318 exit(EX_OK);
6e2f38be
EA
1319}
1320\f/*
721fad23
EA
1321** INITMACROS -- initialize the macro system
1322**
1323** This just involves defining some macros that are actually
1324** used internally as metasymbols to be themselves.
1325**
1326** Parameters:
1327** none.
1328**
1329** Returns:
1330** none.
1331**
1332** Side Effects:
1333** initializes several macros to be themselves.
1334*/
1335
9dbc8d99
EA
1336struct metamac MetaMacros[] =
1337{
eca244ca 1338 /* LHS pattern matching characters */
42fa5d67
EA
1339 '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE,
1340 '=', MATCHCLASS, '~', MATCHNCLASS,
721fad23
EA
1341
1342 /* these are RHS metasymbols */
42fa5d67
EA
1343 '#', CANONNET, '@', CANONHOST, ':', CANONUSER,
1344 '>', CALLSUBR,
41173b8f 1345 '{', MATCHLOOKUP, '}', MATCHELOOKUP,
721fad23 1346
eca244ca 1347 /* the conditional operations */
42fa5d67 1348 '?', CONDIF, '|', CONDELSE, '.', CONDFI,
9dbc8d99 1349
1ac3479f 1350 /* the hostname lookup characters */
42fa5d67
EA
1351 '[', HOSTBEGIN, ']', HOSTEND,
1352 '(', LOOKUPBEGIN, ')', LOOKUPEND,
eca244ca 1353
1ac3479f
EA
1354 /* miscellaneous control characters */
1355 '&', MACRODEXPAND,
1356
9dbc8d99 1357 '\0'
721fad23
EA
1358};
1359
72d3092a
EA
1360initmacros(e)
1361 register ENVELOPE *e;
721fad23 1362{
9dbc8d99
EA
1363 register struct metamac *m;
1364 char buf[5];
1365 register int c;
721fad23 1366
9dbc8d99
EA
1367 for (m = MetaMacros; m->metaname != '\0'; m++)
1368 {
1369 buf[0] = m->metaval;
1370 buf[1] = '\0';
72d3092a 1371 define(m->metaname, newstr(buf), e);
9dbc8d99
EA
1372 }
1373 buf[0] = MATCHREPL;
1374 buf[2] = '\0';
1375 for (c = '0'; c <= '9'; c++)
1376 {
1377 buf[1] = c;
72d3092a 1378 define(c, newstr(buf), e);
9dbc8d99 1379 }
72d3092a
EA
1380
1381 /* set defaults for some macros sendmail will use later */
1382 define('e', "\201j Sendmail \201v ready at \201b", e);
1383 define('l', "From \201g \201d", e);
1384 define('n', "MAILER-DAEMON", e);
1385 define('o', ".:@[]", e);
1386 define('q', "<\201g>", e);
721fad23 1387}
dd1fe05b 1388\f/*
813d8709
EA
1389** DISCONNECT -- remove our connection with any foreground process
1390**
1391** Parameters:
9bc46e51
EA
1392** droplev -- how "deeply" we should drop the line.
1393** 0 -- ignore signals, mail back errors, make sure
1394** output goes to stdout.
1395** 1 -- also, make stdout go to transcript.
1396** 2 -- also, disconnect from controlling terminal
1397** (only for daemon mode).
1398** e -- the current envelope.
813d8709
EA
1399**
1400** Returns:
1401** none
1402**
1403** Side Effects:
1404** Trys to insure that we are immune to vagaries of
1405** the controlling tty.
1406*/
1407
9bc46e51
EA
1408disconnect(droplev, e)
1409 int droplev;
58edf3ec 1410 register ENVELOPE *e;
813d8709
EA
1411{
1412 int fd;
1413
e6f08ab1 1414 if (tTd(52, 1))
58edf3ec
EA
1415 printf("disconnect: In %d Out %d, e=%x\n",
1416 fileno(InChannel), fileno(OutChannel), e);
e6f08ab1 1417 if (tTd(52, 5))
813d8709 1418 {
e6f08ab1
EA
1419 printf("don't\n");
1420 return;
813d8709 1421 }
813d8709
EA
1422
1423 /* be sure we don't get nasty signals */
39270cfd
EA
1424 (void) setsignal(SIGINT, SIG_IGN);
1425 (void) setsignal(SIGQUIT, SIG_IGN);
813d8709
EA
1426
1427 /* we can't communicate with our caller, so.... */
7338e3d4 1428 HoldErrs = TRUE;
8c8e8e94 1429 CurEnv->e_errormode = EM_MAIL;
813d8709 1430 Verbose = FALSE;
33cbaada 1431 DisConnected = TRUE;
813d8709
EA
1432
1433 /* all input from /dev/null */
813d8709 1434 if (InChannel != stdin)
b9accadd
EA
1435 {
1436 (void) fclose(InChannel);
1437 InChannel = stdin;
1438 }
1439 (void) freopen("/dev/null", "r", stdin);
813d8709
EA
1440
1441 /* output to the transcript */
b9accadd 1442 if (OutChannel != stdout)
813d8709 1443 {
b9accadd
EA
1444 (void) fclose(OutChannel);
1445 OutChannel = stdout;
813d8709 1446 }
9bc46e51
EA
1447 if (droplev > 0)
1448 {
1449 if (e->e_xfp == NULL)
1450 fd = open("/dev/null", O_WRONLY, 0666);
1451 else
1452 fd = fileno(e->e_xfp);
1453 (void) fflush(stdout);
1454 dup2(fd, STDOUT_FILENO);
1455 dup2(fd, STDERR_FILENO);
1456 if (e->e_xfp == NULL)
1457 close(fd);
1458 }
813d8709 1459
e6f08ab1 1460 /* drop our controlling TTY completely if possible */
9bc46e51 1461 if (droplev > 1)
e6f08ab1 1462 {
5229f34d 1463 (void) setsid();
70faa7c8 1464 errno = 0;
e6f08ab1 1465 }
e6f08ab1 1466
061a3d08
EA
1467#ifdef XDEBUG
1468 checkfd012("disconnect");
1469#endif
1470
813d8709 1471# ifdef LOG
68f7099c 1472 if (LogLevel > 71)
813d8709 1473 syslog(LOG_DEBUG, "in background, pid=%d", getpid());
f3d8f6d6 1474# endif /* LOG */
813d8709
EA
1475
1476 errno = 0;
1477}
b2d4b27a
KB
1478
1479static void
1480obsolete(argv)
1481 char *argv[];
1482{
685eaca2
EA
1483 register char *ap;
1484 register char *op;
b2d4b27a 1485
a3934270 1486 while ((ap = *++argv) != NULL)
b2d4b27a
KB
1487 {
1488 /* Return if "--" or not an option of any form. */
1489 if (ap[0] != '-' || ap[1] == '-')
1490 return;
1491
685eaca2
EA
1492 /* skip over options that do have a value */
1493 op = strchr(OPTIONS, ap[1]);
1494 if (op != NULL && *++op == ':' && ap[2] == '\0' &&
be982eb2 1495 ap[1] != 'd' && argv[1] != NULL && argv[1][0] != '-')
685eaca2
EA
1496 {
1497 argv++;
1498 continue;
1499 }
1500
b2d4b27a
KB
1501 /* If -C doesn't have an argument, use sendmail.cf. */
1502#define __DEFPATH "sendmail.cf"
685eaca2 1503 if (ap[1] == 'C' && ap[2] == '\0')
b2d4b27a
KB
1504 {
1505 *argv = xalloc(sizeof(__DEFPATH) + 2);
1506 argv[0][0] = '-';
1507 argv[0][1] = 'C';
1508 (void)strcpy(&argv[0][2], __DEFPATH);
1509 }
f96fa7de
EA
1510
1511 /* If -q doesn't have an argument, run it once. */
685eaca2 1512 if (ap[1] == 'q' && ap[2] == '\0')
f96fa7de 1513 *argv = "-q0";
a0431b8d
EA
1514
1515 /* if -d doesn't have an argument, use 0-99.1 */
685eaca2 1516 if (ap[1] == 'd' && ap[2] == '\0')
a0431b8d 1517 *argv = "-d0-99.1";
b2d4b27a
KB
1518 }
1519}
94bc039a
EA
1520\f/*
1521** AUTH_WARNING -- specify authorization warning
1522**
1523** Parameters:
1524** e -- the current envelope.
1525** msg -- the text of the message.
1526** args -- arguments to the message.
1527**
1528** Returns:
1529** none.
1530*/
1531
94bc039a 1532void
319b1ec0 1533#ifdef __STDC__
c51d6c4c 1534auth_warning(register ENVELOPE *e, const char *msg, ...)
94bc039a
EA
1535#else
1536auth_warning(e, msg, va_alist)
1537 register ENVELOPE *e;
c51d6c4c 1538 const char *msg;
94bc039a
EA
1539 va_dcl
1540#endif
1541{
1542 char buf[MAXLINE];
1543 VA_LOCAL_DECL
1544
1545 if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags))
1546 {
1547 register char *p;
1548 static char hostbuf[48];
a8ec2376 1549 extern struct hostent *myhostname();
94bc039a
EA
1550
1551 if (hostbuf[0] == '\0')
1552 (void) myhostname(hostbuf, sizeof hostbuf);
1553
db2c06cc 1554 (void) sprintf(buf, "%s: ", hostbuf);
94bc039a
EA
1555 p = &buf[strlen(buf)];
1556 VA_START(msg);
1557 vsprintf(p, msg, ap);
1558 VA_END;
c23930c0 1559 addheader("X-Authentication-Warning", buf, &e->e_header);
94bc039a
EA
1560 }
1561}
f0b11c9b 1562\f/*
6e48b8f0 1563** DUMPSTATE -- dump state
f0b11c9b
EA
1564**
1565** For debugging.
1566*/
1567
1568void
6e48b8f0
EA
1569dumpstate(when)
1570 char *when;
f0b11c9b
EA
1571{
1572#ifdef LOG
e478285e 1573 register char *j = macvalue('j', CurEnv);
e478285e 1574
6e48b8f0
EA
1575 syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---",
1576 when,
1577 j == NULL ? "<NULL>" : j);
1578 if (j != NULL)
1579 {
c85d44ca 1580 if (!wordinclass(j, 'w'))
6e48b8f0
EA
1581 syslog(LOG_DEBUG, "*** $j not in $=w ***");
1582 }
e478285e 1583 syslog(LOG_DEBUG, "--- open file descriptors: ---");
f0b11c9b
EA
1584 printopenfds(TRUE);
1585 syslog(LOG_DEBUG, "--- connection cache: ---");
1586 mci_dump_all(TRUE);
76b4b35d
EA
1587 if (RewriteRules[89] != NULL)
1588 {
1589 int stat;
1590 register char **pvp;
1591 char *pv[MAXATOM + 1];
1592
1593 pv[0] = NULL;
1594 stat = rewrite(pv, 89, 0, CurEnv);
1595 syslog(LOG_DEBUG, "--- ruleset 89 returns stat %d, pv: ---",
1596 stat);
1597 for (pvp = pv; *pvp != NULL; pvp++)
1598 syslog(LOG_DEBUG, "%s", *pvp);
1599 }
f0b11c9b
EA
1600 syslog(LOG_DEBUG, "--- end of state dump ---");
1601#endif
1602}
6e48b8f0
EA
1603
1604
1605void
1606sigusr1()
1607{
1608 dumpstate("user signal");
1609}
8357eea5
EA
1610
1611
1612void
1613sighup()
1614{
1615#ifdef LOG
1616 if (LogLevel > 3)
1617 syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]);
1618#endif
1619 execv(SaveArgv[0], SaveArgv);
1620#ifdef LOG
1621 if (LogLevel > 0)
1622 syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]);
1623#endif
1624 exit(EX_OSFILE);
1625}