Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
c1f0acb8 KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
e1f691b3 | 10 | static char sccsid[] = "@(#)recipient.c 8.74 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
72041f93 | 13 | # include "sendmail.h" |
6eefe4f6 | 14 | # include <pwd.h> |
6eefe4f6 | 15 | |
6eefe4f6 | 16 | /* |
811a6cf3 | 17 | ** SENDTOLIST -- Designate a send list. |
6eefe4f6 EA |
18 | ** |
19 | ** The parameter is a comma-separated list of people to send to. | |
20 | ** This routine arranges to send to all of them. | |
21 | ** | |
abae7b2d EA |
22 | ** The `ctladdr' is the address that expanded to be this one, |
23 | ** e.g., in an alias expansion. This is used for a number of | |
24 | ** purposed, most notably inheritance of uid/gid for protection | |
25 | ** purposes. It is also used to detect self-reference in group | |
26 | ** expansions and the like. | |
27 | ** | |
6eefe4f6 EA |
28 | ** Parameters: |
29 | ** list -- the send list. | |
1bf7c76b EA |
30 | ** ctladdr -- the address template for the person to |
31 | ** send to -- effective uid/gid are important. | |
d4f42161 EA |
32 | ** This is typically the alias that caused this |
33 | ** expansion. | |
34 | ** sendq -- a pointer to the head of a queue to put | |
35 | ** these people into. | |
f8c2f9fd EA |
36 | ** aliaslevel -- the current alias nesting depth -- to |
37 | ** diagnose loops. | |
118e6693 | 38 | ** e -- the envelope in which to add these recipients. |
abae7b2d | 39 | ** qflags -- special flags to set in the q_flags field. |
6eefe4f6 EA |
40 | ** |
41 | ** Returns: | |
abae7b2d | 42 | ** pointer to chain of addresses. |
6eefe4f6 EA |
43 | ** |
44 | ** Side Effects: | |
45 | ** none. | |
46 | */ | |
47 | ||
68d9129a EA |
48 | #define MAXRCRSN 10 /* maximum levels of alias recursion */ |
49 | ||
50 | /* q_flags bits inherited from ctladdr */ | |
e1f691b3 | 51 | #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) |
6eefe4f6 | 52 | |
d51d925d | 53 | int |
abae7b2d EA |
54 | ADDRESS * |
55 | sendto(list, copyf, ctladdr, qflags) | |
6eefe4f6 | 56 | char *list; |
1bf7c76b | 57 | ADDRESS *ctladdr; |
4e5e456f | 58 | ADDRESS **sendq; |
f8c2f9fd | 59 | int aliaslevel; |
a4076aed | 60 | register ENVELOPE *e; |
abae7b2d | 61 | u_short qflags; |
6eefe4f6 EA |
62 | { |
63 | register char *p; | |
7b955214 | 64 | register ADDRESS *al; /* list of addresses to send to */ |
92f12b98 | 65 | bool firstone; /* set on first address sent */ |
d3f52e20 | 66 | char delimiter; /* the address delimiter */ |
1c7897ef | 67 | int naddrs; |
c6fde7ee | 68 | int i; |
d1147db7 | 69 | char *oldto = e->e_to; |
c6fde7ee | 70 | char *bufp; |
93df3047 | 71 | char buf[MAXNAME + 1]; |
abae7b2d EA |
72 | ADDRESS *sibl; /* sibling pointer in tree */ |
73 | ADDRESS *prev; /* previous sibling */ | |
d6b27179 | 74 | |
5aec60fc EA |
75 | if (list == NULL) |
76 | { | |
77 | syserr("sendtolist: null list"); | |
78 | return 0; | |
79 | } | |
80 | ||
9678c96d | 81 | if (tTd(25, 1)) |
331b7c9f EA |
82 | { |
83 | printf("sendto: %s\n ctladdr=", list); | |
84 | printaddr(ctladdr, FALSE); | |
85 | } | |
6eefe4f6 | 86 | |
7b955214 | 87 | /* heuristic to determine old versus new style addresses */ |
a2983993 | 88 | if (ctladdr == NULL && |
f3d8f6d6 EA |
89 | (strchr(list, ',') != NULL || strchr(list, ';') != NULL || |
90 | strchr(list, '<') != NULL || strchr(list, '(') != NULL)) | |
a4076aed | 91 | e->e_flags &= ~EF_OLDSTYLE; |
d3f52e20 | 92 | delimiter = ' '; |
a4076aed | 93 | if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) |
d3f52e20 | 94 | delimiter = ','; |
7b955214 | 95 | |
92f12b98 | 96 | firstone = TRUE; |
d6b27179 | 97 | al = NULL; |
1c7897ef | 98 | naddrs = 0; |
7b955214 | 99 | |
c6fde7ee EA |
100 | /* make sure we have enough space to copy the string */ |
101 | i = strlen(list) + 1; | |
102 | if (i <= sizeof buf) | |
93df3047 | 103 | bufp = buf; |
c6fde7ee EA |
104 | else |
105 | bufp = xalloc(i); | |
dcf45886 | 106 | strcpy(bufp, denlstring(list, FALSE, TRUE)); |
93df3047 EA |
107 | |
108 | for (p = bufp; *p != '\0'; ) | |
6eefe4f6 | 109 | { |
9e2cf26f | 110 | auto char *delimptr; |
506fc377 | 111 | register ADDRESS *a; |
6eefe4f6 EA |
112 | |
113 | /* parse the address */ | |
2bee003d | 114 | while ((isascii(*p) && isspace(*p)) || *p == ',') |
506fc377 | 115 | p++; |
28f94061 | 116 | a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); |
9e2cf26f | 117 | p = delimptr; |
b9fadd5b EA |
118 | if (a == NULL) |
119 | continue; | |
d6b27179 | 120 | a->q_next = al; |
1bf7c76b | 121 | a->q_alias = ctladdr; |
abae7b2d EA |
122 | if (ctladdr != NULL) |
123 | a->q_flags |= ctladdr->q_flags & ~QPRIMARY; | |
124 | a->q_flags |= qflags; | |
331b7c9f EA |
125 | |
126 | /* see if this should be marked as a primary address */ | |
92f12b98 | 127 | if (ctladdr == NULL || |
506fc377 | 128 | (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) |
92f12b98 | 129 | a->q_flags |= QPRIMARY; |
331b7c9f | 130 | |
abae7b2d EA |
131 | sibl = recipient(a); |
132 | if (sibl != NULL) | |
133 | { | |
134 | extern ADDRESS *addrref(); | |
135 | ||
136 | /* inherit full name */ | |
137 | if (sibl->q_fullname == NULL && ctladdr != NULL) | |
138 | sibl->q_fullname = ctladdr->q_fullname; | |
139 | ||
140 | /* link tree together (but only if the node is new) */ | |
141 | if (sibl == a) | |
142 | { | |
143 | sibl->q_sibling = prev; | |
144 | prev = sibl; | |
145 | } | |
146 | } | |
6eefe4f6 | 147 | } |
d6b27179 | 148 | |
d1147db7 | 149 | e->e_to = oldto; |
c6fde7ee EA |
150 | if (bufp != buf) |
151 | free(bufp); | |
1c7897ef | 152 | return (naddrs); |
abae7b2d EA |
153 | if (ctladdr != NULL) |
154 | ctladdr->q_child = prev; | |
155 | return (prev); | |
156 | } | |
157 | \f/* | |
158 | ** ADDRREF -- return pointer to address that references another address. | |
159 | ** | |
160 | ** Parameters: | |
161 | ** a -- address to check. | |
162 | ** r -- reference to find. | |
163 | ** | |
164 | ** Returns: | |
165 | ** address of node in tree rooted at 'a' that references | |
166 | ** 'r'. | |
167 | ** NULL if no such node exists. | |
168 | ** | |
169 | ** Side Effects: | |
170 | ** none. | |
171 | */ | |
172 | ||
173 | ADDRESS * | |
174 | addrref(a, r) | |
175 | register ADDRESS *a; | |
176 | register ADDRESS *r; | |
177 | { | |
178 | register ADDRESS *q; | |
179 | ||
180 | while (a != NULL) | |
181 | { | |
182 | if (a->q_child == r || a->q_sibling == r) | |
183 | return (a); | |
184 | q = addrref(a->q_child, r); | |
185 | if (q != NULL) | |
186 | return (q); | |
187 | a = a->q_sibling; | |
188 | } | |
189 | return (NULL); | |
6eefe4f6 EA |
190 | } |
191 | \f/* | |
192 | ** RECIPIENT -- Designate a message recipient | |
193 | ** | |
194 | ** Saves the named person for future mailing. | |
195 | ** | |
196 | ** Parameters: | |
197 | ** a -- the (preparsed) address header for the recipient. | |
d4f42161 EA |
198 | ** sendq -- a pointer to the head of a queue to put the |
199 | ** recipient in. Duplicate supression is done | |
200 | ** in this queue. | |
f8c2f9fd | 201 | ** aliaslevel -- the current alias nesting depth. |
78bbbc48 | 202 | ** e -- the current envelope. |
6eefe4f6 EA |
203 | ** |
204 | ** Returns: | |
abae7b2d | 205 | ** pointer to address actually inserted in send list. |
6eefe4f6 EA |
206 | ** |
207 | ** Side Effects: | |
208 | ** none. | |
209 | */ | |
210 | ||
d344c0b7 | 211 | ADDRESS * |
abae7b2d | 212 | ADDRESS * |
f8c2f9fd | 213 | recipient(a, sendq, aliaslevel, e) |
6eefe4f6 | 214 | register ADDRESS *a; |
d4f42161 | 215 | register ADDRESS **sendq; |
f8c2f9fd | 216 | int aliaslevel; |
a4076aed | 217 | register ENVELOPE *e; |
6eefe4f6 EA |
218 | { |
219 | register ADDRESS *q; | |
74c5fe7c | 220 | ADDRESS **pq; |
6eefe4f6 | 221 | register struct mailer *m; |
98f46225 EA |
222 | register char *p; |
223 | bool quoted = FALSE; /* set if the addr has a quote bit */ | |
7f0fd60b | 224 | int findusercount = 0; |
f466bb18 EA |
225 | int i; |
226 | char *buf; | |
8446c922 | 227 | char buf0[MAXNAME + 1]; /* unquoted image of the user name */ |
118e6693 | 228 | extern int safefile(); |
6eefe4f6 | 229 | |
a4076aed | 230 | e->e_to = a->q_paddr; |
179c1218 | 231 | m = a->q_mailer; |
6eefe4f6 | 232 | errno = 0; |
9678c96d | 233 | if (tTd(26, 1)) |
331b7c9f EA |
234 | { |
235 | printf("\nrecipient: "); | |
236 | printaddr(a, FALSE); | |
237 | } | |
6eefe4f6 | 238 | |
e4a5cf08 EA |
239 | /* if this is primary, add it to the original recipient list */ |
240 | if (a->q_alias == NULL) | |
241 | { | |
242 | if (e->e_origrcpt == NULL) | |
243 | e->e_origrcpt = a->q_paddr; | |
244 | else if (e->e_origrcpt != a->q_paddr) | |
245 | e->e_origrcpt = ""; | |
246 | } | |
247 | ||
6eefe4f6 | 248 | /* break aliasing loops */ |
f8c2f9fd | 249 | if (aliaslevel > MAXRCRSN) |
6eefe4f6 | 250 | { |
d51d925d EA |
251 | usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", |
252 | aliaslevel, MAXRCRSN); | |
abae7b2d | 253 | return (NULL); |
6eefe4f6 EA |
254 | } |
255 | ||
256 | /* | |
ed45aae1 | 257 | ** Finish setting up address structure. |
6eefe4f6 EA |
258 | */ |
259 | ||
0fe3917f | 260 | /* get unquoted user for file, program or user.name check */ |
f466bb18 | 261 | i = strlen(a->q_user); |
8446c922 | 262 | if (i >= sizeof buf0) |
f466bb18 EA |
263 | buf = xalloc(i + 1); |
264 | else | |
265 | buf = buf0; | |
98f46225 EA |
266 | (void) strcpy(buf, a->q_user); |
267 | for (p = buf; *p != '\0' && !quoted; p++) | |
268 | { | |
3eb4fac4 | 269 | if (*p == '\\') |
98f46225 EA |
270 | quoted = TRUE; |
271 | } | |
85c61679 | 272 | stripquotes(buf); |
98f46225 | 273 | |
98e5062b | 274 | /* check for direct mailing to restricted mailers */ |
78a504b0 | 275 | if (m == ProgMailer) |
6eefe4f6 | 276 | { |
78a504b0 EA |
277 | if (a->q_alias == NULL) |
278 | { | |
279 | a->q_flags |= QBADADDR; | |
280 | usrerr("550 Cannot mail directly to programs"); | |
281 | } | |
282 | else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) | |
283 | { | |
284 | a->q_flags |= QBADADDR; | |
285 | usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", | |
286 | a->q_alias->q_ruser, MyHostName); | |
287 | } | |
288 | else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) | |
289 | { | |
290 | a->q_flags |= QBADADDR; | |
291 | usrerr("550 Address %s is unsafe for mailing to programs", | |
292 | a->q_alias->q_paddr); | |
293 | } | |
6eefe4f6 EA |
294 | } |
295 | ||
296 | /* | |
b9ca6d11 EA |
297 | ** Look up this person in the recipient list. |
298 | ** If they are there already, return, otherwise continue. | |
299 | ** If the list is empty, just add it. Notice the cute | |
300 | ** hack to make from addresses suppress things correctly: | |
301 | ** the QDONTSEND bit will be set in the send list. | |
302 | ** [Please note: the emphasis is on "hack."] | |
6eefe4f6 EA |
303 | */ |
304 | ||
d4f42161 | 305 | for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) |
6eefe4f6 | 306 | { |
35943e55 | 307 | if (sameaddr(q, a)) |
6eefe4f6 | 308 | { |
1d303d98 EA |
309 | /* if this is a reinsertion, just go ahead */ |
310 | if (bitset(QVERIFIED, q->q_flags)) | |
311 | break; | |
312 | ||
9678c96d | 313 | if (tTd(26, 1)) |
331b7c9f EA |
314 | { |
315 | printf("%s in sendq: ", a->q_paddr); | |
316 | printaddr(q, FALSE); | |
317 | } | |
34bc9a9c | 318 | if (!bitset(QPRIMARY, q->q_flags)) |
f7eca811 | 319 | { |
34bc9a9c | 320 | if (!bitset(QDONTSEND, a->q_flags)) |
b6edea3d | 321 | message("duplicate suppressed"); |
34bc9a9c | 322 | q->q_flags |= a->q_flags; |
f7eca811 | 323 | } |
34bc9a9c EA |
324 | else if (bitset(QSELFREF, q->q_flags)) |
325 | q->q_flags |= a->q_flags & ~QDONTSEND; | |
abae7b2d EA |
326 | if (!bitset(QPSEUDO, a->q_flags)) |
327 | q->q_flags &= ~QPSEUDO; | |
328 | return (q); | |
6eefe4f6 | 329 | } |
6eefe4f6 | 330 | } |
74c5fe7c EA |
331 | |
332 | /* add address on list */ | |
1d303d98 EA |
333 | if (*pq != a) |
334 | { | |
335 | *pq = a; | |
336 | a->q_next = NULL; | |
337 | } | |
338 | ||
339 | a->q_flags &= ~QVERIFIED; | |
6eefe4f6 EA |
340 | |
341 | /* | |
98e5062b | 342 | ** Alias the name and handle special mailer types. |
6eefe4f6 EA |
343 | */ |
344 | ||
7f0fd60b | 345 | trylocaluser: |
42450b5a EA |
346 | if (tTd(29, 7)) |
347 | printf("at trylocaluser %s\n", a->q_user); | |
348 | ||
bc854e30 | 349 | if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) |
d1147db7 | 350 | goto testselfdestruct; |
98e5062b EA |
351 | |
352 | if (m == InclMailer) | |
6eefe4f6 | 353 | { |
98e5062b | 354 | a->q_flags |= QDONTSEND; |
46361811 | 355 | if (a->q_alias == NULL) |
6eefe4f6 | 356 | { |
bc854e30 | 357 | a->q_flags |= QBADADDR; |
b6edea3d | 358 | usrerr("550 Cannot mail directly to :include:s"); |
6eefe4f6 EA |
359 | } |
360 | else | |
8a12fae4 | 361 | { |
d50bcc17 | 362 | int ret; |
118e6693 | 363 | |
b6edea3d | 364 | message("including file %s", a->q_user); |
f8c2f9fd | 365 | ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); |
d50bcc17 EA |
366 | if (transienterror(ret)) |
367 | { | |
368 | #ifdef LOG | |
369 | if (LogLevel > 2) | |
24ba7f88 | 370 | syslog(LOG_ERR, "%s: include %s: transient error: %s", |
1db90aeb EA |
371 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
372 | a->q_user, errstring(ret)); | |
d50bcc17 | 373 | #endif |
c069e0df | 374 | a->q_flags |= QQUEUEUP; |
4281694e | 375 | a->q_flags &= ~QDONTSEND; |
d50bcc17 EA |
376 | usrerr("451 Cannot open %s: %s", |
377 | a->q_user, errstring(ret)); | |
378 | } | |
379 | else if (ret != 0) | |
380 | { | |
32c83608 | 381 | a->q_flags |= QBADADDR; |
d50bcc17 EA |
382 | usrerr("550 Cannot open %s: %s", |
383 | a->q_user, errstring(ret)); | |
d50bcc17 | 384 | } |
8a12fae4 | 385 | } |
98e5062b | 386 | } |
6e99f903 | 387 | else if (m == FileMailer) |
6eefe4f6 | 388 | { |
a0554f81 | 389 | extern bool writable(); |
6eefe4f6 | 390 | |
d13779b1 | 391 | /* check if writable or creatable */ |
46361811 | 392 | if (a->q_alias == NULL) |
6eefe4f6 | 393 | { |
bc854e30 | 394 | a->q_flags |= QBADADDR; |
b6edea3d | 395 | usrerr("550 Cannot mail directly to files"); |
d13779b1 | 396 | } |
78a504b0 EA |
397 | else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) |
398 | { | |
399 | a->q_flags |= QBADADDR; | |
400 | usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", | |
401 | a->q_alias->q_ruser, MyHostName); | |
402 | } | |
403 | else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) | |
404 | { | |
405 | a->q_flags |= QBADADDR; | |
406 | usrerr("550 Address %s is unsafe for mailing to files", | |
407 | a->q_alias->q_paddr); | |
408 | } | |
d52f8819 | 409 | else if (!writable(buf, getctladdr(a), SFF_CREAT)) |
d13779b1 | 410 | { |
bc854e30 | 411 | a->q_flags |= QBADADDR; |
3500a891 EA |
412 | giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, |
413 | (time_t) 0, e); | |
d13779b1 | 414 | } |
d13779b1 EA |
415 | } |
416 | ||
98e5062b | 417 | /* try aliasing */ |
2bade550 | 418 | if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) |
f8c2f9fd | 419 | alias(a, sendq, aliaslevel, e); |
98e5062b EA |
420 | |
421 | # ifdef USERDB | |
422 | /* if not aliased, look it up in the user database */ | |
2bade550 EA |
423 | if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && |
424 | bitnset(M_CHECKUDB, m->m_flags)) | |
98e5062b EA |
425 | { |
426 | extern int udbexpand(); | |
427 | ||
f8c2f9fd | 428 | if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) |
98e5062b | 429 | { |
c069e0df | 430 | a->q_flags |= QQUEUEUP; |
98e5062b EA |
431 | if (e->e_message == NULL) |
432 | e->e_message = newstr("Deferred: user database error"); | |
433 | # ifdef LOG | |
68f7099c | 434 | if (LogLevel > 8) |
3f0792d1 | 435 | syslog(LOG_INFO, "%s: deferred: udbexpand: %s", |
1db90aeb EA |
436 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
437 | errstring(errno)); | |
98e5062b | 438 | # endif |
73f6752a EA |
439 | message("queued (user database error): %s", |
440 | errstring(errno)); | |
6e99f903 | 441 | e->e_nrcpts++; |
d1147db7 | 442 | goto testselfdestruct; |
98e5062b EA |
443 | } |
444 | } | |
445 | # endif | |
446 | ||
d13779b1 EA |
447 | /* |
448 | ** If we have a level two config file, then pass the name through | |
449 | ** Ruleset 5 before sending it off. Ruleset 5 has the right | |
450 | ** to send rewrite it to another mailer. This gives us a hook | |
451 | ** after local aliasing has been done. | |
452 | */ | |
453 | ||
454 | if (tTd(29, 5)) | |
455 | { | |
456 | printf("recipient: testing local? cl=%d, rr5=%x\n\t", | |
457 | ConfigLevel, RewriteRules[5]); | |
458 | printaddr(a, FALSE); | |
459 | } | |
2bade550 EA |
460 | if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && |
461 | ConfigLevel >= 2 && RewriteRules[5] != NULL && | |
462 | bitnset(M_TRYRULESET5, m->m_flags)) | |
d13779b1 | 463 | { |
f8c2f9fd | 464 | maplocaluser(a, sendq, aliaslevel, e); |
d13779b1 EA |
465 | } |
466 | ||
467 | /* | |
468 | ** If it didn't get rewritten to another mailer, go ahead | |
469 | ** and deliver it. | |
470 | */ | |
471 | ||
2bade550 EA |
472 | if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && |
473 | bitnset(M_HASPWENT, m->m_flags)) | |
d13779b1 | 474 | { |
42450b5a | 475 | auto bool fuzzy; |
d13779b1 EA |
476 | register struct passwd *pw; |
477 | extern struct passwd *finduser(); | |
478 | ||
479 | /* warning -- finduser may trash buf */ | |
42450b5a | 480 | pw = finduser(buf, &fuzzy); |
d13779b1 EA |
481 | if (pw == NULL) |
482 | { | |
bc854e30 | 483 | a->q_flags |= QBADADDR; |
3500a891 EA |
484 | giveresponse(EX_NOUSER, m, NULL, a->q_alias, |
485 | (time_t) 0, e); | |
6eefe4f6 EA |
486 | } |
487 | else | |
488 | { | |
8446c922 | 489 | char nbuf[MAXNAME + 1]; |
ff3e3c1c | 490 | |
42450b5a | 491 | if (fuzzy) |
6eefe4f6 | 492 | { |
7f0fd60b | 493 | /* name was a fuzzy match */ |
d13779b1 | 494 | a->q_user = newstr(pw->pw_name); |
7f0fd60b EA |
495 | if (findusercount++ > 3) |
496 | { | |
bc854e30 | 497 | a->q_flags |= QBADADDR; |
b6edea3d | 498 | usrerr("554 aliasing/forwarding loop for %s broken", |
7f0fd60b | 499 | pw->pw_name); |
f466bb18 | 500 | goto done; |
7f0fd60b EA |
501 | } |
502 | ||
503 | /* see if it aliases */ | |
d13779b1 | 504 | (void) strcpy(buf, pw->pw_name); |
7f0fd60b | 505 | goto trylocaluser; |
6eefe4f6 | 506 | } |
c841d671 EA |
507 | if (strcmp(pw->pw_dir, "/") == 0) |
508 | a->q_home = ""; | |
509 | else | |
510 | a->q_home = newstr(pw->pw_dir); | |
d13779b1 EA |
511 | a->q_uid = pw->pw_uid; |
512 | a->q_gid = pw->pw_gid; | |
61cbea4c | 513 | a->q_ruser = newstr(pw->pw_name); |
d13779b1 EA |
514 | a->q_flags |= QGOODUID; |
515 | buildfname(pw->pw_gecos, pw->pw_name, nbuf); | |
516 | if (nbuf[0] != '\0') | |
517 | a->q_fullname = newstr(nbuf); | |
1ee33f7d EA |
518 | if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && |
519 | !usershellok(pw->pw_shell)) | |
52d85a9d | 520 | { |
1ee33f7d | 521 | a->q_flags |= QBOGUSSHELL; |
52d85a9d | 522 | } |
d13779b1 | 523 | if (!quoted) |
f8c2f9fd | 524 | forward(a, sendq, aliaslevel, e); |
6eefe4f6 EA |
525 | } |
526 | } | |
6e99f903 EA |
527 | if (!bitset(QDONTSEND, a->q_flags)) |
528 | e->e_nrcpts++; | |
d1147db7 EA |
529 | |
530 | testselfdestruct: | |
cd361139 | 531 | if (tTd(26, 8)) |
d1147db7 | 532 | { |
cd361139 EA |
533 | printf("testselfdestruct: "); |
534 | printaddr(a, TRUE); | |
535 | } | |
536 | if (a->q_alias == NULL && a != &e->e_from && | |
537 | bitset(QDONTSEND, a->q_flags)) | |
538 | { | |
539 | q = *sendq; | |
0fc3fb21 | 540 | while (q != NULL && bitset(QDONTSEND, q->q_flags)) |
d1147db7 | 541 | q = q->q_next; |
cd361139 | 542 | if (q == NULL) |
d1147db7 EA |
543 | { |
544 | a->q_flags |= QBADADDR; | |
545 | usrerr("554 aliasing/forwarding loop broken"); | |
546 | } | |
547 | } | |
f466bb18 EA |
548 | |
549 | done: | |
550 | if (buf != buf0) | |
551 | free(buf); | |
d344c0b7 | 552 | return (a); |
abae7b2d EA |
553 | |
554 | return (a); | |
6eefe4f6 EA |
555 | } |
556 | \f/* | |
ff3e3c1c EA |
557 | ** FINDUSER -- find the password entry for a user. |
558 | ** | |
559 | ** This looks a lot like getpwnam, except that it may want to | |
560 | ** do some fancier pattern matching in /etc/passwd. | |
561 | ** | |
7338e3d4 EA |
562 | ** This routine contains most of the time of many sendmail runs. |
563 | ** It deserves to be optimized. | |
564 | ** | |
ff3e3c1c EA |
565 | ** Parameters: |
566 | ** name -- the name to match against. | |
42450b5a EA |
567 | ** fuzzyp -- an outarg that is set to TRUE if this entry |
568 | ** was found using the fuzzy matching algorithm; | |
569 | ** set to FALSE otherwise. | |
ff3e3c1c EA |
570 | ** |
571 | ** Returns: | |
572 | ** A pointer to a pw struct. | |
573 | ** NULL if name is unknown or ambiguous. | |
574 | ** | |
575 | ** Side Effects: | |
29c33ff6 | 576 | ** may modify name. |
ff3e3c1c EA |
577 | */ |
578 | ||
579 | struct passwd * | |
42450b5a | 580 | finduser(name, fuzzyp) |
ff3e3c1c | 581 | char *name; |
42450b5a | 582 | bool *fuzzyp; |
ff3e3c1c | 583 | { |
2b5e3c25 | 584 | register struct passwd *pw; |
29c33ff6 | 585 | register char *p; |
f74d8dce EA |
586 | extern struct passwd *getpwent(); |
587 | extern struct passwd *getpwnam(); | |
29c33ff6 | 588 | |
42450b5a EA |
589 | if (tTd(29, 4)) |
590 | printf("finduser(%s): ", name); | |
591 | ||
42450b5a | 592 | *fuzzyp = FALSE; |
ff3e3c1c | 593 | |
e28a0bbb | 594 | #ifdef HESIOD |
06b7bf4a EA |
595 | /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ |
596 | for (p = name; *p != '\0'; p++) | |
597 | if (!isascii(*p) || !isdigit(*p)) | |
598 | break; | |
599 | if (*p == '\0') | |
600 | { | |
601 | if (tTd(29, 4)) | |
602 | printf("failed (numeric input)\n"); | |
603 | return NULL; | |
604 | } | |
e28a0bbb | 605 | #endif |
06b7bf4a | 606 | |
639d8b98 | 607 | /* look up this login name using fast path */ |
77b16ff1 | 608 | if ((pw = getpwnam(name)) != NULL) |
42450b5a EA |
609 | { |
610 | if (tTd(29, 4)) | |
611 | printf("found (non-fuzzy)\n"); | |
77b16ff1 | 612 | return (pw); |
42450b5a | 613 | } |
77b16ff1 | 614 | |
7f0fd60b EA |
615 | #ifdef MATCHGECOS |
616 | /* see if fuzzy matching allowed */ | |
617 | if (!MatchGecos) | |
42450b5a EA |
618 | { |
619 | if (tTd(29, 4)) | |
620 | printf("not found (fuzzy disabled)\n"); | |
7f0fd60b | 621 | return NULL; |
42450b5a | 622 | } |
7f0fd60b | 623 | |
77b16ff1 | 624 | /* search for a matching full name instead */ |
639d8b98 EA |
625 | for (p = name; *p != '\0'; p++) |
626 | { | |
627 | if (*p == (SpaceSub & 0177) || *p == '_') | |
628 | *p = ' '; | |
629 | } | |
03388044 | 630 | (void) setpwent(); |
2b5e3c25 EA |
631 | while ((pw = getpwent()) != NULL) |
632 | { | |
abae7b2d | 633 | char buf[MAXNAME]; |
2b5e3c25 | 634 | |
abae7b2d | 635 | fullname(pw, buf); |
f3d8f6d6 | 636 | if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) |
36292825 | 637 | { |
42450b5a EA |
638 | if (tTd(29, 4)) |
639 | printf("fuzzy matches %s\n", pw->pw_name); | |
abae7b2d EA |
640 | message(Arpa_Info, "sending to %s <%s>", |
641 | buf, pw->pw_name); | |
2b5e3c25 | 642 | return (pw); |
36292825 | 643 | } |
2b5e3c25 | 644 | } |
42450b5a EA |
645 | if (tTd(29, 4)) |
646 | printf("no fuzzy match found\n"); | |
70ce33b6 EA |
647 | #else |
648 | if (tTd(29, 4)) | |
649 | printf("not found (fuzzy disabled)\n"); | |
650 | #endif | |
2b5e3c25 | 651 | return (NULL); |
ff3e3c1c EA |
652 | } |
653 | \f/* | |
a0554f81 EA |
654 | ** WRITABLE -- predicate returning if the file is writable. |
655 | ** | |
656 | ** This routine must duplicate the algorithm in sys/fio.c. | |
657 | ** Unfortunately, we cannot use the access call since we | |
658 | ** won't necessarily be the real uid when we try to | |
659 | ** actually open the file. | |
660 | ** | |
661 | ** Notice that ANY file with ANY execute bit is automatically | |
662 | ** not writable. This is also enforced by mailfile. | |
663 | ** | |
664 | ** Parameters: | |
c9bddda6 | 665 | ** filename -- the file name to check. |
75cdfff0 | 666 | ** ctladdr -- the controlling address for this file. |
c9bddda6 | 667 | ** flags -- SFF_* flags to control the function. |
a0554f81 EA |
668 | ** |
669 | ** Returns: | |
670 | ** TRUE -- if we will be able to write this file. | |
671 | ** FALSE -- if we cannot write this file. | |
672 | ** | |
673 | ** Side Effects: | |
674 | ** none. | |
675 | */ | |
676 | ||
677 | bool | |
75cdfff0 | 678 | writable(filename, ctladdr, flags) |
793aec0f | 679 | char *filename; |
75cdfff0 | 680 | ADDRESS *ctladdr; |
c9bddda6 | 681 | int flags; |
a0554f81 | 682 | { |
44967af8 EA |
683 | uid_t euid; |
684 | gid_t egid; | |
a0554f81 | 685 | int bits; |
fce21cb9 EA |
686 | register char *p; |
687 | char *uname; | |
a0554f81 | 688 | |
793aec0f | 689 | if (tTd(29, 5)) |
c9bddda6 | 690 | printf("writable(%s, %x)\n", filename, flags); |
fce21cb9 | 691 | |
d2865fc3 EA |
692 | #ifdef SUID_ROOT_FILES_OK |
693 | /* really ought to be passed down -- and not a good idea */ | |
694 | flags |= SFF_ROOTOK; | |
695 | #endif | |
696 | ||
fce21cb9 EA |
697 | /* |
698 | ** File does exist -- check that it is writable. | |
699 | */ | |
700 | ||
75cdfff0 | 701 | if (ctladdr != NULL && geteuid() == 0) |
fce21cb9 | 702 | { |
75cdfff0 EA |
703 | euid = ctladdr->q_uid; |
704 | egid = ctladdr->q_gid; | |
705 | uname = ctladdr->q_user; | |
706 | } | |
0c35b842 | 707 | #ifdef RUN_AS_REAL_UID |
75cdfff0 EA |
708 | else |
709 | { | |
d52f8819 EA |
710 | extern char RealUserName[]; |
711 | ||
75cdfff0 EA |
712 | euid = RealUid; |
713 | egid = RealGid; | |
714 | uname = RealUserName; | |
fce21cb9 | 715 | } |
0c35b842 EA |
716 | #else |
717 | else if (FileMailer != NULL) | |
718 | { | |
719 | euid = FileMailer->m_uid; | |
720 | egid = FileMailer->m_gid; | |
721 | } | |
722 | else | |
723 | { | |
724 | euid = egid = 0; | |
725 | } | |
726 | #endif | |
0aa35b96 EA |
727 | if (euid == 0) |
728 | { | |
729 | euid = DefUid; | |
730 | uname = DefUser; | |
731 | } | |
732 | if (egid == 0) | |
733 | egid = DefGid; | |
a0554f81 | 734 | if (geteuid() == 0) |
d52f8819 | 735 | flags |= SFF_SETUIDOK; |
a0554f81 | 736 | |
d52f8819 | 737 | errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); |
7763037f | 738 | return errno == 0; |
a0554f81 EA |
739 | } |
740 | \f/* | |
6eefe4f6 EA |
741 | ** INCLUDE -- handle :include: specification. |
742 | ** | |
743 | ** Parameters: | |
744 | ** fname -- filename to include. | |
a90a7c55 EA |
745 | ** forwarding -- if TRUE, we are reading a .forward file. |
746 | ** if FALSE, it's a :include: file. | |
1bf7c76b EA |
747 | ** ctladdr -- address template to use to fill in these |
748 | ** addresses -- effective user/group id are | |
749 | ** the important things. | |
d4f42161 EA |
750 | ** sendq -- a pointer to the head of the send queue |
751 | ** to put these addresses in. | |
f8c2f9fd EA |
752 | ** aliaslevel -- the alias nesting depth. |
753 | ** e -- the current envelope. | |
6eefe4f6 EA |
754 | ** |
755 | ** Returns: | |
e0136832 | 756 | ** open error status |
6eefe4f6 EA |
757 | ** |
758 | ** Side Effects: | |
759 | ** reads the :include: file and sends to everyone | |
760 | ** listed in that file. | |
247efdd6 EA |
761 | ** |
762 | ** Security Note: | |
763 | ** If you have restricted chown (that is, you can't | |
764 | ** give a file away), it is reasonable to allow programs | |
765 | ** and files called from this :include: file to be to be | |
766 | ** run as the owner of the :include: file. This is bogus | |
767 | ** if there is any chance of someone giving away a file. | |
768 | ** We assume that pre-POSIX systems can give away files. | |
769 | ** | |
770 | ** There is an additional restriction that if you | |
771 | ** forward to a :include: file, it will not take on | |
772 | ** the ownership of the :include: file. This may not | |
773 | ** be necessary, but shouldn't hurt. | |
6eefe4f6 EA |
774 | */ |
775 | ||
a90a7c55 | 776 | static jmp_buf CtxIncludeTimeout; |
ea07b2d2 | 777 | static void includetimeout(); |
a90a7c55 | 778 | |
e0136832 | 779 | int |
f8c2f9fd | 780 | include(fname, forwarding, ctladdr, sendq, aliaslevel, e) |
6eefe4f6 | 781 | char *fname; |
a90a7c55 | 782 | bool forwarding; |
1bf7c76b | 783 | ADDRESS *ctladdr; |
d4f42161 | 784 | ADDRESS **sendq; |
f8c2f9fd | 785 | int aliaslevel; |
a4076aed | 786 | ENVELOPE *e; |
6eefe4f6 | 787 | { |
ea07b2d2 | 788 | FILE *fp = NULL; |
a4076aed | 789 | char *oldto = e->e_to; |
7338e3d4 EA |
790 | char *oldfilename = FileName; |
791 | int oldlinenumber = LineNumber; | |
a90a7c55 | 792 | register EVENT *ev = NULL; |
1c7897ef | 793 | int nincludes; |
a614cf3b EA |
794 | register ADDRESS *ca; |
795 | uid_t saveduid, uid; | |
796 | gid_t savedgid, gid; | |
2b9924bc | 797 | char *uname; |
a614cf3b | 798 | int rval = 0; |
51cc57b9 | 799 | int sfflags = SFF_REGONLY; |
78a504b0 | 800 | struct stat st; |
117c4023 | 801 | char buf[MAXLINE]; |
247efdd6 | 802 | #ifdef _POSIX_CHOWN_RESTRICTED |
117c4023 EA |
803 | # if _POSIX_CHOWN_RESTRICTED == -1 |
804 | # define safechown FALSE | |
805 | # else | |
806 | # define safechown TRUE | |
807 | # endif | |
808 | #else | |
809 | # ifdef _PC_CHOWN_RESTRICTED | |
247efdd6 | 810 | bool safechown; |
117c4023 EA |
811 | # else |
812 | # ifdef BSD | |
813 | # define safechown TRUE | |
814 | # else | |
815 | # define safechown FALSE | |
816 | # endif | |
817 | # endif | |
247efdd6 | 818 | #endif |
117c4023 | 819 | extern bool chownsafe(); |
a90a7c55 | 820 | |
b21ec539 EA |
821 | if (tTd(27, 2)) |
822 | printf("include(%s)\n", fname); | |
ba6514e2 EA |
823 | if (tTd(27, 4)) |
824 | printf(" ruid=%d euid=%d\n", getuid(), geteuid()); | |
5d32a96c EA |
825 | if (tTd(27, 14)) |
826 | { | |
827 | printf("ctladdr "); | |
828 | printaddr(ctladdr, FALSE); | |
829 | } | |
b21ec539 | 830 | |
a614cf3b EA |
831 | if (tTd(27, 9)) |
832 | printf("include: old uid = %d/%d\n", getuid(), geteuid()); | |
a90a7c55 | 833 | |
51cc57b9 EA |
834 | if (forwarding) |
835 | sfflags |= SFF_MUSTOWN; | |
836 | ||
5d32a96c EA |
837 | ca = getctladdr(ctladdr); |
838 | if (ca == NULL) | |
2b9924bc | 839 | { |
f161b3d2 EA |
840 | uid = DefUid; |
841 | gid = DefGid; | |
842 | uname = DefUser; | |
2b9924bc | 843 | } |
5d32a96c | 844 | else |
2b9924bc | 845 | { |
5d32a96c | 846 | uid = ca->q_uid; |
2b9924bc EA |
847 | gid = ca->q_gid; |
848 | uname = ca->q_user; | |
af698ca4 | 849 | } |
a614cf3b | 850 | #ifdef HASSETREUID |
af698ca4 EA |
851 | saveduid = geteuid(); |
852 | savedgid = getegid(); | |
853 | if (saveduid == 0) | |
854 | { | |
855 | initgroups(uname, gid); | |
856 | if (uid != 0) | |
a614cf3b | 857 | { |
af698ca4 EA |
858 | if (setreuid(0, uid) < 0) |
859 | syserr("setreuid(0, %d) failure (real=%d, eff=%d)", | |
860 | uid, getuid(), geteuid()); | |
861 | else | |
862 | sfflags |= SFF_NOPATHCHECK; | |
a614cf3b | 863 | } |
2b9924bc | 864 | } |
af698ca4 | 865 | #endif |
5d32a96c | 866 | |
a614cf3b EA |
867 | if (tTd(27, 9)) |
868 | printf("include: new uid = %d/%d\n", getuid(), geteuid()); | |
869 | ||
870 | /* | |
871 | ** If home directory is remote mounted but server is down, | |
872 | ** this can hang or give errors; use a timeout to avoid this | |
873 | */ | |
874 | ||
a90a7c55 EA |
875 | if (setjmp(CtxIncludeTimeout) != 0) |
876 | { | |
c069e0df | 877 | ctladdr->q_flags |= QQUEUEUP; |
a90a7c55 | 878 | errno = 0; |
92f2b65e EA |
879 | |
880 | /* return pseudo-error code */ | |
a614cf3b EA |
881 | rval = EOPENTIMEOUT; |
882 | goto resetuid; | |
a90a7c55 | 883 | } |
039f3bb5 EA |
884 | if (TimeOuts.to_fileopen > 0) |
885 | ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); | |
886 | else | |
887 | ev = NULL; | |
a90a7c55 | 888 | |
5d32a96c | 889 | /* the input file must be marked safe */ |
d52f8819 | 890 | rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); |
09beeadc | 891 | if (rval != 0) |
a90a7c55 | 892 | { |
a614cf3b | 893 | /* don't use this :include: file */ |
b21ec539 | 894 | if (tTd(27, 4)) |
118e6693 | 895 | printf("include: not safe (uid=%d): %s\n", |
09beeadc | 896 | uid, errstring(rval)); |
a90a7c55 | 897 | } |
78a504b0 | 898 | else |
962c3fb2 | 899 | { |
78a504b0 EA |
900 | fp = fopen(fname, "r"); |
901 | if (fp == NULL) | |
5d41b806 | 902 | { |
09beeadc | 903 | rval = errno; |
78a504b0 EA |
904 | if (tTd(27, 4)) |
905 | printf("include: open: %s\n", errstring(rval)); | |
a2cdf9f6 | 906 | } |
962c3fb2 | 907 | } |
039f3bb5 EA |
908 | if (ev != NULL) |
909 | clrevent(ev); | |
a90a7c55 | 910 | |
a2cdf9f6 EA |
911 | resetuid: |
912 | ||
913 | #ifdef HASSETREUID | |
914 | if (saveduid == 0) | |
915 | { | |
916 | if (uid != 0) | |
8822417b EA |
917 | { |
918 | if (setreuid(-1, 0) < 0) | |
919 | syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", | |
920 | getuid(), geteuid()); | |
921 | if (setreuid(RealUid, 0) < 0) | |
a2cdf9f6 EA |
922 | syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", |
923 | RealUid, getuid(), geteuid()); | |
8822417b | 924 | } |
a2cdf9f6 EA |
925 | setgid(savedgid); |
926 | } | |
927 | #endif | |
928 | ||
929 | if (tTd(27, 9)) | |
930 | printf("include: reset uid = %d/%d\n", getuid(), geteuid()); | |
931 | ||
34bc9a9c EA |
932 | if (rval == EOPENTIMEOUT) |
933 | usrerr("451 open timeout on %s", fname); | |
934 | ||
a2cdf9f6 EA |
935 | if (fp == NULL) |
936 | return rval; | |
937 | ||
78a504b0 EA |
938 | if (fstat(fileno(fp), &st) < 0) |
939 | { | |
940 | rval = errno; | |
941 | syserr("Cannot fstat %s!", fname); | |
942 | return rval; | |
943 | } | |
944 | ||
117c4023 EA |
945 | #ifndef safechown |
946 | safechown = chownsafe(fileno(fp)); | |
947 | #endif | |
247efdd6 | 948 | if (ca == NULL && safechown) |
78a504b0 EA |
949 | { |
950 | ctladdr->q_uid = st.st_uid; | |
951 | ctladdr->q_gid = st.st_gid; | |
952 | ctladdr->q_flags |= QGOODUID; | |
953 | } | |
954 | if (ca != NULL && ca->q_uid == st.st_uid) | |
955 | { | |
956 | /* optimization -- avoid getpwuid if we already have info */ | |
957 | ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; | |
958 | ctladdr->q_ruser = ca->q_ruser; | |
959 | } | |
960 | else | |
961 | { | |
962 | register struct passwd *pw; | |
963 | ||
964 | pw = getpwuid(st.st_uid); | |
247efdd6 | 965 | if (pw == NULL) |
78a504b0 | 966 | ctladdr->q_flags |= QBOGUSSHELL; |
0c35b842 | 967 | else |
247efdd6 | 968 | { |
0c35b842 EA |
969 | char *sh; |
970 | ||
971 | ctladdr->q_ruser = newstr(pw->pw_name); | |
247efdd6 | 972 | if (safechown) |
0c35b842 | 973 | sh = pw->pw_shell; |
247efdd6 | 974 | else |
0c35b842 EA |
975 | sh = "/SENDMAIL/ANY/SHELL/"; |
976 | if (!usershellok(sh)) | |
977 | { | |
978 | if (safechown) | |
979 | ctladdr->q_flags |= QBOGUSSHELL; | |
980 | else | |
981 | ctladdr->q_flags |= QUNSAFEADDR; | |
982 | } | |
78a504b0 EA |
983 | } |
984 | } | |
985 | ||
8f48def8 EA |
986 | if (bitset(EF_VRFYONLY, e->e_flags)) |
987 | { | |
988 | /* don't do any more now */ | |
5f6654cf | 989 | ctladdr->q_flags |= QVERIFIED; |
a7dc53bd | 990 | e->e_nrcpts++; |
bc854e30 | 991 | xfclose(fp, "include", fname); |
a2cdf9f6 | 992 | return rval; |
8f48def8 EA |
993 | } |
994 | ||
78a504b0 EA |
995 | /* |
996 | ** Check to see if some bad guy can write this file | |
997 | ** | |
998 | ** This should really do something clever with group | |
999 | ** permissions; currently we just view world writable | |
1000 | ** as unsafe. Also, we don't check for writable | |
1001 | ** directories in the path. We've got to leave | |
1002 | ** something for the local sysad to do. | |
1003 | */ | |
1004 | ||
1005 | if (bitset(S_IWOTH, st.st_mode)) | |
1006 | ctladdr->q_flags |= QUNSAFEADDR; | |
1007 | ||
6eefe4f6 | 1008 | /* read the file -- each line is a comma-separated list. */ |
7338e3d4 EA |
1009 | FileName = fname; |
1010 | LineNumber = 0; | |
1c7897ef EA |
1011 | ctladdr->q_flags &= ~QSELFREF; |
1012 | nincludes = 0; | |
6eefe4f6 EA |
1013 | while (fgets(buf, sizeof buf, fp) != NULL) |
1014 | { | |
f3d8f6d6 | 1015 | register char *p = strchr(buf, '\n'); |
6eefe4f6 | 1016 | |
dd0758e5 | 1017 | LineNumber++; |
6eefe4f6 EA |
1018 | if (p != NULL) |
1019 | *p = '\0'; | |
b21ec539 | 1020 | if (buf[0] == '#' || buf[0] == '\0') |
af04f6e4 | 1021 | continue; |
51d9cc47 | 1022 | e->e_to = NULL; |
b6edea3d | 1023 | message("%s to %s", |
a90a7c55 | 1024 | forwarding ? "forwarding" : "sending", buf); |
aa102c71 | 1025 | #ifdef LOG |
68f7099c | 1026 | if (forwarding && LogLevel > 9) |
aa102c71 | 1027 | syslog(LOG_INFO, "%s: forward %s => %s", |
1db90aeb EA |
1028 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
1029 | oldto, buf); | |
aa102c71 EA |
1030 | #endif |
1031 | ||
f8c2f9fd | 1032 | nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); |
6eefe4f6 | 1033 | } |
ba6514e2 EA |
1034 | |
1035 | if (ferror(fp) && tTd(27, 3)) | |
1036 | printf("include: read error: %s\n", errstring(errno)); | |
1c7897ef | 1037 | if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) |
f7eca811 EA |
1038 | { |
1039 | if (tTd(27, 5)) | |
1040 | { | |
1041 | printf("include: QDONTSEND "); | |
1042 | printaddr(ctladdr, FALSE); | |
1043 | } | |
1044 | ctladdr->q_flags |= QDONTSEND; | |
1045 | } | |
6eefe4f6 | 1046 | |
bc854e30 | 1047 | (void) xfclose(fp, "include", fname); |
7338e3d4 EA |
1048 | FileName = oldfilename; |
1049 | LineNumber = oldlinenumber; | |
d1147db7 | 1050 | e->e_to = oldto; |
a614cf3b | 1051 | return rval; |
6eefe4f6 | 1052 | } |
a90a7c55 | 1053 | |
ea07b2d2 | 1054 | static void |
a90a7c55 EA |
1055 | includetimeout() |
1056 | { | |
1057 | longjmp(CtxIncludeTimeout, 1); | |
1058 | } | |
d6b27179 EA |
1059 | \f/* |
1060 | ** SENDTOARGV -- send to an argument vector. | |
1061 | ** | |
1062 | ** Parameters: | |
1063 | ** argv -- argument vector to send to. | |
118e6693 | 1064 | ** e -- the current envelope. |
d6b27179 EA |
1065 | ** |
1066 | ** Returns: | |
1067 | ** none. | |
1068 | ** | |
1069 | ** Side Effects: | |
1070 | ** puts all addresses on the argument vector onto the | |
1071 | ** send queue. | |
1072 | */ | |
1073 | ||
a4076aed | 1074 | sendtoargv(argv, e) |
d6b27179 | 1075 | register char **argv; |
a4076aed | 1076 | register ENVELOPE *e; |
d6b27179 EA |
1077 | { |
1078 | register char *p; | |
d6b27179 EA |
1079 | |
1080 | while ((p = *argv++) != NULL) | |
1081 | { | |
abae7b2d | 1082 | sendto(p, 0, (ADDRESS *) NULL, 0); |
d6b27179 EA |
1083 | } |
1084 | } | |
1bf7c76b EA |
1085 | \f/* |
1086 | ** GETCTLADDR -- get controlling address from an address header. | |
1087 | ** | |
1088 | ** If none, get one corresponding to the effective userid. | |
1089 | ** | |
1090 | ** Parameters: | |
1091 | ** a -- the address to find the controller of. | |
1092 | ** | |
1093 | ** Returns: | |
1094 | ** the controlling address. | |
1095 | ** | |
1096 | ** Side Effects: | |
1097 | ** none. | |
1098 | */ | |
1099 | ||
1100 | ADDRESS * | |
1101 | getctladdr(a) | |
1102 | register ADDRESS *a; | |
1103 | { | |
2c1457f0 | 1104 | while (a != NULL && !bitset(QGOODUID, a->q_flags)) |
1bf7c76b | 1105 | a = a->q_alias; |
1bf7c76b EA |
1106 | return (a); |
1107 | } |