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