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