1 | /* |
---|
2 | * Copyright (c) 1998 Sendmail, Inc. All rights reserved. |
---|
3 | * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. |
---|
4 | * Copyright (c) 1988, 1993 |
---|
5 | * The Regents of the University of California. All rights reserved. |
---|
6 | * |
---|
7 | * By using this file, you agree to the terms and conditions set |
---|
8 | * forth in the LICENSE file which can be found at the top level of |
---|
9 | * the sendmail distribution. |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | #ifndef lint |
---|
14 | static char copyright[] = |
---|
15 | "@(#) Copyright (c) 1998 Sendmail, Inc. All rights reserved.\n\ |
---|
16 | Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.\n\ |
---|
17 | Copyright (c) 1988, 1993\n\ |
---|
18 | The Regents of the University of California. All rights reserved.\n"; |
---|
19 | #endif /* not lint */ |
---|
20 | |
---|
21 | #ifndef lint |
---|
22 | static char sccsid[] = "@(#)main.c 8.322 (Berkeley) 12/18/1998"; |
---|
23 | #endif /* not lint */ |
---|
24 | |
---|
25 | #define _DEFINE |
---|
26 | |
---|
27 | #include "sendmail.h" |
---|
28 | #include <arpa/inet.h> |
---|
29 | #include <grp.h> |
---|
30 | #if NAMED_BIND |
---|
31 | #include <resolv.h> |
---|
32 | #endif |
---|
33 | |
---|
34 | /* |
---|
35 | ** SENDMAIL -- Post mail to a set of destinations. |
---|
36 | ** |
---|
37 | ** This is the basic mail router. All user mail programs should |
---|
38 | ** call this routine to actually deliver mail. Sendmail in |
---|
39 | ** turn calls a bunch of mail servers that do the real work of |
---|
40 | ** delivering the mail. |
---|
41 | ** |
---|
42 | ** Sendmail is driven by settings read in from /etc/sendmail.cf |
---|
43 | ** (read by readcf.c). |
---|
44 | ** |
---|
45 | ** Usage: |
---|
46 | ** /usr/lib/sendmail [flags] addr ... |
---|
47 | ** |
---|
48 | ** See the associated documentation for details. |
---|
49 | ** |
---|
50 | ** Author: |
---|
51 | ** Eric Allman, UCB/INGRES (until 10/81). |
---|
52 | ** Britton-Lee, Inc., purveyors of fine |
---|
53 | ** database computers (11/81 - 10/88). |
---|
54 | ** International Computer Science Institute |
---|
55 | ** (11/88 - 9/89). |
---|
56 | ** UCB/Mammoth Project (10/89 - 7/95). |
---|
57 | ** InReference, Inc. (8/95 - 1/97). |
---|
58 | ** Sendmail, Inc. (1/98 - present). |
---|
59 | ** The support of the my employers is gratefully acknowledged. |
---|
60 | ** Few of them (Britton-Lee in particular) have had |
---|
61 | ** anything to gain from my involvement in this project. |
---|
62 | */ |
---|
63 | |
---|
64 | |
---|
65 | int NextMailer; /* "free" index into Mailer struct */ |
---|
66 | char *FullName; /* sender's full name */ |
---|
67 | ENVELOPE BlankEnvelope; /* a "blank" envelope */ |
---|
68 | ENVELOPE MainEnvelope; /* the envelope around the basic letter */ |
---|
69 | ADDRESS NullAddress = /* a null address */ |
---|
70 | { "", "", NULL, "" }; |
---|
71 | char *CommandLineArgs; /* command line args for pid file */ |
---|
72 | bool Warn_Q_option = FALSE; /* warn about Q option use */ |
---|
73 | char **SaveArgv; /* argument vector for re-execing */ |
---|
74 | int MissingFds = 0; /* bit map of fds missing on startup */ |
---|
75 | |
---|
76 | #ifdef NGROUPS_MAX |
---|
77 | GIDSET_T InitialGidSet[NGROUPS_MAX]; |
---|
78 | #endif |
---|
79 | |
---|
80 | static void obsolete __P((char **)); |
---|
81 | extern void printmailer __P((MAILER *)); |
---|
82 | extern void tTflag __P((char *)); |
---|
83 | |
---|
84 | #if DAEMON && !SMTP |
---|
85 | ERROR %%%% Cannot have DAEMON mode without SMTP %%%% ERROR |
---|
86 | #endif /* DAEMON && !SMTP */ |
---|
87 | #if SMTP && !QUEUE |
---|
88 | ERROR %%%% Cannot have SMTP mode without QUEUE %%%% ERROR |
---|
89 | #endif /* DAEMON && !SMTP */ |
---|
90 | |
---|
91 | #define MAXCONFIGLEVEL 8 /* highest config version level known */ |
---|
92 | |
---|
93 | int |
---|
94 | main(argc, argv, envp) |
---|
95 | int argc; |
---|
96 | char **argv; |
---|
97 | char **envp; |
---|
98 | { |
---|
99 | register char *p; |
---|
100 | char **av; |
---|
101 | extern char Version[]; |
---|
102 | char *ep, *from; |
---|
103 | STAB *st; |
---|
104 | register int i; |
---|
105 | int j; |
---|
106 | bool queuemode = FALSE; /* process queue requests */ |
---|
107 | bool safecf = TRUE; |
---|
108 | bool warn_C_flag = FALSE; |
---|
109 | char warn_f_flag = '\0'; |
---|
110 | bool run_in_foreground = FALSE; /* -bD mode */ |
---|
111 | static bool reenter = FALSE; |
---|
112 | struct passwd *pw; |
---|
113 | struct hostent *hp; |
---|
114 | char *nullserver = NULL; |
---|
115 | bool forged; |
---|
116 | char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ |
---|
117 | static char rnamebuf[MAXNAME]; /* holds RealUserName */ |
---|
118 | char *emptyenviron[1]; |
---|
119 | QUEUE_CHAR *new; |
---|
120 | extern int DtableSize; |
---|
121 | extern int optind; |
---|
122 | extern int opterr; |
---|
123 | extern char *optarg; |
---|
124 | extern char **environ; |
---|
125 | extern time_t convtime __P((char *, char)); |
---|
126 | extern SIGFUNC_DECL intsig __P((int)); |
---|
127 | extern struct hostent *myhostname __P((char *, int)); |
---|
128 | extern char *getauthinfo __P((int, bool *)); |
---|
129 | extern char *getcfname __P((void)); |
---|
130 | extern SIGFUNC_DECL sigusr1 __P((int)); |
---|
131 | extern SIGFUNC_DECL sighup __P((int)); |
---|
132 | extern SIGFUNC_DECL quiesce __P((int)); |
---|
133 | extern void initmacros __P((ENVELOPE *)); |
---|
134 | extern void init_md __P((int, char **)); |
---|
135 | extern int getdtsize __P((void)); |
---|
136 | extern void tTsetup __P((u_char *, int, char *)); |
---|
137 | extern void setdefaults __P((ENVELOPE *)); |
---|
138 | extern void initsetproctitle __P((int, char **, char **)); |
---|
139 | extern void init_vendor_macros __P((ENVELOPE *)); |
---|
140 | extern void load_if_names __P((void)); |
---|
141 | extern void vendor_pre_defaults __P((ENVELOPE *)); |
---|
142 | extern void vendor_post_defaults __P((ENVELOPE *)); |
---|
143 | extern void readcf __P((char *, bool, ENVELOPE *)); |
---|
144 | extern void printqueue __P((void)); |
---|
145 | extern void sendtoargv __P((char **, ENVELOPE *)); |
---|
146 | extern void resetlimits __P((void)); |
---|
147 | #ifndef HASUNSETENV |
---|
148 | extern void unsetenv __P((char *)); |
---|
149 | #endif |
---|
150 | |
---|
151 | /* |
---|
152 | ** Check to see if we reentered. |
---|
153 | ** This would normally happen if e_putheader or e_putbody |
---|
154 | ** were NULL when invoked. |
---|
155 | */ |
---|
156 | |
---|
157 | if (reenter) |
---|
158 | { |
---|
159 | syserr("main: reentered!"); |
---|
160 | abort(); |
---|
161 | } |
---|
162 | reenter = TRUE; |
---|
163 | |
---|
164 | /* avoid null pointer dereferences */ |
---|
165 | TermEscape.te_rv_on = TermEscape.te_rv_off = ""; |
---|
166 | |
---|
167 | /* do machine-dependent initializations */ |
---|
168 | init_md(argc, argv); |
---|
169 | |
---|
170 | /* in 4.4BSD, the table can be huge; impose a reasonable limit */ |
---|
171 | DtableSize = getdtsize(); |
---|
172 | if (DtableSize > 256) |
---|
173 | DtableSize = 256; |
---|
174 | |
---|
175 | /* |
---|
176 | ** Be sure we have enough file descriptors. |
---|
177 | ** But also be sure that 0, 1, & 2 are open. |
---|
178 | */ |
---|
179 | |
---|
180 | fill_fd(STDIN_FILENO, NULL); |
---|
181 | fill_fd(STDOUT_FILENO, NULL); |
---|
182 | fill_fd(STDERR_FILENO, NULL); |
---|
183 | |
---|
184 | i = DtableSize; |
---|
185 | while (--i > 0) |
---|
186 | { |
---|
187 | if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) |
---|
188 | (void) close(i); |
---|
189 | } |
---|
190 | errno = 0; |
---|
191 | |
---|
192 | #if LOG |
---|
193 | # ifdef LOG_MAIL |
---|
194 | openlog("sendmail", LOG_PID, LOG_MAIL); |
---|
195 | # else |
---|
196 | openlog("sendmail", LOG_PID); |
---|
197 | # endif |
---|
198 | #endif |
---|
199 | |
---|
200 | if (MissingFds != 0) |
---|
201 | { |
---|
202 | char mbuf[MAXLINE]; |
---|
203 | |
---|
204 | mbuf[0] = '\0'; |
---|
205 | if (bitset(1 << STDIN_FILENO, MissingFds)) |
---|
206 | strcat(mbuf, ", stdin"); |
---|
207 | if (bitset(1 << STDOUT_FILENO, MissingFds)) |
---|
208 | strcat(mbuf, ", stdout"); |
---|
209 | if (bitset(1 << STDERR_FILENO, MissingFds)) |
---|
210 | strcat(mbuf, ", stderr"); |
---|
211 | syserr("File descriptors missing on startup: %s", &mbuf[2]); |
---|
212 | } |
---|
213 | |
---|
214 | /* reset status from syserr() calls for missing file descriptors */ |
---|
215 | Errors = 0; |
---|
216 | ExitStat = EX_OK; |
---|
217 | |
---|
218 | #if XDEBUG |
---|
219 | checkfd012("after openlog"); |
---|
220 | #endif |
---|
221 | |
---|
222 | tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); |
---|
223 | |
---|
224 | #ifdef NGROUPS_MAX |
---|
225 | /* save initial group set for future checks */ |
---|
226 | i = getgroups(NGROUPS_MAX, InitialGidSet); |
---|
227 | if (i == 0) |
---|
228 | InitialGidSet[0] = (GID_T) -1; |
---|
229 | while (i < NGROUPS_MAX) |
---|
230 | InitialGidSet[i++] = InitialGidSet[0]; |
---|
231 | #endif |
---|
232 | |
---|
233 | /* drop group id privileges (RunAsUser not yet set) */ |
---|
234 | (void) drop_privileges(FALSE); |
---|
235 | |
---|
236 | #ifdef SIGUSR1 |
---|
237 | /* arrange to dump state on user-1 signal */ |
---|
238 | setsignal(SIGUSR1, sigusr1); |
---|
239 | #endif |
---|
240 | |
---|
241 | /* initialize for setproctitle */ |
---|
242 | initsetproctitle(argc, argv, envp); |
---|
243 | |
---|
244 | /* Handle any non-getoptable constructions. */ |
---|
245 | obsolete(argv); |
---|
246 | |
---|
247 | /* |
---|
248 | ** Do a quick prescan of the argument list. |
---|
249 | */ |
---|
250 | |
---|
251 | #if defined(__osf__) || defined(_AIX3) |
---|
252 | # define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x" |
---|
253 | #endif |
---|
254 | #if defined(sony_news) |
---|
255 | # define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:" |
---|
256 | #endif |
---|
257 | #ifndef OPTIONS |
---|
258 | # define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:" |
---|
259 | #endif |
---|
260 | opterr = 0; |
---|
261 | while ((j = getopt(argc, argv, OPTIONS)) != -1) |
---|
262 | { |
---|
263 | switch (j) |
---|
264 | { |
---|
265 | case 'd': |
---|
266 | /* hack attack -- see if should use ANSI mode */ |
---|
267 | if (strcmp(optarg, "ANSI") == 0) |
---|
268 | { |
---|
269 | TermEscape.te_rv_on = "\033[7m"; |
---|
270 | TermEscape.te_rv_off = "\033[0m"; |
---|
271 | break; |
---|
272 | } |
---|
273 | tTflag(optarg); |
---|
274 | setbuf(stdout, (char *) NULL); |
---|
275 | break; |
---|
276 | } |
---|
277 | } |
---|
278 | opterr = 1; |
---|
279 | |
---|
280 | /* set up the blank envelope */ |
---|
281 | BlankEnvelope.e_puthdr = putheader; |
---|
282 | BlankEnvelope.e_putbody = putbody; |
---|
283 | BlankEnvelope.e_xfp = NULL; |
---|
284 | STRUCTCOPY(NullAddress, BlankEnvelope.e_from); |
---|
285 | CurEnv = &BlankEnvelope; |
---|
286 | STRUCTCOPY(NullAddress, MainEnvelope.e_from); |
---|
287 | |
---|
288 | /* |
---|
289 | ** Set default values for variables. |
---|
290 | ** These cannot be in initialized data space. |
---|
291 | */ |
---|
292 | |
---|
293 | setdefaults(&BlankEnvelope); |
---|
294 | |
---|
295 | RealUid = getuid(); |
---|
296 | RealGid = getgid(); |
---|
297 | |
---|
298 | pw = sm_getpwuid(RealUid); |
---|
299 | if (pw != NULL) |
---|
300 | (void) snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); |
---|
301 | else |
---|
302 | (void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d", RealUid); |
---|
303 | RealUserName = rnamebuf; |
---|
304 | |
---|
305 | if (tTd(0, 101)) |
---|
306 | { |
---|
307 | printf("Version %s\n", Version); |
---|
308 | finis(FALSE, EX_OK); |
---|
309 | } |
---|
310 | |
---|
311 | /* |
---|
312 | ** if running non-setuid binary as non-root, pretend |
---|
313 | ** we are the RunAsUid |
---|
314 | */ |
---|
315 | if (RealUid != 0 && geteuid() == RealUid) |
---|
316 | { |
---|
317 | if (tTd(47, 1)) |
---|
318 | printf("Non-setuid binary: RunAsUid = RealUid = %d\n", |
---|
319 | (int)RealUid); |
---|
320 | RunAsUid = RealUid; |
---|
321 | } |
---|
322 | else if (geteuid() != 0) |
---|
323 | RunAsUid = geteuid(); |
---|
324 | |
---|
325 | if (RealUid != 0 && getegid() == RealGid) |
---|
326 | RunAsGid = RealGid; |
---|
327 | |
---|
328 | if (tTd(47, 5)) |
---|
329 | { |
---|
330 | printf("main: e/ruid = %d/%d e/rgid = %d/%d\n", |
---|
331 | (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); |
---|
332 | printf("main: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); |
---|
333 | } |
---|
334 | |
---|
335 | /* save command line arguments */ |
---|
336 | i = 0; |
---|
337 | for (av = argv; *av != NULL; ) |
---|
338 | i += strlen(*av++) + 1; |
---|
339 | SaveArgv = (char **) xalloc(sizeof (char *) * (argc + 1)); |
---|
340 | CommandLineArgs = xalloc(i); |
---|
341 | p = CommandLineArgs; |
---|
342 | for (av = argv, i = 0; *av != NULL; ) |
---|
343 | { |
---|
344 | SaveArgv[i++] = newstr(*av); |
---|
345 | if (av != argv) |
---|
346 | *p++ = ' '; |
---|
347 | strcpy(p, *av++); |
---|
348 | p += strlen(p); |
---|
349 | } |
---|
350 | SaveArgv[i] = NULL; |
---|
351 | |
---|
352 | if (tTd(0, 1)) |
---|
353 | { |
---|
354 | int ll; |
---|
355 | extern char *CompileOptions[]; |
---|
356 | |
---|
357 | printf("Version %s\n Compiled with:", Version); |
---|
358 | av = CompileOptions; |
---|
359 | ll = 7; |
---|
360 | while (*av != NULL) |
---|
361 | { |
---|
362 | if (ll + strlen(*av) > 63) |
---|
363 | { |
---|
364 | putchar('\n'); |
---|
365 | ll = 0; |
---|
366 | } |
---|
367 | if (ll == 0) |
---|
368 | { |
---|
369 | putchar('\t'); |
---|
370 | putchar('\t'); |
---|
371 | } |
---|
372 | else |
---|
373 | putchar(' '); |
---|
374 | printf("%s", *av); |
---|
375 | ll += strlen(*av++) + 1; |
---|
376 | } |
---|
377 | putchar('\n'); |
---|
378 | } |
---|
379 | if (tTd(0, 10)) |
---|
380 | { |
---|
381 | int ll; |
---|
382 | extern char *OsCompileOptions[]; |
---|
383 | |
---|
384 | printf(" OS Defines:"); |
---|
385 | av = OsCompileOptions; |
---|
386 | ll = 7; |
---|
387 | while (*av != NULL) |
---|
388 | { |
---|
389 | if (ll + strlen(*av) > 63) |
---|
390 | { |
---|
391 | putchar('\n'); |
---|
392 | ll = 0; |
---|
393 | } |
---|
394 | if (ll == 0) |
---|
395 | { |
---|
396 | putchar('\t'); |
---|
397 | putchar('\t'); |
---|
398 | } |
---|
399 | else |
---|
400 | putchar(' '); |
---|
401 | printf("%s", *av); |
---|
402 | ll += strlen(*av++) + 1; |
---|
403 | } |
---|
404 | putchar('\n'); |
---|
405 | #ifdef _PATH_UNIX |
---|
406 | printf("Kernel symbols:\t%s\n", _PATH_UNIX); |
---|
407 | #endif |
---|
408 | printf(" Def Conf file:\t%s\n", getcfname()); |
---|
409 | printf(" Pid file:\t%s\n", PidFile); |
---|
410 | } |
---|
411 | |
---|
412 | InChannel = stdin; |
---|
413 | OutChannel = stdout; |
---|
414 | |
---|
415 | /* clear sendmail's environment */ |
---|
416 | ExternalEnviron = environ; |
---|
417 | emptyenviron[0] = NULL; |
---|
418 | environ = emptyenviron; |
---|
419 | |
---|
420 | /* |
---|
421 | ** restore any original TZ setting until TimeZoneSpec has been |
---|
422 | ** determined - or early log messages may get bogus time stamps |
---|
423 | */ |
---|
424 | if ((p = getextenv("TZ")) != NULL) |
---|
425 | { |
---|
426 | char *tz; |
---|
427 | int tzlen; |
---|
428 | |
---|
429 | tzlen = strlen(p) + 4; |
---|
430 | tz = xalloc(tzlen); |
---|
431 | snprintf(tz, tzlen, "TZ=%s", p); |
---|
432 | putenv(tz); |
---|
433 | } |
---|
434 | |
---|
435 | /* prime the child environment */ |
---|
436 | setuserenv("AGENT", "sendmail"); |
---|
437 | |
---|
438 | if (setsignal(SIGINT, SIG_IGN) != SIG_IGN) |
---|
439 | (void) setsignal(SIGINT, intsig); |
---|
440 | (void) setsignal(SIGTERM, intsig); |
---|
441 | (void) setsignal(SIGPIPE, SIG_IGN); |
---|
442 | OldUmask = umask(022); |
---|
443 | OpMode = MD_DELIVER; |
---|
444 | FullName = getextenv("NAME"); |
---|
445 | |
---|
446 | /* |
---|
447 | ** Initialize name server if it is going to be used. |
---|
448 | */ |
---|
449 | |
---|
450 | #if NAMED_BIND |
---|
451 | if (!bitset(RES_INIT, _res.options)) |
---|
452 | res_init(); |
---|
453 | if (tTd(8, 8)) |
---|
454 | _res.options |= RES_DEBUG; |
---|
455 | else |
---|
456 | _res.options &= ~RES_DEBUG; |
---|
457 | # ifdef RES_NOALIASES |
---|
458 | _res.options |= RES_NOALIASES; |
---|
459 | # endif |
---|
460 | #endif |
---|
461 | |
---|
462 | errno = 0; |
---|
463 | from = NULL; |
---|
464 | |
---|
465 | /* initialize some macros, etc. */ |
---|
466 | initmacros(CurEnv); |
---|
467 | init_vendor_macros(CurEnv); |
---|
468 | |
---|
469 | /* version */ |
---|
470 | define('v', Version, CurEnv); |
---|
471 | |
---|
472 | /* hostname */ |
---|
473 | hp = myhostname(jbuf, sizeof jbuf); |
---|
474 | if (jbuf[0] != '\0') |
---|
475 | { |
---|
476 | struct utsname utsname; |
---|
477 | |
---|
478 | if (tTd(0, 4)) |
---|
479 | printf("canonical name: %s\n", jbuf); |
---|
480 | define('w', newstr(jbuf), CurEnv); /* must be new string */ |
---|
481 | define('j', newstr(jbuf), CurEnv); |
---|
482 | setclass('w', jbuf); |
---|
483 | |
---|
484 | p = strchr(jbuf, '.'); |
---|
485 | if (p != NULL) |
---|
486 | { |
---|
487 | if (p[1] != '\0') |
---|
488 | { |
---|
489 | define('m', newstr(&p[1]), CurEnv); |
---|
490 | } |
---|
491 | while (p != NULL && strchr(&p[1], '.') != NULL) |
---|
492 | { |
---|
493 | *p = '\0'; |
---|
494 | if (tTd(0, 4)) |
---|
495 | printf("\ta.k.a.: %s\n", jbuf); |
---|
496 | setclass('w', jbuf); |
---|
497 | *p++ = '.'; |
---|
498 | p = strchr(p, '.'); |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | if (uname(&utsname) >= 0) |
---|
503 | p = utsname.nodename; |
---|
504 | else |
---|
505 | { |
---|
506 | if (tTd(0, 22)) |
---|
507 | printf("uname failed (%s)\n", errstring(errno)); |
---|
508 | makelower(jbuf); |
---|
509 | p = jbuf; |
---|
510 | } |
---|
511 | if (tTd(0, 4)) |
---|
512 | printf(" UUCP nodename: %s\n", p); |
---|
513 | p = newstr(p); |
---|
514 | define('k', p, CurEnv); |
---|
515 | setclass('k', p); |
---|
516 | setclass('w', p); |
---|
517 | } |
---|
518 | if (hp != NULL) |
---|
519 | { |
---|
520 | for (av = hp->h_aliases; av != NULL && *av != NULL; av++) |
---|
521 | { |
---|
522 | if (tTd(0, 4)) |
---|
523 | printf("\ta.k.a.: %s\n", *av); |
---|
524 | setclass('w', *av); |
---|
525 | } |
---|
526 | #if NETINET |
---|
527 | if (hp->h_addrtype == AF_INET && hp->h_length == INADDRSZ) |
---|
528 | { |
---|
529 | for (i = 0; hp->h_addr_list[i] != NULL; i++) |
---|
530 | { |
---|
531 | char ipbuf[103]; |
---|
532 | |
---|
533 | snprintf(ipbuf, sizeof ipbuf, "[%.100s]", |
---|
534 | inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); |
---|
535 | if (tTd(0, 4)) |
---|
536 | printf("\ta.k.a.: %s\n", ipbuf); |
---|
537 | setclass('w', ipbuf); |
---|
538 | } |
---|
539 | } |
---|
540 | #endif |
---|
541 | } |
---|
542 | |
---|
543 | /* current time */ |
---|
544 | define('b', arpadate((char *) NULL), CurEnv); |
---|
545 | |
---|
546 | QueueLimitRecipient = (QUEUE_CHAR *) NULL; |
---|
547 | QueueLimitSender = (QUEUE_CHAR *) NULL; |
---|
548 | QueueLimitId = (QUEUE_CHAR *) NULL; |
---|
549 | |
---|
550 | /* |
---|
551 | ** Crack argv. |
---|
552 | */ |
---|
553 | |
---|
554 | av = argv; |
---|
555 | p = strrchr(*av, '/'); |
---|
556 | if (p++ == NULL) |
---|
557 | p = *av; |
---|
558 | if (strcmp(p, "newaliases") == 0) |
---|
559 | OpMode = MD_INITALIAS; |
---|
560 | else if (strcmp(p, "mailq") == 0) |
---|
561 | OpMode = MD_PRINT; |
---|
562 | else if (strcmp(p, "smtpd") == 0) |
---|
563 | OpMode = MD_DAEMON; |
---|
564 | else if (strcmp(p, "hoststat") == 0) |
---|
565 | OpMode = MD_HOSTSTAT; |
---|
566 | else if (strcmp(p, "purgestat") == 0) |
---|
567 | OpMode = MD_PURGESTAT; |
---|
568 | |
---|
569 | optind = 1; |
---|
570 | while ((j = getopt(argc, argv, OPTIONS)) != -1) |
---|
571 | { |
---|
572 | switch (j) |
---|
573 | { |
---|
574 | case 'b': /* operations mode */ |
---|
575 | switch (j = *optarg) |
---|
576 | { |
---|
577 | case MD_DAEMON: |
---|
578 | case MD_FGDAEMON: |
---|
579 | # if !DAEMON |
---|
580 | usrerr("Daemon mode not implemented"); |
---|
581 | ExitStat = EX_USAGE; |
---|
582 | break; |
---|
583 | # endif /* DAEMON */ |
---|
584 | case MD_SMTP: |
---|
585 | # if !SMTP |
---|
586 | usrerr("I don't speak SMTP"); |
---|
587 | ExitStat = EX_USAGE; |
---|
588 | break; |
---|
589 | # endif /* SMTP */ |
---|
590 | |
---|
591 | case MD_INITALIAS: |
---|
592 | case MD_DELIVER: |
---|
593 | case MD_VERIFY: |
---|
594 | case MD_TEST: |
---|
595 | case MD_PRINT: |
---|
596 | case MD_HOSTSTAT: |
---|
597 | case MD_PURGESTAT: |
---|
598 | case MD_ARPAFTP: |
---|
599 | OpMode = j; |
---|
600 | break; |
---|
601 | |
---|
602 | case MD_FREEZE: |
---|
603 | usrerr("Frozen configurations unsupported"); |
---|
604 | ExitStat = EX_USAGE; |
---|
605 | break; |
---|
606 | |
---|
607 | default: |
---|
608 | usrerr("Invalid operation mode %c", j); |
---|
609 | ExitStat = EX_USAGE; |
---|
610 | break; |
---|
611 | } |
---|
612 | break; |
---|
613 | |
---|
614 | case 'B': /* body type */ |
---|
615 | CurEnv->e_bodytype = optarg; |
---|
616 | break; |
---|
617 | |
---|
618 | case 'C': /* select configuration file (already done) */ |
---|
619 | if (RealUid != 0) |
---|
620 | warn_C_flag = TRUE; |
---|
621 | ConfFile = optarg; |
---|
622 | (void) drop_privileges(TRUE); |
---|
623 | safecf = FALSE; |
---|
624 | break; |
---|
625 | |
---|
626 | case 'd': /* debugging -- already done */ |
---|
627 | break; |
---|
628 | |
---|
629 | case 'f': /* from address */ |
---|
630 | case 'r': /* obsolete -f flag */ |
---|
631 | if (from != NULL) |
---|
632 | { |
---|
633 | usrerr("More than one \"from\" person"); |
---|
634 | ExitStat = EX_USAGE; |
---|
635 | break; |
---|
636 | } |
---|
637 | from = newstr(denlstring(optarg, TRUE, TRUE)); |
---|
638 | if (strcmp(RealUserName, from) != 0) |
---|
639 | warn_f_flag = j; |
---|
640 | break; |
---|
641 | |
---|
642 | case 'F': /* set full name */ |
---|
643 | FullName = newstr(optarg); |
---|
644 | break; |
---|
645 | |
---|
646 | case 'h': /* hop count */ |
---|
647 | CurEnv->e_hopcount = strtol(optarg, &ep, 10); |
---|
648 | if (*ep) |
---|
649 | { |
---|
650 | usrerr("Bad hop count (%s)", optarg); |
---|
651 | ExitStat = EX_USAGE; |
---|
652 | } |
---|
653 | break; |
---|
654 | |
---|
655 | case 'n': /* don't alias */ |
---|
656 | NoAlias = TRUE; |
---|
657 | break; |
---|
658 | |
---|
659 | case 'N': /* delivery status notifications */ |
---|
660 | DefaultNotify |= QHASNOTIFY; |
---|
661 | if (strcasecmp(optarg, "never") == 0) |
---|
662 | break; |
---|
663 | for (p = optarg; p != NULL; optarg = p) |
---|
664 | { |
---|
665 | p = strchr(p, ','); |
---|
666 | if (p != NULL) |
---|
667 | *p++ = '\0'; |
---|
668 | if (strcasecmp(optarg, "success") == 0) |
---|
669 | DefaultNotify |= QPINGONSUCCESS; |
---|
670 | else if (strcasecmp(optarg, "failure") == 0) |
---|
671 | DefaultNotify |= QPINGONFAILURE; |
---|
672 | else if (strcasecmp(optarg, "delay") == 0) |
---|
673 | DefaultNotify |= QPINGONDELAY; |
---|
674 | else |
---|
675 | { |
---|
676 | usrerr("Invalid -N argument"); |
---|
677 | ExitStat = EX_USAGE; |
---|
678 | } |
---|
679 | } |
---|
680 | break; |
---|
681 | |
---|
682 | case 'o': /* set option */ |
---|
683 | setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv); |
---|
684 | break; |
---|
685 | |
---|
686 | case 'O': /* set option (long form) */ |
---|
687 | setoption(' ', optarg, FALSE, TRUE, CurEnv); |
---|
688 | break; |
---|
689 | |
---|
690 | case 'p': /* set protocol */ |
---|
691 | p = strchr(optarg, ':'); |
---|
692 | if (p != NULL) |
---|
693 | { |
---|
694 | *p++ = '\0'; |
---|
695 | if (*p != '\0') |
---|
696 | { |
---|
697 | ep = xalloc(strlen(p) + 1); |
---|
698 | cleanstrcpy(ep, p, MAXNAME); |
---|
699 | define('s', ep, CurEnv); |
---|
700 | } |
---|
701 | } |
---|
702 | if (*optarg != '\0') |
---|
703 | { |
---|
704 | ep = xalloc(strlen(optarg) + 1); |
---|
705 | cleanstrcpy(ep, optarg, MAXNAME); |
---|
706 | define('r', ep, CurEnv); |
---|
707 | } |
---|
708 | break; |
---|
709 | |
---|
710 | case 'q': /* run queue files at intervals */ |
---|
711 | # if QUEUE |
---|
712 | FullName = NULL; |
---|
713 | queuemode = TRUE; |
---|
714 | switch (optarg[0]) |
---|
715 | { |
---|
716 | case 'I': |
---|
717 | if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) |
---|
718 | syserr("!Out of memory!!"); |
---|
719 | new->queue_match = newstr(&optarg[1]); |
---|
720 | new->queue_next = QueueLimitId; |
---|
721 | QueueLimitId = new; |
---|
722 | break; |
---|
723 | |
---|
724 | case 'R': |
---|
725 | if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) |
---|
726 | syserr("!Out of memory!!"); |
---|
727 | new->queue_match = newstr(&optarg[1]); |
---|
728 | new->queue_next = QueueLimitRecipient; |
---|
729 | QueueLimitRecipient = new; |
---|
730 | break; |
---|
731 | |
---|
732 | case 'S': |
---|
733 | if ((new = (QUEUE_CHAR *)malloc(sizeof(QUEUE_CHAR))) == NULL) |
---|
734 | syserr("!Out of memory!!"); |
---|
735 | new->queue_match = newstr(&optarg[1]); |
---|
736 | new->queue_next = QueueLimitSender; |
---|
737 | QueueLimitSender = new; |
---|
738 | break; |
---|
739 | |
---|
740 | default: |
---|
741 | QueueIntvl = convtime(optarg, 'm'); |
---|
742 | break; |
---|
743 | } |
---|
744 | # else /* QUEUE */ |
---|
745 | usrerr("I don't know about queues"); |
---|
746 | ExitStat = EX_USAGE; |
---|
747 | # endif /* QUEUE */ |
---|
748 | break; |
---|
749 | |
---|
750 | case 'R': /* DSN RET: what to return */ |
---|
751 | if (bitset(EF_RET_PARAM, CurEnv->e_flags)) |
---|
752 | { |
---|
753 | usrerr("Duplicate -R flag"); |
---|
754 | ExitStat = EX_USAGE; |
---|
755 | break; |
---|
756 | } |
---|
757 | CurEnv->e_flags |= EF_RET_PARAM; |
---|
758 | if (strcasecmp(optarg, "hdrs") == 0) |
---|
759 | CurEnv->e_flags |= EF_NO_BODY_RETN; |
---|
760 | else if (strcasecmp(optarg, "full") != 0) |
---|
761 | { |
---|
762 | usrerr("Invalid -R value"); |
---|
763 | ExitStat = EX_USAGE; |
---|
764 | } |
---|
765 | break; |
---|
766 | |
---|
767 | case 't': /* read recipients from message */ |
---|
768 | GrabTo = TRUE; |
---|
769 | break; |
---|
770 | |
---|
771 | case 'U': /* initial (user) submission */ |
---|
772 | UserSubmission = TRUE; |
---|
773 | break; |
---|
774 | |
---|
775 | case 'V': /* DSN ENVID: set "original" envelope id */ |
---|
776 | if (!xtextok(optarg)) |
---|
777 | { |
---|
778 | usrerr("Invalid syntax in -V flag"); |
---|
779 | ExitStat = EX_USAGE; |
---|
780 | } |
---|
781 | else |
---|
782 | CurEnv->e_envid = newstr(optarg); |
---|
783 | break; |
---|
784 | |
---|
785 | case 'X': /* traffic log file */ |
---|
786 | (void) drop_privileges(TRUE); |
---|
787 | TrafficLogFile = fopen(optarg, "a"); |
---|
788 | if (TrafficLogFile == NULL) |
---|
789 | { |
---|
790 | syserr("cannot open %s", optarg); |
---|
791 | ExitStat = EX_CANTCREAT; |
---|
792 | break; |
---|
793 | } |
---|
794 | #ifdef HASSETVBUF |
---|
795 | setvbuf(TrafficLogFile, NULL, _IOLBF, 0); |
---|
796 | #else |
---|
797 | setlinebuf(TrafficLogFile); |
---|
798 | #endif |
---|
799 | break; |
---|
800 | |
---|
801 | /* compatibility flags */ |
---|
802 | case 'c': /* connect to non-local mailers */ |
---|
803 | case 'i': /* don't let dot stop me */ |
---|
804 | case 'm': /* send to me too */ |
---|
805 | case 'T': /* set timeout interval */ |
---|
806 | case 'v': /* give blow-by-blow description */ |
---|
807 | setoption(j, "T", FALSE, TRUE, CurEnv); |
---|
808 | break; |
---|
809 | |
---|
810 | case 'e': /* error message disposition */ |
---|
811 | case 'M': /* define macro */ |
---|
812 | setoption(j, optarg, FALSE, TRUE, CurEnv); |
---|
813 | break; |
---|
814 | |
---|
815 | case 's': /* save From lines in headers */ |
---|
816 | setoption('f', "T", FALSE, TRUE, CurEnv); |
---|
817 | break; |
---|
818 | |
---|
819 | # ifdef DBM |
---|
820 | case 'I': /* initialize alias DBM file */ |
---|
821 | OpMode = MD_INITALIAS; |
---|
822 | break; |
---|
823 | # endif /* DBM */ |
---|
824 | |
---|
825 | # if defined(__osf__) || defined(_AIX3) |
---|
826 | case 'x': /* random flag that OSF/1 & AIX mailx passes */ |
---|
827 | break; |
---|
828 | # endif |
---|
829 | # if defined(sony_news) |
---|
830 | case 'E': |
---|
831 | case 'J': /* ignore flags for Japanese code conversion |
---|
832 | impremented on Sony NEWS */ |
---|
833 | break; |
---|
834 | # endif |
---|
835 | |
---|
836 | default: |
---|
837 | finis(TRUE, EX_USAGE); |
---|
838 | break; |
---|
839 | } |
---|
840 | } |
---|
841 | av += optind; |
---|
842 | |
---|
843 | /* |
---|
844 | ** Do basic initialization. |
---|
845 | ** Read system control file. |
---|
846 | ** Extract special fields for local use. |
---|
847 | */ |
---|
848 | |
---|
849 | /* set up ${opMode} for use in config file */ |
---|
850 | { |
---|
851 | char mbuf[2]; |
---|
852 | |
---|
853 | mbuf[0] = OpMode; |
---|
854 | mbuf[1] = '\0'; |
---|
855 | define(MID_OPMODE, newstr(mbuf), CurEnv); |
---|
856 | } |
---|
857 | |
---|
858 | #if XDEBUG |
---|
859 | checkfd012("before readcf"); |
---|
860 | #endif |
---|
861 | vendor_pre_defaults(CurEnv); |
---|
862 | readcf(getcfname(), safecf, CurEnv); |
---|
863 | ConfigFileRead = TRUE; |
---|
864 | vendor_post_defaults(CurEnv); |
---|
865 | |
---|
866 | /* Enforce use of local time (null string overrides this) */ |
---|
867 | if (TimeZoneSpec == NULL) |
---|
868 | unsetenv("TZ"); |
---|
869 | else if (TimeZoneSpec[0] != '\0') |
---|
870 | setuserenv("TZ", TimeZoneSpec); |
---|
871 | else |
---|
872 | setuserenv("TZ", NULL); |
---|
873 | tzset(); |
---|
874 | |
---|
875 | /* avoid denial-of-service attacks */ |
---|
876 | resetlimits(); |
---|
877 | |
---|
878 | if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) |
---|
879 | { |
---|
880 | /* drop privileges -- daemon mode done after socket/bind */ |
---|
881 | (void) drop_privileges(FALSE); |
---|
882 | } |
---|
883 | |
---|
884 | /* |
---|
885 | ** Find our real host name for future logging. |
---|
886 | */ |
---|
887 | |
---|
888 | p = getauthinfo(STDIN_FILENO, &forged); |
---|
889 | define('_', p, CurEnv); |
---|
890 | |
---|
891 | /* suppress error printing if errors mailed back or whatever */ |
---|
892 | if (CurEnv->e_errormode != EM_PRINT) |
---|
893 | HoldErrs = TRUE; |
---|
894 | |
---|
895 | /* set up the $=m class now, after .cf has a chance to redefine $m */ |
---|
896 | expand("\201m", jbuf, sizeof jbuf, CurEnv); |
---|
897 | setclass('m', jbuf); |
---|
898 | |
---|
899 | /* probe interfaces and locate any additional names */ |
---|
900 | if (!DontProbeInterfaces) |
---|
901 | load_if_names(); |
---|
902 | |
---|
903 | if (tTd(0, 1)) |
---|
904 | { |
---|
905 | printf("\n============ SYSTEM IDENTITY (after readcf) ============"); |
---|
906 | printf("\n (short domain name) $w = "); |
---|
907 | xputs(macvalue('w', CurEnv)); |
---|
908 | printf("\n (canonical domain name) $j = "); |
---|
909 | xputs(macvalue('j', CurEnv)); |
---|
910 | printf("\n (subdomain name) $m = "); |
---|
911 | xputs(macvalue('m', CurEnv)); |
---|
912 | printf("\n (node name) $k = "); |
---|
913 | xputs(macvalue('k', CurEnv)); |
---|
914 | printf("\n========================================================\n\n"); |
---|
915 | } |
---|
916 | |
---|
917 | /* |
---|
918 | ** Do more command line checking -- these are things that |
---|
919 | ** have to modify the results of reading the config file. |
---|
920 | */ |
---|
921 | |
---|
922 | /* process authorization warnings from command line */ |
---|
923 | if (warn_C_flag) |
---|
924 | auth_warning(CurEnv, "Processed by %s with -C %s", |
---|
925 | RealUserName, ConfFile); |
---|
926 | if (Warn_Q_option) |
---|
927 | auth_warning(CurEnv, "Processed from queue %s", QueueDir); |
---|
928 | |
---|
929 | /* check body type for legality */ |
---|
930 | if (CurEnv->e_bodytype == NULL) |
---|
931 | /* nothing */ ; |
---|
932 | else if (strcasecmp(CurEnv->e_bodytype, "7BIT") == 0) |
---|
933 | SevenBitInput = TRUE; |
---|
934 | else if (strcasecmp(CurEnv->e_bodytype, "8BITMIME") == 0) |
---|
935 | SevenBitInput = FALSE; |
---|
936 | else |
---|
937 | { |
---|
938 | usrerr("Illegal body type %s", CurEnv->e_bodytype); |
---|
939 | CurEnv->e_bodytype = NULL; |
---|
940 | } |
---|
941 | |
---|
942 | /* tweak default DSN notifications */ |
---|
943 | if (DefaultNotify == 0) |
---|
944 | DefaultNotify = QPINGONFAILURE|QPINGONDELAY; |
---|
945 | |
---|
946 | /* be sure we don't pick up bogus HOSTALIASES environment variable */ |
---|
947 | if (queuemode && RealUid != 0) |
---|
948 | (void) unsetenv("HOSTALIASES"); |
---|
949 | |
---|
950 | /* check for sane configuration level */ |
---|
951 | if (ConfigLevel > MAXCONFIGLEVEL) |
---|
952 | { |
---|
953 | syserr("Warning: .cf version level (%d) exceeds sendmail version %s functionality (%d)", |
---|
954 | ConfigLevel, Version, MAXCONFIGLEVEL); |
---|
955 | } |
---|
956 | |
---|
957 | /* need MCI cache to have persistence */ |
---|
958 | if (HostStatDir != NULL && MaxMciCache == 0) |
---|
959 | { |
---|
960 | HostStatDir = NULL; |
---|
961 | printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); |
---|
962 | } |
---|
963 | |
---|
964 | /* need HostStatusDir in order to have SingleThreadDelivery */ |
---|
965 | if (SingleThreadDelivery && HostStatDir == NULL) |
---|
966 | { |
---|
967 | SingleThreadDelivery = FALSE; |
---|
968 | printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n"); |
---|
969 | } |
---|
970 | |
---|
971 | /* check for permissions */ |
---|
972 | if ((OpMode == MD_DAEMON || |
---|
973 | OpMode == MD_FGDAEMON || |
---|
974 | OpMode == MD_PURGESTAT) && |
---|
975 | RealUid != 0 && |
---|
976 | RealUid != TrustedUid) |
---|
977 | { |
---|
978 | if (LogLevel > 1) |
---|
979 | sm_syslog(LOG_ALERT, NOQID, |
---|
980 | "user %d attempted to %s", |
---|
981 | RealUid, |
---|
982 | OpMode != MD_PURGESTAT ? "run daemon" |
---|
983 | : "purge host status"); |
---|
984 | usrerr("Permission denied"); |
---|
985 | finis(FALSE, EX_USAGE); |
---|
986 | } |
---|
987 | |
---|
988 | if (MeToo) |
---|
989 | BlankEnvelope.e_flags |= EF_METOO; |
---|
990 | |
---|
991 | switch (OpMode) |
---|
992 | { |
---|
993 | case MD_TEST: |
---|
994 | /* don't have persistent host status in test mode */ |
---|
995 | HostStatDir = NULL; |
---|
996 | if (Verbose == 0) |
---|
997 | Verbose = 2; |
---|
998 | CurEnv->e_errormode = EM_PRINT; |
---|
999 | HoldErrs = FALSE; |
---|
1000 | break; |
---|
1001 | |
---|
1002 | case MD_VERIFY: |
---|
1003 | CurEnv->e_errormode = EM_PRINT; |
---|
1004 | HoldErrs = FALSE; |
---|
1005 | /* arrange to exit cleanly on hangup signal */ |
---|
1006 | if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) |
---|
1007 | setsignal(SIGHUP, intsig); |
---|
1008 | break; |
---|
1009 | |
---|
1010 | case MD_FGDAEMON: |
---|
1011 | run_in_foreground = TRUE; |
---|
1012 | OpMode = MD_DAEMON; |
---|
1013 | /* fall through ... */ |
---|
1014 | |
---|
1015 | case MD_DAEMON: |
---|
1016 | vendor_daemon_setup(CurEnv); |
---|
1017 | |
---|
1018 | /* remove things that don't make sense in daemon mode */ |
---|
1019 | FullName = NULL; |
---|
1020 | GrabTo = FALSE; |
---|
1021 | |
---|
1022 | /* arrange to restart on hangup signal */ |
---|
1023 | if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') |
---|
1024 | sm_syslog(LOG_WARNING, NOQID, |
---|
1025 | "daemon invoked without full pathname; kill -1 won't work"); |
---|
1026 | setsignal(SIGHUP, sighup); |
---|
1027 | |
---|
1028 | /* workaround: can't seem to release the signal in the parent */ |
---|
1029 | releasesignal(SIGHUP); |
---|
1030 | break; |
---|
1031 | |
---|
1032 | case MD_INITALIAS: |
---|
1033 | Verbose = 2; |
---|
1034 | CurEnv->e_errormode = EM_PRINT; |
---|
1035 | HoldErrs = FALSE; |
---|
1036 | /* fall through... */ |
---|
1037 | |
---|
1038 | case MD_PRINT: |
---|
1039 | /* to handle sendmail -bp -qSfoobar properly */ |
---|
1040 | queuemode = FALSE; |
---|
1041 | /* fall through... */ |
---|
1042 | |
---|
1043 | default: |
---|
1044 | /* arrange to exit cleanly on hangup signal */ |
---|
1045 | if (setsignal(SIGHUP, SIG_IGN) == (sigfunc_t) SIG_DFL) |
---|
1046 | setsignal(SIGHUP, intsig); |
---|
1047 | break; |
---|
1048 | } |
---|
1049 | |
---|
1050 | /* special considerations for FullName */ |
---|
1051 | if (FullName != NULL) |
---|
1052 | { |
---|
1053 | char *full = NULL; |
---|
1054 | extern bool rfc822_string __P((char *)); |
---|
1055 | |
---|
1056 | /* full names can't have newlines */ |
---|
1057 | if (strchr(FullName, '\n') != NULL) |
---|
1058 | { |
---|
1059 | FullName = full = newstr(denlstring(FullName, TRUE, TRUE)); |
---|
1060 | } |
---|
1061 | /* check for characters that may have to be quoted */ |
---|
1062 | if (!rfc822_string(FullName)) |
---|
1063 | { |
---|
1064 | extern char *addquotes __P((char *)); |
---|
1065 | |
---|
1066 | /* |
---|
1067 | ** Quote a full name with special characters |
---|
1068 | ** as a comment so crackaddr() doesn't destroy |
---|
1069 | ** the name portion of the address. |
---|
1070 | */ |
---|
1071 | FullName = addquotes(FullName); |
---|
1072 | if (full != NULL) |
---|
1073 | free(full); |
---|
1074 | } |
---|
1075 | } |
---|
1076 | |
---|
1077 | /* do heuristic mode adjustment */ |
---|
1078 | if (Verbose) |
---|
1079 | { |
---|
1080 | /* turn off noconnect option */ |
---|
1081 | setoption('c', "F", TRUE, FALSE, CurEnv); |
---|
1082 | |
---|
1083 | /* turn on interactive delivery */ |
---|
1084 | setoption('d', "", TRUE, FALSE, CurEnv); |
---|
1085 | } |
---|
1086 | |
---|
1087 | #ifdef VENDOR_CODE |
---|
1088 | /* check for vendor mismatch */ |
---|
1089 | if (VendorCode != VENDOR_CODE) |
---|
1090 | { |
---|
1091 | extern char *getvendor __P((int)); |
---|
1092 | |
---|
1093 | message("Warning: .cf file vendor code mismatch: sendmail expects vendor %s, .cf file vendor is %s", |
---|
1094 | getvendor(VENDOR_CODE), getvendor(VendorCode)); |
---|
1095 | } |
---|
1096 | #endif |
---|
1097 | |
---|
1098 | /* check for out of date configuration level */ |
---|
1099 | if (ConfigLevel < MAXCONFIGLEVEL) |
---|
1100 | { |
---|
1101 | message("Warning: .cf file is out of date: sendmail %s supports version %d, .cf file is version %d", |
---|
1102 | Version, MAXCONFIGLEVEL, ConfigLevel); |
---|
1103 | } |
---|
1104 | |
---|
1105 | if (ConfigLevel < 3) |
---|
1106 | { |
---|
1107 | UseErrorsTo = TRUE; |
---|
1108 | } |
---|
1109 | |
---|
1110 | /* set options that were previous macros */ |
---|
1111 | if (SmtpGreeting == NULL) |
---|
1112 | { |
---|
1113 | if (ConfigLevel < 7 && (p = macvalue('e', CurEnv)) != NULL) |
---|
1114 | SmtpGreeting = newstr(p); |
---|
1115 | else |
---|
1116 | SmtpGreeting = "\201j Sendmail \201v ready at \201b"; |
---|
1117 | } |
---|
1118 | if (UnixFromLine == NULL) |
---|
1119 | { |
---|
1120 | if (ConfigLevel < 7 && (p = macvalue('l', CurEnv)) != NULL) |
---|
1121 | UnixFromLine = newstr(p); |
---|
1122 | else |
---|
1123 | UnixFromLine = "From \201g \201d"; |
---|
1124 | } |
---|
1125 | |
---|
1126 | /* our name for SMTP codes */ |
---|
1127 | expand("\201j", jbuf, sizeof jbuf, CurEnv); |
---|
1128 | MyHostName = jbuf; |
---|
1129 | if (strchr(jbuf, '.') == NULL) |
---|
1130 | message("WARNING: local host name (%s) is not qualified; fix $j in config file", |
---|
1131 | jbuf); |
---|
1132 | |
---|
1133 | /* make certain that this name is part of the $=w class */ |
---|
1134 | setclass('w', MyHostName); |
---|
1135 | |
---|
1136 | /* the indices of built-in mailers */ |
---|
1137 | st = stab("local", ST_MAILER, ST_FIND); |
---|
1138 | if (st != NULL) |
---|
1139 | LocalMailer = st->s_mailer; |
---|
1140 | else if (OpMode != MD_TEST || !warn_C_flag) |
---|
1141 | syserr("No local mailer defined"); |
---|
1142 | |
---|
1143 | st = stab("prog", ST_MAILER, ST_FIND); |
---|
1144 | if (st == NULL) |
---|
1145 | syserr("No prog mailer defined"); |
---|
1146 | else |
---|
1147 | { |
---|
1148 | ProgMailer = st->s_mailer; |
---|
1149 | clrbitn(M_MUSER, ProgMailer->m_flags); |
---|
1150 | } |
---|
1151 | |
---|
1152 | st = stab("*file*", ST_MAILER, ST_FIND); |
---|
1153 | if (st == NULL) |
---|
1154 | syserr("No *file* mailer defined"); |
---|
1155 | else |
---|
1156 | { |
---|
1157 | FileMailer = st->s_mailer; |
---|
1158 | clrbitn(M_MUSER, FileMailer->m_flags); |
---|
1159 | } |
---|
1160 | |
---|
1161 | st = stab("*include*", ST_MAILER, ST_FIND); |
---|
1162 | if (st == NULL) |
---|
1163 | syserr("No *include* mailer defined"); |
---|
1164 | else |
---|
1165 | InclMailer = st->s_mailer; |
---|
1166 | |
---|
1167 | if (ConfigLevel < 6) |
---|
1168 | { |
---|
1169 | /* heuristic tweaking of local mailer for back compat */ |
---|
1170 | if (LocalMailer != NULL) |
---|
1171 | { |
---|
1172 | setbitn(M_ALIASABLE, LocalMailer->m_flags); |
---|
1173 | setbitn(M_HASPWENT, LocalMailer->m_flags); |
---|
1174 | setbitn(M_TRYRULESET5, LocalMailer->m_flags); |
---|
1175 | setbitn(M_CHECKINCLUDE, LocalMailer->m_flags); |
---|
1176 | setbitn(M_CHECKPROG, LocalMailer->m_flags); |
---|
1177 | setbitn(M_CHECKFILE, LocalMailer->m_flags); |
---|
1178 | setbitn(M_CHECKUDB, LocalMailer->m_flags); |
---|
1179 | } |
---|
1180 | if (ProgMailer != NULL) |
---|
1181 | setbitn(M_RUNASRCPT, ProgMailer->m_flags); |
---|
1182 | if (FileMailer != NULL) |
---|
1183 | setbitn(M_RUNASRCPT, FileMailer->m_flags); |
---|
1184 | } |
---|
1185 | if (ConfigLevel < 7) |
---|
1186 | { |
---|
1187 | if (LocalMailer != NULL) |
---|
1188 | setbitn(M_VRFY250, LocalMailer->m_flags); |
---|
1189 | if (ProgMailer != NULL) |
---|
1190 | setbitn(M_VRFY250, ProgMailer->m_flags); |
---|
1191 | if (FileMailer != NULL) |
---|
1192 | setbitn(M_VRFY250, FileMailer->m_flags); |
---|
1193 | } |
---|
1194 | |
---|
1195 | /* MIME Content-Types that cannot be transfer encoded */ |
---|
1196 | setclass('n', "multipart/signed"); |
---|
1197 | |
---|
1198 | /* MIME message/xxx subtypes that can be treated as messages */ |
---|
1199 | setclass('s', "rfc822"); |
---|
1200 | |
---|
1201 | /* MIME Content-Transfer-Encodings that can be encoded */ |
---|
1202 | setclass('e', "7bit"); |
---|
1203 | setclass('e', "8bit"); |
---|
1204 | setclass('e', "binary"); |
---|
1205 | |
---|
1206 | #ifdef USE_B_CLASS |
---|
1207 | /* MIME Content-Types that should be treated as binary */ |
---|
1208 | setclass('b', "image"); |
---|
1209 | setclass('b', "audio"); |
---|
1210 | setclass('b', "video"); |
---|
1211 | setclass('b', "application/octet-stream"); |
---|
1212 | #endif |
---|
1213 | |
---|
1214 | #if _FFR_MAX_MIME_HEADER_LENGTH |
---|
1215 | /* MIME headers which have fields to check for overflow */ |
---|
1216 | setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-disposition"); |
---|
1217 | setclass(macid("{checkMIMEFieldHeaders}", NULL), "content-type"); |
---|
1218 | |
---|
1219 | /* MIME headers to check for length overflow */ |
---|
1220 | setclass(macid("{checkMIMETextHeaders}", NULL), "content-description"); |
---|
1221 | |
---|
1222 | /* MIME headers to check for overflow and rebalance */ |
---|
1223 | setclass(macid("{checkMIMEHeaders}", NULL), "content-disposition"); |
---|
1224 | setclass(macid("{checkMIMEHeaders}", NULL), "content-id"); |
---|
1225 | setclass(macid("{checkMIMEHeaders}", NULL), "content-transfer-encoding"); |
---|
1226 | setclass(macid("{checkMIMEHeaders}", NULL), "content-type"); |
---|
1227 | setclass(macid("{checkMIMEHeaders}", NULL), "mime-version"); |
---|
1228 | #endif |
---|
1229 | |
---|
1230 | /* operate in queue directory */ |
---|
1231 | if (QueueDir == NULL) |
---|
1232 | { |
---|
1233 | if (OpMode != MD_TEST) |
---|
1234 | { |
---|
1235 | syserr("QueueDirectory (Q) option must be set"); |
---|
1236 | ExitStat = EX_CONFIG; |
---|
1237 | } |
---|
1238 | } |
---|
1239 | else |
---|
1240 | { |
---|
1241 | /* test path to get warning messages */ |
---|
1242 | (void) safedirpath(QueueDir, (uid_t) 0, (gid_t) 0, NULL, SFF_ANYFILE); |
---|
1243 | if (OpMode != MD_TEST && chdir(QueueDir) < 0) |
---|
1244 | { |
---|
1245 | syserr("cannot chdir(%s)", QueueDir); |
---|
1246 | ExitStat = EX_CONFIG; |
---|
1247 | } |
---|
1248 | } |
---|
1249 | |
---|
1250 | /* check host status directory for validity */ |
---|
1251 | if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE)) |
---|
1252 | { |
---|
1253 | /* cannot use this value */ |
---|
1254 | if (tTd(0, 2)) |
---|
1255 | printf("Cannot use HostStatusDirectory = %s: %s\n", |
---|
1256 | HostStatDir, errstring(errno)); |
---|
1257 | HostStatDir = NULL; |
---|
1258 | } |
---|
1259 | |
---|
1260 | # if QUEUE |
---|
1261 | if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) |
---|
1262 | { |
---|
1263 | struct stat stbuf; |
---|
1264 | |
---|
1265 | /* check to see if we own the queue directory */ |
---|
1266 | if (stat(".", &stbuf) < 0) |
---|
1267 | syserr("main: cannot stat %s", QueueDir); |
---|
1268 | if (stbuf.st_uid != RealUid) |
---|
1269 | { |
---|
1270 | /* nope, really a botch */ |
---|
1271 | usrerr("You do not have permission to process the queue"); |
---|
1272 | finis(FALSE, EX_NOPERM); |
---|
1273 | } |
---|
1274 | } |
---|
1275 | # endif /* QUEUE */ |
---|
1276 | |
---|
1277 | /* if we've had errors so far, exit now */ |
---|
1278 | if (ExitStat != EX_OK && OpMode != MD_TEST) |
---|
1279 | finis(FALSE, ExitStat); |
---|
1280 | |
---|
1281 | #if XDEBUG |
---|
1282 | checkfd012("before main() initmaps"); |
---|
1283 | #endif |
---|
1284 | |
---|
1285 | /* |
---|
1286 | ** Do operation-mode-dependent initialization. |
---|
1287 | */ |
---|
1288 | |
---|
1289 | switch (OpMode) |
---|
1290 | { |
---|
1291 | case MD_PRINT: |
---|
1292 | /* print the queue */ |
---|
1293 | #if QUEUE |
---|
1294 | dropenvelope(CurEnv, TRUE); |
---|
1295 | signal(SIGPIPE, quiesce); |
---|
1296 | printqueue(); |
---|
1297 | finis(FALSE, EX_OK); |
---|
1298 | #else /* QUEUE */ |
---|
1299 | usrerr("No queue to print"); |
---|
1300 | finis(FALSE, ExitStat); |
---|
1301 | #endif /* QUEUE */ |
---|
1302 | break; |
---|
1303 | |
---|
1304 | case MD_HOSTSTAT: |
---|
1305 | signal(SIGPIPE, quiesce); |
---|
1306 | mci_traverse_persistent(mci_print_persistent, NULL); |
---|
1307 | finis(FALSE, EX_OK); |
---|
1308 | break; |
---|
1309 | |
---|
1310 | case MD_PURGESTAT: |
---|
1311 | mci_traverse_persistent(mci_purge_persistent, NULL); |
---|
1312 | finis(FALSE, EX_OK); |
---|
1313 | break; |
---|
1314 | |
---|
1315 | case MD_INITALIAS: |
---|
1316 | /* initialize maps */ |
---|
1317 | initmaps(TRUE, CurEnv); |
---|
1318 | finis(FALSE, ExitStat); |
---|
1319 | break; |
---|
1320 | |
---|
1321 | case MD_SMTP: |
---|
1322 | case MD_DAEMON: |
---|
1323 | /* reset DSN parameters */ |
---|
1324 | DefaultNotify = QPINGONFAILURE|QPINGONDELAY; |
---|
1325 | CurEnv->e_envid = NULL; |
---|
1326 | CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); |
---|
1327 | |
---|
1328 | /* don't open maps for daemon -- done below in child */ |
---|
1329 | break; |
---|
1330 | |
---|
1331 | default: |
---|
1332 | /* open the maps */ |
---|
1333 | initmaps(FALSE, CurEnv); |
---|
1334 | break; |
---|
1335 | } |
---|
1336 | |
---|
1337 | if (tTd(0, 15)) |
---|
1338 | { |
---|
1339 | extern void printrules __P((void)); |
---|
1340 | |
---|
1341 | /* print configuration table (or at least part of it) */ |
---|
1342 | if (tTd(0, 90)) |
---|
1343 | printrules(); |
---|
1344 | for (i = 0; i < MAXMAILERS; i++) |
---|
1345 | { |
---|
1346 | if (Mailer[i] != NULL) |
---|
1347 | printmailer(Mailer[i]); |
---|
1348 | } |
---|
1349 | } |
---|
1350 | |
---|
1351 | /* |
---|
1352 | ** Switch to the main envelope. |
---|
1353 | */ |
---|
1354 | |
---|
1355 | CurEnv = newenvelope(&MainEnvelope, CurEnv); |
---|
1356 | MainEnvelope.e_flags = BlankEnvelope.e_flags; |
---|
1357 | |
---|
1358 | /* |
---|
1359 | ** If test mode, read addresses from stdin and process. |
---|
1360 | */ |
---|
1361 | |
---|
1362 | if (OpMode == MD_TEST) |
---|
1363 | { |
---|
1364 | char buf[MAXLINE]; |
---|
1365 | SIGFUNC_DECL intindebug __P((int)); |
---|
1366 | |
---|
1367 | if (isatty(fileno(stdin))) |
---|
1368 | Verbose = 2; |
---|
1369 | |
---|
1370 | if (Verbose) |
---|
1371 | { |
---|
1372 | printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n"); |
---|
1373 | printf("Enter <ruleset> <address>\n"); |
---|
1374 | } |
---|
1375 | if (setjmp(TopFrame) > 0) |
---|
1376 | printf("\n"); |
---|
1377 | (void) setsignal(SIGINT, intindebug); |
---|
1378 | for (;;) |
---|
1379 | { |
---|
1380 | extern void testmodeline __P((char *, ENVELOPE *)); |
---|
1381 | |
---|
1382 | if (Verbose == 2) |
---|
1383 | printf("> "); |
---|
1384 | (void) fflush(stdout); |
---|
1385 | if (fgets(buf, sizeof buf, stdin) == NULL) |
---|
1386 | finis(TRUE, ExitStat); |
---|
1387 | p = strchr(buf, '\n'); |
---|
1388 | if (p != NULL) |
---|
1389 | *p = '\0'; |
---|
1390 | if (Verbose < 2) |
---|
1391 | printf("> %s\n", buf); |
---|
1392 | testmodeline(buf, CurEnv); |
---|
1393 | } |
---|
1394 | } |
---|
1395 | |
---|
1396 | # if QUEUE |
---|
1397 | /* |
---|
1398 | ** If collecting stuff from the queue, go start doing that. |
---|
1399 | */ |
---|
1400 | |
---|
1401 | if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0) |
---|
1402 | { |
---|
1403 | (void) runqueue(FALSE, Verbose); |
---|
1404 | finis(TRUE, ExitStat); |
---|
1405 | } |
---|
1406 | # endif /* QUEUE */ |
---|
1407 | |
---|
1408 | /* |
---|
1409 | ** If a daemon, wait for a request. |
---|
1410 | ** getrequests will always return in a child. |
---|
1411 | ** If we should also be processing the queue, start |
---|
1412 | ** doing it in background. |
---|
1413 | ** We check for any errors that might have happened |
---|
1414 | ** during startup. |
---|
1415 | */ |
---|
1416 | |
---|
1417 | if (OpMode == MD_DAEMON || QueueIntvl != 0) |
---|
1418 | { |
---|
1419 | char dtype[200]; |
---|
1420 | extern void getrequests __P((ENVELOPE *)); |
---|
1421 | |
---|
1422 | if (!run_in_foreground && !tTd(99, 100)) |
---|
1423 | { |
---|
1424 | /* put us in background */ |
---|
1425 | i = fork(); |
---|
1426 | if (i < 0) |
---|
1427 | syserr("daemon: cannot fork"); |
---|
1428 | if (i != 0) |
---|
1429 | finis(FALSE, EX_OK); |
---|
1430 | |
---|
1431 | /* disconnect from our controlling tty */ |
---|
1432 | disconnect(2, CurEnv); |
---|
1433 | } |
---|
1434 | |
---|
1435 | dtype[0] = '\0'; |
---|
1436 | if (OpMode == MD_DAEMON) |
---|
1437 | strcat(dtype, "+SMTP"); |
---|
1438 | if (QueueIntvl != 0) |
---|
1439 | { |
---|
1440 | strcat(dtype, "+queueing@"); |
---|
1441 | strcat(dtype, pintvl(QueueIntvl, TRUE)); |
---|
1442 | } |
---|
1443 | if (tTd(0, 1)) |
---|
1444 | strcat(dtype, "+debugging"); |
---|
1445 | |
---|
1446 | sm_syslog(LOG_INFO, NOQID, |
---|
1447 | "starting daemon (%s): %s", Version, dtype + 1); |
---|
1448 | #ifdef XLA |
---|
1449 | xla_create_file(); |
---|
1450 | #endif |
---|
1451 | |
---|
1452 | # if QUEUE |
---|
1453 | if (queuemode) |
---|
1454 | { |
---|
1455 | (void) runqueue(TRUE, FALSE); |
---|
1456 | if (OpMode != MD_DAEMON) |
---|
1457 | { |
---|
1458 | for (;;) |
---|
1459 | { |
---|
1460 | pause(); |
---|
1461 | if (DoQueueRun) |
---|
1462 | (void) runqueue(TRUE, FALSE); |
---|
1463 | } |
---|
1464 | } |
---|
1465 | } |
---|
1466 | # endif /* QUEUE */ |
---|
1467 | dropenvelope(CurEnv, TRUE); |
---|
1468 | |
---|
1469 | #if DAEMON |
---|
1470 | getrequests(CurEnv); |
---|
1471 | |
---|
1472 | /* drop privileges */ |
---|
1473 | (void) drop_privileges(FALSE); |
---|
1474 | |
---|
1475 | /* at this point we are in a child: reset state */ |
---|
1476 | (void) newenvelope(CurEnv, CurEnv); |
---|
1477 | |
---|
1478 | /* |
---|
1479 | ** Get authentication data |
---|
1480 | */ |
---|
1481 | |
---|
1482 | p = getauthinfo(fileno(InChannel), &forged); |
---|
1483 | define('_', p, &BlankEnvelope); |
---|
1484 | #endif /* DAEMON */ |
---|
1485 | } |
---|
1486 | |
---|
1487 | # if SMTP |
---|
1488 | /* |
---|
1489 | ** If running SMTP protocol, start collecting and executing |
---|
1490 | ** commands. This will never return. |
---|
1491 | */ |
---|
1492 | |
---|
1493 | if (OpMode == MD_SMTP || OpMode == MD_DAEMON) |
---|
1494 | { |
---|
1495 | char pbuf[20]; |
---|
1496 | extern void smtp __P((char *, ENVELOPE *)); |
---|
1497 | |
---|
1498 | /* |
---|
1499 | ** Save some macros for check_* rulesets. |
---|
1500 | */ |
---|
1501 | |
---|
1502 | if (forged) |
---|
1503 | { |
---|
1504 | char ipbuf[103]; |
---|
1505 | |
---|
1506 | snprintf(ipbuf, sizeof ipbuf, "[%.100s]", |
---|
1507 | inet_ntoa(RealHostAddr.sin.sin_addr)); |
---|
1508 | |
---|
1509 | define(macid("{client_name}", NULL), |
---|
1510 | newstr(ipbuf), &BlankEnvelope); |
---|
1511 | } |
---|
1512 | else |
---|
1513 | define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope); |
---|
1514 | define(macid("{client_addr}", NULL), |
---|
1515 | newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); |
---|
1516 | if (RealHostAddr.sa.sa_family == AF_INET) |
---|
1517 | snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port); |
---|
1518 | else |
---|
1519 | snprintf(pbuf, sizeof pbuf, "0"); |
---|
1520 | define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); |
---|
1521 | |
---|
1522 | /* initialize maps now for check_relay ruleset */ |
---|
1523 | initmaps(FALSE, CurEnv); |
---|
1524 | |
---|
1525 | if (OpMode == MD_DAEMON) |
---|
1526 | { |
---|
1527 | /* validate the connection */ |
---|
1528 | HoldErrs = TRUE; |
---|
1529 | nullserver = validate_connection(&RealHostAddr, |
---|
1530 | RealHostName, CurEnv); |
---|
1531 | HoldErrs = FALSE; |
---|
1532 | } |
---|
1533 | smtp(nullserver, CurEnv); |
---|
1534 | } |
---|
1535 | # endif /* SMTP */ |
---|
1536 | |
---|
1537 | clearenvelope(CurEnv, FALSE); |
---|
1538 | if (OpMode == MD_VERIFY) |
---|
1539 | { |
---|
1540 | CurEnv->e_sendmode = SM_VERIFY; |
---|
1541 | PostMasterCopy = NULL; |
---|
1542 | } |
---|
1543 | else |
---|
1544 | { |
---|
1545 | /* interactive -- all errors are global */ |
---|
1546 | CurEnv->e_flags |= EF_GLOBALERRS|EF_LOGSENDER; |
---|
1547 | } |
---|
1548 | |
---|
1549 | /* |
---|
1550 | ** Do basic system initialization and set the sender |
---|
1551 | */ |
---|
1552 | |
---|
1553 | initsys(CurEnv); |
---|
1554 | if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't')) |
---|
1555 | auth_warning(CurEnv, "%s set sender to %s using -%c", |
---|
1556 | RealUserName, from, warn_f_flag); |
---|
1557 | setsender(from, CurEnv, NULL, '\0', FALSE); |
---|
1558 | if (macvalue('s', CurEnv) == NULL) |
---|
1559 | define('s', RealHostName, CurEnv); |
---|
1560 | |
---|
1561 | if (*av == NULL && !GrabTo) |
---|
1562 | { |
---|
1563 | CurEnv->e_flags |= EF_GLOBALERRS; |
---|
1564 | usrerr("Recipient names must be specified"); |
---|
1565 | |
---|
1566 | /* collect body for UUCP return */ |
---|
1567 | if (OpMode != MD_VERIFY) |
---|
1568 | collect(InChannel, FALSE, NULL, CurEnv); |
---|
1569 | finis(TRUE, ExitStat); |
---|
1570 | } |
---|
1571 | |
---|
1572 | /* |
---|
1573 | ** Scan argv and deliver the message to everyone. |
---|
1574 | */ |
---|
1575 | |
---|
1576 | sendtoargv(av, CurEnv); |
---|
1577 | |
---|
1578 | /* if we have had errors sofar, arrange a meaningful exit stat */ |
---|
1579 | if (Errors > 0 && ExitStat == EX_OK) |
---|
1580 | ExitStat = EX_USAGE; |
---|
1581 | |
---|
1582 | #if _FFR_FIX_DASHT |
---|
1583 | /* |
---|
1584 | ** If using -t, force not sending to argv recipients, even |
---|
1585 | ** if they are mentioned in the headers. |
---|
1586 | */ |
---|
1587 | |
---|
1588 | if (GrabTo) |
---|
1589 | { |
---|
1590 | ADDRESS *q; |
---|
1591 | |
---|
1592 | for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) |
---|
1593 | q->q_flags |= QDONTSEND; |
---|
1594 | } |
---|
1595 | #endif |
---|
1596 | |
---|
1597 | /* |
---|
1598 | ** Read the input mail. |
---|
1599 | */ |
---|
1600 | |
---|
1601 | CurEnv->e_to = NULL; |
---|
1602 | if (OpMode != MD_VERIFY || GrabTo) |
---|
1603 | { |
---|
1604 | long savedflags = CurEnv->e_flags & EF_FATALERRS; |
---|
1605 | |
---|
1606 | CurEnv->e_flags |= EF_GLOBALERRS; |
---|
1607 | CurEnv->e_flags &= ~EF_FATALERRS; |
---|
1608 | collect(InChannel, FALSE, NULL, CurEnv); |
---|
1609 | |
---|
1610 | /* bail out if message too large */ |
---|
1611 | if (bitset(EF_CLRQUEUE, CurEnv->e_flags)) |
---|
1612 | { |
---|
1613 | finis(TRUE, ExitStat); |
---|
1614 | /*NOTREACHED*/ |
---|
1615 | return -1; |
---|
1616 | } |
---|
1617 | CurEnv->e_flags |= savedflags; |
---|
1618 | } |
---|
1619 | errno = 0; |
---|
1620 | |
---|
1621 | if (tTd(1, 1)) |
---|
1622 | printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr); |
---|
1623 | |
---|
1624 | /* |
---|
1625 | ** Actually send everything. |
---|
1626 | ** If verifying, just ack. |
---|
1627 | */ |
---|
1628 | |
---|
1629 | CurEnv->e_from.q_flags |= QDONTSEND; |
---|
1630 | if (tTd(1, 5)) |
---|
1631 | { |
---|
1632 | printf("main: QDONTSEND "); |
---|
1633 | printaddr(&CurEnv->e_from, FALSE); |
---|
1634 | } |
---|
1635 | CurEnv->e_to = NULL; |
---|
1636 | CurrentLA = getla(); |
---|
1637 | GrabTo = FALSE; |
---|
1638 | sendall(CurEnv, SM_DEFAULT); |
---|
1639 | |
---|
1640 | /* |
---|
1641 | ** All done. |
---|
1642 | ** Don't send return error message if in VERIFY mode. |
---|
1643 | */ |
---|
1644 | |
---|
1645 | finis(TRUE, ExitStat); |
---|
1646 | /*NOTREACHED*/ |
---|
1647 | return -1; |
---|
1648 | } |
---|
1649 | |
---|
1650 | /* ARGSUSED */ |
---|
1651 | SIGFUNC_DECL |
---|
1652 | quiesce(sig) |
---|
1653 | int sig; |
---|
1654 | { |
---|
1655 | finis(FALSE, EX_OK); |
---|
1656 | } |
---|
1657 | |
---|
1658 | /* ARGSUSED */ |
---|
1659 | SIGFUNC_DECL |
---|
1660 | intindebug(sig) |
---|
1661 | int sig; |
---|
1662 | { |
---|
1663 | longjmp(TopFrame, 1); |
---|
1664 | return SIGFUNC_RETURN; |
---|
1665 | } |
---|
1666 | |
---|
1667 | |
---|
1668 | /* |
---|
1669 | ** FINIS -- Clean up and exit. |
---|
1670 | ** |
---|
1671 | ** Parameters: |
---|
1672 | ** drop -- whether or not to drop CurEnv envelope |
---|
1673 | ** exitstat -- exit status to use for exit() call |
---|
1674 | ** |
---|
1675 | ** Returns: |
---|
1676 | ** never |
---|
1677 | ** |
---|
1678 | ** Side Effects: |
---|
1679 | ** exits sendmail |
---|
1680 | */ |
---|
1681 | |
---|
1682 | void |
---|
1683 | finis(drop, exitstat) |
---|
1684 | bool drop; |
---|
1685 | volatile int exitstat; |
---|
1686 | { |
---|
1687 | extern void closemaps __P((void)); |
---|
1688 | #ifdef USERDB |
---|
1689 | extern void _udbx_close __P((void)); |
---|
1690 | #endif |
---|
1691 | |
---|
1692 | if (tTd(2, 1)) |
---|
1693 | { |
---|
1694 | extern void printenvflags __P((ENVELOPE *)); |
---|
1695 | |
---|
1696 | printf("\n====finis: stat %d e_id=%s e_flags=", |
---|
1697 | exitstat, |
---|
1698 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); |
---|
1699 | printenvflags(CurEnv); |
---|
1700 | } |
---|
1701 | if (tTd(2, 9)) |
---|
1702 | printopenfds(FALSE); |
---|
1703 | |
---|
1704 | /* if we fail in finis(), just exit */ |
---|
1705 | if (setjmp(TopFrame) != 0) |
---|
1706 | { |
---|
1707 | /* failed -- just give it up */ |
---|
1708 | goto forceexit; |
---|
1709 | } |
---|
1710 | |
---|
1711 | /* clean up temp files */ |
---|
1712 | CurEnv->e_to = NULL; |
---|
1713 | if (drop && CurEnv->e_id != NULL) |
---|
1714 | dropenvelope(CurEnv, TRUE); |
---|
1715 | |
---|
1716 | /* flush any cached connections */ |
---|
1717 | mci_flush(TRUE, NULL); |
---|
1718 | |
---|
1719 | /* close maps belonging to this pid */ |
---|
1720 | closemaps(); |
---|
1721 | |
---|
1722 | #ifdef USERDB |
---|
1723 | /* close UserDatabase */ |
---|
1724 | _udbx_close(); |
---|
1725 | #endif |
---|
1726 | |
---|
1727 | # ifdef XLA |
---|
1728 | /* clean up extended load average stuff */ |
---|
1729 | xla_all_end(); |
---|
1730 | # endif |
---|
1731 | |
---|
1732 | /* and exit */ |
---|
1733 | forceexit: |
---|
1734 | if (LogLevel > 78) |
---|
1735 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
1736 | "finis, pid=%d", |
---|
1737 | getpid()); |
---|
1738 | if (exitstat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) |
---|
1739 | exitstat = EX_OK; |
---|
1740 | |
---|
1741 | /* reset uid for process accounting */ |
---|
1742 | endpwent(); |
---|
1743 | setuid(RealUid); |
---|
1744 | |
---|
1745 | exit(exitstat); |
---|
1746 | } |
---|
1747 | /* |
---|
1748 | ** INTSIG -- clean up on interrupt |
---|
1749 | ** |
---|
1750 | ** This just arranges to exit. It pessimises in that it |
---|
1751 | ** may resend a message. |
---|
1752 | ** |
---|
1753 | ** Parameters: |
---|
1754 | ** none. |
---|
1755 | ** |
---|
1756 | ** Returns: |
---|
1757 | ** none. |
---|
1758 | ** |
---|
1759 | ** Side Effects: |
---|
1760 | ** Unlocks the current job. |
---|
1761 | */ |
---|
1762 | |
---|
1763 | /* ARGSUSED */ |
---|
1764 | SIGFUNC_DECL |
---|
1765 | intsig(sig) |
---|
1766 | int sig; |
---|
1767 | { |
---|
1768 | if (LogLevel > 79) |
---|
1769 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt"); |
---|
1770 | FileName = NULL; |
---|
1771 | unlockqueue(CurEnv); |
---|
1772 | closecontrolsocket(TRUE); |
---|
1773 | #ifdef XLA |
---|
1774 | xla_all_end(); |
---|
1775 | #endif |
---|
1776 | finis(FALSE, EX_OK); |
---|
1777 | } |
---|
1778 | /* |
---|
1779 | ** INITMACROS -- initialize the macro system |
---|
1780 | ** |
---|
1781 | ** This just involves defining some macros that are actually |
---|
1782 | ** used internally as metasymbols to be themselves. |
---|
1783 | ** |
---|
1784 | ** Parameters: |
---|
1785 | ** none. |
---|
1786 | ** |
---|
1787 | ** Returns: |
---|
1788 | ** none. |
---|
1789 | ** |
---|
1790 | ** Side Effects: |
---|
1791 | ** initializes several macros to be themselves. |
---|
1792 | */ |
---|
1793 | |
---|
1794 | struct metamac MetaMacros[] = |
---|
1795 | { |
---|
1796 | /* LHS pattern matching characters */ |
---|
1797 | { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE }, |
---|
1798 | { '=', MATCHCLASS }, { '~', MATCHNCLASS }, |
---|
1799 | |
---|
1800 | /* these are RHS metasymbols */ |
---|
1801 | { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER }, |
---|
1802 | { '>', CALLSUBR }, |
---|
1803 | |
---|
1804 | /* the conditional operations */ |
---|
1805 | { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI }, |
---|
1806 | |
---|
1807 | /* the hostname lookup characters */ |
---|
1808 | { '[', HOSTBEGIN }, { ']', HOSTEND }, |
---|
1809 | { '(', LOOKUPBEGIN }, { ')', LOOKUPEND }, |
---|
1810 | |
---|
1811 | /* miscellaneous control characters */ |
---|
1812 | { '&', MACRODEXPAND }, |
---|
1813 | |
---|
1814 | { '\0' } |
---|
1815 | }; |
---|
1816 | |
---|
1817 | #define MACBINDING(name, mid) \ |
---|
1818 | stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \ |
---|
1819 | MacroName[mid] = name; |
---|
1820 | |
---|
1821 | void |
---|
1822 | initmacros(e) |
---|
1823 | register ENVELOPE *e; |
---|
1824 | { |
---|
1825 | register struct metamac *m; |
---|
1826 | register int c; |
---|
1827 | char buf[5]; |
---|
1828 | extern char *MacroName[256]; |
---|
1829 | |
---|
1830 | for (m = MetaMacros; m->metaname != '\0'; m++) |
---|
1831 | { |
---|
1832 | buf[0] = m->metaval; |
---|
1833 | buf[1] = '\0'; |
---|
1834 | define(m->metaname, newstr(buf), e); |
---|
1835 | } |
---|
1836 | buf[0] = MATCHREPL; |
---|
1837 | buf[2] = '\0'; |
---|
1838 | for (c = '0'; c <= '9'; c++) |
---|
1839 | { |
---|
1840 | buf[1] = c; |
---|
1841 | define(c, newstr(buf), e); |
---|
1842 | } |
---|
1843 | |
---|
1844 | /* set defaults for some macros sendmail will use later */ |
---|
1845 | define('n', "MAILER-DAEMON", e); |
---|
1846 | |
---|
1847 | /* set up external names for some internal macros */ |
---|
1848 | MACBINDING("opMode", MID_OPMODE); |
---|
1849 | /*XXX should probably add equivalents for all short macros here XXX*/ |
---|
1850 | } |
---|
1851 | /* |
---|
1852 | ** DISCONNECT -- remove our connection with any foreground process |
---|
1853 | ** |
---|
1854 | ** Parameters: |
---|
1855 | ** droplev -- how "deeply" we should drop the line. |
---|
1856 | ** 0 -- ignore signals, mail back errors, make sure |
---|
1857 | ** output goes to stdout. |
---|
1858 | ** 1 -- also, make stdout go to transcript. |
---|
1859 | ** 2 -- also, disconnect from controlling terminal |
---|
1860 | ** (only for daemon mode). |
---|
1861 | ** e -- the current envelope. |
---|
1862 | ** |
---|
1863 | ** Returns: |
---|
1864 | ** none |
---|
1865 | ** |
---|
1866 | ** Side Effects: |
---|
1867 | ** Trys to insure that we are immune to vagaries of |
---|
1868 | ** the controlling tty. |
---|
1869 | */ |
---|
1870 | |
---|
1871 | void |
---|
1872 | disconnect(droplev, e) |
---|
1873 | int droplev; |
---|
1874 | register ENVELOPE *e; |
---|
1875 | { |
---|
1876 | int fd; |
---|
1877 | |
---|
1878 | if (tTd(52, 1)) |
---|
1879 | printf("disconnect: In %d Out %d, e=%lx\n", |
---|
1880 | fileno(InChannel), fileno(OutChannel), (u_long) e); |
---|
1881 | if (tTd(52, 100)) |
---|
1882 | { |
---|
1883 | printf("don't\n"); |
---|
1884 | return; |
---|
1885 | } |
---|
1886 | if (LogLevel > 93) |
---|
1887 | sm_syslog(LOG_DEBUG, e->e_id, |
---|
1888 | "disconnect level %d", |
---|
1889 | droplev); |
---|
1890 | |
---|
1891 | /* be sure we don't get nasty signals */ |
---|
1892 | (void) setsignal(SIGINT, SIG_IGN); |
---|
1893 | (void) setsignal(SIGQUIT, SIG_IGN); |
---|
1894 | |
---|
1895 | /* we can't communicate with our caller, so.... */ |
---|
1896 | HoldErrs = TRUE; |
---|
1897 | CurEnv->e_errormode = EM_MAIL; |
---|
1898 | Verbose = 0; |
---|
1899 | DisConnected = TRUE; |
---|
1900 | |
---|
1901 | /* all input from /dev/null */ |
---|
1902 | if (InChannel != stdin) |
---|
1903 | { |
---|
1904 | (void) fclose(InChannel); |
---|
1905 | InChannel = stdin; |
---|
1906 | } |
---|
1907 | if (freopen("/dev/null", "r", stdin) == NULL) |
---|
1908 | sm_syslog(LOG_ERR, e->e_id, |
---|
1909 | "disconnect: freopen(\"/dev/null\") failed: %s", |
---|
1910 | errstring(errno)); |
---|
1911 | |
---|
1912 | /* output to the transcript */ |
---|
1913 | if (OutChannel != stdout) |
---|
1914 | { |
---|
1915 | (void) fclose(OutChannel); |
---|
1916 | OutChannel = stdout; |
---|
1917 | } |
---|
1918 | if (droplev > 0) |
---|
1919 | { |
---|
1920 | if (e->e_xfp == NULL) |
---|
1921 | { |
---|
1922 | fd = open("/dev/null", O_WRONLY, 0666); |
---|
1923 | if (fd == -1) |
---|
1924 | sm_syslog(LOG_ERR, e->e_id, |
---|
1925 | "disconnect: open(\"/dev/null\") failed: %s", |
---|
1926 | errstring(errno)); |
---|
1927 | } |
---|
1928 | else |
---|
1929 | { |
---|
1930 | fd = fileno(e->e_xfp); |
---|
1931 | if (fd == -1) |
---|
1932 | sm_syslog(LOG_ERR, e->e_id, |
---|
1933 | "disconnect: fileno(e->e_xfp) failed: %s", |
---|
1934 | errstring(errno)); |
---|
1935 | } |
---|
1936 | (void) fflush(stdout); |
---|
1937 | dup2(fd, STDOUT_FILENO); |
---|
1938 | dup2(fd, STDERR_FILENO); |
---|
1939 | if (e->e_xfp == NULL) |
---|
1940 | close(fd); |
---|
1941 | } |
---|
1942 | |
---|
1943 | /* drop our controlling TTY completely if possible */ |
---|
1944 | if (droplev > 1) |
---|
1945 | { |
---|
1946 | (void) setsid(); |
---|
1947 | errno = 0; |
---|
1948 | } |
---|
1949 | |
---|
1950 | #if XDEBUG |
---|
1951 | checkfd012("disconnect"); |
---|
1952 | #endif |
---|
1953 | |
---|
1954 | if (LogLevel > 71) |
---|
1955 | sm_syslog(LOG_DEBUG, e->e_id, |
---|
1956 | "in background, pid=%d", |
---|
1957 | getpid()); |
---|
1958 | |
---|
1959 | errno = 0; |
---|
1960 | } |
---|
1961 | |
---|
1962 | static void |
---|
1963 | obsolete(argv) |
---|
1964 | char *argv[]; |
---|
1965 | { |
---|
1966 | register char *ap; |
---|
1967 | register char *op; |
---|
1968 | |
---|
1969 | while ((ap = *++argv) != NULL) |
---|
1970 | { |
---|
1971 | /* Return if "--" or not an option of any form. */ |
---|
1972 | if (ap[0] != '-' || ap[1] == '-') |
---|
1973 | return; |
---|
1974 | |
---|
1975 | /* skip over options that do have a value */ |
---|
1976 | op = strchr(OPTIONS, ap[1]); |
---|
1977 | if (op != NULL && *++op == ':' && ap[2] == '\0' && |
---|
1978 | ap[1] != 'd' && |
---|
1979 | #if defined(sony_news) |
---|
1980 | ap[1] != 'E' && ap[1] != 'J' && |
---|
1981 | #endif |
---|
1982 | argv[1] != NULL && argv[1][0] != '-') |
---|
1983 | { |
---|
1984 | argv++; |
---|
1985 | continue; |
---|
1986 | } |
---|
1987 | |
---|
1988 | /* If -C doesn't have an argument, use sendmail.cf. */ |
---|
1989 | #define __DEFPATH "sendmail.cf" |
---|
1990 | if (ap[1] == 'C' && ap[2] == '\0') |
---|
1991 | { |
---|
1992 | *argv = xalloc(sizeof(__DEFPATH) + 2); |
---|
1993 | argv[0][0] = '-'; |
---|
1994 | argv[0][1] = 'C'; |
---|
1995 | (void)strcpy(&argv[0][2], __DEFPATH); |
---|
1996 | } |
---|
1997 | |
---|
1998 | /* If -q doesn't have an argument, run it once. */ |
---|
1999 | if (ap[1] == 'q' && ap[2] == '\0') |
---|
2000 | *argv = "-q0"; |
---|
2001 | |
---|
2002 | /* if -d doesn't have an argument, use 0-99.1 */ |
---|
2003 | if (ap[1] == 'd' && ap[2] == '\0') |
---|
2004 | *argv = "-d0-99.1"; |
---|
2005 | |
---|
2006 | # if defined(sony_news) |
---|
2007 | /* if -E doesn't have an argument, use -EC */ |
---|
2008 | if (ap[1] == 'E' && ap[2] == '\0') |
---|
2009 | *argv = "-EC"; |
---|
2010 | |
---|
2011 | /* if -J doesn't have an argument, use -JJ */ |
---|
2012 | if (ap[1] == 'J' && ap[2] == '\0') |
---|
2013 | *argv = "-JJ"; |
---|
2014 | # endif |
---|
2015 | } |
---|
2016 | } |
---|
2017 | /* |
---|
2018 | ** AUTH_WARNING -- specify authorization warning |
---|
2019 | ** |
---|
2020 | ** Parameters: |
---|
2021 | ** e -- the current envelope. |
---|
2022 | ** msg -- the text of the message. |
---|
2023 | ** args -- arguments to the message. |
---|
2024 | ** |
---|
2025 | ** Returns: |
---|
2026 | ** none. |
---|
2027 | */ |
---|
2028 | |
---|
2029 | void |
---|
2030 | #ifdef __STDC__ |
---|
2031 | auth_warning(register ENVELOPE *e, const char *msg, ...) |
---|
2032 | #else |
---|
2033 | auth_warning(e, msg, va_alist) |
---|
2034 | register ENVELOPE *e; |
---|
2035 | const char *msg; |
---|
2036 | va_dcl |
---|
2037 | #endif |
---|
2038 | { |
---|
2039 | char buf[MAXLINE]; |
---|
2040 | VA_LOCAL_DECL |
---|
2041 | |
---|
2042 | if (bitset(PRIV_AUTHWARNINGS, PrivacyFlags)) |
---|
2043 | { |
---|
2044 | register char *p; |
---|
2045 | static char hostbuf[48]; |
---|
2046 | extern struct hostent *myhostname __P((char *, int)); |
---|
2047 | |
---|
2048 | if (hostbuf[0] == '\0') |
---|
2049 | (void) myhostname(hostbuf, sizeof hostbuf); |
---|
2050 | |
---|
2051 | (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); |
---|
2052 | p = &buf[strlen(buf)]; |
---|
2053 | VA_START(msg); |
---|
2054 | vsnprintf(p, SPACELEFT(buf, p), msg, ap); |
---|
2055 | VA_END; |
---|
2056 | addheader("X-Authentication-Warning", buf, &e->e_header); |
---|
2057 | if (LogLevel > 3) |
---|
2058 | sm_syslog(LOG_INFO, e->e_id, |
---|
2059 | "Authentication-Warning: %.400s", |
---|
2060 | buf); |
---|
2061 | } |
---|
2062 | } |
---|
2063 | /* |
---|
2064 | ** GETEXTENV -- get from external environment |
---|
2065 | ** |
---|
2066 | ** Parameters: |
---|
2067 | ** envar -- the name of the variable to retrieve |
---|
2068 | ** |
---|
2069 | ** Returns: |
---|
2070 | ** The value, if any. |
---|
2071 | */ |
---|
2072 | |
---|
2073 | char * |
---|
2074 | getextenv(envar) |
---|
2075 | const char *envar; |
---|
2076 | { |
---|
2077 | char **envp; |
---|
2078 | int l; |
---|
2079 | |
---|
2080 | l = strlen(envar); |
---|
2081 | for (envp = ExternalEnviron; *envp != NULL; envp++) |
---|
2082 | { |
---|
2083 | if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') |
---|
2084 | return &(*envp)[l + 1]; |
---|
2085 | } |
---|
2086 | return NULL; |
---|
2087 | } |
---|
2088 | /* |
---|
2089 | ** SETUSERENV -- set an environment in the propogated environment |
---|
2090 | ** |
---|
2091 | ** Parameters: |
---|
2092 | ** envar -- the name of the environment variable. |
---|
2093 | ** value -- the value to which it should be set. If |
---|
2094 | ** null, this is extracted from the incoming |
---|
2095 | ** environment. If that is not set, the call |
---|
2096 | ** to setuserenv is ignored. |
---|
2097 | ** |
---|
2098 | ** Returns: |
---|
2099 | ** none. |
---|
2100 | */ |
---|
2101 | |
---|
2102 | void |
---|
2103 | setuserenv(envar, value) |
---|
2104 | const char *envar; |
---|
2105 | const char *value; |
---|
2106 | { |
---|
2107 | int i; |
---|
2108 | char **evp = UserEnviron; |
---|
2109 | char *p; |
---|
2110 | |
---|
2111 | if (value == NULL) |
---|
2112 | { |
---|
2113 | value = getextenv(envar); |
---|
2114 | if (value == NULL) |
---|
2115 | return; |
---|
2116 | } |
---|
2117 | |
---|
2118 | i = strlen(envar); |
---|
2119 | p = (char *) xalloc(strlen(value) + i + 2); |
---|
2120 | strcpy(p, envar); |
---|
2121 | p[i++] = '='; |
---|
2122 | strcpy(&p[i], value); |
---|
2123 | |
---|
2124 | while (*evp != NULL && strncmp(*evp, p, i) != 0) |
---|
2125 | evp++; |
---|
2126 | if (*evp != NULL) |
---|
2127 | { |
---|
2128 | *evp++ = p; |
---|
2129 | } |
---|
2130 | else if (evp < &UserEnviron[MAXUSERENVIRON]) |
---|
2131 | { |
---|
2132 | *evp++ = p; |
---|
2133 | *evp = NULL; |
---|
2134 | } |
---|
2135 | |
---|
2136 | /* make sure it is in our environment as well */ |
---|
2137 | if (putenv(p) < 0) |
---|
2138 | syserr("setuserenv: putenv(%s) failed", p); |
---|
2139 | } |
---|
2140 | /* |
---|
2141 | ** DUMPSTATE -- dump state |
---|
2142 | ** |
---|
2143 | ** For debugging. |
---|
2144 | */ |
---|
2145 | |
---|
2146 | void |
---|
2147 | dumpstate(when) |
---|
2148 | char *when; |
---|
2149 | { |
---|
2150 | register char *j = macvalue('j', CurEnv); |
---|
2151 | int rs; |
---|
2152 | |
---|
2153 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
2154 | "--- dumping state on %s: $j = %s ---", |
---|
2155 | when, |
---|
2156 | j == NULL ? "<NULL>" : j); |
---|
2157 | if (j != NULL) |
---|
2158 | { |
---|
2159 | if (!wordinclass(j, 'w')) |
---|
2160 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
2161 | "*** $j not in $=w ***"); |
---|
2162 | } |
---|
2163 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "CurChildren = %d", CurChildren); |
---|
2164 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- open file descriptors: ---"); |
---|
2165 | printopenfds(TRUE); |
---|
2166 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- connection cache: ---"); |
---|
2167 | mci_dump_all(TRUE); |
---|
2168 | rs = strtorwset("debug_dumpstate", NULL, ST_FIND); |
---|
2169 | if (rs > 0) |
---|
2170 | { |
---|
2171 | int stat; |
---|
2172 | register char **pvp; |
---|
2173 | char *pv[MAXATOM + 1]; |
---|
2174 | |
---|
2175 | pv[0] = NULL; |
---|
2176 | stat = rewrite(pv, rs, 0, CurEnv); |
---|
2177 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
2178 | "--- ruleset debug_dumpstate returns stat %d, pv: ---", |
---|
2179 | stat); |
---|
2180 | for (pvp = pv; *pvp != NULL; pvp++) |
---|
2181 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s", *pvp); |
---|
2182 | } |
---|
2183 | sm_syslog(LOG_DEBUG, CurEnv->e_id, "--- end of state dump ---"); |
---|
2184 | } |
---|
2185 | |
---|
2186 | |
---|
2187 | /* ARGSUSED */ |
---|
2188 | SIGFUNC_DECL |
---|
2189 | sigusr1(sig) |
---|
2190 | int sig; |
---|
2191 | { |
---|
2192 | dumpstate("user signal"); |
---|
2193 | return SIGFUNC_RETURN; |
---|
2194 | } |
---|
2195 | |
---|
2196 | |
---|
2197 | /* ARGSUSED */ |
---|
2198 | SIGFUNC_DECL |
---|
2199 | sighup(sig) |
---|
2200 | int sig; |
---|
2201 | { |
---|
2202 | if (SaveArgv[0][0] != '/') |
---|
2203 | { |
---|
2204 | if (LogLevel > 3) |
---|
2205 | sm_syslog(LOG_INFO, NOQID, "could not restart: need full path"); |
---|
2206 | finis(FALSE, EX_OSFILE); |
---|
2207 | } |
---|
2208 | if (LogLevel > 3) |
---|
2209 | sm_syslog(LOG_INFO, NOQID, "restarting %s on signal", SaveArgv[0]); |
---|
2210 | alarm(0); |
---|
2211 | releasesignal(SIGHUP); |
---|
2212 | closecontrolsocket(TRUE); |
---|
2213 | if (drop_privileges(TRUE) != EX_OK) |
---|
2214 | { |
---|
2215 | if (LogLevel > 0) |
---|
2216 | sm_syslog(LOG_ALERT, NOQID, "could not set[ug]id(%d, %d): %m", |
---|
2217 | RunAsUid, RunAsGid); |
---|
2218 | finis(FALSE, EX_OSERR); |
---|
2219 | } |
---|
2220 | execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); |
---|
2221 | if (LogLevel > 0) |
---|
2222 | sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m", SaveArgv[0]); |
---|
2223 | finis(FALSE, EX_OSFILE); |
---|
2224 | } |
---|
2225 | /* |
---|
2226 | ** DROP_PRIVILEGES -- reduce privileges to those of the RunAsUser option |
---|
2227 | ** |
---|
2228 | ** Parameters: |
---|
2229 | ** to_real_uid -- if set, drop to the real uid instead |
---|
2230 | ** of the RunAsUser. |
---|
2231 | ** |
---|
2232 | ** Returns: |
---|
2233 | ** EX_OSERR if the setuid failed. |
---|
2234 | ** EX_OK otherwise. |
---|
2235 | */ |
---|
2236 | |
---|
2237 | int |
---|
2238 | drop_privileges(to_real_uid) |
---|
2239 | bool to_real_uid; |
---|
2240 | { |
---|
2241 | int rval = EX_OK; |
---|
2242 | GIDSET_T emptygidset[1]; |
---|
2243 | |
---|
2244 | if (tTd(47, 1)) |
---|
2245 | printf("drop_privileges(%d): Real[UG]id=%d:%d, RunAs[UG]id=%d:%d\n", |
---|
2246 | (int)to_real_uid, (int)RealUid, (int)RealGid, (int)RunAsUid, (int)RunAsGid); |
---|
2247 | |
---|
2248 | if (to_real_uid) |
---|
2249 | { |
---|
2250 | RunAsUserName = RealUserName; |
---|
2251 | RunAsUid = RealUid; |
---|
2252 | RunAsGid = RealGid; |
---|
2253 | } |
---|
2254 | |
---|
2255 | /* make sure no one can grab open descriptors for secret files */ |
---|
2256 | endpwent(); |
---|
2257 | |
---|
2258 | /* reset group permissions; these can be set later */ |
---|
2259 | emptygidset[0] = (to_real_uid || RunAsGid != 0) ? RunAsGid : getegid(); |
---|
2260 | if (setgroups(1, emptygidset) == -1 && geteuid() == 0) |
---|
2261 | rval = EX_OSERR; |
---|
2262 | |
---|
2263 | /* reset primary group and user id */ |
---|
2264 | if ((to_real_uid || RunAsGid != 0) && setgid(RunAsGid) < 0) |
---|
2265 | rval = EX_OSERR; |
---|
2266 | if ((to_real_uid || RunAsUid != 0) && setuid(RunAsUid) < 0) |
---|
2267 | rval = EX_OSERR; |
---|
2268 | if (tTd(47, 5)) |
---|
2269 | { |
---|
2270 | printf("drop_privileges: e/ruid = %d/%d e/rgid = %d/%d\n", |
---|
2271 | (int)geteuid(), (int)getuid(), (int)getegid(), (int)getgid()); |
---|
2272 | printf("drop_privileges: RunAsUser = %d:%d\n", (int)RunAsUid, (int)RunAsGid); |
---|
2273 | } |
---|
2274 | return rval; |
---|
2275 | } |
---|
2276 | /* |
---|
2277 | ** FILL_FD -- make sure a file descriptor has been properly allocated |
---|
2278 | ** |
---|
2279 | ** Used to make sure that stdin/out/err are allocated on startup |
---|
2280 | ** |
---|
2281 | ** Parameters: |
---|
2282 | ** fd -- the file descriptor to be filled. |
---|
2283 | ** where -- a string used for logging. If NULL, this is |
---|
2284 | ** being called on startup, and logging should |
---|
2285 | ** not be done. |
---|
2286 | ** |
---|
2287 | ** Returns: |
---|
2288 | ** none |
---|
2289 | */ |
---|
2290 | |
---|
2291 | void |
---|
2292 | fill_fd(fd, where) |
---|
2293 | int fd; |
---|
2294 | char *where; |
---|
2295 | { |
---|
2296 | int i; |
---|
2297 | struct stat stbuf; |
---|
2298 | |
---|
2299 | if (fstat(fd, &stbuf) >= 0 || errno != EBADF) |
---|
2300 | return; |
---|
2301 | |
---|
2302 | if (where != NULL) |
---|
2303 | syserr("fill_fd: %s: fd %d not open", where, fd); |
---|
2304 | else |
---|
2305 | MissingFds |= 1 << fd; |
---|
2306 | i = open("/dev/null", fd == 0 ? O_RDONLY : O_WRONLY, 0666); |
---|
2307 | if (i < 0) |
---|
2308 | { |
---|
2309 | syserr("!fill_fd: %s: cannot open /dev/null", |
---|
2310 | where == NULL ? "startup" : where); |
---|
2311 | } |
---|
2312 | if (fd != i) |
---|
2313 | { |
---|
2314 | (void) dup2(i, fd); |
---|
2315 | (void) close(i); |
---|
2316 | } |
---|
2317 | } |
---|
2318 | /* |
---|
2319 | ** TESTMODELINE -- process a test mode input line |
---|
2320 | ** |
---|
2321 | ** Parameters: |
---|
2322 | ** line -- the input line. |
---|
2323 | ** e -- the current environment. |
---|
2324 | ** Syntax: |
---|
2325 | ** # a comment |
---|
2326 | ** .X process X as a configuration line |
---|
2327 | ** =X dump a configuration item (such as mailers) |
---|
2328 | ** $X dump a macro or class |
---|
2329 | ** /X try an activity |
---|
2330 | ** X normal process through rule set X |
---|
2331 | */ |
---|
2332 | |
---|
2333 | void |
---|
2334 | testmodeline(line, e) |
---|
2335 | char *line; |
---|
2336 | ENVELOPE *e; |
---|
2337 | { |
---|
2338 | register char *p; |
---|
2339 | char *q; |
---|
2340 | auto char *delimptr; |
---|
2341 | int mid; |
---|
2342 | int i, rs; |
---|
2343 | STAB *map; |
---|
2344 | char **s; |
---|
2345 | struct rewrite *rw; |
---|
2346 | ADDRESS a; |
---|
2347 | static int tryflags = RF_COPYNONE; |
---|
2348 | char exbuf[MAXLINE]; |
---|
2349 | extern bool invalidaddr __P((char *, char *)); |
---|
2350 | extern char *crackaddr __P((char *)); |
---|
2351 | extern void dump_class __P((STAB *, int)); |
---|
2352 | extern void translate_dollars __P((char *)); |
---|
2353 | extern void help __P((char *)); |
---|
2354 | |
---|
2355 | switch (line[0]) |
---|
2356 | { |
---|
2357 | case '#': |
---|
2358 | case 0: |
---|
2359 | return; |
---|
2360 | |
---|
2361 | case '?': |
---|
2362 | help("-bt"); |
---|
2363 | return; |
---|
2364 | |
---|
2365 | case '.': /* config-style settings */ |
---|
2366 | switch (line[1]) |
---|
2367 | { |
---|
2368 | case 'D': |
---|
2369 | mid = macid(&line[2], &delimptr); |
---|
2370 | if (mid == '\0') |
---|
2371 | return; |
---|
2372 | translate_dollars(delimptr); |
---|
2373 | define(mid, newstr(delimptr), e); |
---|
2374 | break; |
---|
2375 | |
---|
2376 | case 'C': |
---|
2377 | if (line[2] == '\0') /* not to call syserr() */ |
---|
2378 | return; |
---|
2379 | |
---|
2380 | mid = macid(&line[2], &delimptr); |
---|
2381 | if (mid == '\0') |
---|
2382 | return; |
---|
2383 | translate_dollars(delimptr); |
---|
2384 | expand(delimptr, exbuf, sizeof exbuf, e); |
---|
2385 | p = exbuf; |
---|
2386 | while (*p != '\0') |
---|
2387 | { |
---|
2388 | register char *wd; |
---|
2389 | char delim; |
---|
2390 | |
---|
2391 | while (*p != '\0' && isascii(*p) && isspace(*p)) |
---|
2392 | p++; |
---|
2393 | wd = p; |
---|
2394 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
2395 | p++; |
---|
2396 | delim = *p; |
---|
2397 | *p = '\0'; |
---|
2398 | if (wd[0] != '\0') |
---|
2399 | setclass(mid, wd); |
---|
2400 | *p = delim; |
---|
2401 | } |
---|
2402 | break; |
---|
2403 | |
---|
2404 | case '\0': |
---|
2405 | printf("Usage: .[DC]macro value(s)\n"); |
---|
2406 | break; |
---|
2407 | |
---|
2408 | default: |
---|
2409 | printf("Unknown \".\" command %s\n", line); |
---|
2410 | break; |
---|
2411 | } |
---|
2412 | return; |
---|
2413 | |
---|
2414 | case '=': /* config-style settings */ |
---|
2415 | switch (line[1]) |
---|
2416 | { |
---|
2417 | case 'S': /* dump rule set */ |
---|
2418 | rs = strtorwset(&line[2], NULL, ST_FIND); |
---|
2419 | if (rs < 0) |
---|
2420 | { |
---|
2421 | printf("Undefined ruleset %s\n", &line[2]); |
---|
2422 | return; |
---|
2423 | } |
---|
2424 | rw = RewriteRules[rs]; |
---|
2425 | if (rw == NULL) |
---|
2426 | return; |
---|
2427 | do |
---|
2428 | { |
---|
2429 | putchar('R'); |
---|
2430 | s = rw->r_lhs; |
---|
2431 | while (*s != NULL) |
---|
2432 | { |
---|
2433 | xputs(*s++); |
---|
2434 | putchar(' '); |
---|
2435 | } |
---|
2436 | putchar('\t'); |
---|
2437 | putchar('\t'); |
---|
2438 | s = rw->r_rhs; |
---|
2439 | while (*s != NULL) |
---|
2440 | { |
---|
2441 | xputs(*s++); |
---|
2442 | putchar(' '); |
---|
2443 | } |
---|
2444 | putchar('\n'); |
---|
2445 | } while ((rw = rw->r_next) != NULL); |
---|
2446 | break; |
---|
2447 | |
---|
2448 | case 'M': |
---|
2449 | for (i = 0; i < MAXMAILERS; i++) |
---|
2450 | { |
---|
2451 | if (Mailer[i] != NULL) |
---|
2452 | printmailer(Mailer[i]); |
---|
2453 | } |
---|
2454 | break; |
---|
2455 | |
---|
2456 | case '\0': |
---|
2457 | printf("Usage: =Sruleset or =M\n"); |
---|
2458 | break; |
---|
2459 | |
---|
2460 | default: |
---|
2461 | printf("Unknown \"=\" command %s\n", line); |
---|
2462 | break; |
---|
2463 | } |
---|
2464 | return; |
---|
2465 | |
---|
2466 | case '-': /* set command-line-like opts */ |
---|
2467 | switch (line[1]) |
---|
2468 | { |
---|
2469 | case 'd': |
---|
2470 | tTflag(&line[2]); |
---|
2471 | break; |
---|
2472 | |
---|
2473 | case '\0': |
---|
2474 | printf("Usage: -d{debug arguments}\n"); |
---|
2475 | break; |
---|
2476 | |
---|
2477 | default: |
---|
2478 | printf("Unknown \"-\" command %s\n", line); |
---|
2479 | break; |
---|
2480 | } |
---|
2481 | return; |
---|
2482 | |
---|
2483 | case '$': |
---|
2484 | if (line[1] == '=') |
---|
2485 | { |
---|
2486 | mid = macid(&line[2], NULL); |
---|
2487 | if (mid != '\0') |
---|
2488 | stabapply(dump_class, mid); |
---|
2489 | return; |
---|
2490 | } |
---|
2491 | mid = macid(&line[1], NULL); |
---|
2492 | if (mid == '\0') |
---|
2493 | return; |
---|
2494 | p = macvalue(mid, e); |
---|
2495 | if (p == NULL) |
---|
2496 | printf("Undefined\n"); |
---|
2497 | else |
---|
2498 | { |
---|
2499 | xputs(p); |
---|
2500 | printf("\n"); |
---|
2501 | } |
---|
2502 | return; |
---|
2503 | |
---|
2504 | case '/': /* miscellaneous commands */ |
---|
2505 | p = &line[strlen(line)]; |
---|
2506 | while (--p >= line && isascii(*p) && isspace(*p)) |
---|
2507 | *p = '\0'; |
---|
2508 | p = strpbrk(line, " \t"); |
---|
2509 | if (p != NULL) |
---|
2510 | { |
---|
2511 | while (isascii(*p) && isspace(*p)) |
---|
2512 | *p++ = '\0'; |
---|
2513 | } |
---|
2514 | else |
---|
2515 | p = ""; |
---|
2516 | if (line[1] == '\0') |
---|
2517 | { |
---|
2518 | printf("Usage: /[canon|map|mx|parse|try|tryflags]\n"); |
---|
2519 | return; |
---|
2520 | } |
---|
2521 | if (strcasecmp(&line[1], "mx") == 0) |
---|
2522 | { |
---|
2523 | #if NAMED_BIND |
---|
2524 | /* look up MX records */ |
---|
2525 | int nmx; |
---|
2526 | auto int rcode; |
---|
2527 | char *mxhosts[MAXMXHOSTS + 1]; |
---|
2528 | |
---|
2529 | if (*p == '\0') |
---|
2530 | { |
---|
2531 | printf("Usage: /mx address\n"); |
---|
2532 | return; |
---|
2533 | } |
---|
2534 | nmx = getmxrr(p, mxhosts, FALSE, &rcode); |
---|
2535 | printf("getmxrr(%s) returns %d value(s):\n", p, nmx); |
---|
2536 | for (i = 0; i < nmx; i++) |
---|
2537 | printf("\t%s\n", mxhosts[i]); |
---|
2538 | #else |
---|
2539 | printf("No MX code compiled in\n"); |
---|
2540 | #endif |
---|
2541 | } |
---|
2542 | else if (strcasecmp(&line[1], "canon") == 0) |
---|
2543 | { |
---|
2544 | char host[MAXHOSTNAMELEN]; |
---|
2545 | |
---|
2546 | if (*p == '\0') |
---|
2547 | { |
---|
2548 | printf("Usage: /canon address\n"); |
---|
2549 | return; |
---|
2550 | } |
---|
2551 | else if (strlen(p) >= sizeof host) |
---|
2552 | { |
---|
2553 | printf("Name too long\n"); |
---|
2554 | return; |
---|
2555 | } |
---|
2556 | strcpy(host, p); |
---|
2557 | (void) getcanonname(host, sizeof(host), HasWildcardMX); |
---|
2558 | printf("getcanonname(%s) returns %s\n", p, host); |
---|
2559 | } |
---|
2560 | else if (strcasecmp(&line[1], "map") == 0) |
---|
2561 | { |
---|
2562 | auto int rcode = EX_OK; |
---|
2563 | char *av[2]; |
---|
2564 | |
---|
2565 | if (*p == '\0') |
---|
2566 | { |
---|
2567 | printf("Usage: /map mapname key\n"); |
---|
2568 | return; |
---|
2569 | } |
---|
2570 | for (q = p; *q != '\0' && !(isascii(*q) && isspace(*q)); q++) |
---|
2571 | continue; |
---|
2572 | if (*q == '\0') |
---|
2573 | { |
---|
2574 | printf("No key specified\n"); |
---|
2575 | return; |
---|
2576 | } |
---|
2577 | *q++ = '\0'; |
---|
2578 | map = stab(p, ST_MAP, ST_FIND); |
---|
2579 | if (map == NULL) |
---|
2580 | { |
---|
2581 | printf("Map named \"%s\" not found\n", p); |
---|
2582 | return; |
---|
2583 | } |
---|
2584 | if (!bitset(MF_OPEN, map->s_map.map_mflags)) |
---|
2585 | { |
---|
2586 | printf("Map named \"%s\" not open\n", p); |
---|
2587 | return; |
---|
2588 | } |
---|
2589 | printf("map_lookup: %s (%s) ", p, q); |
---|
2590 | av[0] = q; |
---|
2591 | av[1] = NULL; |
---|
2592 | p = (*map->s_map.map_class->map_lookup) |
---|
2593 | (&map->s_map, q, av, &rcode); |
---|
2594 | if (p == NULL) |
---|
2595 | printf("no match (%d)\n", rcode); |
---|
2596 | else |
---|
2597 | printf("returns %s (%d)\n", p, rcode); |
---|
2598 | } |
---|
2599 | else if (strcasecmp(&line[1], "try") == 0) |
---|
2600 | { |
---|
2601 | MAILER *m; |
---|
2602 | STAB *s; |
---|
2603 | auto int rcode = EX_OK; |
---|
2604 | |
---|
2605 | q = strpbrk(p, " \t"); |
---|
2606 | if (q != NULL) |
---|
2607 | { |
---|
2608 | while (isascii(*q) && isspace(*q)) |
---|
2609 | *q++ = '\0'; |
---|
2610 | } |
---|
2611 | if (q == NULL || *q == '\0') |
---|
2612 | { |
---|
2613 | printf("Usage: /try mailer address\n"); |
---|
2614 | return; |
---|
2615 | } |
---|
2616 | s = stab(p, ST_MAILER, ST_FIND); |
---|
2617 | if (s == NULL) |
---|
2618 | { |
---|
2619 | printf("Unknown mailer %s\n", p); |
---|
2620 | return; |
---|
2621 | } |
---|
2622 | m = s->s_mailer; |
---|
2623 | printf("Trying %s %s address %s for mailer %s\n", |
---|
2624 | bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", |
---|
2625 | bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient", |
---|
2626 | q, p); |
---|
2627 | p = remotename(q, m, tryflags, &rcode, CurEnv); |
---|
2628 | printf("Rcode = %d, addr = %s\n", |
---|
2629 | rcode, p == NULL ? "<NULL>" : p); |
---|
2630 | e->e_to = NULL; |
---|
2631 | } |
---|
2632 | else if (strcasecmp(&line[1], "tryflags") == 0) |
---|
2633 | { |
---|
2634 | if (*p == '\0') |
---|
2635 | { |
---|
2636 | printf("Usage: /tryflags [Hh|Ee][Ss|Rr]\n"); |
---|
2637 | return; |
---|
2638 | } |
---|
2639 | for (; *p != '\0'; p++) |
---|
2640 | { |
---|
2641 | switch (*p) |
---|
2642 | { |
---|
2643 | case 'H': |
---|
2644 | case 'h': |
---|
2645 | tryflags |= RF_HEADERADDR; |
---|
2646 | break; |
---|
2647 | |
---|
2648 | case 'E': |
---|
2649 | case 'e': |
---|
2650 | tryflags &= ~RF_HEADERADDR; |
---|
2651 | break; |
---|
2652 | |
---|
2653 | case 'S': |
---|
2654 | case 's': |
---|
2655 | tryflags |= RF_SENDERADDR; |
---|
2656 | break; |
---|
2657 | |
---|
2658 | case 'R': |
---|
2659 | case 'r': |
---|
2660 | tryflags &= ~RF_SENDERADDR; |
---|
2661 | break; |
---|
2662 | } |
---|
2663 | } |
---|
2664 | } |
---|
2665 | else if (strcasecmp(&line[1], "parse") == 0) |
---|
2666 | { |
---|
2667 | if (*p == '\0') |
---|
2668 | { |
---|
2669 | printf("Usage: /parse address\n"); |
---|
2670 | return; |
---|
2671 | } |
---|
2672 | q = crackaddr(p); |
---|
2673 | printf("Cracked address = "); |
---|
2674 | xputs(q); |
---|
2675 | printf("\nParsing %s %s address\n", |
---|
2676 | bitset(RF_HEADERADDR, tryflags) ? "header" : "envelope", |
---|
2677 | bitset(RF_SENDERADDR, tryflags) ? "sender" : "recipient"); |
---|
2678 | if (parseaddr(p, &a, tryflags, '\0', NULL, e) == NULL) |
---|
2679 | printf("Cannot parse\n"); |
---|
2680 | else if (a.q_host != NULL && a.q_host[0] != '\0') |
---|
2681 | printf("mailer %s, host %s, user %s\n", |
---|
2682 | a.q_mailer->m_name, a.q_host, a.q_user); |
---|
2683 | else |
---|
2684 | printf("mailer %s, user %s\n", |
---|
2685 | a.q_mailer->m_name, a.q_user); |
---|
2686 | e->e_to = NULL; |
---|
2687 | } |
---|
2688 | else |
---|
2689 | { |
---|
2690 | printf("Unknown \"/\" command %s\n", line); |
---|
2691 | } |
---|
2692 | return; |
---|
2693 | } |
---|
2694 | |
---|
2695 | for (p = line; isascii(*p) && isspace(*p); p++) |
---|
2696 | continue; |
---|
2697 | q = p; |
---|
2698 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) |
---|
2699 | p++; |
---|
2700 | if (*p == '\0') |
---|
2701 | { |
---|
2702 | printf("No address!\n"); |
---|
2703 | return; |
---|
2704 | } |
---|
2705 | *p = '\0'; |
---|
2706 | if (invalidaddr(p + 1, NULL)) |
---|
2707 | return; |
---|
2708 | do |
---|
2709 | { |
---|
2710 | register char **pvp; |
---|
2711 | char pvpbuf[PSBUFSIZE]; |
---|
2712 | |
---|
2713 | pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, |
---|
2714 | &delimptr, NULL); |
---|
2715 | if (pvp == NULL) |
---|
2716 | continue; |
---|
2717 | p = q; |
---|
2718 | while (*p != '\0') |
---|
2719 | { |
---|
2720 | int stat; |
---|
2721 | |
---|
2722 | rs = strtorwset(p, NULL, ST_FIND); |
---|
2723 | if (rs < 0) |
---|
2724 | { |
---|
2725 | printf("Undefined ruleset %s\n", p); |
---|
2726 | break; |
---|
2727 | } |
---|
2728 | stat = rewrite(pvp, rs, 0, e); |
---|
2729 | if (stat != EX_OK) |
---|
2730 | printf("== Ruleset %s (%d) status %d\n", |
---|
2731 | p, rs, stat); |
---|
2732 | while (*p != '\0' && *p++ != ',') |
---|
2733 | continue; |
---|
2734 | } |
---|
2735 | } while (*(p = delimptr) != '\0'); |
---|
2736 | } |
---|
2737 | |
---|
2738 | |
---|
2739 | void |
---|
2740 | dump_class(s, id) |
---|
2741 | register STAB *s; |
---|
2742 | int id; |
---|
2743 | { |
---|
2744 | if (s->s_type != ST_CLASS) |
---|
2745 | return; |
---|
2746 | if (bitnset(id & 0xff, s->s_class)) |
---|
2747 | printf("%s\n", s->s_name); |
---|
2748 | } |
---|