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