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