1 | /* |
---|
2 | * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. |
---|
3 | * All rights reserved. |
---|
4 | * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. |
---|
5 | * Copyright (c) 1988, 1993 |
---|
6 | * The Regents of the University of California. All rights reserved. |
---|
7 | * |
---|
8 | * By using this file, you agree to the terms and conditions set |
---|
9 | * forth in the LICENSE file which can be found at the top level of |
---|
10 | * the sendmail distribution. |
---|
11 | * |
---|
12 | */ |
---|
13 | |
---|
14 | #include <sendmail.h> |
---|
15 | |
---|
16 | SM_RCSID("@(#)$Id: recipient.c,v 1.1.1.1 2003-04-08 15:08:04 zacheiss Exp $") |
---|
17 | |
---|
18 | static void includetimeout __P((void)); |
---|
19 | static ADDRESS *self_reference __P((ADDRESS *)); |
---|
20 | static int sortexpensive __P((ADDRESS *, ADDRESS *)); |
---|
21 | static int sortbysignature __P((ADDRESS *, ADDRESS *)); |
---|
22 | static int sorthost __P((ADDRESS *, ADDRESS *)); |
---|
23 | |
---|
24 | typedef int sortfn_t __P((ADDRESS *, ADDRESS *)); |
---|
25 | |
---|
26 | /* |
---|
27 | ** SORTHOST -- strcmp()-like func for host portion of an ADDRESS |
---|
28 | ** |
---|
29 | ** Parameters: |
---|
30 | ** xx -- first ADDRESS |
---|
31 | ** yy -- second ADDRESS |
---|
32 | ** |
---|
33 | ** Returns: |
---|
34 | ** <0 when xx->q_host is less than yy->q_host |
---|
35 | ** >0 when xx->q_host is greater than yy->q_host |
---|
36 | ** 0 when equal |
---|
37 | */ |
---|
38 | |
---|
39 | static int |
---|
40 | sorthost(xx, yy) |
---|
41 | register ADDRESS *xx; |
---|
42 | register ADDRESS *yy; |
---|
43 | { |
---|
44 | #if _FFR_HOST_SORT_REVERSE |
---|
45 | /* XXX maybe compare hostnames from the end? */ |
---|
46 | return sm_strrevcasecmp(xx->q_host, yy->q_host); |
---|
47 | #else /* _FFR_HOST_SORT_REVERSE */ |
---|
48 | return sm_strcasecmp(xx->q_host, yy->q_host); |
---|
49 | #endif /* _FFR_HOST_SORT_REVERSE */ |
---|
50 | } |
---|
51 | |
---|
52 | /* |
---|
53 | ** SORTEXPENSIVE -- strcmp()-like func for expensive mailers |
---|
54 | ** |
---|
55 | ** The mailer has been noted already as "expensive" for 'xx'. This |
---|
56 | ** will give a result relative to 'yy'. Expensive mailers get rated |
---|
57 | ** "greater than" non-expensive mailers because during the delivery phase |
---|
58 | ** it will get queued -- no use it getting in the way of less expensive |
---|
59 | ** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are |
---|
60 | ** expensive since an MX RR lookup happens when extracted from the queue |
---|
61 | ** later. |
---|
62 | ** |
---|
63 | ** Parameters: |
---|
64 | ** xx -- first ADDRESS |
---|
65 | ** yy -- second ADDRESS |
---|
66 | ** |
---|
67 | ** Returns: |
---|
68 | ** <0 when xx->q_host is less than yy->q_host and both are |
---|
69 | ** expensive |
---|
70 | ** >0 when xx->q_host is greater than yy->q_host, or when |
---|
71 | ** 'yy' is non-expensive |
---|
72 | ** 0 when equal (by expense and q_host) |
---|
73 | */ |
---|
74 | |
---|
75 | static int |
---|
76 | sortexpensive(xx, yy) |
---|
77 | ADDRESS *xx; |
---|
78 | ADDRESS *yy; |
---|
79 | { |
---|
80 | if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags)) |
---|
81 | return 1; /* xx should go later */ |
---|
82 | #if _FFR_HOST_SORT_REVERSE |
---|
83 | /* XXX maybe compare hostnames from the end? */ |
---|
84 | return sm_strrevcasecmp(xx->q_host, yy->q_host); |
---|
85 | #else /* _FFR_HOST_SORT_REVERSE */ |
---|
86 | return sm_strcasecmp(xx->q_host, yy->q_host); |
---|
87 | #endif /* _FFR_HOST_SORT_REVERSE */ |
---|
88 | } |
---|
89 | |
---|
90 | /* |
---|
91 | ** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS |
---|
92 | ** |
---|
93 | ** Parameters: |
---|
94 | ** xx -- first ADDRESS |
---|
95 | ** yy -- second ADDRESS |
---|
96 | ** |
---|
97 | ** Returns: |
---|
98 | ** 0 when the "signature"'s are same |
---|
99 | ** <0 when xx->q_signature is less than yy->q_signature |
---|
100 | ** >0 when xx->q_signature is greater than yy->q_signature |
---|
101 | ** |
---|
102 | ** Side Effect: |
---|
103 | ** May set ADDRESS pointer for q_signature if not already set. |
---|
104 | */ |
---|
105 | |
---|
106 | static int |
---|
107 | sortbysignature(xx, yy) |
---|
108 | ADDRESS *xx; |
---|
109 | ADDRESS *yy; |
---|
110 | { |
---|
111 | register int ret; |
---|
112 | |
---|
113 | /* Let's avoid redoing the signature over and over again */ |
---|
114 | if (xx->q_signature == NULL) |
---|
115 | xx->q_signature = hostsignature(xx->q_mailer, xx->q_host); |
---|
116 | if (yy->q_signature == NULL) |
---|
117 | yy->q_signature = hostsignature(yy->q_mailer, yy->q_host); |
---|
118 | ret = strcmp(xx->q_signature, yy->q_signature); |
---|
119 | |
---|
120 | /* |
---|
121 | ** If the two signatures are the same then we will return a sort |
---|
122 | ** value based on 'q_user'. But note that we have reversed xx and yy |
---|
123 | ** on purpose. This additional compare helps reduce the number of |
---|
124 | ** sameaddr() calls and loops in recipient() for the case when |
---|
125 | ** the rcpt list has been provided already in-order. |
---|
126 | */ |
---|
127 | |
---|
128 | if (ret == 0) |
---|
129 | return strcmp(yy->q_user, xx->q_user); |
---|
130 | else |
---|
131 | return ret; |
---|
132 | } |
---|
133 | |
---|
134 | /* |
---|
135 | ** SENDTOLIST -- Designate a send list. |
---|
136 | ** |
---|
137 | ** The parameter is a comma-separated list of people to send to. |
---|
138 | ** This routine arranges to send to all of them. |
---|
139 | ** |
---|
140 | ** Parameters: |
---|
141 | ** list -- the send list. |
---|
142 | ** ctladdr -- the address template for the person to |
---|
143 | ** send to -- effective uid/gid are important. |
---|
144 | ** This is typically the alias that caused this |
---|
145 | ** expansion. |
---|
146 | ** sendq -- a pointer to the head of a queue to put |
---|
147 | ** these people into. |
---|
148 | ** aliaslevel -- the current alias nesting depth -- to |
---|
149 | ** diagnose loops. |
---|
150 | ** e -- the envelope in which to add these recipients. |
---|
151 | ** |
---|
152 | ** Returns: |
---|
153 | ** The number of addresses actually on the list. |
---|
154 | */ |
---|
155 | |
---|
156 | /* q_flags bits inherited from ctladdr */ |
---|
157 | #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) |
---|
158 | |
---|
159 | int |
---|
160 | sendtolist(list, ctladdr, sendq, aliaslevel, e) |
---|
161 | char *list; |
---|
162 | ADDRESS *ctladdr; |
---|
163 | ADDRESS **sendq; |
---|
164 | int aliaslevel; |
---|
165 | register ENVELOPE *e; |
---|
166 | { |
---|
167 | register char *p; |
---|
168 | register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */ |
---|
169 | SM_NONVOLATILE char delimiter; /* the address delimiter */ |
---|
170 | SM_NONVOLATILE int naddrs; |
---|
171 | SM_NONVOLATILE int i; |
---|
172 | char *oldto = e->e_to; |
---|
173 | char *SM_NONVOLATILE bufp; |
---|
174 | char buf[MAXNAME + 1]; |
---|
175 | |
---|
176 | if (list == NULL) |
---|
177 | { |
---|
178 | syserr("sendtolist: null list"); |
---|
179 | return 0; |
---|
180 | } |
---|
181 | |
---|
182 | if (tTd(25, 1)) |
---|
183 | { |
---|
184 | sm_dprintf("sendto: %s\n ctladdr=", list); |
---|
185 | printaddr(ctladdr, false); |
---|
186 | } |
---|
187 | |
---|
188 | /* heuristic to determine old versus new style addresses */ |
---|
189 | if (ctladdr == NULL && |
---|
190 | (strchr(list, ',') != NULL || strchr(list, ';') != NULL || |
---|
191 | strchr(list, '<') != NULL || strchr(list, '(') != NULL)) |
---|
192 | e->e_flags &= ~EF_OLDSTYLE; |
---|
193 | delimiter = ' '; |
---|
194 | if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) |
---|
195 | delimiter = ','; |
---|
196 | |
---|
197 | al = NULL; |
---|
198 | naddrs = 0; |
---|
199 | |
---|
200 | /* make sure we have enough space to copy the string */ |
---|
201 | i = strlen(list) + 1; |
---|
202 | if (i <= sizeof buf) |
---|
203 | { |
---|
204 | bufp = buf; |
---|
205 | i = sizeof buf; |
---|
206 | } |
---|
207 | else |
---|
208 | bufp = sm_malloc_x(i); |
---|
209 | |
---|
210 | SM_TRY |
---|
211 | { |
---|
212 | (void) sm_strlcpy(bufp, denlstring(list, false, true), i); |
---|
213 | |
---|
214 | macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); |
---|
215 | for (p = bufp; *p != '\0'; ) |
---|
216 | { |
---|
217 | auto char *delimptr; |
---|
218 | register ADDRESS *a; |
---|
219 | |
---|
220 | /* parse the address */ |
---|
221 | while ((isascii(*p) && isspace(*p)) || *p == ',') |
---|
222 | p++; |
---|
223 | a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, |
---|
224 | &delimptr, e, true); |
---|
225 | p = delimptr; |
---|
226 | if (a == NULL) |
---|
227 | continue; |
---|
228 | a->q_next = al; |
---|
229 | a->q_alias = ctladdr; |
---|
230 | |
---|
231 | /* arrange to inherit attributes from parent */ |
---|
232 | if (ctladdr != NULL) |
---|
233 | { |
---|
234 | ADDRESS *b; |
---|
235 | |
---|
236 | /* self reference test */ |
---|
237 | if (sameaddr(ctladdr, a)) |
---|
238 | { |
---|
239 | if (tTd(27, 5)) |
---|
240 | { |
---|
241 | sm_dprintf("sendtolist: QSELFREF "); |
---|
242 | printaddr(ctladdr, false); |
---|
243 | } |
---|
244 | ctladdr->q_flags |= QSELFREF; |
---|
245 | } |
---|
246 | |
---|
247 | /* check for address loops */ |
---|
248 | b = self_reference(a); |
---|
249 | if (b != NULL) |
---|
250 | { |
---|
251 | b->q_flags |= QSELFREF; |
---|
252 | if (tTd(27, 5)) |
---|
253 | { |
---|
254 | sm_dprintf("sendtolist: QSELFREF "); |
---|
255 | printaddr(b, false); |
---|
256 | } |
---|
257 | if (a != b) |
---|
258 | { |
---|
259 | if (tTd(27, 5)) |
---|
260 | { |
---|
261 | sm_dprintf("sendtolist: QS_DONTSEND "); |
---|
262 | printaddr(a, false); |
---|
263 | } |
---|
264 | a->q_state = QS_DONTSEND; |
---|
265 | b->q_flags |= a->q_flags & QNOTREMOTE; |
---|
266 | continue; |
---|
267 | } |
---|
268 | } |
---|
269 | |
---|
270 | /* full name */ |
---|
271 | if (a->q_fullname == NULL) |
---|
272 | a->q_fullname = ctladdr->q_fullname; |
---|
273 | |
---|
274 | /* various flag bits */ |
---|
275 | a->q_flags &= ~QINHERITEDBITS; |
---|
276 | a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; |
---|
277 | |
---|
278 | /* DSN recipient information */ |
---|
279 | a->q_finalrcpt = ctladdr->q_finalrcpt; |
---|
280 | a->q_orcpt = ctladdr->q_orcpt; |
---|
281 | } |
---|
282 | |
---|
283 | al = a; |
---|
284 | } |
---|
285 | |
---|
286 | /* arrange to send to everyone on the local send list */ |
---|
287 | while (al != NULL) |
---|
288 | { |
---|
289 | register ADDRESS *a = al; |
---|
290 | |
---|
291 | al = a->q_next; |
---|
292 | a = recipient(a, sendq, aliaslevel, e); |
---|
293 | naddrs++; |
---|
294 | } |
---|
295 | } |
---|
296 | SM_FINALLY |
---|
297 | { |
---|
298 | e->e_to = oldto; |
---|
299 | if (bufp != buf) |
---|
300 | sm_free(bufp); |
---|
301 | macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); |
---|
302 | } |
---|
303 | SM_END_TRY |
---|
304 | return naddrs; |
---|
305 | } |
---|
306 | #if MILTER |
---|
307 | /* |
---|
308 | ** REMOVEFROMLIST -- Remove addresses from a send list. |
---|
309 | ** |
---|
310 | ** The parameter is a comma-separated list of recipients to remove. |
---|
311 | ** Note that it only deletes matching addresses. If those addresses |
---|
312 | ** have been expanded already in the sendq, it won't mark the |
---|
313 | ** expanded recipients as QS_REMOVED. |
---|
314 | ** |
---|
315 | ** Parameters: |
---|
316 | ** list -- the list to remove. |
---|
317 | ** sendq -- a pointer to the head of a queue to remove |
---|
318 | ** these addresses from. |
---|
319 | ** e -- the envelope in which to remove these recipients. |
---|
320 | ** |
---|
321 | ** Returns: |
---|
322 | ** The number of addresses removed from the list. |
---|
323 | ** |
---|
324 | */ |
---|
325 | |
---|
326 | int |
---|
327 | removefromlist(list, sendq, e) |
---|
328 | char *list; |
---|
329 | ADDRESS **sendq; |
---|
330 | ENVELOPE *e; |
---|
331 | { |
---|
332 | SM_NONVOLATILE char delimiter; /* the address delimiter */ |
---|
333 | SM_NONVOLATILE int naddrs; |
---|
334 | SM_NONVOLATILE int i; |
---|
335 | char *p; |
---|
336 | char *oldto = e->e_to; |
---|
337 | char *SM_NONVOLATILE bufp; |
---|
338 | char buf[MAXNAME + 1]; |
---|
339 | |
---|
340 | if (list == NULL) |
---|
341 | { |
---|
342 | syserr("removefromlist: null list"); |
---|
343 | return 0; |
---|
344 | } |
---|
345 | |
---|
346 | if (tTd(25, 1)) |
---|
347 | sm_dprintf("removefromlist: %s\n", list); |
---|
348 | |
---|
349 | /* heuristic to determine old versus new style addresses */ |
---|
350 | if (strchr(list, ',') != NULL || strchr(list, ';') != NULL || |
---|
351 | strchr(list, '<') != NULL || strchr(list, '(') != NULL) |
---|
352 | e->e_flags &= ~EF_OLDSTYLE; |
---|
353 | delimiter = ' '; |
---|
354 | if (!bitset(EF_OLDSTYLE, e->e_flags)) |
---|
355 | delimiter = ','; |
---|
356 | |
---|
357 | naddrs = 0; |
---|
358 | |
---|
359 | /* make sure we have enough space to copy the string */ |
---|
360 | i = strlen(list) + 1; |
---|
361 | if (i <= sizeof buf) |
---|
362 | { |
---|
363 | bufp = buf; |
---|
364 | i = sizeof buf; |
---|
365 | } |
---|
366 | else |
---|
367 | bufp = sm_malloc_x(i); |
---|
368 | |
---|
369 | SM_TRY |
---|
370 | { |
---|
371 | (void) sm_strlcpy(bufp, denlstring(list, false, true), i); |
---|
372 | |
---|
373 | macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); |
---|
374 | for (p = bufp; *p != '\0'; ) |
---|
375 | { |
---|
376 | ADDRESS a; /* parsed address to be removed */ |
---|
377 | ADDRESS *q; |
---|
378 | ADDRESS **pq; |
---|
379 | char *delimptr; |
---|
380 | |
---|
381 | /* parse the address */ |
---|
382 | while ((isascii(*p) && isspace(*p)) || *p == ',') |
---|
383 | p++; |
---|
384 | if (parseaddr(p, &a, RF_COPYALL, |
---|
385 | delimiter, &delimptr, e, true) == NULL) |
---|
386 | { |
---|
387 | p = delimptr; |
---|
388 | continue; |
---|
389 | } |
---|
390 | p = delimptr; |
---|
391 | for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) |
---|
392 | { |
---|
393 | if (!QS_IS_DEAD(q->q_state) && |
---|
394 | sameaddr(q, &a)) |
---|
395 | { |
---|
396 | if (tTd(25, 5)) |
---|
397 | { |
---|
398 | sm_dprintf("removefromlist: QS_REMOVED "); |
---|
399 | printaddr(&a, false); |
---|
400 | } |
---|
401 | q->q_state = QS_REMOVED; |
---|
402 | naddrs++; |
---|
403 | break; |
---|
404 | } |
---|
405 | } |
---|
406 | } |
---|
407 | } |
---|
408 | SM_FINALLY |
---|
409 | { |
---|
410 | e->e_to = oldto; |
---|
411 | if (bufp != buf) |
---|
412 | sm_free(bufp); |
---|
413 | macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); |
---|
414 | } |
---|
415 | SM_END_TRY |
---|
416 | return naddrs; |
---|
417 | } |
---|
418 | #endif /* MILTER */ |
---|
419 | /* |
---|
420 | ** RECIPIENT -- Designate a message recipient |
---|
421 | ** |
---|
422 | ** Saves the named person for future mailing. |
---|
423 | ** |
---|
424 | ** Parameters: |
---|
425 | ** new -- the (preparsed) address header for the recipient. |
---|
426 | ** sendq -- a pointer to the head of a queue to put the |
---|
427 | ** recipient in. Duplicate suppression is done |
---|
428 | ** in this queue. |
---|
429 | ** aliaslevel -- the current alias nesting depth. |
---|
430 | ** e -- the current envelope. |
---|
431 | ** |
---|
432 | ** Returns: |
---|
433 | ** The actual address in the queue. This will be "a" if |
---|
434 | ** the address is not a duplicate, else the original address. |
---|
435 | ** |
---|
436 | */ |
---|
437 | |
---|
438 | ADDRESS * |
---|
439 | recipient(new, sendq, aliaslevel, e) |
---|
440 | register ADDRESS *new; |
---|
441 | register ADDRESS **sendq; |
---|
442 | int aliaslevel; |
---|
443 | register ENVELOPE *e; |
---|
444 | { |
---|
445 | register ADDRESS *q; |
---|
446 | ADDRESS **pq; |
---|
447 | ADDRESS **prev; |
---|
448 | register struct mailer *m; |
---|
449 | register char *p; |
---|
450 | int i, buflen; |
---|
451 | bool quoted; /* set if the addr has a quote bit */ |
---|
452 | bool insert; |
---|
453 | int findusercount; |
---|
454 | bool initialdontsend; |
---|
455 | char *buf; |
---|
456 | char buf0[MAXNAME + 1]; /* unquoted image of the user name */ |
---|
457 | sortfn_t *sortfn; |
---|
458 | |
---|
459 | p = NULL; |
---|
460 | quoted = false; |
---|
461 | insert = false; |
---|
462 | findusercount = 0; |
---|
463 | initialdontsend = QS_IS_DEAD(new->q_state); |
---|
464 | e->e_to = new->q_paddr; |
---|
465 | m = new->q_mailer; |
---|
466 | errno = 0; |
---|
467 | if (aliaslevel == 0) |
---|
468 | new->q_flags |= QPRIMARY; |
---|
469 | if (tTd(26, 1)) |
---|
470 | { |
---|
471 | sm_dprintf("\nrecipient (%d): ", aliaslevel); |
---|
472 | printaddr(new, false); |
---|
473 | } |
---|
474 | |
---|
475 | /* if this is primary, use it as original recipient */ |
---|
476 | if (new->q_alias == NULL) |
---|
477 | { |
---|
478 | if (e->e_origrcpt == NULL) |
---|
479 | e->e_origrcpt = new->q_paddr; |
---|
480 | else if (e->e_origrcpt != new->q_paddr) |
---|
481 | e->e_origrcpt = ""; |
---|
482 | } |
---|
483 | |
---|
484 | /* find parent recipient for finalrcpt and orcpt */ |
---|
485 | for (q = new; q->q_alias != NULL; q = q->q_alias) |
---|
486 | continue; |
---|
487 | |
---|
488 | /* find final recipient DSN address */ |
---|
489 | if (new->q_finalrcpt == NULL && |
---|
490 | e->e_from.q_mailer != NULL) |
---|
491 | { |
---|
492 | char frbuf[MAXLINE]; |
---|
493 | |
---|
494 | p = e->e_from.q_mailer->m_addrtype; |
---|
495 | if (p == NULL) |
---|
496 | p = "rfc822"; |
---|
497 | if (sm_strcasecmp(p, "rfc822") != 0) |
---|
498 | { |
---|
499 | (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", |
---|
500 | q->q_mailer->m_addrtype, |
---|
501 | q->q_user); |
---|
502 | } |
---|
503 | else if (strchr(q->q_user, '@') != NULL) |
---|
504 | { |
---|
505 | (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", |
---|
506 | p, q->q_user); |
---|
507 | } |
---|
508 | else if (strchr(q->q_paddr, '@') != NULL) |
---|
509 | { |
---|
510 | char *qp; |
---|
511 | bool b; |
---|
512 | |
---|
513 | qp = q->q_paddr; |
---|
514 | |
---|
515 | /* strip brackets from address */ |
---|
516 | b = false; |
---|
517 | if (*qp == '<') |
---|
518 | { |
---|
519 | b = qp[strlen(qp) - 1] == '>'; |
---|
520 | if (b) |
---|
521 | qp[strlen(qp) - 1] = '\0'; |
---|
522 | qp++; |
---|
523 | } |
---|
524 | (void) sm_snprintf(frbuf, sizeof frbuf, "%s; %.800s", |
---|
525 | p, qp); |
---|
526 | |
---|
527 | /* undo damage */ |
---|
528 | if (b) |
---|
529 | qp[strlen(qp)] = '>'; |
---|
530 | } |
---|
531 | else |
---|
532 | { |
---|
533 | (void) sm_snprintf(frbuf, sizeof frbuf, |
---|
534 | "%s; %.700s@%.100s", |
---|
535 | p, q->q_user, MyHostName); |
---|
536 | } |
---|
537 | new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf); |
---|
538 | } |
---|
539 | |
---|
540 | #if _FFR_GEN_ORCPT |
---|
541 | /* set ORCPT DSN arg if not already set */ |
---|
542 | if (new->q_orcpt == NULL) |
---|
543 | { |
---|
544 | /* check for an existing ORCPT */ |
---|
545 | if (q->q_orcpt != NULL) |
---|
546 | new->q_orcpt = q->q_orcpt; |
---|
547 | else |
---|
548 | { |
---|
549 | /* make our own */ |
---|
550 | bool b = false; |
---|
551 | char *qp; |
---|
552 | char obuf[MAXLINE]; |
---|
553 | |
---|
554 | if (e->e_from.q_mailer != NULL) |
---|
555 | p = e->e_from.q_mailer->m_addrtype; |
---|
556 | if (p == NULL) |
---|
557 | p = "rfc822"; |
---|
558 | (void) sm_strlcpyn(obuf, sizeof obuf, 2, p, ";"); |
---|
559 | |
---|
560 | qp = q->q_paddr; |
---|
561 | |
---|
562 | /* FFR: Needs to strip comments from stdin addrs */ |
---|
563 | |
---|
564 | /* strip brackets from address */ |
---|
565 | if (*qp == '<') |
---|
566 | { |
---|
567 | b = qp[strlen(qp) - 1] == '>'; |
---|
568 | if (b) |
---|
569 | qp[strlen(qp) - 1] = '\0'; |
---|
570 | qp++; |
---|
571 | } |
---|
572 | |
---|
573 | p = xtextify(denlstring(qp, true, false), NULL); |
---|
574 | |
---|
575 | if (sm_strlcat(obuf, p, sizeof obuf) >= sizeof obuf) |
---|
576 | { |
---|
577 | /* if too big, don't use it */ |
---|
578 | obuf[0] = '\0'; |
---|
579 | } |
---|
580 | |
---|
581 | /* undo damage */ |
---|
582 | if (b) |
---|
583 | qp[strlen(qp)] = '>'; |
---|
584 | |
---|
585 | if (obuf[0] != '\0') |
---|
586 | new->q_orcpt = |
---|
587 | sm_rpool_strdup_x(e->e_rpool, obuf); |
---|
588 | } |
---|
589 | } |
---|
590 | #endif /* _FFR_GEN_ORCPT */ |
---|
591 | |
---|
592 | /* break aliasing loops */ |
---|
593 | if (aliaslevel > MaxAliasRecursion) |
---|
594 | { |
---|
595 | new->q_state = QS_BADADDR; |
---|
596 | new->q_status = "5.4.6"; |
---|
597 | usrerrenh(new->q_status, |
---|
598 | "554 aliasing/forwarding loop broken (%d aliases deep; %d max)", |
---|
599 | aliaslevel, MaxAliasRecursion); |
---|
600 | return new; |
---|
601 | } |
---|
602 | |
---|
603 | /* |
---|
604 | ** Finish setting up address structure. |
---|
605 | */ |
---|
606 | |
---|
607 | /* get unquoted user for file, program or user.name check */ |
---|
608 | i = strlen(new->q_user); |
---|
609 | if (i >= sizeof buf0) |
---|
610 | { |
---|
611 | buflen = i + 1; |
---|
612 | buf = xalloc(buflen); |
---|
613 | } |
---|
614 | else |
---|
615 | { |
---|
616 | buf = buf0; |
---|
617 | buflen = sizeof buf0; |
---|
618 | } |
---|
619 | (void) sm_strlcpy(buf, new->q_user, buflen); |
---|
620 | for (p = buf; *p != '\0' && !quoted; p++) |
---|
621 | { |
---|
622 | if (*p == '\\') |
---|
623 | quoted = true; |
---|
624 | } |
---|
625 | stripquotes(buf); |
---|
626 | |
---|
627 | /* check for direct mailing to restricted mailers */ |
---|
628 | if (m == ProgMailer) |
---|
629 | { |
---|
630 | if (new->q_alias == NULL || UseMSP || |
---|
631 | bitset(EF_UNSAFE, e->e_flags)) |
---|
632 | { |
---|
633 | new->q_state = QS_BADADDR; |
---|
634 | new->q_status = "5.7.1"; |
---|
635 | usrerrenh(new->q_status, |
---|
636 | "550 Cannot mail directly to programs"); |
---|
637 | } |
---|
638 | else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) |
---|
639 | { |
---|
640 | new->q_state = QS_BADADDR; |
---|
641 | new->q_status = "5.7.1"; |
---|
642 | if (new->q_alias->q_ruser == NULL) |
---|
643 | usrerrenh(new->q_status, |
---|
644 | "550 UID %d is an unknown user: cannot mail to programs", |
---|
645 | new->q_alias->q_uid); |
---|
646 | else |
---|
647 | usrerrenh(new->q_status, |
---|
648 | "550 User %s@%s doesn't have a valid shell for mailing to programs", |
---|
649 | new->q_alias->q_ruser, MyHostName); |
---|
650 | } |
---|
651 | else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) |
---|
652 | { |
---|
653 | new->q_state = QS_BADADDR; |
---|
654 | new->q_status = "5.7.1"; |
---|
655 | new->q_rstatus = "550 Unsafe for mailing to programs"; |
---|
656 | usrerrenh(new->q_status, |
---|
657 | "550 Address %s is unsafe for mailing to programs", |
---|
658 | new->q_alias->q_paddr); |
---|
659 | } |
---|
660 | } |
---|
661 | |
---|
662 | /* |
---|
663 | ** Look up this person in the recipient list. |
---|
664 | ** If they are there already, return, otherwise continue. |
---|
665 | ** If the list is empty, just add it. Notice the cute |
---|
666 | ** hack to make from addresses suppress things correctly: |
---|
667 | ** the QS_DUPLICATE state will be set in the send list. |
---|
668 | ** [Please note: the emphasis is on "hack."] |
---|
669 | */ |
---|
670 | |
---|
671 | prev = NULL; |
---|
672 | |
---|
673 | /* |
---|
674 | ** If this message is going to the queue or FastSplit is set |
---|
675 | ** and it is the first try and the envelope hasn't split, then we |
---|
676 | ** avoid doing an MX RR lookup now because one will be done when the |
---|
677 | ** message is extracted from the queue later. It can go to the queue |
---|
678 | ** because all messages are going to the queue or this mailer of |
---|
679 | ** the current recipient is marked expensive. |
---|
680 | */ |
---|
681 | |
---|
682 | if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) || |
---|
683 | (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 && |
---|
684 | FastSplit > 0)) |
---|
685 | sortfn = sorthost; |
---|
686 | else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags)) |
---|
687 | sortfn = sortexpensive; |
---|
688 | else |
---|
689 | sortfn = sortbysignature; |
---|
690 | |
---|
691 | for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) |
---|
692 | { |
---|
693 | /* |
---|
694 | ** If address is "less than" it should be inserted now. |
---|
695 | ** If address is "greater than" current comparison it'll |
---|
696 | ** insert later in the list; so loop again (if possible). |
---|
697 | ** If address is "equal" (different equal than sameaddr() |
---|
698 | ** call) then check if sameaddr() will be true. |
---|
699 | ** Because this list is now sorted, it'll mean fewer |
---|
700 | ** comparisons and fewer loops which is important for more |
---|
701 | ** recipients. |
---|
702 | */ |
---|
703 | |
---|
704 | i = (*sortfn)(new, q); |
---|
705 | if (i == 0) /* equal */ |
---|
706 | { |
---|
707 | /* |
---|
708 | ** Sortbysignature() has said that the two have |
---|
709 | ** equal MX RR's and the same user. Calling sameaddr() |
---|
710 | ** now checks if the two hosts are as identical as the |
---|
711 | ** MX RR's are (which might not be the case) |
---|
712 | ** before saying these are the identical addresses. |
---|
713 | */ |
---|
714 | |
---|
715 | if (sameaddr(q, new) && |
---|
716 | (bitset(QRCPTOK, q->q_flags) || |
---|
717 | !bitset(QPRIMARY, q->q_flags))) |
---|
718 | { |
---|
719 | if (tTd(26, 1)) |
---|
720 | { |
---|
721 | sm_dprintf("%s in sendq: ", |
---|
722 | new->q_paddr); |
---|
723 | printaddr(q, false); |
---|
724 | } |
---|
725 | if (!bitset(QPRIMARY, q->q_flags)) |
---|
726 | { |
---|
727 | if (!QS_IS_DEAD(new->q_state)) |
---|
728 | message("duplicate suppressed"); |
---|
729 | else |
---|
730 | q->q_state = QS_DUPLICATE; |
---|
731 | q->q_flags |= new->q_flags; |
---|
732 | } |
---|
733 | else if (bitset(QSELFREF, q->q_flags) |
---|
734 | || q->q_state == QS_REMOVED) |
---|
735 | { |
---|
736 | /* |
---|
737 | ** If an earlier milter removed the |
---|
738 | ** address, a later one can still add |
---|
739 | ** it back. |
---|
740 | */ |
---|
741 | |
---|
742 | q->q_state = new->q_state; |
---|
743 | q->q_flags |= new->q_flags; |
---|
744 | } |
---|
745 | new = q; |
---|
746 | goto done; |
---|
747 | } |
---|
748 | } |
---|
749 | else if (i < 0) /* less than */ |
---|
750 | { |
---|
751 | insert = true; |
---|
752 | break; |
---|
753 | } |
---|
754 | prev = pq; |
---|
755 | } |
---|
756 | |
---|
757 | /* pq should point to an address, never NULL */ |
---|
758 | SM_ASSERT(pq != NULL); |
---|
759 | |
---|
760 | /* add address on list */ |
---|
761 | if (insert) |
---|
762 | { |
---|
763 | /* |
---|
764 | ** insert before 'pq'. Only possible when at least 1 |
---|
765 | ** ADDRESS is in the list already. |
---|
766 | */ |
---|
767 | |
---|
768 | new->q_next = *pq; |
---|
769 | if (prev == NULL) |
---|
770 | *sendq = new; /* To be the first ADDRESS */ |
---|
771 | else |
---|
772 | (*prev)->q_next = new; |
---|
773 | } |
---|
774 | else |
---|
775 | { |
---|
776 | /* |
---|
777 | ** Place in list at current 'pq' position. Possible |
---|
778 | ** when there are 0 or more ADDRESS's in the list. |
---|
779 | */ |
---|
780 | |
---|
781 | new->q_next = NULL; |
---|
782 | *pq = new; |
---|
783 | } |
---|
784 | |
---|
785 | /* added a new address: clear split flag */ |
---|
786 | e->e_flags &= ~EF_SPLIT; |
---|
787 | |
---|
788 | /* |
---|
789 | ** Alias the name and handle special mailer types. |
---|
790 | */ |
---|
791 | |
---|
792 | trylocaluser: |
---|
793 | if (tTd(29, 7)) |
---|
794 | { |
---|
795 | sm_dprintf("at trylocaluser: "); |
---|
796 | printaddr(new, false); |
---|
797 | } |
---|
798 | |
---|
799 | if (!QS_IS_OK(new->q_state)) |
---|
800 | { |
---|
801 | if (QS_IS_UNDELIVERED(new->q_state)) |
---|
802 | e->e_nrcpts++; |
---|
803 | goto testselfdestruct; |
---|
804 | } |
---|
805 | |
---|
806 | if (m == InclMailer) |
---|
807 | { |
---|
808 | new->q_state = QS_INCLUDED; |
---|
809 | if (new->q_alias == NULL || UseMSP || |
---|
810 | bitset(EF_UNSAFE, e->e_flags)) |
---|
811 | { |
---|
812 | new->q_state = QS_BADADDR; |
---|
813 | new->q_status = "5.7.1"; |
---|
814 | usrerrenh(new->q_status, |
---|
815 | "550 Cannot mail directly to :include:s"); |
---|
816 | } |
---|
817 | else |
---|
818 | { |
---|
819 | int ret; |
---|
820 | |
---|
821 | message("including file %s", new->q_user); |
---|
822 | ret = include(new->q_user, false, new, |
---|
823 | sendq, aliaslevel, e); |
---|
824 | if (transienterror(ret)) |
---|
825 | { |
---|
826 | if (LogLevel > 2) |
---|
827 | sm_syslog(LOG_ERR, e->e_id, |
---|
828 | "include %s: transient error: %s", |
---|
829 | shortenstring(new->q_user, |
---|
830 | MAXSHORTSTR), |
---|
831 | sm_errstring(ret)); |
---|
832 | new->q_state = QS_QUEUEUP; |
---|
833 | usrerr("451 4.2.4 Cannot open %s: %s", |
---|
834 | shortenstring(new->q_user, |
---|
835 | MAXSHORTSTR), |
---|
836 | sm_errstring(ret)); |
---|
837 | } |
---|
838 | else if (ret != 0) |
---|
839 | { |
---|
840 | new->q_state = QS_BADADDR; |
---|
841 | new->q_status = "5.2.4"; |
---|
842 | usrerrenh(new->q_status, |
---|
843 | "550 Cannot open %s: %s", |
---|
844 | shortenstring(new->q_user, |
---|
845 | MAXSHORTSTR), |
---|
846 | sm_errstring(ret)); |
---|
847 | } |
---|
848 | } |
---|
849 | } |
---|
850 | else if (m == FileMailer) |
---|
851 | { |
---|
852 | /* check if allowed */ |
---|
853 | if (new->q_alias == NULL || UseMSP || |
---|
854 | bitset(EF_UNSAFE, e->e_flags)) |
---|
855 | { |
---|
856 | new->q_state = QS_BADADDR; |
---|
857 | new->q_status = "5.7.1"; |
---|
858 | usrerrenh(new->q_status, |
---|
859 | "550 Cannot mail directly to files"); |
---|
860 | } |
---|
861 | else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) |
---|
862 | { |
---|
863 | new->q_state = QS_BADADDR; |
---|
864 | new->q_status = "5.7.1"; |
---|
865 | if (new->q_alias->q_ruser == NULL) |
---|
866 | usrerrenh(new->q_status, |
---|
867 | "550 UID %d is an unknown user: cannot mail to files", |
---|
868 | new->q_alias->q_uid); |
---|
869 | else |
---|
870 | usrerrenh(new->q_status, |
---|
871 | "550 User %s@%s doesn't have a valid shell for mailing to files", |
---|
872 | new->q_alias->q_ruser, MyHostName); |
---|
873 | } |
---|
874 | else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) |
---|
875 | { |
---|
876 | new->q_state = QS_BADADDR; |
---|
877 | new->q_status = "5.7.1"; |
---|
878 | new->q_rstatus = "550 Unsafe for mailing to files"; |
---|
879 | usrerrenh(new->q_status, |
---|
880 | "550 Address %s is unsafe for mailing to files", |
---|
881 | new->q_alias->q_paddr); |
---|
882 | } |
---|
883 | } |
---|
884 | |
---|
885 | /* try aliasing */ |
---|
886 | if (!quoted && QS_IS_OK(new->q_state) && |
---|
887 | bitnset(M_ALIASABLE, m->m_flags)) |
---|
888 | alias(new, sendq, aliaslevel, e); |
---|
889 | |
---|
890 | #if USERDB |
---|
891 | /* if not aliased, look it up in the user database */ |
---|
892 | if (!bitset(QNOTREMOTE, new->q_flags) && |
---|
893 | QS_IS_SENDABLE(new->q_state) && |
---|
894 | bitnset(M_CHECKUDB, m->m_flags)) |
---|
895 | { |
---|
896 | if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL) |
---|
897 | { |
---|
898 | new->q_state = QS_QUEUEUP; |
---|
899 | if (e->e_message == NULL) |
---|
900 | e->e_message = "Deferred: user database error"; |
---|
901 | if (new->q_message == NULL) |
---|
902 | new->q_message = "Deferred: user database error"; |
---|
903 | if (LogLevel > 8) |
---|
904 | sm_syslog(LOG_INFO, e->e_id, |
---|
905 | "deferred: udbexpand: %s", |
---|
906 | sm_errstring(errno)); |
---|
907 | message("queued (user database error): %s", |
---|
908 | sm_errstring(errno)); |
---|
909 | e->e_nrcpts++; |
---|
910 | goto testselfdestruct; |
---|
911 | } |
---|
912 | } |
---|
913 | #endif /* USERDB */ |
---|
914 | |
---|
915 | /* |
---|
916 | ** If we have a level two config file, then pass the name through |
---|
917 | ** Ruleset 5 before sending it off. Ruleset 5 has the right |
---|
918 | ** to rewrite it to another mailer. This gives us a hook |
---|
919 | ** after local aliasing has been done. |
---|
920 | */ |
---|
921 | |
---|
922 | if (tTd(29, 5)) |
---|
923 | { |
---|
924 | sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", |
---|
925 | ConfigLevel, RewriteRules[5]); |
---|
926 | printaddr(new, false); |
---|
927 | } |
---|
928 | if (ConfigLevel >= 2 && RewriteRules[5] != NULL && |
---|
929 | bitnset(M_TRYRULESET5, m->m_flags) && |
---|
930 | !bitset(QNOTREMOTE, new->q_flags) && |
---|
931 | QS_IS_OK(new->q_state)) |
---|
932 | { |
---|
933 | maplocaluser(new, sendq, aliaslevel + 1, e); |
---|
934 | } |
---|
935 | |
---|
936 | /* |
---|
937 | ** If it didn't get rewritten to another mailer, go ahead |
---|
938 | ** and deliver it. |
---|
939 | */ |
---|
940 | |
---|
941 | if (QS_IS_OK(new->q_state) && |
---|
942 | bitnset(M_HASPWENT, m->m_flags)) |
---|
943 | { |
---|
944 | auto bool fuzzy; |
---|
945 | SM_MBDB_T user; |
---|
946 | int status; |
---|
947 | |
---|
948 | /* warning -- finduser may trash buf */ |
---|
949 | status = finduser(buf, &fuzzy, &user); |
---|
950 | switch (status) |
---|
951 | { |
---|
952 | case EX_TEMPFAIL: |
---|
953 | new->q_state = QS_QUEUEUP; |
---|
954 | new->q_status = "4.5.2"; |
---|
955 | giveresponse(EX_TEMPFAIL, new->q_status, m, NULL, |
---|
956 | new->q_alias, (time_t) 0, e, new); |
---|
957 | break; |
---|
958 | default: |
---|
959 | new->q_state = QS_BADADDR; |
---|
960 | new->q_status = "5.1.1"; |
---|
961 | new->q_rstatus = "550 5.1.1 User unknown"; |
---|
962 | giveresponse(EX_NOUSER, new->q_status, m, NULL, |
---|
963 | new->q_alias, (time_t) 0, e, new); |
---|
964 | break; |
---|
965 | case EX_OK: |
---|
966 | if (fuzzy) |
---|
967 | { |
---|
968 | /* name was a fuzzy match */ |
---|
969 | new->q_user = sm_rpool_strdup_x(e->e_rpool, |
---|
970 | user.mbdb_name); |
---|
971 | if (findusercount++ > 3) |
---|
972 | { |
---|
973 | new->q_state = QS_BADADDR; |
---|
974 | new->q_status = "5.4.6"; |
---|
975 | usrerrenh(new->q_status, |
---|
976 | "554 aliasing/forwarding loop for %s broken", |
---|
977 | user.mbdb_name); |
---|
978 | goto done; |
---|
979 | } |
---|
980 | |
---|
981 | /* see if it aliases */ |
---|
982 | (void) sm_strlcpy(buf, user.mbdb_name, buflen); |
---|
983 | goto trylocaluser; |
---|
984 | } |
---|
985 | if (*user.mbdb_homedir == '\0') |
---|
986 | new->q_home = NULL; |
---|
987 | else if (strcmp(user.mbdb_homedir, "/") == 0) |
---|
988 | new->q_home = ""; |
---|
989 | else |
---|
990 | new->q_home = sm_rpool_strdup_x(e->e_rpool, |
---|
991 | user.mbdb_homedir); |
---|
992 | if (user.mbdb_uid != SM_NO_UID) |
---|
993 | { |
---|
994 | new->q_uid = user.mbdb_uid; |
---|
995 | new->q_gid = user.mbdb_gid; |
---|
996 | new->q_flags |= QGOODUID; |
---|
997 | } |
---|
998 | new->q_ruser = sm_rpool_strdup_x(e->e_rpool, |
---|
999 | user.mbdb_name); |
---|
1000 | if (user.mbdb_fullname[0] != '\0') |
---|
1001 | new->q_fullname = sm_rpool_strdup_x(e->e_rpool, |
---|
1002 | user.mbdb_fullname); |
---|
1003 | if (!usershellok(user.mbdb_name, user.mbdb_shell)) |
---|
1004 | { |
---|
1005 | new->q_flags |= QBOGUSSHELL; |
---|
1006 | } |
---|
1007 | if (bitset(EF_VRFYONLY, e->e_flags)) |
---|
1008 | { |
---|
1009 | /* don't do any more now */ |
---|
1010 | new->q_state = QS_VERIFIED; |
---|
1011 | } |
---|
1012 | else if (!quoted) |
---|
1013 | forward(new, sendq, aliaslevel, e); |
---|
1014 | } |
---|
1015 | } |
---|
1016 | if (!QS_IS_DEAD(new->q_state)) |
---|
1017 | e->e_nrcpts++; |
---|
1018 | |
---|
1019 | testselfdestruct: |
---|
1020 | new->q_flags |= QTHISPASS; |
---|
1021 | if (tTd(26, 8)) |
---|
1022 | { |
---|
1023 | sm_dprintf("testselfdestruct: "); |
---|
1024 | printaddr(new, false); |
---|
1025 | if (tTd(26, 10)) |
---|
1026 | { |
---|
1027 | sm_dprintf("SENDQ:\n"); |
---|
1028 | printaddr(*sendq, true); |
---|
1029 | sm_dprintf("----\n"); |
---|
1030 | } |
---|
1031 | } |
---|
1032 | if (new->q_alias == NULL && new != &e->e_from && |
---|
1033 | QS_IS_DEAD(new->q_state)) |
---|
1034 | { |
---|
1035 | for (q = *sendq; q != NULL; q = q->q_next) |
---|
1036 | { |
---|
1037 | if (!QS_IS_DEAD(q->q_state)) |
---|
1038 | break; |
---|
1039 | } |
---|
1040 | if (q == NULL) |
---|
1041 | { |
---|
1042 | new->q_state = QS_BADADDR; |
---|
1043 | new->q_status = "5.4.6"; |
---|
1044 | usrerrenh(new->q_status, |
---|
1045 | "554 aliasing/forwarding loop broken"); |
---|
1046 | } |
---|
1047 | } |
---|
1048 | |
---|
1049 | done: |
---|
1050 | new->q_flags |= QTHISPASS; |
---|
1051 | if (buf != buf0) |
---|
1052 | sm_free(buf); /* XXX leak if above code raises exception */ |
---|
1053 | |
---|
1054 | /* |
---|
1055 | ** If we are at the top level, check to see if this has |
---|
1056 | ** expanded to exactly one address. If so, it can inherit |
---|
1057 | ** the primaryness of the address. |
---|
1058 | ** |
---|
1059 | ** While we're at it, clear the QTHISPASS bits. |
---|
1060 | */ |
---|
1061 | |
---|
1062 | if (aliaslevel == 0) |
---|
1063 | { |
---|
1064 | int nrcpts = 0; |
---|
1065 | ADDRESS *only = NULL; |
---|
1066 | |
---|
1067 | for (q = *sendq; q != NULL; q = q->q_next) |
---|
1068 | { |
---|
1069 | if (bitset(QTHISPASS, q->q_flags) && |
---|
1070 | QS_IS_SENDABLE(q->q_state)) |
---|
1071 | { |
---|
1072 | nrcpts++; |
---|
1073 | only = q; |
---|
1074 | } |
---|
1075 | q->q_flags &= ~QTHISPASS; |
---|
1076 | } |
---|
1077 | if (nrcpts == 1) |
---|
1078 | { |
---|
1079 | /* check to see if this actually got a new owner */ |
---|
1080 | q = only; |
---|
1081 | while ((q = q->q_alias) != NULL) |
---|
1082 | { |
---|
1083 | if (q->q_owner != NULL) |
---|
1084 | break; |
---|
1085 | } |
---|
1086 | if (q == NULL) |
---|
1087 | only->q_flags |= QPRIMARY; |
---|
1088 | } |
---|
1089 | else if (!initialdontsend && nrcpts > 0) |
---|
1090 | { |
---|
1091 | /* arrange for return receipt */ |
---|
1092 | e->e_flags |= EF_SENDRECEIPT; |
---|
1093 | new->q_flags |= QEXPANDED; |
---|
1094 | if (e->e_xfp != NULL && |
---|
1095 | bitset(QPINGONSUCCESS, new->q_flags)) |
---|
1096 | (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, |
---|
1097 | "%s... expanded to multiple addresses\n", |
---|
1098 | new->q_paddr); |
---|
1099 | } |
---|
1100 | } |
---|
1101 | new->q_flags |= QRCPTOK; |
---|
1102 | (void) sm_snprintf(buf0, sizeof buf0, "%d", e->e_nrcpts); |
---|
1103 | macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0); |
---|
1104 | return new; |
---|
1105 | } |
---|
1106 | /* |
---|
1107 | ** FINDUSER -- find the password entry for a user. |
---|
1108 | ** |
---|
1109 | ** This looks a lot like getpwnam, except that it may want to |
---|
1110 | ** do some fancier pattern matching in /etc/passwd. |
---|
1111 | ** |
---|
1112 | ** This routine contains most of the time of many sendmail runs. |
---|
1113 | ** It deserves to be optimized. |
---|
1114 | ** |
---|
1115 | ** Parameters: |
---|
1116 | ** name -- the name to match against. |
---|
1117 | ** fuzzyp -- an outarg that is set to true if this entry |
---|
1118 | ** was found using the fuzzy matching algorithm; |
---|
1119 | ** set to false otherwise. |
---|
1120 | ** user -- structure to fill in if user is found |
---|
1121 | ** |
---|
1122 | ** Returns: |
---|
1123 | ** On success, fill in *user, set *fuzzyp and return EX_OK. |
---|
1124 | ** If the user was not found, return EX_NOUSER. |
---|
1125 | ** On error, return EX_TEMPFAIL or EX_OSERR. |
---|
1126 | ** |
---|
1127 | ** Side Effects: |
---|
1128 | ** may modify name. |
---|
1129 | */ |
---|
1130 | |
---|
1131 | int |
---|
1132 | finduser(name, fuzzyp, user) |
---|
1133 | char *name; |
---|
1134 | bool *fuzzyp; |
---|
1135 | SM_MBDB_T *user; |
---|
1136 | { |
---|
1137 | #if MATCHGECOS |
---|
1138 | register struct passwd *pw; |
---|
1139 | #endif /* MATCHGECOS */ |
---|
1140 | register char *p; |
---|
1141 | bool tryagain; |
---|
1142 | int status; |
---|
1143 | |
---|
1144 | if (tTd(29, 4)) |
---|
1145 | sm_dprintf("finduser(%s): ", name); |
---|
1146 | |
---|
1147 | *fuzzyp = false; |
---|
1148 | |
---|
1149 | #if HESIOD |
---|
1150 | /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ |
---|
1151 | for (p = name; *p != '\0'; p++) |
---|
1152 | if (!isascii(*p) || !isdigit(*p)) |
---|
1153 | break; |
---|
1154 | if (*p == '\0') |
---|
1155 | { |
---|
1156 | if (tTd(29, 4)) |
---|
1157 | sm_dprintf("failed (numeric input)\n"); |
---|
1158 | return EX_NOUSER; |
---|
1159 | } |
---|
1160 | #endif /* HESIOD */ |
---|
1161 | |
---|
1162 | /* look up this login name using fast path */ |
---|
1163 | status = sm_mbdb_lookup(name, user); |
---|
1164 | if (status != EX_NOUSER) |
---|
1165 | { |
---|
1166 | if (tTd(29, 4)) |
---|
1167 | sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status)); |
---|
1168 | return status; |
---|
1169 | } |
---|
1170 | |
---|
1171 | /* try mapping it to lower case */ |
---|
1172 | tryagain = false; |
---|
1173 | for (p = name; *p != '\0'; p++) |
---|
1174 | { |
---|
1175 | if (isascii(*p) && isupper(*p)) |
---|
1176 | { |
---|
1177 | *p = tolower(*p); |
---|
1178 | tryagain = true; |
---|
1179 | } |
---|
1180 | } |
---|
1181 | if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER) |
---|
1182 | { |
---|
1183 | if (tTd(29, 4)) |
---|
1184 | sm_dprintf("%s (lower case)\n", sm_strexit(status)); |
---|
1185 | *fuzzyp = true; |
---|
1186 | return status; |
---|
1187 | } |
---|
1188 | |
---|
1189 | #if MATCHGECOS |
---|
1190 | /* see if fuzzy matching allowed */ |
---|
1191 | if (!MatchGecos) |
---|
1192 | { |
---|
1193 | if (tTd(29, 4)) |
---|
1194 | sm_dprintf("not found (fuzzy disabled)\n"); |
---|
1195 | return EX_NOUSER; |
---|
1196 | } |
---|
1197 | |
---|
1198 | /* search for a matching full name instead */ |
---|
1199 | for (p = name; *p != '\0'; p++) |
---|
1200 | { |
---|
1201 | if (*p == (SpaceSub & 0177) || *p == '_') |
---|
1202 | *p = ' '; |
---|
1203 | } |
---|
1204 | (void) setpwent(); |
---|
1205 | while ((pw = getpwent()) != NULL) |
---|
1206 | { |
---|
1207 | char buf[MAXNAME + 1]; |
---|
1208 | |
---|
1209 | # if 0 |
---|
1210 | if (sm_strcasecmp(pw->pw_name, name) == 0) |
---|
1211 | { |
---|
1212 | if (tTd(29, 4)) |
---|
1213 | sm_dprintf("found (case wrapped)\n"); |
---|
1214 | break; |
---|
1215 | } |
---|
1216 | # endif /* 0 */ |
---|
1217 | |
---|
1218 | sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof buf); |
---|
1219 | if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0) |
---|
1220 | { |
---|
1221 | if (tTd(29, 4)) |
---|
1222 | sm_dprintf("fuzzy matches %s\n", pw->pw_name); |
---|
1223 | message("sending to login name %s", pw->pw_name); |
---|
1224 | break; |
---|
1225 | } |
---|
1226 | } |
---|
1227 | if (pw != NULL) |
---|
1228 | *fuzzyp = true; |
---|
1229 | else if (tTd(29, 4)) |
---|
1230 | sm_dprintf("no fuzzy match found\n"); |
---|
1231 | # if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ |
---|
1232 | endpwent(); |
---|
1233 | # endif /* DEC_OSF_BROKEN_GETPWENT */ |
---|
1234 | if (pw == NULL) |
---|
1235 | return EX_NOUSER; |
---|
1236 | sm_mbdb_frompw(user, pw); |
---|
1237 | return EX_OK; |
---|
1238 | #else /* MATCHGECOS */ |
---|
1239 | if (tTd(29, 4)) |
---|
1240 | sm_dprintf("not found (fuzzy disabled)\n"); |
---|
1241 | return EX_NOUSER; |
---|
1242 | #endif /* MATCHGECOS */ |
---|
1243 | } |
---|
1244 | /* |
---|
1245 | ** WRITABLE -- predicate returning if the file is writable. |
---|
1246 | ** |
---|
1247 | ** This routine must duplicate the algorithm in sys/fio.c. |
---|
1248 | ** Unfortunately, we cannot use the access call since we |
---|
1249 | ** won't necessarily be the real uid when we try to |
---|
1250 | ** actually open the file. |
---|
1251 | ** |
---|
1252 | ** Notice that ANY file with ANY execute bit is automatically |
---|
1253 | ** not writable. This is also enforced by mailfile. |
---|
1254 | ** |
---|
1255 | ** Parameters: |
---|
1256 | ** filename -- the file name to check. |
---|
1257 | ** ctladdr -- the controlling address for this file. |
---|
1258 | ** flags -- SFF_* flags to control the function. |
---|
1259 | ** |
---|
1260 | ** Returns: |
---|
1261 | ** true -- if we will be able to write this file. |
---|
1262 | ** false -- if we cannot write this file. |
---|
1263 | ** |
---|
1264 | ** Side Effects: |
---|
1265 | ** none. |
---|
1266 | */ |
---|
1267 | |
---|
1268 | bool |
---|
1269 | writable(filename, ctladdr, flags) |
---|
1270 | char *filename; |
---|
1271 | ADDRESS *ctladdr; |
---|
1272 | long flags; |
---|
1273 | { |
---|
1274 | uid_t euid = 0; |
---|
1275 | gid_t egid = 0; |
---|
1276 | char *user = NULL; |
---|
1277 | |
---|
1278 | if (tTd(44, 5)) |
---|
1279 | sm_dprintf("writable(%s, 0x%lx)\n", filename, flags); |
---|
1280 | |
---|
1281 | /* |
---|
1282 | ** File does exist -- check that it is writable. |
---|
1283 | */ |
---|
1284 | |
---|
1285 | if (geteuid() != 0) |
---|
1286 | { |
---|
1287 | euid = geteuid(); |
---|
1288 | egid = getegid(); |
---|
1289 | user = NULL; |
---|
1290 | } |
---|
1291 | else if (ctladdr != NULL) |
---|
1292 | { |
---|
1293 | euid = ctladdr->q_uid; |
---|
1294 | egid = ctladdr->q_gid; |
---|
1295 | user = ctladdr->q_user; |
---|
1296 | } |
---|
1297 | else if (bitset(SFF_RUNASREALUID, flags)) |
---|
1298 | { |
---|
1299 | euid = RealUid; |
---|
1300 | egid = RealGid; |
---|
1301 | user = RealUserName; |
---|
1302 | } |
---|
1303 | else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) |
---|
1304 | { |
---|
1305 | euid = FileMailer->m_uid; |
---|
1306 | egid = FileMailer->m_gid; |
---|
1307 | user = NULL; |
---|
1308 | } |
---|
1309 | else |
---|
1310 | { |
---|
1311 | euid = egid = 0; |
---|
1312 | user = NULL; |
---|
1313 | } |
---|
1314 | if (!bitset(SFF_ROOTOK, flags)) |
---|
1315 | { |
---|
1316 | if (euid == 0) |
---|
1317 | { |
---|
1318 | euid = DefUid; |
---|
1319 | user = DefUser; |
---|
1320 | } |
---|
1321 | if (egid == 0) |
---|
1322 | egid = DefGid; |
---|
1323 | } |
---|
1324 | if (geteuid() == 0 && |
---|
1325 | (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) |
---|
1326 | flags |= SFF_SETUIDOK; |
---|
1327 | |
---|
1328 | if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) |
---|
1329 | flags |= SFF_NOSLINK; |
---|
1330 | if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) |
---|
1331 | flags |= SFF_NOHLINK; |
---|
1332 | |
---|
1333 | errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); |
---|
1334 | return errno == 0; |
---|
1335 | } |
---|
1336 | /* |
---|
1337 | ** INCLUDE -- handle :include: specification. |
---|
1338 | ** |
---|
1339 | ** Parameters: |
---|
1340 | ** fname -- filename to include. |
---|
1341 | ** forwarding -- if true, we are reading a .forward file. |
---|
1342 | ** if false, it's a :include: file. |
---|
1343 | ** ctladdr -- address template to use to fill in these |
---|
1344 | ** addresses -- effective user/group id are |
---|
1345 | ** the important things. |
---|
1346 | ** sendq -- a pointer to the head of the send queue |
---|
1347 | ** to put these addresses in. |
---|
1348 | ** aliaslevel -- the alias nesting depth. |
---|
1349 | ** e -- the current envelope. |
---|
1350 | ** |
---|
1351 | ** Returns: |
---|
1352 | ** open error status |
---|
1353 | ** |
---|
1354 | ** Side Effects: |
---|
1355 | ** reads the :include: file and sends to everyone |
---|
1356 | ** listed in that file. |
---|
1357 | ** |
---|
1358 | ** Security Note: |
---|
1359 | ** If you have restricted chown (that is, you can't |
---|
1360 | ** give a file away), it is reasonable to allow programs |
---|
1361 | ** and files called from this :include: file to be to be |
---|
1362 | ** run as the owner of the :include: file. This is bogus |
---|
1363 | ** if there is any chance of someone giving away a file. |
---|
1364 | ** We assume that pre-POSIX systems can give away files. |
---|
1365 | ** |
---|
1366 | ** There is an additional restriction that if you |
---|
1367 | ** forward to a :include: file, it will not take on |
---|
1368 | ** the ownership of the :include: file. This may not |
---|
1369 | ** be necessary, but shouldn't hurt. |
---|
1370 | */ |
---|
1371 | |
---|
1372 | static jmp_buf CtxIncludeTimeout; |
---|
1373 | |
---|
1374 | int |
---|
1375 | include(fname, forwarding, ctladdr, sendq, aliaslevel, e) |
---|
1376 | char *fname; |
---|
1377 | bool forwarding; |
---|
1378 | ADDRESS *ctladdr; |
---|
1379 | ADDRESS **sendq; |
---|
1380 | int aliaslevel; |
---|
1381 | ENVELOPE *e; |
---|
1382 | { |
---|
1383 | SM_FILE_T *volatile fp = NULL; |
---|
1384 | char *oldto = e->e_to; |
---|
1385 | char *oldfilename = FileName; |
---|
1386 | int oldlinenumber = LineNumber; |
---|
1387 | register SM_EVENT *ev = NULL; |
---|
1388 | int nincludes; |
---|
1389 | int mode; |
---|
1390 | volatile bool maxreached = false; |
---|
1391 | register ADDRESS *ca; |
---|
1392 | volatile uid_t saveduid; |
---|
1393 | volatile gid_t savedgid; |
---|
1394 | volatile uid_t uid; |
---|
1395 | volatile gid_t gid; |
---|
1396 | char *volatile user; |
---|
1397 | int rval = 0; |
---|
1398 | volatile long sfflags = SFF_REGONLY; |
---|
1399 | register char *p; |
---|
1400 | bool safechown = false; |
---|
1401 | volatile bool safedir = false; |
---|
1402 | struct stat st; |
---|
1403 | char buf[MAXLINE]; |
---|
1404 | |
---|
1405 | if (tTd(27, 2)) |
---|
1406 | sm_dprintf("include(%s)\n", fname); |
---|
1407 | if (tTd(27, 4)) |
---|
1408 | sm_dprintf(" ruid=%d euid=%d\n", |
---|
1409 | (int) getuid(), (int) geteuid()); |
---|
1410 | if (tTd(27, 14)) |
---|
1411 | { |
---|
1412 | sm_dprintf("ctladdr "); |
---|
1413 | printaddr(ctladdr, false); |
---|
1414 | } |
---|
1415 | |
---|
1416 | if (tTd(27, 9)) |
---|
1417 | sm_dprintf("include: old uid = %d/%d\n", |
---|
1418 | (int) getuid(), (int) geteuid()); |
---|
1419 | |
---|
1420 | if (forwarding) |
---|
1421 | { |
---|
1422 | sfflags |= SFF_MUSTOWN|SFF_ROOTOK; |
---|
1423 | if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) |
---|
1424 | sfflags |= SFF_NOGWFILES; |
---|
1425 | if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) |
---|
1426 | sfflags |= SFF_NOWWFILES; |
---|
1427 | } |
---|
1428 | else |
---|
1429 | { |
---|
1430 | if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) |
---|
1431 | sfflags |= SFF_NOGWFILES; |
---|
1432 | if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) |
---|
1433 | sfflags |= SFF_NOWWFILES; |
---|
1434 | } |
---|
1435 | |
---|
1436 | /* |
---|
1437 | ** If RunAsUser set, won't be able to run programs as user |
---|
1438 | ** so mark them as unsafe unless the administrator knows better. |
---|
1439 | */ |
---|
1440 | |
---|
1441 | if ((geteuid() != 0 || RunAsUid != 0) && |
---|
1442 | !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) |
---|
1443 | { |
---|
1444 | if (tTd(27, 4)) |
---|
1445 | sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", |
---|
1446 | (int) geteuid(), (int) RunAsUid); |
---|
1447 | ctladdr->q_flags |= QUNSAFEADDR; |
---|
1448 | } |
---|
1449 | |
---|
1450 | ca = getctladdr(ctladdr); |
---|
1451 | if (ca == NULL || |
---|
1452 | (ca->q_uid == DefUid && ca->q_gid == 0)) |
---|
1453 | { |
---|
1454 | uid = DefUid; |
---|
1455 | gid = DefGid; |
---|
1456 | user = DefUser; |
---|
1457 | } |
---|
1458 | else |
---|
1459 | { |
---|
1460 | uid = ca->q_uid; |
---|
1461 | gid = ca->q_gid; |
---|
1462 | user = ca->q_user; |
---|
1463 | } |
---|
1464 | #if MAILER_SETUID_METHOD != USE_SETUID |
---|
1465 | saveduid = geteuid(); |
---|
1466 | savedgid = getegid(); |
---|
1467 | if (saveduid == 0) |
---|
1468 | { |
---|
1469 | if (!DontInitGroups) |
---|
1470 | { |
---|
1471 | if (initgroups(user, gid) == -1) |
---|
1472 | { |
---|
1473 | rval = EAGAIN; |
---|
1474 | syserr("include: initgroups(%s, %d) failed", |
---|
1475 | user, gid); |
---|
1476 | goto resetuid; |
---|
1477 | } |
---|
1478 | } |
---|
1479 | else |
---|
1480 | { |
---|
1481 | GIDSET_T gidset[1]; |
---|
1482 | |
---|
1483 | gidset[0] = gid; |
---|
1484 | if (setgroups(1, gidset) == -1) |
---|
1485 | { |
---|
1486 | rval = EAGAIN; |
---|
1487 | syserr("include: setgroups() failed"); |
---|
1488 | goto resetuid; |
---|
1489 | } |
---|
1490 | } |
---|
1491 | |
---|
1492 | if (gid != 0 && setgid(gid) < -1) |
---|
1493 | { |
---|
1494 | rval = EAGAIN; |
---|
1495 | syserr("setgid(%d) failure", gid); |
---|
1496 | goto resetuid; |
---|
1497 | } |
---|
1498 | if (uid != 0) |
---|
1499 | { |
---|
1500 | # if MAILER_SETUID_METHOD == USE_SETEUID |
---|
1501 | if (seteuid(uid) < 0) |
---|
1502 | { |
---|
1503 | rval = EAGAIN; |
---|
1504 | syserr("seteuid(%d) failure (real=%d, eff=%d)", |
---|
1505 | uid, (int) getuid(), (int) geteuid()); |
---|
1506 | goto resetuid; |
---|
1507 | } |
---|
1508 | # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ |
---|
1509 | # if MAILER_SETUID_METHOD == USE_SETREUID |
---|
1510 | if (setreuid(0, uid) < 0) |
---|
1511 | { |
---|
1512 | rval = EAGAIN; |
---|
1513 | syserr("setreuid(0, %d) failure (real=%d, eff=%d)", |
---|
1514 | uid, (int) getuid(), (int) geteuid()); |
---|
1515 | goto resetuid; |
---|
1516 | } |
---|
1517 | # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ |
---|
1518 | } |
---|
1519 | } |
---|
1520 | #endif /* MAILER_SETUID_METHOD != USE_SETUID */ |
---|
1521 | |
---|
1522 | if (tTd(27, 9)) |
---|
1523 | sm_dprintf("include: new uid = %d/%d\n", |
---|
1524 | (int) getuid(), (int) geteuid()); |
---|
1525 | |
---|
1526 | /* |
---|
1527 | ** If home directory is remote mounted but server is down, |
---|
1528 | ** this can hang or give errors; use a timeout to avoid this |
---|
1529 | */ |
---|
1530 | |
---|
1531 | if (setjmp(CtxIncludeTimeout) != 0) |
---|
1532 | { |
---|
1533 | ctladdr->q_state = QS_QUEUEUP; |
---|
1534 | errno = 0; |
---|
1535 | |
---|
1536 | /* return pseudo-error code */ |
---|
1537 | rval = E_SM_OPENTIMEOUT; |
---|
1538 | goto resetuid; |
---|
1539 | } |
---|
1540 | if (TimeOuts.to_fileopen > 0) |
---|
1541 | ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); |
---|
1542 | else |
---|
1543 | ev = NULL; |
---|
1544 | |
---|
1545 | |
---|
1546 | /* check for writable parent directory */ |
---|
1547 | p = strrchr(fname, '/'); |
---|
1548 | if (p != NULL) |
---|
1549 | { |
---|
1550 | int ret; |
---|
1551 | |
---|
1552 | *p = '\0'; |
---|
1553 | ret = safedirpath(fname, uid, gid, user, |
---|
1554 | sfflags|SFF_SAFEDIRPATH, 0, 0); |
---|
1555 | if (ret == 0) |
---|
1556 | { |
---|
1557 | /* in safe directory: relax chown & link rules */ |
---|
1558 | safedir = true; |
---|
1559 | sfflags |= SFF_NOPATHCHECK; |
---|
1560 | } |
---|
1561 | else |
---|
1562 | { |
---|
1563 | if (bitnset((forwarding ? |
---|
1564 | DBS_FORWARDFILEINUNSAFEDIRPATH : |
---|
1565 | DBS_INCLUDEFILEINUNSAFEDIRPATH), |
---|
1566 | DontBlameSendmail)) |
---|
1567 | sfflags |= SFF_NOPATHCHECK; |
---|
1568 | else if (bitnset((forwarding ? |
---|
1569 | DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : |
---|
1570 | DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), |
---|
1571 | DontBlameSendmail) && |
---|
1572 | ret == E_SM_GWDIR) |
---|
1573 | { |
---|
1574 | setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, |
---|
1575 | DontBlameSendmail); |
---|
1576 | ret = safedirpath(fname, uid, gid, user, |
---|
1577 | sfflags|SFF_SAFEDIRPATH, |
---|
1578 | 0, 0); |
---|
1579 | clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, |
---|
1580 | DontBlameSendmail); |
---|
1581 | if (ret == 0) |
---|
1582 | sfflags |= SFF_NOPATHCHECK; |
---|
1583 | else |
---|
1584 | sfflags |= SFF_SAFEDIRPATH; |
---|
1585 | } |
---|
1586 | else |
---|
1587 | sfflags |= SFF_SAFEDIRPATH; |
---|
1588 | if (ret > E_PSEUDOBASE && |
---|
1589 | !bitnset((forwarding ? |
---|
1590 | DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : |
---|
1591 | DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), |
---|
1592 | DontBlameSendmail)) |
---|
1593 | { |
---|
1594 | if (LogLevel > 11) |
---|
1595 | sm_syslog(LOG_INFO, e->e_id, |
---|
1596 | "%s: unsafe directory path, marked unsafe", |
---|
1597 | shortenstring(fname, MAXSHORTSTR)); |
---|
1598 | ctladdr->q_flags |= QUNSAFEADDR; |
---|
1599 | } |
---|
1600 | } |
---|
1601 | *p = '/'; |
---|
1602 | } |
---|
1603 | |
---|
1604 | /* allow links only in unwritable directories */ |
---|
1605 | if (!safedir && |
---|
1606 | !bitnset((forwarding ? |
---|
1607 | DBS_LINKEDFORWARDFILEINWRITABLEDIR : |
---|
1608 | DBS_LINKEDINCLUDEFILEINWRITABLEDIR), |
---|
1609 | DontBlameSendmail)) |
---|
1610 | sfflags |= SFF_NOLINK; |
---|
1611 | |
---|
1612 | rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); |
---|
1613 | if (rval != 0) |
---|
1614 | { |
---|
1615 | /* don't use this :include: file */ |
---|
1616 | if (tTd(27, 4)) |
---|
1617 | sm_dprintf("include: not safe (uid=%d): %s\n", |
---|
1618 | (int) uid, sm_errstring(rval)); |
---|
1619 | } |
---|
1620 | else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, |
---|
1621 | SM_IO_RDONLY, NULL)) == NULL) |
---|
1622 | { |
---|
1623 | rval = errno; |
---|
1624 | if (tTd(27, 4)) |
---|
1625 | sm_dprintf("include: open: %s\n", sm_errstring(rval)); |
---|
1626 | } |
---|
1627 | else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) |
---|
1628 | { |
---|
1629 | rval = E_SM_FILECHANGE; |
---|
1630 | if (tTd(27, 4)) |
---|
1631 | sm_dprintf("include: file changed after open\n"); |
---|
1632 | } |
---|
1633 | if (ev != NULL) |
---|
1634 | sm_clrevent(ev); |
---|
1635 | |
---|
1636 | resetuid: |
---|
1637 | |
---|
1638 | #if HASSETREUID || USESETEUID |
---|
1639 | if (saveduid == 0) |
---|
1640 | { |
---|
1641 | if (uid != 0) |
---|
1642 | { |
---|
1643 | # if USESETEUID |
---|
1644 | if (seteuid(0) < 0) |
---|
1645 | syserr("!seteuid(0) failure (real=%d, eff=%d)", |
---|
1646 | (int) getuid(), (int) geteuid()); |
---|
1647 | # else /* USESETEUID */ |
---|
1648 | if (setreuid(-1, 0) < 0) |
---|
1649 | syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", |
---|
1650 | (int) getuid(), (int) geteuid()); |
---|
1651 | if (setreuid(RealUid, 0) < 0) |
---|
1652 | syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", |
---|
1653 | (int) RealUid, (int) getuid(), |
---|
1654 | (int) geteuid()); |
---|
1655 | # endif /* USESETEUID */ |
---|
1656 | } |
---|
1657 | if (setgid(savedgid) < 0) |
---|
1658 | syserr("!setgid(%d) failure (real=%d eff=%d)", |
---|
1659 | (int) savedgid, (int) getgid(), |
---|
1660 | (int) getegid()); |
---|
1661 | } |
---|
1662 | #endif /* HASSETREUID || USESETEUID */ |
---|
1663 | |
---|
1664 | if (tTd(27, 9)) |
---|
1665 | sm_dprintf("include: reset uid = %d/%d\n", |
---|
1666 | (int) getuid(), (int) geteuid()); |
---|
1667 | |
---|
1668 | if (rval == E_SM_OPENTIMEOUT) |
---|
1669 | usrerr("451 4.4.1 open timeout on %s", fname); |
---|
1670 | |
---|
1671 | if (fp == NULL) |
---|
1672 | return rval; |
---|
1673 | |
---|
1674 | if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) |
---|
1675 | { |
---|
1676 | rval = errno; |
---|
1677 | syserr("Cannot fstat %s!", fname); |
---|
1678 | (void) sm_io_close(fp, SM_TIME_DEFAULT); |
---|
1679 | return rval; |
---|
1680 | } |
---|
1681 | |
---|
1682 | /* if path was writable, check to avoid file giveaway tricks */ |
---|
1683 | safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); |
---|
1684 | if (tTd(27, 6)) |
---|
1685 | sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", |
---|
1686 | fname, safedir ? "safe" : "dangerous", |
---|
1687 | safechown ? "" : "un"); |
---|
1688 | |
---|
1689 | /* if no controlling user or coming from an alias delivery */ |
---|
1690 | if (safechown && |
---|
1691 | (ca == NULL || |
---|
1692 | (ca->q_uid == DefUid && ca->q_gid == 0))) |
---|
1693 | { |
---|
1694 | ctladdr->q_uid = st.st_uid; |
---|
1695 | ctladdr->q_gid = st.st_gid; |
---|
1696 | ctladdr->q_flags |= QGOODUID; |
---|
1697 | } |
---|
1698 | if (ca != NULL && ca->q_uid == st.st_uid) |
---|
1699 | { |
---|
1700 | /* optimization -- avoid getpwuid if we already have info */ |
---|
1701 | ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; |
---|
1702 | ctladdr->q_ruser = ca->q_ruser; |
---|
1703 | } |
---|
1704 | else if (!forwarding) |
---|
1705 | { |
---|
1706 | register struct passwd *pw; |
---|
1707 | |
---|
1708 | pw = sm_getpwuid(st.st_uid); |
---|
1709 | if (pw == NULL) |
---|
1710 | { |
---|
1711 | ctladdr->q_uid = st.st_uid; |
---|
1712 | ctladdr->q_flags |= QBOGUSSHELL; |
---|
1713 | } |
---|
1714 | else |
---|
1715 | { |
---|
1716 | char *sh; |
---|
1717 | |
---|
1718 | ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, |
---|
1719 | pw->pw_name); |
---|
1720 | if (safechown) |
---|
1721 | sh = pw->pw_shell; |
---|
1722 | else |
---|
1723 | sh = "/SENDMAIL/ANY/SHELL/"; |
---|
1724 | if (!usershellok(pw->pw_name, sh)) |
---|
1725 | { |
---|
1726 | if (LogLevel > 11) |
---|
1727 | sm_syslog(LOG_INFO, e->e_id, |
---|
1728 | "%s: user %s has bad shell %s, marked %s", |
---|
1729 | shortenstring(fname, |
---|
1730 | MAXSHORTSTR), |
---|
1731 | pw->pw_name, sh, |
---|
1732 | safechown ? "bogus" : "unsafe"); |
---|
1733 | if (safechown) |
---|
1734 | ctladdr->q_flags |= QBOGUSSHELL; |
---|
1735 | else |
---|
1736 | ctladdr->q_flags |= QUNSAFEADDR; |
---|
1737 | } |
---|
1738 | } |
---|
1739 | } |
---|
1740 | |
---|
1741 | if (bitset(EF_VRFYONLY, e->e_flags)) |
---|
1742 | { |
---|
1743 | /* don't do any more now */ |
---|
1744 | ctladdr->q_state = QS_VERIFIED; |
---|
1745 | e->e_nrcpts++; |
---|
1746 | (void) sm_io_close(fp, SM_TIME_DEFAULT); |
---|
1747 | return rval; |
---|
1748 | } |
---|
1749 | |
---|
1750 | /* |
---|
1751 | ** Check to see if some bad guy can write this file |
---|
1752 | ** |
---|
1753 | ** Group write checking could be more clever, e.g., |
---|
1754 | ** guessing as to which groups are actually safe ("sys" |
---|
1755 | ** may be; "user" probably is not). |
---|
1756 | */ |
---|
1757 | |
---|
1758 | mode = S_IWOTH; |
---|
1759 | if (!bitnset((forwarding ? |
---|
1760 | DBS_GROUPWRITABLEFORWARDFILESAFE : |
---|
1761 | DBS_GROUPWRITABLEINCLUDEFILESAFE), |
---|
1762 | DontBlameSendmail)) |
---|
1763 | mode |= S_IWGRP; |
---|
1764 | |
---|
1765 | if (bitset(mode, st.st_mode)) |
---|
1766 | { |
---|
1767 | if (tTd(27, 6)) |
---|
1768 | sm_dprintf("include: %s is %s writable, marked unsafe\n", |
---|
1769 | shortenstring(fname, MAXSHORTSTR), |
---|
1770 | bitset(S_IWOTH, st.st_mode) ? "world" |
---|
1771 | : "group"); |
---|
1772 | if (LogLevel > 11) |
---|
1773 | sm_syslog(LOG_INFO, e->e_id, |
---|
1774 | "%s: %s writable %s file, marked unsafe", |
---|
1775 | shortenstring(fname, MAXSHORTSTR), |
---|
1776 | bitset(S_IWOTH, st.st_mode) ? "world" : "group", |
---|
1777 | forwarding ? "forward" : ":include:"); |
---|
1778 | ctladdr->q_flags |= QUNSAFEADDR; |
---|
1779 | } |
---|
1780 | |
---|
1781 | /* read the file -- each line is a comma-separated list. */ |
---|
1782 | FileName = fname; |
---|
1783 | LineNumber = 0; |
---|
1784 | ctladdr->q_flags &= ~QSELFREF; |
---|
1785 | nincludes = 0; |
---|
1786 | while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof buf) != NULL && |
---|
1787 | !maxreached) |
---|
1788 | { |
---|
1789 | fixcrlf(buf, true); |
---|
1790 | LineNumber++; |
---|
1791 | if (buf[0] == '#' || buf[0] == '\0') |
---|
1792 | continue; |
---|
1793 | |
---|
1794 | /* <sp>#@# introduces a comment anywhere */ |
---|
1795 | /* for Japanese character sets */ |
---|
1796 | for (p = buf; (p = strchr(++p, '#')) != NULL; ) |
---|
1797 | { |
---|
1798 | if (p[1] == '@' && p[2] == '#' && |
---|
1799 | isascii(p[-1]) && isspace(p[-1]) && |
---|
1800 | (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) |
---|
1801 | { |
---|
1802 | --p; |
---|
1803 | while (p > buf && isascii(p[-1]) && |
---|
1804 | isspace(p[-1])) |
---|
1805 | --p; |
---|
1806 | p[0] = '\0'; |
---|
1807 | break; |
---|
1808 | } |
---|
1809 | } |
---|
1810 | if (buf[0] == '\0') |
---|
1811 | continue; |
---|
1812 | |
---|
1813 | e->e_to = NULL; |
---|
1814 | message("%s to %s", |
---|
1815 | forwarding ? "forwarding" : "sending", buf); |
---|
1816 | if (forwarding && LogLevel > 10) |
---|
1817 | sm_syslog(LOG_INFO, e->e_id, |
---|
1818 | "forward %.200s => %s", |
---|
1819 | oldto, shortenstring(buf, MAXSHORTSTR)); |
---|
1820 | |
---|
1821 | nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); |
---|
1822 | |
---|
1823 | if (forwarding && |
---|
1824 | MaxForwardEntries > 0 && |
---|
1825 | nincludes >= MaxForwardEntries) |
---|
1826 | { |
---|
1827 | /* just stop reading and processing further entries */ |
---|
1828 | #if 0 |
---|
1829 | /* additional: (?) */ |
---|
1830 | ctladdr->q_state = QS_DONTSEND; |
---|
1831 | #endif /* 0 */ |
---|
1832 | |
---|
1833 | syserr("Attempt to forward to more than %d addresses (in %s)!", |
---|
1834 | MaxForwardEntries, fname); |
---|
1835 | maxreached = true; |
---|
1836 | } |
---|
1837 | } |
---|
1838 | |
---|
1839 | if (sm_io_error(fp) && tTd(27, 3)) |
---|
1840 | sm_dprintf("include: read error: %s\n", sm_errstring(errno)); |
---|
1841 | if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) |
---|
1842 | { |
---|
1843 | if (tTd(27, 5)) |
---|
1844 | { |
---|
1845 | sm_dprintf("include: QS_DONTSEND "); |
---|
1846 | printaddr(ctladdr, false); |
---|
1847 | } |
---|
1848 | ctladdr->q_state = QS_DONTSEND; |
---|
1849 | } |
---|
1850 | |
---|
1851 | (void) sm_io_close(fp, SM_TIME_DEFAULT); |
---|
1852 | FileName = oldfilename; |
---|
1853 | LineNumber = oldlinenumber; |
---|
1854 | e->e_to = oldto; |
---|
1855 | return rval; |
---|
1856 | } |
---|
1857 | |
---|
1858 | static void |
---|
1859 | includetimeout() |
---|
1860 | { |
---|
1861 | /* |
---|
1862 | ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD |
---|
1863 | ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE |
---|
1864 | ** DOING. |
---|
1865 | */ |
---|
1866 | |
---|
1867 | errno = ETIMEDOUT; |
---|
1868 | longjmp(CtxIncludeTimeout, 1); |
---|
1869 | } |
---|
1870 | /* |
---|
1871 | ** SENDTOARGV -- send to an argument vector. |
---|
1872 | ** |
---|
1873 | ** Parameters: |
---|
1874 | ** argv -- argument vector to send to. |
---|
1875 | ** e -- the current envelope. |
---|
1876 | ** |
---|
1877 | ** Returns: |
---|
1878 | ** none. |
---|
1879 | ** |
---|
1880 | ** Side Effects: |
---|
1881 | ** puts all addresses on the argument vector onto the |
---|
1882 | ** send queue. |
---|
1883 | */ |
---|
1884 | |
---|
1885 | void |
---|
1886 | sendtoargv(argv, e) |
---|
1887 | register char **argv; |
---|
1888 | register ENVELOPE *e; |
---|
1889 | { |
---|
1890 | register char *p; |
---|
1891 | |
---|
1892 | while ((p = *argv++) != NULL) |
---|
1893 | (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); |
---|
1894 | } |
---|
1895 | /* |
---|
1896 | ** GETCTLADDR -- get controlling address from an address header. |
---|
1897 | ** |
---|
1898 | ** If none, get one corresponding to the effective userid. |
---|
1899 | ** |
---|
1900 | ** Parameters: |
---|
1901 | ** a -- the address to find the controller of. |
---|
1902 | ** |
---|
1903 | ** Returns: |
---|
1904 | ** the controlling address. |
---|
1905 | */ |
---|
1906 | |
---|
1907 | ADDRESS * |
---|
1908 | getctladdr(a) |
---|
1909 | register ADDRESS *a; |
---|
1910 | { |
---|
1911 | while (a != NULL && !bitset(QGOODUID, a->q_flags)) |
---|
1912 | a = a->q_alias; |
---|
1913 | return a; |
---|
1914 | } |
---|
1915 | /* |
---|
1916 | ** SELF_REFERENCE -- check to see if an address references itself |
---|
1917 | ** |
---|
1918 | ** The check is done through a chain of aliases. If it is part of |
---|
1919 | ** a loop, break the loop at the "best" address, that is, the one |
---|
1920 | ** that exists as a real user. |
---|
1921 | ** |
---|
1922 | ** This is to handle the case of: |
---|
1923 | ** awc: Andrew.Chang |
---|
1924 | ** Andrew.Chang: awc@mail.server |
---|
1925 | ** which is a problem only on mail.server. |
---|
1926 | ** |
---|
1927 | ** Parameters: |
---|
1928 | ** a -- the address to check. |
---|
1929 | ** |
---|
1930 | ** Returns: |
---|
1931 | ** The address that should be retained. |
---|
1932 | */ |
---|
1933 | |
---|
1934 | static ADDRESS * |
---|
1935 | self_reference(a) |
---|
1936 | ADDRESS *a; |
---|
1937 | { |
---|
1938 | ADDRESS *b; /* top entry in self ref loop */ |
---|
1939 | ADDRESS *c; /* entry that point to a real mail box */ |
---|
1940 | |
---|
1941 | if (tTd(27, 1)) |
---|
1942 | sm_dprintf("self_reference(%s)\n", a->q_paddr); |
---|
1943 | |
---|
1944 | for (b = a->q_alias; b != NULL; b = b->q_alias) |
---|
1945 | { |
---|
1946 | if (sameaddr(a, b)) |
---|
1947 | break; |
---|
1948 | } |
---|
1949 | |
---|
1950 | if (b == NULL) |
---|
1951 | { |
---|
1952 | if (tTd(27, 1)) |
---|
1953 | sm_dprintf("\t... no self ref\n"); |
---|
1954 | return NULL; |
---|
1955 | } |
---|
1956 | |
---|
1957 | /* |
---|
1958 | ** Pick the first address that resolved to a real mail box |
---|
1959 | ** i.e has a mbdb entry. The returned value will be marked |
---|
1960 | ** QSELFREF in recipient(), which in turn will disable alias() |
---|
1961 | ** from marking it as QS_IS_DEAD(), which mean it will be used |
---|
1962 | ** as a deliverable address. |
---|
1963 | ** |
---|
1964 | ** The 2 key thing to note here are: |
---|
1965 | ** 1) we are in a recursive call sequence: |
---|
1966 | ** alias->sendtolist->recipient->alias |
---|
1967 | ** 2) normally, when we return back to alias(), the address |
---|
1968 | ** will be marked QS_EXPANDED, since alias() assumes the |
---|
1969 | ** expanded form will be used instead of the current address. |
---|
1970 | ** This behaviour is turned off if the address is marked |
---|
1971 | ** QSELFREF. We set QSELFREF when we return to recipient(). |
---|
1972 | */ |
---|
1973 | |
---|
1974 | c = a; |
---|
1975 | while (c != NULL) |
---|
1976 | { |
---|
1977 | if (tTd(27, 10)) |
---|
1978 | sm_dprintf(" %s", c->q_user); |
---|
1979 | if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) |
---|
1980 | { |
---|
1981 | SM_MBDB_T user; |
---|
1982 | |
---|
1983 | if (tTd(27, 2)) |
---|
1984 | sm_dprintf("\t... getpwnam(%s)... ", c->q_user); |
---|
1985 | if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) |
---|
1986 | { |
---|
1987 | if (tTd(27, 2)) |
---|
1988 | sm_dprintf("found\n"); |
---|
1989 | |
---|
1990 | /* ought to cache results here */ |
---|
1991 | if (sameaddr(b, c)) |
---|
1992 | return b; |
---|
1993 | else |
---|
1994 | return c; |
---|
1995 | } |
---|
1996 | if (tTd(27, 2)) |
---|
1997 | sm_dprintf("failed\n"); |
---|
1998 | } |
---|
1999 | else |
---|
2000 | { |
---|
2001 | /* if local delivery, compare usernames */ |
---|
2002 | if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && |
---|
2003 | b->q_mailer == c->q_mailer) |
---|
2004 | { |
---|
2005 | if (tTd(27, 2)) |
---|
2006 | sm_dprintf("\t... local match (%s)\n", |
---|
2007 | c->q_user); |
---|
2008 | if (sameaddr(b, c)) |
---|
2009 | return b; |
---|
2010 | else |
---|
2011 | return c; |
---|
2012 | } |
---|
2013 | } |
---|
2014 | if (tTd(27, 10)) |
---|
2015 | sm_dprintf("\n"); |
---|
2016 | c = c->q_alias; |
---|
2017 | } |
---|
2018 | |
---|
2019 | if (tTd(27, 1)) |
---|
2020 | sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); |
---|
2021 | |
---|
2022 | return NULL; |
---|
2023 | } |
---|