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