17c478bd9Sstevel@tonic-gate /* 2058561cbSjbeck * Copyright (c) 1998-2003, 2006 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 107c478bd9Sstevel@tonic-gate * the sendmail distribution. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate */ 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #include <sendmail.h> 177c478bd9Sstevel@tonic-gate 18*7800901eSjbeck SM_RCSID("@(#)$Id: recipient.c,v 8.349 2007/07/10 17:01:22 ca Exp $") 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate static void includetimeout __P((int)); 217c478bd9Sstevel@tonic-gate static ADDRESS *self_reference __P((ADDRESS *)); 227c478bd9Sstevel@tonic-gate static int sortexpensive __P((ADDRESS *, ADDRESS *)); 237c478bd9Sstevel@tonic-gate static int sortbysignature __P((ADDRESS *, ADDRESS *)); 247c478bd9Sstevel@tonic-gate static int sorthost __P((ADDRESS *, ADDRESS *)); 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate typedef int sortfn_t __P((ADDRESS *, ADDRESS *)); 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate ** SORTHOST -- strcmp()-like func for host portion of an ADDRESS 307c478bd9Sstevel@tonic-gate ** 317c478bd9Sstevel@tonic-gate ** Parameters: 327c478bd9Sstevel@tonic-gate ** xx -- first ADDRESS 337c478bd9Sstevel@tonic-gate ** yy -- second ADDRESS 347c478bd9Sstevel@tonic-gate ** 357c478bd9Sstevel@tonic-gate ** Returns: 367c478bd9Sstevel@tonic-gate ** <0 when xx->q_host is less than yy->q_host 377c478bd9Sstevel@tonic-gate ** >0 when xx->q_host is greater than yy->q_host 387c478bd9Sstevel@tonic-gate ** 0 when equal 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate static int 427c478bd9Sstevel@tonic-gate sorthost(xx, yy) 437c478bd9Sstevel@tonic-gate register ADDRESS *xx; 447c478bd9Sstevel@tonic-gate register ADDRESS *yy; 457c478bd9Sstevel@tonic-gate { 467c478bd9Sstevel@tonic-gate #if _FFR_HOST_SORT_REVERSE 477c478bd9Sstevel@tonic-gate /* XXX maybe compare hostnames from the end? */ 487c478bd9Sstevel@tonic-gate return sm_strrevcasecmp(xx->q_host, yy->q_host); 497c478bd9Sstevel@tonic-gate #else /* _FFR_HOST_SORT_REVERSE */ 507c478bd9Sstevel@tonic-gate return sm_strcasecmp(xx->q_host, yy->q_host); 517c478bd9Sstevel@tonic-gate #endif /* _FFR_HOST_SORT_REVERSE */ 527c478bd9Sstevel@tonic-gate } 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate ** SORTEXPENSIVE -- strcmp()-like func for expensive mailers 567c478bd9Sstevel@tonic-gate ** 577c478bd9Sstevel@tonic-gate ** The mailer has been noted already as "expensive" for 'xx'. This 587c478bd9Sstevel@tonic-gate ** will give a result relative to 'yy'. Expensive mailers get rated 597c478bd9Sstevel@tonic-gate ** "greater than" non-expensive mailers because during the delivery phase 607c478bd9Sstevel@tonic-gate ** it will get queued -- no use it getting in the way of less expensive 617c478bd9Sstevel@tonic-gate ** recipients. We avoid an MX RR lookup when both 'xx' and 'yy' are 627c478bd9Sstevel@tonic-gate ** expensive since an MX RR lookup happens when extracted from the queue 637c478bd9Sstevel@tonic-gate ** later. 647c478bd9Sstevel@tonic-gate ** 657c478bd9Sstevel@tonic-gate ** Parameters: 667c478bd9Sstevel@tonic-gate ** xx -- first ADDRESS 677c478bd9Sstevel@tonic-gate ** yy -- second ADDRESS 687c478bd9Sstevel@tonic-gate ** 697c478bd9Sstevel@tonic-gate ** Returns: 707c478bd9Sstevel@tonic-gate ** <0 when xx->q_host is less than yy->q_host and both are 717c478bd9Sstevel@tonic-gate ** expensive 727c478bd9Sstevel@tonic-gate ** >0 when xx->q_host is greater than yy->q_host, or when 737c478bd9Sstevel@tonic-gate ** 'yy' is non-expensive 747c478bd9Sstevel@tonic-gate ** 0 when equal (by expense and q_host) 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static int 787c478bd9Sstevel@tonic-gate sortexpensive(xx, yy) 797c478bd9Sstevel@tonic-gate ADDRESS *xx; 807c478bd9Sstevel@tonic-gate ADDRESS *yy; 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate if (!bitnset(M_EXPENSIVE, yy->q_mailer->m_flags)) 837c478bd9Sstevel@tonic-gate return 1; /* xx should go later */ 847c478bd9Sstevel@tonic-gate #if _FFR_HOST_SORT_REVERSE 857c478bd9Sstevel@tonic-gate /* XXX maybe compare hostnames from the end? */ 867c478bd9Sstevel@tonic-gate return sm_strrevcasecmp(xx->q_host, yy->q_host); 877c478bd9Sstevel@tonic-gate #else /* _FFR_HOST_SORT_REVERSE */ 887c478bd9Sstevel@tonic-gate return sm_strcasecmp(xx->q_host, yy->q_host); 897c478bd9Sstevel@tonic-gate #endif /* _FFR_HOST_SORT_REVERSE */ 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate ** SORTBYSIGNATURE -- a strcmp()-like func for q_mailer and q_host in ADDRESS 947c478bd9Sstevel@tonic-gate ** 957c478bd9Sstevel@tonic-gate ** Parameters: 967c478bd9Sstevel@tonic-gate ** xx -- first ADDRESS 977c478bd9Sstevel@tonic-gate ** yy -- second ADDRESS 987c478bd9Sstevel@tonic-gate ** 997c478bd9Sstevel@tonic-gate ** Returns: 1007c478bd9Sstevel@tonic-gate ** 0 when the "signature"'s are same 1017c478bd9Sstevel@tonic-gate ** <0 when xx->q_signature is less than yy->q_signature 1027c478bd9Sstevel@tonic-gate ** >0 when xx->q_signature is greater than yy->q_signature 1037c478bd9Sstevel@tonic-gate ** 1047c478bd9Sstevel@tonic-gate ** Side Effect: 1057c478bd9Sstevel@tonic-gate ** May set ADDRESS pointer for q_signature if not already set. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static int 1097c478bd9Sstevel@tonic-gate sortbysignature(xx, yy) 1107c478bd9Sstevel@tonic-gate ADDRESS *xx; 1117c478bd9Sstevel@tonic-gate ADDRESS *yy; 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate register int ret; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* Let's avoid redoing the signature over and over again */ 1167c478bd9Sstevel@tonic-gate if (xx->q_signature == NULL) 1177c478bd9Sstevel@tonic-gate xx->q_signature = hostsignature(xx->q_mailer, xx->q_host); 1187c478bd9Sstevel@tonic-gate if (yy->q_signature == NULL) 1197c478bd9Sstevel@tonic-gate yy->q_signature = hostsignature(yy->q_mailer, yy->q_host); 1207c478bd9Sstevel@tonic-gate ret = strcmp(xx->q_signature, yy->q_signature); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate ** If the two signatures are the same then we will return a sort 1247c478bd9Sstevel@tonic-gate ** value based on 'q_user'. But note that we have reversed xx and yy 1257c478bd9Sstevel@tonic-gate ** on purpose. This additional compare helps reduce the number of 1267c478bd9Sstevel@tonic-gate ** sameaddr() calls and loops in recipient() for the case when 1277c478bd9Sstevel@tonic-gate ** the rcpt list has been provided already in-order. 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if (ret == 0) 1317c478bd9Sstevel@tonic-gate return strcmp(yy->q_user, xx->q_user); 1327c478bd9Sstevel@tonic-gate else 1337c478bd9Sstevel@tonic-gate return ret; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* 1377c478bd9Sstevel@tonic-gate ** SENDTOLIST -- Designate a send list. 1387c478bd9Sstevel@tonic-gate ** 1397c478bd9Sstevel@tonic-gate ** The parameter is a comma-separated list of people to send to. 1407c478bd9Sstevel@tonic-gate ** This routine arranges to send to all of them. 1417c478bd9Sstevel@tonic-gate ** 1427c478bd9Sstevel@tonic-gate ** Parameters: 1437c478bd9Sstevel@tonic-gate ** list -- the send list. 1447c478bd9Sstevel@tonic-gate ** ctladdr -- the address template for the person to 1457c478bd9Sstevel@tonic-gate ** send to -- effective uid/gid are important. 1467c478bd9Sstevel@tonic-gate ** This is typically the alias that caused this 1477c478bd9Sstevel@tonic-gate ** expansion. 1487c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of a queue to put 1497c478bd9Sstevel@tonic-gate ** these people into. 1507c478bd9Sstevel@tonic-gate ** aliaslevel -- the current alias nesting depth -- to 1517c478bd9Sstevel@tonic-gate ** diagnose loops. 1527c478bd9Sstevel@tonic-gate ** e -- the envelope in which to add these recipients. 1537c478bd9Sstevel@tonic-gate ** 1547c478bd9Sstevel@tonic-gate ** Returns: 1557c478bd9Sstevel@tonic-gate ** The number of addresses actually on the list. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* q_flags bits inherited from ctladdr */ 1597c478bd9Sstevel@tonic-gate #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate int 1627c478bd9Sstevel@tonic-gate sendtolist(list, ctladdr, sendq, aliaslevel, e) 1637c478bd9Sstevel@tonic-gate char *list; 1647c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 1657c478bd9Sstevel@tonic-gate ADDRESS **sendq; 1667c478bd9Sstevel@tonic-gate int aliaslevel; 1677c478bd9Sstevel@tonic-gate register ENVELOPE *e; 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate register char *p; 1707c478bd9Sstevel@tonic-gate register ADDRESS *SM_NONVOLATILE al; /* list of addresses to send to */ 1717c478bd9Sstevel@tonic-gate SM_NONVOLATILE char delimiter; /* the address delimiter */ 1727c478bd9Sstevel@tonic-gate SM_NONVOLATILE int naddrs; 1737c478bd9Sstevel@tonic-gate SM_NONVOLATILE int i; 1747c478bd9Sstevel@tonic-gate char *endp; 1757c478bd9Sstevel@tonic-gate char *oldto = e->e_to; 1767c478bd9Sstevel@tonic-gate char *SM_NONVOLATILE bufp; 1777c478bd9Sstevel@tonic-gate char buf[MAXNAME + 1]; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (list == NULL) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate syserr("sendtolist: null list"); 1827c478bd9Sstevel@tonic-gate return 0; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (tTd(25, 1)) 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate sm_dprintf("sendto: %s\n ctladdr=", list); 1887c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* heuristic to determine old versus new style addresses */ 1927c478bd9Sstevel@tonic-gate if (ctladdr == NULL && 1937c478bd9Sstevel@tonic-gate (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 1947c478bd9Sstevel@tonic-gate strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 1957c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_OLDSTYLE; 1967c478bd9Sstevel@tonic-gate delimiter = ' '; 1977c478bd9Sstevel@tonic-gate if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 1987c478bd9Sstevel@tonic-gate delimiter = ','; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate al = NULL; 2017c478bd9Sstevel@tonic-gate naddrs = 0; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* make sure we have enough space to copy the string */ 2047c478bd9Sstevel@tonic-gate i = strlen(list) + 1; 205058561cbSjbeck if (i <= sizeof(buf)) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate bufp = buf; 208058561cbSjbeck i = sizeof(buf); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate else 2117c478bd9Sstevel@tonic-gate bufp = sm_malloc_x(i); 2127c478bd9Sstevel@tonic-gate endp = bufp + i; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate SM_TRY 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bufp, denlstring(list, false, true), i); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 2197c478bd9Sstevel@tonic-gate for (p = bufp; *p != '\0'; ) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate auto char *delimptr; 2227c478bd9Sstevel@tonic-gate register ADDRESS *a; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate SM_ASSERT(p < endp); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* parse the address */ 2277c478bd9Sstevel@tonic-gate while ((isascii(*p) && isspace(*p)) || *p == ',') 2287c478bd9Sstevel@tonic-gate p++; 2297c478bd9Sstevel@tonic-gate SM_ASSERT(p < endp); 2307c478bd9Sstevel@tonic-gate a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, 2317c478bd9Sstevel@tonic-gate &delimptr, e, true); 2327c478bd9Sstevel@tonic-gate p = delimptr; 2337c478bd9Sstevel@tonic-gate SM_ASSERT(p < endp); 2347c478bd9Sstevel@tonic-gate if (a == NULL) 2357c478bd9Sstevel@tonic-gate continue; 2367c478bd9Sstevel@tonic-gate a->q_next = al; 2377c478bd9Sstevel@tonic-gate a->q_alias = ctladdr; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* arrange to inherit attributes from parent */ 2407c478bd9Sstevel@tonic-gate if (ctladdr != NULL) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate ADDRESS *b; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* self reference test */ 2457c478bd9Sstevel@tonic-gate if (sameaddr(ctladdr, a)) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate if (tTd(27, 5)) 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate sm_dprintf("sendtolist: QSELFREF "); 2507c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QSELFREF; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* check for address loops */ 2567c478bd9Sstevel@tonic-gate b = self_reference(a); 2577c478bd9Sstevel@tonic-gate if (b != NULL) 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate b->q_flags |= QSELFREF; 2607c478bd9Sstevel@tonic-gate if (tTd(27, 5)) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate sm_dprintf("sendtolist: QSELFREF "); 2637c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), b, false); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate if (a != b) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate if (tTd(27, 5)) 2687c478bd9Sstevel@tonic-gate { 2697c478bd9Sstevel@tonic-gate sm_dprintf("sendtolist: QS_DONTSEND "); 2707c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate a->q_state = QS_DONTSEND; 2737c478bd9Sstevel@tonic-gate b->q_flags |= a->q_flags & QNOTREMOTE; 2747c478bd9Sstevel@tonic-gate continue; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* full name */ 2797c478bd9Sstevel@tonic-gate if (a->q_fullname == NULL) 2807c478bd9Sstevel@tonic-gate a->q_fullname = ctladdr->q_fullname; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* various flag bits */ 2837c478bd9Sstevel@tonic-gate a->q_flags &= ~QINHERITEDBITS; 2847c478bd9Sstevel@tonic-gate a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate /* DSN recipient information */ 2877c478bd9Sstevel@tonic-gate a->q_finalrcpt = ctladdr->q_finalrcpt; 2887c478bd9Sstevel@tonic-gate a->q_orcpt = ctladdr->q_orcpt; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate al = a; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* arrange to send to everyone on the local send list */ 2957c478bd9Sstevel@tonic-gate while (al != NULL) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate register ADDRESS *a = al; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate al = a->q_next; 3007c478bd9Sstevel@tonic-gate a = recipient(a, sendq, aliaslevel, e); 3017c478bd9Sstevel@tonic-gate naddrs++; 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate SM_FINALLY 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate e->e_to = oldto; 3077c478bd9Sstevel@tonic-gate if (bufp != buf) 3087c478bd9Sstevel@tonic-gate sm_free(bufp); 3097c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate SM_END_TRY 3127c478bd9Sstevel@tonic-gate return naddrs; 3137c478bd9Sstevel@tonic-gate } 314058561cbSjbeck 3157c478bd9Sstevel@tonic-gate #if MILTER 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate ** REMOVEFROMLIST -- Remove addresses from a send list. 3187c478bd9Sstevel@tonic-gate ** 3197c478bd9Sstevel@tonic-gate ** The parameter is a comma-separated list of recipients to remove. 3207c478bd9Sstevel@tonic-gate ** Note that it only deletes matching addresses. If those addresses 3217c478bd9Sstevel@tonic-gate ** have been expanded already in the sendq, it won't mark the 3227c478bd9Sstevel@tonic-gate ** expanded recipients as QS_REMOVED. 3237c478bd9Sstevel@tonic-gate ** 3247c478bd9Sstevel@tonic-gate ** Parameters: 3257c478bd9Sstevel@tonic-gate ** list -- the list to remove. 3267c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of a queue to remove 3277c478bd9Sstevel@tonic-gate ** these addresses from. 3287c478bd9Sstevel@tonic-gate ** e -- the envelope in which to remove these recipients. 3297c478bd9Sstevel@tonic-gate ** 3307c478bd9Sstevel@tonic-gate ** Returns: 3317c478bd9Sstevel@tonic-gate ** The number of addresses removed from the list. 3327c478bd9Sstevel@tonic-gate ** 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate int 3367c478bd9Sstevel@tonic-gate removefromlist(list, sendq, e) 3377c478bd9Sstevel@tonic-gate char *list; 3387c478bd9Sstevel@tonic-gate ADDRESS **sendq; 3397c478bd9Sstevel@tonic-gate ENVELOPE *e; 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate SM_NONVOLATILE char delimiter; /* the address delimiter */ 3427c478bd9Sstevel@tonic-gate SM_NONVOLATILE int naddrs; 3437c478bd9Sstevel@tonic-gate SM_NONVOLATILE int i; 3447c478bd9Sstevel@tonic-gate char *p; 3457c478bd9Sstevel@tonic-gate char *oldto = e->e_to; 3467c478bd9Sstevel@tonic-gate char *SM_NONVOLATILE bufp; 3477c478bd9Sstevel@tonic-gate char buf[MAXNAME + 1]; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (list == NULL) 3507c478bd9Sstevel@tonic-gate { 3517c478bd9Sstevel@tonic-gate syserr("removefromlist: null list"); 3527c478bd9Sstevel@tonic-gate return 0; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate if (tTd(25, 1)) 3567c478bd9Sstevel@tonic-gate sm_dprintf("removefromlist: %s\n", list); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* heuristic to determine old versus new style addresses */ 3597c478bd9Sstevel@tonic-gate if (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 3607c478bd9Sstevel@tonic-gate strchr(list, '<') != NULL || strchr(list, '(') != NULL) 3617c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_OLDSTYLE; 3627c478bd9Sstevel@tonic-gate delimiter = ' '; 3637c478bd9Sstevel@tonic-gate if (!bitset(EF_OLDSTYLE, e->e_flags)) 3647c478bd9Sstevel@tonic-gate delimiter = ','; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate naddrs = 0; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* make sure we have enough space to copy the string */ 3697c478bd9Sstevel@tonic-gate i = strlen(list) + 1; 370058561cbSjbeck if (i <= sizeof(buf)) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate bufp = buf; 373058561cbSjbeck i = sizeof(buf); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate else 3767c478bd9Sstevel@tonic-gate bufp = sm_malloc_x(i); 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate SM_TRY 3797c478bd9Sstevel@tonic-gate { 3807c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bufp, denlstring(list, false, true), i); 3817c478bd9Sstevel@tonic-gate 382*7800901eSjbeck #if _FFR_ADDR_TYPE_MODES 383*7800901eSjbeck if (AddrTypeModes) 384*7800901eSjbeck macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), 385*7800901eSjbeck "e r d"); 386*7800901eSjbeck else 387*7800901eSjbeck #endif /* _FFR_ADDR_TYPE_MODES */ 3887c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 3897c478bd9Sstevel@tonic-gate for (p = bufp; *p != '\0'; ) 3907c478bd9Sstevel@tonic-gate { 3917c478bd9Sstevel@tonic-gate ADDRESS a; /* parsed address to be removed */ 3927c478bd9Sstevel@tonic-gate ADDRESS *q; 3937c478bd9Sstevel@tonic-gate ADDRESS **pq; 3947c478bd9Sstevel@tonic-gate char *delimptr; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* parse the address */ 3977c478bd9Sstevel@tonic-gate while ((isascii(*p) && isspace(*p)) || *p == ',') 3987c478bd9Sstevel@tonic-gate p++; 399058561cbSjbeck if (parseaddr(p, &a, RF_COPYALL|RF_RM_ADDR, 4007c478bd9Sstevel@tonic-gate delimiter, &delimptr, e, true) == NULL) 4017c478bd9Sstevel@tonic-gate { 4027c478bd9Sstevel@tonic-gate p = delimptr; 4037c478bd9Sstevel@tonic-gate continue; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate p = delimptr; 4067c478bd9Sstevel@tonic-gate for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate if (!QS_IS_DEAD(q->q_state) && 4097c478bd9Sstevel@tonic-gate (sameaddr(q, &a) || 4107c478bd9Sstevel@tonic-gate strcmp(q->q_paddr, a.q_paddr) == 0)) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate if (tTd(25, 5)) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate sm_dprintf("removefromlist: QS_REMOVED "); 4157c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), &a, false); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate q->q_state = QS_REMOVED; 4187c478bd9Sstevel@tonic-gate naddrs++; 4197c478bd9Sstevel@tonic-gate break; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate SM_FINALLY 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate e->e_to = oldto; 4277c478bd9Sstevel@tonic-gate if (bufp != buf) 4287c478bd9Sstevel@tonic-gate sm_free(bufp); 4297c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate SM_END_TRY 4327c478bd9Sstevel@tonic-gate return naddrs; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate #endif /* MILTER */ 435058561cbSjbeck 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate ** RECIPIENT -- Designate a message recipient 4384aac33d3Sjbeck ** Saves the named person for future mailing (after some checks). 4397c478bd9Sstevel@tonic-gate ** 4407c478bd9Sstevel@tonic-gate ** Parameters: 4417c478bd9Sstevel@tonic-gate ** new -- the (preparsed) address header for the recipient. 4427c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of a queue to put the 4437c478bd9Sstevel@tonic-gate ** recipient in. Duplicate suppression is done 4447c478bd9Sstevel@tonic-gate ** in this queue. 4457c478bd9Sstevel@tonic-gate ** aliaslevel -- the current alias nesting depth. 4467c478bd9Sstevel@tonic-gate ** e -- the current envelope. 4477c478bd9Sstevel@tonic-gate ** 4487c478bd9Sstevel@tonic-gate ** Returns: 4497c478bd9Sstevel@tonic-gate ** The actual address in the queue. This will be "a" if 4507c478bd9Sstevel@tonic-gate ** the address is not a duplicate, else the original address. 4517c478bd9Sstevel@tonic-gate ** 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate ADDRESS * 4557c478bd9Sstevel@tonic-gate recipient(new, sendq, aliaslevel, e) 4567c478bd9Sstevel@tonic-gate register ADDRESS *new; 4577c478bd9Sstevel@tonic-gate register ADDRESS **sendq; 4587c478bd9Sstevel@tonic-gate int aliaslevel; 4597c478bd9Sstevel@tonic-gate register ENVELOPE *e; 4607c478bd9Sstevel@tonic-gate { 4617c478bd9Sstevel@tonic-gate register ADDRESS *q; 4627c478bd9Sstevel@tonic-gate ADDRESS **pq; 4637c478bd9Sstevel@tonic-gate ADDRESS **prev; 4647c478bd9Sstevel@tonic-gate register struct mailer *m; 4657c478bd9Sstevel@tonic-gate register char *p; 4667c478bd9Sstevel@tonic-gate int i, buflen; 4677c478bd9Sstevel@tonic-gate bool quoted; /* set if the addr has a quote bit */ 4687c478bd9Sstevel@tonic-gate bool insert; 4697c478bd9Sstevel@tonic-gate int findusercount; 4707c478bd9Sstevel@tonic-gate bool initialdontsend; 4717c478bd9Sstevel@tonic-gate char *buf; 4727c478bd9Sstevel@tonic-gate char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 4737c478bd9Sstevel@tonic-gate sortfn_t *sortfn; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate p = NULL; 4767c478bd9Sstevel@tonic-gate quoted = false; 4777c478bd9Sstevel@tonic-gate insert = false; 4787c478bd9Sstevel@tonic-gate findusercount = 0; 4797c478bd9Sstevel@tonic-gate initialdontsend = QS_IS_DEAD(new->q_state); 4807c478bd9Sstevel@tonic-gate e->e_to = new->q_paddr; 4817c478bd9Sstevel@tonic-gate m = new->q_mailer; 4827c478bd9Sstevel@tonic-gate errno = 0; 4837c478bd9Sstevel@tonic-gate if (aliaslevel == 0) 4847c478bd9Sstevel@tonic-gate new->q_flags |= QPRIMARY; 4857c478bd9Sstevel@tonic-gate if (tTd(26, 1)) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate sm_dprintf("\nrecipient (%d): ", aliaslevel); 4887c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), new, false); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* if this is primary, use it as original recipient */ 4927c478bd9Sstevel@tonic-gate if (new->q_alias == NULL) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate if (e->e_origrcpt == NULL) 4957c478bd9Sstevel@tonic-gate e->e_origrcpt = new->q_paddr; 4967c478bd9Sstevel@tonic-gate else if (e->e_origrcpt != new->q_paddr) 4977c478bd9Sstevel@tonic-gate e->e_origrcpt = ""; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* find parent recipient for finalrcpt and orcpt */ 5017c478bd9Sstevel@tonic-gate for (q = new; q->q_alias != NULL; q = q->q_alias) 5027c478bd9Sstevel@tonic-gate continue; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* find final recipient DSN address */ 5057c478bd9Sstevel@tonic-gate if (new->q_finalrcpt == NULL && 5067c478bd9Sstevel@tonic-gate e->e_from.q_mailer != NULL) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate char frbuf[MAXLINE]; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate p = e->e_from.q_mailer->m_addrtype; 5117c478bd9Sstevel@tonic-gate if (p == NULL) 5127c478bd9Sstevel@tonic-gate p = "rfc822"; 5137c478bd9Sstevel@tonic-gate if (sm_strcasecmp(p, "rfc822") != 0) 5147c478bd9Sstevel@tonic-gate { 515058561cbSjbeck (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 5167c478bd9Sstevel@tonic-gate q->q_mailer->m_addrtype, 5177c478bd9Sstevel@tonic-gate q->q_user); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate else if (strchr(q->q_user, '@') != NULL) 5207c478bd9Sstevel@tonic-gate { 521058561cbSjbeck (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 5227c478bd9Sstevel@tonic-gate p, q->q_user); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate else if (strchr(q->q_paddr, '@') != NULL) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate char *qp; 5277c478bd9Sstevel@tonic-gate bool b; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate qp = q->q_paddr; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* strip brackets from address */ 5327c478bd9Sstevel@tonic-gate b = false; 5337c478bd9Sstevel@tonic-gate if (*qp == '<') 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate b = qp[strlen(qp) - 1] == '>'; 5367c478bd9Sstevel@tonic-gate if (b) 5377c478bd9Sstevel@tonic-gate qp[strlen(qp) - 1] = '\0'; 5387c478bd9Sstevel@tonic-gate qp++; 5397c478bd9Sstevel@tonic-gate } 540058561cbSjbeck (void) sm_snprintf(frbuf, sizeof(frbuf), "%s; %.800s", 5417c478bd9Sstevel@tonic-gate p, qp); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* undo damage */ 5447c478bd9Sstevel@tonic-gate if (b) 5457c478bd9Sstevel@tonic-gate qp[strlen(qp)] = '>'; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate else 5487c478bd9Sstevel@tonic-gate { 549058561cbSjbeck (void) sm_snprintf(frbuf, sizeof(frbuf), 5507c478bd9Sstevel@tonic-gate "%s; %.700s@%.100s", 5517c478bd9Sstevel@tonic-gate p, q->q_user, MyHostName); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate new->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool, frbuf); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate #if _FFR_GEN_ORCPT 5577c478bd9Sstevel@tonic-gate /* set ORCPT DSN arg if not already set */ 5587c478bd9Sstevel@tonic-gate if (new->q_orcpt == NULL) 5597c478bd9Sstevel@tonic-gate { 5607c478bd9Sstevel@tonic-gate /* check for an existing ORCPT */ 5617c478bd9Sstevel@tonic-gate if (q->q_orcpt != NULL) 5627c478bd9Sstevel@tonic-gate new->q_orcpt = q->q_orcpt; 5637c478bd9Sstevel@tonic-gate else 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate /* make our own */ 5667c478bd9Sstevel@tonic-gate bool b = false; 5677c478bd9Sstevel@tonic-gate char *qp; 5687c478bd9Sstevel@tonic-gate char obuf[MAXLINE]; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (e->e_from.q_mailer != NULL) 5717c478bd9Sstevel@tonic-gate p = e->e_from.q_mailer->m_addrtype; 5727c478bd9Sstevel@tonic-gate if (p == NULL) 5737c478bd9Sstevel@tonic-gate p = "rfc822"; 574058561cbSjbeck (void) sm_strlcpyn(obuf, sizeof(obuf), 2, p, ";"); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate qp = q->q_paddr; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* FFR: Needs to strip comments from stdin addrs */ 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* strip brackets from address */ 5817c478bd9Sstevel@tonic-gate if (*qp == '<') 5827c478bd9Sstevel@tonic-gate { 5837c478bd9Sstevel@tonic-gate b = qp[strlen(qp) - 1] == '>'; 5847c478bd9Sstevel@tonic-gate if (b) 5857c478bd9Sstevel@tonic-gate qp[strlen(qp) - 1] = '\0'; 5867c478bd9Sstevel@tonic-gate qp++; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 589058561cbSjbeck p = xtextify(denlstring(qp, true, false), "="); 5907c478bd9Sstevel@tonic-gate 591058561cbSjbeck if (sm_strlcat(obuf, p, sizeof(obuf)) >= sizeof(obuf)) 5927c478bd9Sstevel@tonic-gate { 5937c478bd9Sstevel@tonic-gate /* if too big, don't use it */ 5947c478bd9Sstevel@tonic-gate obuf[0] = '\0'; 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* undo damage */ 5987c478bd9Sstevel@tonic-gate if (b) 5997c478bd9Sstevel@tonic-gate qp[strlen(qp)] = '>'; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if (obuf[0] != '\0') 6027c478bd9Sstevel@tonic-gate new->q_orcpt = 6037c478bd9Sstevel@tonic-gate sm_rpool_strdup_x(e->e_rpool, obuf); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate #endif /* _FFR_GEN_ORCPT */ 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* break aliasing loops */ 6097c478bd9Sstevel@tonic-gate if (aliaslevel > MaxAliasRecursion) 6107c478bd9Sstevel@tonic-gate { 6117c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 6127c478bd9Sstevel@tonic-gate new->q_status = "5.4.6"; 613058561cbSjbeck if (new->q_alias != NULL) 614058561cbSjbeck { 615058561cbSjbeck new->q_alias->q_state = QS_BADADDR; 616058561cbSjbeck new->q_alias->q_status = "5.4.6"; 617058561cbSjbeck } 618058561cbSjbeck if ((SuprErrs || !LogUsrErrs) && LogLevel > 0) 619058561cbSjbeck { 620058561cbSjbeck sm_syslog(LOG_ERR, e->e_id, 621058561cbSjbeck "aliasing/forwarding loop broken: %s (%d aliases deep; %d max)", 622058561cbSjbeck FileName != NULL ? FileName : "", aliaslevel, 623058561cbSjbeck MaxAliasRecursion); 624058561cbSjbeck } 6257c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 6267c478bd9Sstevel@tonic-gate "554 aliasing/forwarding loop broken (%d aliases deep; %d max)", 6277c478bd9Sstevel@tonic-gate aliaslevel, MaxAliasRecursion); 6287c478bd9Sstevel@tonic-gate return new; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate ** Finish setting up address structure. 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* get unquoted user for file, program or user.name check */ 6367c478bd9Sstevel@tonic-gate i = strlen(new->q_user); 637058561cbSjbeck if (i >= sizeof(buf0)) 6387c478bd9Sstevel@tonic-gate { 6397c478bd9Sstevel@tonic-gate buflen = i + 1; 6407c478bd9Sstevel@tonic-gate buf = xalloc(buflen); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate else 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate buf = buf0; 645058561cbSjbeck buflen = sizeof(buf0); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, new->q_user, buflen); 6487c478bd9Sstevel@tonic-gate for (p = buf; *p != '\0' && !quoted; p++) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate if (*p == '\\') 6517c478bd9Sstevel@tonic-gate quoted = true; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate stripquotes(buf); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* check for direct mailing to restricted mailers */ 6567c478bd9Sstevel@tonic-gate if (m == ProgMailer) 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate if (new->q_alias == NULL || UseMSP || 6597c478bd9Sstevel@tonic-gate bitset(EF_UNSAFE, e->e_flags)) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 6627c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 6637c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 6647c478bd9Sstevel@tonic-gate "550 Cannot mail directly to programs"); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 6697c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 6707c478bd9Sstevel@tonic-gate if (new->q_alias->q_ruser == NULL) 6717c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 6727c478bd9Sstevel@tonic-gate "550 UID %d is an unknown user: cannot mail to programs", 6737c478bd9Sstevel@tonic-gate new->q_alias->q_uid); 6747c478bd9Sstevel@tonic-gate else 6757c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 6767c478bd9Sstevel@tonic-gate "550 User %s@%s doesn't have a valid shell for mailing to programs", 6777c478bd9Sstevel@tonic-gate new->q_alias->q_ruser, MyHostName); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 6807c478bd9Sstevel@tonic-gate { 6817c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 6827c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 6837c478bd9Sstevel@tonic-gate new->q_rstatus = "550 Unsafe for mailing to programs"; 6847c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 6857c478bd9Sstevel@tonic-gate "550 Address %s is unsafe for mailing to programs", 6867c478bd9Sstevel@tonic-gate new->q_alias->q_paddr); 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate ** Look up this person in the recipient list. 6927c478bd9Sstevel@tonic-gate ** If they are there already, return, otherwise continue. 6937c478bd9Sstevel@tonic-gate ** If the list is empty, just add it. Notice the cute 6947c478bd9Sstevel@tonic-gate ** hack to make from addresses suppress things correctly: 6957c478bd9Sstevel@tonic-gate ** the QS_DUPLICATE state will be set in the send list. 6967c478bd9Sstevel@tonic-gate ** [Please note: the emphasis is on "hack."] 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate prev = NULL; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate ** If this message is going to the queue or FastSplit is set 7037c478bd9Sstevel@tonic-gate ** and it is the first try and the envelope hasn't split, then we 7047c478bd9Sstevel@tonic-gate ** avoid doing an MX RR lookup now because one will be done when the 7057c478bd9Sstevel@tonic-gate ** message is extracted from the queue later. It can go to the queue 7067c478bd9Sstevel@tonic-gate ** because all messages are going to the queue or this mailer of 7077c478bd9Sstevel@tonic-gate ** the current recipient is marked expensive. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (UseMSP || WILL_BE_QUEUED(e->e_sendmode) || 7117c478bd9Sstevel@tonic-gate (!bitset(EF_SPLIT, e->e_flags) && e->e_ntries == 0 && 7127c478bd9Sstevel@tonic-gate FastSplit > 0)) 7137c478bd9Sstevel@tonic-gate sortfn = sorthost; 7147c478bd9Sstevel@tonic-gate else if (NoConnect && bitnset(M_EXPENSIVE, new->q_mailer->m_flags)) 7157c478bd9Sstevel@tonic-gate sortfn = sortexpensive; 7167c478bd9Sstevel@tonic-gate else 7177c478bd9Sstevel@tonic-gate sortfn = sortbysignature; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 7207c478bd9Sstevel@tonic-gate { 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate ** If address is "less than" it should be inserted now. 7237c478bd9Sstevel@tonic-gate ** If address is "greater than" current comparison it'll 7247c478bd9Sstevel@tonic-gate ** insert later in the list; so loop again (if possible). 7257c478bd9Sstevel@tonic-gate ** If address is "equal" (different equal than sameaddr() 7267c478bd9Sstevel@tonic-gate ** call) then check if sameaddr() will be true. 7277c478bd9Sstevel@tonic-gate ** Because this list is now sorted, it'll mean fewer 7287c478bd9Sstevel@tonic-gate ** comparisons and fewer loops which is important for more 7297c478bd9Sstevel@tonic-gate ** recipients. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate i = (*sortfn)(new, q); 7337c478bd9Sstevel@tonic-gate if (i == 0) /* equal */ 7347c478bd9Sstevel@tonic-gate { 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate ** Sortbysignature() has said that the two have 7377c478bd9Sstevel@tonic-gate ** equal MX RR's and the same user. Calling sameaddr() 7387c478bd9Sstevel@tonic-gate ** now checks if the two hosts are as identical as the 7397c478bd9Sstevel@tonic-gate ** MX RR's are (which might not be the case) 7407c478bd9Sstevel@tonic-gate ** before saying these are the identical addresses. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if (sameaddr(q, new) && 7447c478bd9Sstevel@tonic-gate (bitset(QRCPTOK, q->q_flags) || 7457c478bd9Sstevel@tonic-gate !bitset(QPRIMARY, q->q_flags))) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate if (tTd(26, 1)) 7487c478bd9Sstevel@tonic-gate { 7497c478bd9Sstevel@tonic-gate sm_dprintf("%s in sendq: ", 7507c478bd9Sstevel@tonic-gate new->q_paddr); 7517c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), q, false); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate if (!bitset(QPRIMARY, q->q_flags)) 7547c478bd9Sstevel@tonic-gate { 7557c478bd9Sstevel@tonic-gate if (!QS_IS_DEAD(new->q_state)) 7567c478bd9Sstevel@tonic-gate message("duplicate suppressed"); 7577c478bd9Sstevel@tonic-gate else 7587c478bd9Sstevel@tonic-gate q->q_state = QS_DUPLICATE; 7597c478bd9Sstevel@tonic-gate q->q_flags |= new->q_flags; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate else if (bitset(QSELFREF, q->q_flags) 7627c478bd9Sstevel@tonic-gate || q->q_state == QS_REMOVED) 7637c478bd9Sstevel@tonic-gate { 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate ** If an earlier milter removed the 7667c478bd9Sstevel@tonic-gate ** address, a later one can still add 7677c478bd9Sstevel@tonic-gate ** it back. 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate q->q_state = new->q_state; 7717c478bd9Sstevel@tonic-gate q->q_flags |= new->q_flags; 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate new = q; 7747c478bd9Sstevel@tonic-gate goto done; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate else if (i < 0) /* less than */ 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate insert = true; 7807c478bd9Sstevel@tonic-gate break; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate prev = pq; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* pq should point to an address, never NULL */ 7867c478bd9Sstevel@tonic-gate SM_ASSERT(pq != NULL); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* add address on list */ 7897c478bd9Sstevel@tonic-gate if (insert) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate ** insert before 'pq'. Only possible when at least 1 7937c478bd9Sstevel@tonic-gate ** ADDRESS is in the list already. 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate new->q_next = *pq; 7977c478bd9Sstevel@tonic-gate if (prev == NULL) 7987c478bd9Sstevel@tonic-gate *sendq = new; /* To be the first ADDRESS */ 7997c478bd9Sstevel@tonic-gate else 8007c478bd9Sstevel@tonic-gate (*prev)->q_next = new; 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate else 8037c478bd9Sstevel@tonic-gate { 8047c478bd9Sstevel@tonic-gate /* 8057c478bd9Sstevel@tonic-gate ** Place in list at current 'pq' position. Possible 8067c478bd9Sstevel@tonic-gate ** when there are 0 or more ADDRESS's in the list. 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate new->q_next = NULL; 8107c478bd9Sstevel@tonic-gate *pq = new; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* added a new address: clear split flag */ 8147c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_SPLIT; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate ** Alias the name and handle special mailer types. 8187c478bd9Sstevel@tonic-gate */ 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate trylocaluser: 8217c478bd9Sstevel@tonic-gate if (tTd(29, 7)) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate sm_dprintf("at trylocaluser: "); 8247c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), new, false); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if (!QS_IS_OK(new->q_state)) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate if (QS_IS_UNDELIVERED(new->q_state)) 8307c478bd9Sstevel@tonic-gate e->e_nrcpts++; 8317c478bd9Sstevel@tonic-gate goto testselfdestruct; 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if (m == InclMailer) 8357c478bd9Sstevel@tonic-gate { 8367c478bd9Sstevel@tonic-gate new->q_state = QS_INCLUDED; 8377c478bd9Sstevel@tonic-gate if (new->q_alias == NULL || UseMSP || 8387c478bd9Sstevel@tonic-gate bitset(EF_UNSAFE, e->e_flags)) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 8417c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 8427c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 8437c478bd9Sstevel@tonic-gate "550 Cannot mail directly to :include:s"); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate else 8467c478bd9Sstevel@tonic-gate { 8477c478bd9Sstevel@tonic-gate int ret; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate message("including file %s", new->q_user); 8507c478bd9Sstevel@tonic-gate ret = include(new->q_user, false, new, 8517c478bd9Sstevel@tonic-gate sendq, aliaslevel, e); 8527c478bd9Sstevel@tonic-gate if (transienterror(ret)) 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate if (LogLevel > 2) 8557c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 8567c478bd9Sstevel@tonic-gate "include %s: transient error: %s", 8577c478bd9Sstevel@tonic-gate shortenstring(new->q_user, 8587c478bd9Sstevel@tonic-gate MAXSHORTSTR), 8597c478bd9Sstevel@tonic-gate sm_errstring(ret)); 8607c478bd9Sstevel@tonic-gate new->q_state = QS_QUEUEUP; 8617c478bd9Sstevel@tonic-gate usrerr("451 4.2.4 Cannot open %s: %s", 8627c478bd9Sstevel@tonic-gate shortenstring(new->q_user, 8637c478bd9Sstevel@tonic-gate MAXSHORTSTR), 8647c478bd9Sstevel@tonic-gate sm_errstring(ret)); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate else if (ret != 0) 8677c478bd9Sstevel@tonic-gate { 8687c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 8697c478bd9Sstevel@tonic-gate new->q_status = "5.2.4"; 8707c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 8717c478bd9Sstevel@tonic-gate "550 Cannot open %s: %s", 8727c478bd9Sstevel@tonic-gate shortenstring(new->q_user, 8737c478bd9Sstevel@tonic-gate MAXSHORTSTR), 8747c478bd9Sstevel@tonic-gate sm_errstring(ret)); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate else if (m == FileMailer) 8797c478bd9Sstevel@tonic-gate { 8807c478bd9Sstevel@tonic-gate /* check if allowed */ 8817c478bd9Sstevel@tonic-gate if (new->q_alias == NULL || UseMSP || 8827c478bd9Sstevel@tonic-gate bitset(EF_UNSAFE, e->e_flags)) 8837c478bd9Sstevel@tonic-gate { 8847c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 8857c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 8867c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 8877c478bd9Sstevel@tonic-gate "550 Cannot mail directly to files"); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate else if (bitset(QBOGUSSHELL, new->q_alias->q_flags)) 8907c478bd9Sstevel@tonic-gate { 8917c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 8927c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 8937c478bd9Sstevel@tonic-gate if (new->q_alias->q_ruser == NULL) 8947c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 8957c478bd9Sstevel@tonic-gate "550 UID %d is an unknown user: cannot mail to files", 8967c478bd9Sstevel@tonic-gate new->q_alias->q_uid); 8977c478bd9Sstevel@tonic-gate else 8987c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 8997c478bd9Sstevel@tonic-gate "550 User %s@%s doesn't have a valid shell for mailing to files", 9007c478bd9Sstevel@tonic-gate new->q_alias->q_ruser, MyHostName); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate else if (bitset(QUNSAFEADDR, new->q_alias->q_flags)) 9037c478bd9Sstevel@tonic-gate { 9047c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 9057c478bd9Sstevel@tonic-gate new->q_status = "5.7.1"; 9067c478bd9Sstevel@tonic-gate new->q_rstatus = "550 Unsafe for mailing to files"; 9077c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 9087c478bd9Sstevel@tonic-gate "550 Address %s is unsafe for mailing to files", 9097c478bd9Sstevel@tonic-gate new->q_alias->q_paddr); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* try aliasing */ 9147c478bd9Sstevel@tonic-gate if (!quoted && QS_IS_OK(new->q_state) && 9157c478bd9Sstevel@tonic-gate bitnset(M_ALIASABLE, m->m_flags)) 9167c478bd9Sstevel@tonic-gate alias(new, sendq, aliaslevel, e); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate #if USERDB 9197c478bd9Sstevel@tonic-gate /* if not aliased, look it up in the user database */ 9207c478bd9Sstevel@tonic-gate if (!bitset(QNOTREMOTE, new->q_flags) && 9217c478bd9Sstevel@tonic-gate QS_IS_SENDABLE(new->q_state) && 9227c478bd9Sstevel@tonic-gate bitnset(M_CHECKUDB, m->m_flags)) 9237c478bd9Sstevel@tonic-gate { 9247c478bd9Sstevel@tonic-gate if (udbexpand(new, sendq, aliaslevel, e) == EX_TEMPFAIL) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate new->q_state = QS_QUEUEUP; 9277c478bd9Sstevel@tonic-gate if (e->e_message == NULL) 928058561cbSjbeck e->e_message = sm_rpool_strdup_x(e->e_rpool, 929058561cbSjbeck "Deferred: user database error"); 9307c478bd9Sstevel@tonic-gate if (new->q_message == NULL) 9317c478bd9Sstevel@tonic-gate new->q_message = "Deferred: user database error"; 9327c478bd9Sstevel@tonic-gate if (LogLevel > 8) 9337c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 9347c478bd9Sstevel@tonic-gate "deferred: udbexpand: %s", 9357c478bd9Sstevel@tonic-gate sm_errstring(errno)); 9367c478bd9Sstevel@tonic-gate message("queued (user database error): %s", 9377c478bd9Sstevel@tonic-gate sm_errstring(errno)); 9387c478bd9Sstevel@tonic-gate e->e_nrcpts++; 9397c478bd9Sstevel@tonic-gate goto testselfdestruct; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate #endif /* USERDB */ 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate ** If we have a level two config file, then pass the name through 9467c478bd9Sstevel@tonic-gate ** Ruleset 5 before sending it off. Ruleset 5 has the right 9477c478bd9Sstevel@tonic-gate ** to rewrite it to another mailer. This gives us a hook 9487c478bd9Sstevel@tonic-gate ** after local aliasing has been done. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (tTd(29, 5)) 9527c478bd9Sstevel@tonic-gate { 9537c478bd9Sstevel@tonic-gate sm_dprintf("recipient: testing local? cl=%d, rr5=%p\n\t", 9547c478bd9Sstevel@tonic-gate ConfigLevel, RewriteRules[5]); 9557c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), new, false); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate if (ConfigLevel >= 2 && RewriteRules[5] != NULL && 9587c478bd9Sstevel@tonic-gate bitnset(M_TRYRULESET5, m->m_flags) && 9597c478bd9Sstevel@tonic-gate !bitset(QNOTREMOTE, new->q_flags) && 9607c478bd9Sstevel@tonic-gate QS_IS_OK(new->q_state)) 9617c478bd9Sstevel@tonic-gate { 9627c478bd9Sstevel@tonic-gate maplocaluser(new, sendq, aliaslevel + 1, e); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate ** If it didn't get rewritten to another mailer, go ahead 9677c478bd9Sstevel@tonic-gate ** and deliver it. 9687c478bd9Sstevel@tonic-gate */ 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate if (QS_IS_OK(new->q_state) && 9717c478bd9Sstevel@tonic-gate bitnset(M_HASPWENT, m->m_flags)) 9727c478bd9Sstevel@tonic-gate { 9737c478bd9Sstevel@tonic-gate auto bool fuzzy; 9747c478bd9Sstevel@tonic-gate SM_MBDB_T user; 9757c478bd9Sstevel@tonic-gate int status; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* warning -- finduser may trash buf */ 9787c478bd9Sstevel@tonic-gate status = finduser(buf, &fuzzy, &user); 9797c478bd9Sstevel@tonic-gate switch (status) 9807c478bd9Sstevel@tonic-gate { 9817c478bd9Sstevel@tonic-gate case EX_TEMPFAIL: 9827c478bd9Sstevel@tonic-gate new->q_state = QS_QUEUEUP; 9837c478bd9Sstevel@tonic-gate new->q_status = "4.5.2"; 9847c478bd9Sstevel@tonic-gate giveresponse(EX_TEMPFAIL, new->q_status, m, NULL, 9857c478bd9Sstevel@tonic-gate new->q_alias, (time_t) 0, e, new); 9867c478bd9Sstevel@tonic-gate break; 9877c478bd9Sstevel@tonic-gate default: 9887c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 9897c478bd9Sstevel@tonic-gate new->q_status = "5.1.1"; 9907c478bd9Sstevel@tonic-gate new->q_rstatus = "550 5.1.1 User unknown"; 9917c478bd9Sstevel@tonic-gate giveresponse(EX_NOUSER, new->q_status, m, NULL, 9927c478bd9Sstevel@tonic-gate new->q_alias, (time_t) 0, e, new); 9937c478bd9Sstevel@tonic-gate break; 9947c478bd9Sstevel@tonic-gate case EX_OK: 9957c478bd9Sstevel@tonic-gate if (fuzzy) 9967c478bd9Sstevel@tonic-gate { 9977c478bd9Sstevel@tonic-gate /* name was a fuzzy match */ 9987c478bd9Sstevel@tonic-gate new->q_user = sm_rpool_strdup_x(e->e_rpool, 9997c478bd9Sstevel@tonic-gate user.mbdb_name); 10007c478bd9Sstevel@tonic-gate if (findusercount++ > 3) 10017c478bd9Sstevel@tonic-gate { 10027c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 10037c478bd9Sstevel@tonic-gate new->q_status = "5.4.6"; 10047c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 10057c478bd9Sstevel@tonic-gate "554 aliasing/forwarding loop for %s broken", 10067c478bd9Sstevel@tonic-gate user.mbdb_name); 10077c478bd9Sstevel@tonic-gate goto done; 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* see if it aliases */ 10117c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, user.mbdb_name, buflen); 10127c478bd9Sstevel@tonic-gate goto trylocaluser; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate if (*user.mbdb_homedir == '\0') 10157c478bd9Sstevel@tonic-gate new->q_home = NULL; 10167c478bd9Sstevel@tonic-gate else if (strcmp(user.mbdb_homedir, "/") == 0) 10177c478bd9Sstevel@tonic-gate new->q_home = ""; 10187c478bd9Sstevel@tonic-gate else 10197c478bd9Sstevel@tonic-gate new->q_home = sm_rpool_strdup_x(e->e_rpool, 10207c478bd9Sstevel@tonic-gate user.mbdb_homedir); 10217c478bd9Sstevel@tonic-gate if (user.mbdb_uid != SM_NO_UID) 10227c478bd9Sstevel@tonic-gate { 10237c478bd9Sstevel@tonic-gate new->q_uid = user.mbdb_uid; 10247c478bd9Sstevel@tonic-gate new->q_gid = user.mbdb_gid; 10257c478bd9Sstevel@tonic-gate new->q_flags |= QGOODUID; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate new->q_ruser = sm_rpool_strdup_x(e->e_rpool, 10287c478bd9Sstevel@tonic-gate user.mbdb_name); 10297c478bd9Sstevel@tonic-gate if (user.mbdb_fullname[0] != '\0') 10307c478bd9Sstevel@tonic-gate new->q_fullname = sm_rpool_strdup_x(e->e_rpool, 10317c478bd9Sstevel@tonic-gate user.mbdb_fullname); 10327c478bd9Sstevel@tonic-gate if (!usershellok(user.mbdb_name, user.mbdb_shell)) 10337c478bd9Sstevel@tonic-gate { 10347c478bd9Sstevel@tonic-gate new->q_flags |= QBOGUSSHELL; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate if (bitset(EF_VRFYONLY, e->e_flags)) 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate /* don't do any more now */ 10397c478bd9Sstevel@tonic-gate new->q_state = QS_VERIFIED; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate else if (!quoted) 10427c478bd9Sstevel@tonic-gate forward(new, sendq, aliaslevel, e); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (!QS_IS_DEAD(new->q_state)) 10467c478bd9Sstevel@tonic-gate e->e_nrcpts++; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate testselfdestruct: 10497c478bd9Sstevel@tonic-gate new->q_flags |= QTHISPASS; 10507c478bd9Sstevel@tonic-gate if (tTd(26, 8)) 10517c478bd9Sstevel@tonic-gate { 10527c478bd9Sstevel@tonic-gate sm_dprintf("testselfdestruct: "); 10537c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), new, false); 10547c478bd9Sstevel@tonic-gate if (tTd(26, 10)) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate sm_dprintf("SENDQ:\n"); 10577c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), *sendq, true); 10587c478bd9Sstevel@tonic-gate sm_dprintf("----\n"); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate if (new->q_alias == NULL && new != &e->e_from && 10627c478bd9Sstevel@tonic-gate QS_IS_DEAD(new->q_state)) 10637c478bd9Sstevel@tonic-gate { 10647c478bd9Sstevel@tonic-gate for (q = *sendq; q != NULL; q = q->q_next) 10657c478bd9Sstevel@tonic-gate { 10667c478bd9Sstevel@tonic-gate if (!QS_IS_DEAD(q->q_state)) 10677c478bd9Sstevel@tonic-gate break; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate if (q == NULL) 10707c478bd9Sstevel@tonic-gate { 10717c478bd9Sstevel@tonic-gate new->q_state = QS_BADADDR; 10727c478bd9Sstevel@tonic-gate new->q_status = "5.4.6"; 10737c478bd9Sstevel@tonic-gate usrerrenh(new->q_status, 10747c478bd9Sstevel@tonic-gate "554 aliasing/forwarding loop broken"); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate done: 10797c478bd9Sstevel@tonic-gate new->q_flags |= QTHISPASS; 10807c478bd9Sstevel@tonic-gate if (buf != buf0) 10817c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX leak if above code raises exception */ 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate /* 10847c478bd9Sstevel@tonic-gate ** If we are at the top level, check to see if this has 10857c478bd9Sstevel@tonic-gate ** expanded to exactly one address. If so, it can inherit 10867c478bd9Sstevel@tonic-gate ** the primaryness of the address. 10877c478bd9Sstevel@tonic-gate ** 10887c478bd9Sstevel@tonic-gate ** While we're at it, clear the QTHISPASS bits. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (aliaslevel == 0) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate int nrcpts = 0; 10947c478bd9Sstevel@tonic-gate ADDRESS *only = NULL; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate for (q = *sendq; q != NULL; q = q->q_next) 10977c478bd9Sstevel@tonic-gate { 10987c478bd9Sstevel@tonic-gate if (bitset(QTHISPASS, q->q_flags) && 10997c478bd9Sstevel@tonic-gate QS_IS_SENDABLE(q->q_state)) 11007c478bd9Sstevel@tonic-gate { 11017c478bd9Sstevel@tonic-gate nrcpts++; 11027c478bd9Sstevel@tonic-gate only = q; 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate q->q_flags &= ~QTHISPASS; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate if (nrcpts == 1) 11077c478bd9Sstevel@tonic-gate { 11087c478bd9Sstevel@tonic-gate /* check to see if this actually got a new owner */ 11097c478bd9Sstevel@tonic-gate q = only; 11107c478bd9Sstevel@tonic-gate while ((q = q->q_alias) != NULL) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate if (q->q_owner != NULL) 11137c478bd9Sstevel@tonic-gate break; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate if (q == NULL) 11167c478bd9Sstevel@tonic-gate only->q_flags |= QPRIMARY; 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate else if (!initialdontsend && nrcpts > 0) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate /* arrange for return receipt */ 11217c478bd9Sstevel@tonic-gate e->e_flags |= EF_SENDRECEIPT; 11227c478bd9Sstevel@tonic-gate new->q_flags |= QEXPANDED; 11237c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL && 11247c478bd9Sstevel@tonic-gate bitset(QPINGONSUCCESS, new->q_flags)) 11257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 11267c478bd9Sstevel@tonic-gate "%s... expanded to multiple addresses\n", 11277c478bd9Sstevel@tonic-gate new->q_paddr); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate new->q_flags |= QRCPTOK; 1131058561cbSjbeck (void) sm_snprintf(buf0, sizeof(buf0), "%d", e->e_nrcpts); 11327c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{nrcpts}"), buf0); 11337c478bd9Sstevel@tonic-gate return new; 11347c478bd9Sstevel@tonic-gate } 1135058561cbSjbeck 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate ** FINDUSER -- find the password entry for a user. 11387c478bd9Sstevel@tonic-gate ** 11397c478bd9Sstevel@tonic-gate ** This looks a lot like getpwnam, except that it may want to 11407c478bd9Sstevel@tonic-gate ** do some fancier pattern matching in /etc/passwd. 11417c478bd9Sstevel@tonic-gate ** 11427c478bd9Sstevel@tonic-gate ** This routine contains most of the time of many sendmail runs. 11437c478bd9Sstevel@tonic-gate ** It deserves to be optimized. 11447c478bd9Sstevel@tonic-gate ** 11457c478bd9Sstevel@tonic-gate ** Parameters: 11467c478bd9Sstevel@tonic-gate ** name -- the name to match against. 11477c478bd9Sstevel@tonic-gate ** fuzzyp -- an outarg that is set to true if this entry 11487c478bd9Sstevel@tonic-gate ** was found using the fuzzy matching algorithm; 11497c478bd9Sstevel@tonic-gate ** set to false otherwise. 11507c478bd9Sstevel@tonic-gate ** user -- structure to fill in if user is found 11517c478bd9Sstevel@tonic-gate ** 11527c478bd9Sstevel@tonic-gate ** Returns: 11537c478bd9Sstevel@tonic-gate ** On success, fill in *user, set *fuzzyp and return EX_OK. 11547c478bd9Sstevel@tonic-gate ** If the user was not found, return EX_NOUSER. 11557c478bd9Sstevel@tonic-gate ** On error, return EX_TEMPFAIL or EX_OSERR. 11567c478bd9Sstevel@tonic-gate ** 11577c478bd9Sstevel@tonic-gate ** Side Effects: 11587c478bd9Sstevel@tonic-gate ** may modify name. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate int 11627c478bd9Sstevel@tonic-gate finduser(name, fuzzyp, user) 11637c478bd9Sstevel@tonic-gate char *name; 11647c478bd9Sstevel@tonic-gate bool *fuzzyp; 11657c478bd9Sstevel@tonic-gate SM_MBDB_T *user; 11667c478bd9Sstevel@tonic-gate { 11677c478bd9Sstevel@tonic-gate #if MATCHGECOS 11687c478bd9Sstevel@tonic-gate register struct passwd *pw; 11697c478bd9Sstevel@tonic-gate #endif /* MATCHGECOS */ 11707c478bd9Sstevel@tonic-gate register char *p; 11717c478bd9Sstevel@tonic-gate bool tryagain; 11727c478bd9Sstevel@tonic-gate int status; 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 11757c478bd9Sstevel@tonic-gate sm_dprintf("finduser(%s): ", name); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate *fuzzyp = false; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate #if HESIOD 11807c478bd9Sstevel@tonic-gate /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 11817c478bd9Sstevel@tonic-gate for (p = name; *p != '\0'; p++) 11827c478bd9Sstevel@tonic-gate if (!isascii(*p) || !isdigit(*p)) 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate if (*p == '\0') 11857c478bd9Sstevel@tonic-gate { 11867c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 11877c478bd9Sstevel@tonic-gate sm_dprintf("failed (numeric input)\n"); 11887c478bd9Sstevel@tonic-gate return EX_NOUSER; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate #endif /* HESIOD */ 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate /* look up this login name using fast path */ 11937c478bd9Sstevel@tonic-gate status = sm_mbdb_lookup(name, user); 11947c478bd9Sstevel@tonic-gate if (status != EX_NOUSER) 11957c478bd9Sstevel@tonic-gate { 11967c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 11977c478bd9Sstevel@tonic-gate sm_dprintf("%s (non-fuzzy)\n", sm_strexit(status)); 11987c478bd9Sstevel@tonic-gate return status; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* try mapping it to lower case */ 12027c478bd9Sstevel@tonic-gate tryagain = false; 12037c478bd9Sstevel@tonic-gate for (p = name; *p != '\0'; p++) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate if (isascii(*p) && isupper(*p)) 12067c478bd9Sstevel@tonic-gate { 12077c478bd9Sstevel@tonic-gate *p = tolower(*p); 12087c478bd9Sstevel@tonic-gate tryagain = true; 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate if (tryagain && (status = sm_mbdb_lookup(name, user)) != EX_NOUSER) 12127c478bd9Sstevel@tonic-gate { 12137c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 12147c478bd9Sstevel@tonic-gate sm_dprintf("%s (lower case)\n", sm_strexit(status)); 12157c478bd9Sstevel@tonic-gate *fuzzyp = true; 12167c478bd9Sstevel@tonic-gate return status; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate #if MATCHGECOS 12207c478bd9Sstevel@tonic-gate /* see if fuzzy matching allowed */ 12217c478bd9Sstevel@tonic-gate if (!MatchGecos) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 12247c478bd9Sstevel@tonic-gate sm_dprintf("not found (fuzzy disabled)\n"); 12257c478bd9Sstevel@tonic-gate return EX_NOUSER; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* search for a matching full name instead */ 12297c478bd9Sstevel@tonic-gate for (p = name; *p != '\0'; p++) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate if (*p == (SpaceSub & 0177) || *p == '_') 12327c478bd9Sstevel@tonic-gate *p = ' '; 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate (void) setpwent(); 12357c478bd9Sstevel@tonic-gate while ((pw = getpwent()) != NULL) 12367c478bd9Sstevel@tonic-gate { 12377c478bd9Sstevel@tonic-gate char buf[MAXNAME + 1]; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate # if 0 12407c478bd9Sstevel@tonic-gate if (sm_strcasecmp(pw->pw_name, name) == 0) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 12437c478bd9Sstevel@tonic-gate sm_dprintf("found (case wrapped)\n"); 12447c478bd9Sstevel@tonic-gate break; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate # endif /* 0 */ 12477c478bd9Sstevel@tonic-gate 1248058561cbSjbeck sm_pwfullname(pw->pw_gecos, pw->pw_name, buf, sizeof(buf)); 12497c478bd9Sstevel@tonic-gate if (strchr(buf, ' ') != NULL && sm_strcasecmp(buf, name) == 0) 12507c478bd9Sstevel@tonic-gate { 12517c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 12527c478bd9Sstevel@tonic-gate sm_dprintf("fuzzy matches %s\n", pw->pw_name); 12537c478bd9Sstevel@tonic-gate message("sending to login name %s", pw->pw_name); 12547c478bd9Sstevel@tonic-gate break; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate if (pw != NULL) 12587c478bd9Sstevel@tonic-gate *fuzzyp = true; 12597c478bd9Sstevel@tonic-gate else if (tTd(29, 4)) 12607c478bd9Sstevel@tonic-gate sm_dprintf("no fuzzy match found\n"); 12617c478bd9Sstevel@tonic-gate # if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ 12627c478bd9Sstevel@tonic-gate endpwent(); 12637c478bd9Sstevel@tonic-gate # endif /* DEC_OSF_BROKEN_GETPWENT */ 12647c478bd9Sstevel@tonic-gate if (pw == NULL) 12657c478bd9Sstevel@tonic-gate return EX_NOUSER; 12667c478bd9Sstevel@tonic-gate sm_mbdb_frompw(user, pw); 12677c478bd9Sstevel@tonic-gate return EX_OK; 12687c478bd9Sstevel@tonic-gate #else /* MATCHGECOS */ 12697c478bd9Sstevel@tonic-gate if (tTd(29, 4)) 12707c478bd9Sstevel@tonic-gate sm_dprintf("not found (fuzzy disabled)\n"); 12717c478bd9Sstevel@tonic-gate return EX_NOUSER; 12727c478bd9Sstevel@tonic-gate #endif /* MATCHGECOS */ 12737c478bd9Sstevel@tonic-gate } 1274058561cbSjbeck 12757c478bd9Sstevel@tonic-gate /* 12767c478bd9Sstevel@tonic-gate ** WRITABLE -- predicate returning if the file is writable. 12777c478bd9Sstevel@tonic-gate ** 12787c478bd9Sstevel@tonic-gate ** This routine must duplicate the algorithm in sys/fio.c. 12797c478bd9Sstevel@tonic-gate ** Unfortunately, we cannot use the access call since we 12807c478bd9Sstevel@tonic-gate ** won't necessarily be the real uid when we try to 12817c478bd9Sstevel@tonic-gate ** actually open the file. 12827c478bd9Sstevel@tonic-gate ** 12837c478bd9Sstevel@tonic-gate ** Notice that ANY file with ANY execute bit is automatically 12847c478bd9Sstevel@tonic-gate ** not writable. This is also enforced by mailfile. 12857c478bd9Sstevel@tonic-gate ** 12867c478bd9Sstevel@tonic-gate ** Parameters: 12877c478bd9Sstevel@tonic-gate ** filename -- the file name to check. 12887c478bd9Sstevel@tonic-gate ** ctladdr -- the controlling address for this file. 12897c478bd9Sstevel@tonic-gate ** flags -- SFF_* flags to control the function. 12907c478bd9Sstevel@tonic-gate ** 12917c478bd9Sstevel@tonic-gate ** Returns: 12927c478bd9Sstevel@tonic-gate ** true -- if we will be able to write this file. 12937c478bd9Sstevel@tonic-gate ** false -- if we cannot write this file. 12947c478bd9Sstevel@tonic-gate ** 12957c478bd9Sstevel@tonic-gate ** Side Effects: 12967c478bd9Sstevel@tonic-gate ** none. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate bool 13007c478bd9Sstevel@tonic-gate writable(filename, ctladdr, flags) 13017c478bd9Sstevel@tonic-gate char *filename; 13027c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 13037c478bd9Sstevel@tonic-gate long flags; 13047c478bd9Sstevel@tonic-gate { 13057c478bd9Sstevel@tonic-gate uid_t euid = 0; 13067c478bd9Sstevel@tonic-gate gid_t egid = 0; 13077c478bd9Sstevel@tonic-gate char *user = NULL; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (tTd(44, 5)) 13107c478bd9Sstevel@tonic-gate sm_dprintf("writable(%s, 0x%lx)\n", filename, flags); 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate /* 13137c478bd9Sstevel@tonic-gate ** File does exist -- check that it is writable. 13147c478bd9Sstevel@tonic-gate */ 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (geteuid() != 0) 13177c478bd9Sstevel@tonic-gate { 13187c478bd9Sstevel@tonic-gate euid = geteuid(); 13197c478bd9Sstevel@tonic-gate egid = getegid(); 13207c478bd9Sstevel@tonic-gate user = NULL; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate else if (ctladdr != NULL) 13237c478bd9Sstevel@tonic-gate { 13247c478bd9Sstevel@tonic-gate euid = ctladdr->q_uid; 13257c478bd9Sstevel@tonic-gate egid = ctladdr->q_gid; 13267c478bd9Sstevel@tonic-gate user = ctladdr->q_user; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate else if (bitset(SFF_RUNASREALUID, flags)) 13297c478bd9Sstevel@tonic-gate { 13307c478bd9Sstevel@tonic-gate euid = RealUid; 13317c478bd9Sstevel@tonic-gate egid = RealGid; 13327c478bd9Sstevel@tonic-gate user = RealUserName; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate else if (FileMailer != NULL && !bitset(SFF_ROOTOK, flags)) 13357c478bd9Sstevel@tonic-gate { 13367c478bd9Sstevel@tonic-gate if (FileMailer->m_uid == NO_UID) 13377c478bd9Sstevel@tonic-gate { 13387c478bd9Sstevel@tonic-gate euid = DefUid; 13397c478bd9Sstevel@tonic-gate user = DefUser; 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate else 13427c478bd9Sstevel@tonic-gate { 13437c478bd9Sstevel@tonic-gate euid = FileMailer->m_uid; 13447c478bd9Sstevel@tonic-gate user = NULL; 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate if (FileMailer->m_gid == NO_GID) 13477c478bd9Sstevel@tonic-gate egid = DefGid; 13487c478bd9Sstevel@tonic-gate else 13497c478bd9Sstevel@tonic-gate egid = FileMailer->m_gid; 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate else 13527c478bd9Sstevel@tonic-gate { 13537c478bd9Sstevel@tonic-gate euid = egid = 0; 13547c478bd9Sstevel@tonic-gate user = NULL; 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate if (!bitset(SFF_ROOTOK, flags)) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate if (euid == 0) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate euid = DefUid; 13617c478bd9Sstevel@tonic-gate user = DefUser; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate if (egid == 0) 13647c478bd9Sstevel@tonic-gate egid = DefGid; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate if (geteuid() == 0 && 13677c478bd9Sstevel@tonic-gate (ctladdr == NULL || !bitset(QGOODUID, ctladdr->q_flags))) 13687c478bd9Sstevel@tonic-gate flags |= SFF_SETUIDOK; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOSYMLINK, DontBlameSendmail)) 13717c478bd9Sstevel@tonic-gate flags |= SFF_NOSLINK; 13727c478bd9Sstevel@tonic-gate if (!bitnset(DBS_FILEDELIVERYTOHARDLINK, DontBlameSendmail)) 13737c478bd9Sstevel@tonic-gate flags |= SFF_NOHLINK; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate errno = safefile(filename, euid, egid, user, flags, S_IWRITE, NULL); 13767c478bd9Sstevel@tonic-gate return errno == 0; 13777c478bd9Sstevel@tonic-gate } 1378058561cbSjbeck 13797c478bd9Sstevel@tonic-gate /* 13807c478bd9Sstevel@tonic-gate ** INCLUDE -- handle :include: specification. 13817c478bd9Sstevel@tonic-gate ** 13827c478bd9Sstevel@tonic-gate ** Parameters: 13837c478bd9Sstevel@tonic-gate ** fname -- filename to include. 13847c478bd9Sstevel@tonic-gate ** forwarding -- if true, we are reading a .forward file. 13857c478bd9Sstevel@tonic-gate ** if false, it's a :include: file. 13867c478bd9Sstevel@tonic-gate ** ctladdr -- address template to use to fill in these 13877c478bd9Sstevel@tonic-gate ** addresses -- effective user/group id are 13887c478bd9Sstevel@tonic-gate ** the important things. 13897c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of the send queue 13907c478bd9Sstevel@tonic-gate ** to put these addresses in. 13917c478bd9Sstevel@tonic-gate ** aliaslevel -- the alias nesting depth. 13927c478bd9Sstevel@tonic-gate ** e -- the current envelope. 13937c478bd9Sstevel@tonic-gate ** 13947c478bd9Sstevel@tonic-gate ** Returns: 13957c478bd9Sstevel@tonic-gate ** open error status 13967c478bd9Sstevel@tonic-gate ** 13977c478bd9Sstevel@tonic-gate ** Side Effects: 13987c478bd9Sstevel@tonic-gate ** reads the :include: file and sends to everyone 13997c478bd9Sstevel@tonic-gate ** listed in that file. 14007c478bd9Sstevel@tonic-gate ** 14017c478bd9Sstevel@tonic-gate ** Security Note: 14027c478bd9Sstevel@tonic-gate ** If you have restricted chown (that is, you can't 14037c478bd9Sstevel@tonic-gate ** give a file away), it is reasonable to allow programs 14047c478bd9Sstevel@tonic-gate ** and files called from this :include: file to be to be 14057c478bd9Sstevel@tonic-gate ** run as the owner of the :include: file. This is bogus 14067c478bd9Sstevel@tonic-gate ** if there is any chance of someone giving away a file. 14077c478bd9Sstevel@tonic-gate ** We assume that pre-POSIX systems can give away files. 14087c478bd9Sstevel@tonic-gate ** 14097c478bd9Sstevel@tonic-gate ** There is an additional restriction that if you 14107c478bd9Sstevel@tonic-gate ** forward to a :include: file, it will not take on 14117c478bd9Sstevel@tonic-gate ** the ownership of the :include: file. This may not 14127c478bd9Sstevel@tonic-gate ** be necessary, but shouldn't hurt. 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate static jmp_buf CtxIncludeTimeout; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate int 14187c478bd9Sstevel@tonic-gate include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 14197c478bd9Sstevel@tonic-gate char *fname; 14207c478bd9Sstevel@tonic-gate bool forwarding; 14217c478bd9Sstevel@tonic-gate ADDRESS *ctladdr; 14227c478bd9Sstevel@tonic-gate ADDRESS **sendq; 14237c478bd9Sstevel@tonic-gate int aliaslevel; 14247c478bd9Sstevel@tonic-gate ENVELOPE *e; 14257c478bd9Sstevel@tonic-gate { 14267c478bd9Sstevel@tonic-gate SM_FILE_T *volatile fp = NULL; 14277c478bd9Sstevel@tonic-gate char *oldto = e->e_to; 14287c478bd9Sstevel@tonic-gate char *oldfilename = FileName; 14297c478bd9Sstevel@tonic-gate int oldlinenumber = LineNumber; 14307c478bd9Sstevel@tonic-gate register SM_EVENT *ev = NULL; 14317c478bd9Sstevel@tonic-gate int nincludes; 14327c478bd9Sstevel@tonic-gate int mode; 14337c478bd9Sstevel@tonic-gate volatile bool maxreached = false; 14347c478bd9Sstevel@tonic-gate register ADDRESS *ca; 14357c478bd9Sstevel@tonic-gate volatile uid_t saveduid; 14367c478bd9Sstevel@tonic-gate volatile gid_t savedgid; 14377c478bd9Sstevel@tonic-gate volatile uid_t uid; 14387c478bd9Sstevel@tonic-gate volatile gid_t gid; 14397c478bd9Sstevel@tonic-gate char *volatile user; 14407c478bd9Sstevel@tonic-gate int rval = 0; 14417c478bd9Sstevel@tonic-gate volatile long sfflags = SFF_REGONLY; 14427c478bd9Sstevel@tonic-gate register char *p; 14437c478bd9Sstevel@tonic-gate bool safechown = false; 14447c478bd9Sstevel@tonic-gate volatile bool safedir = false; 14457c478bd9Sstevel@tonic-gate struct stat st; 14467c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate if (tTd(27, 2)) 14497c478bd9Sstevel@tonic-gate sm_dprintf("include(%s)\n", fname); 14507c478bd9Sstevel@tonic-gate if (tTd(27, 4)) 14517c478bd9Sstevel@tonic-gate sm_dprintf(" ruid=%d euid=%d\n", 14527c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 14537c478bd9Sstevel@tonic-gate if (tTd(27, 14)) 14547c478bd9Sstevel@tonic-gate { 14557c478bd9Sstevel@tonic-gate sm_dprintf("ctladdr "); 14567c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), ctladdr, false); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate if (tTd(27, 9)) 14607c478bd9Sstevel@tonic-gate sm_dprintf("include: old uid = %d/%d\n", 14617c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (forwarding) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate sfflags |= SFF_MUSTOWN|SFF_ROOTOK; 14667c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPWRITABLEFORWARDFILE, DontBlameSendmail)) 14677c478bd9Sstevel@tonic-gate sfflags |= SFF_NOGWFILES; 14687c478bd9Sstevel@tonic-gate if (!bitnset(DBS_WORLDWRITABLEFORWARDFILE, DontBlameSendmail)) 14697c478bd9Sstevel@tonic-gate sfflags |= SFF_NOWWFILES; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate else 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPWRITABLEINCLUDEFILE, DontBlameSendmail)) 14747c478bd9Sstevel@tonic-gate sfflags |= SFF_NOGWFILES; 14757c478bd9Sstevel@tonic-gate if (!bitnset(DBS_WORLDWRITABLEINCLUDEFILE, DontBlameSendmail)) 14767c478bd9Sstevel@tonic-gate sfflags |= SFF_NOWWFILES; 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate ** If RunAsUser set, won't be able to run programs as user 14817c478bd9Sstevel@tonic-gate ** so mark them as unsafe unless the administrator knows better. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate if ((geteuid() != 0 || RunAsUid != 0) && 14857c478bd9Sstevel@tonic-gate !bitnset(DBS_NONROOTSAFEADDR, DontBlameSendmail)) 14867c478bd9Sstevel@tonic-gate { 14877c478bd9Sstevel@tonic-gate if (tTd(27, 4)) 14887c478bd9Sstevel@tonic-gate sm_dprintf("include: not safe (euid=%d, RunAsUid=%d)\n", 14897c478bd9Sstevel@tonic-gate (int) geteuid(), (int) RunAsUid); 14907c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QUNSAFEADDR; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate ca = getctladdr(ctladdr); 14947c478bd9Sstevel@tonic-gate if (ca == NULL || 14957c478bd9Sstevel@tonic-gate (ca->q_uid == DefUid && ca->q_gid == 0)) 14967c478bd9Sstevel@tonic-gate { 14977c478bd9Sstevel@tonic-gate uid = DefUid; 14987c478bd9Sstevel@tonic-gate gid = DefGid; 14997c478bd9Sstevel@tonic-gate user = DefUser; 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate else 15027c478bd9Sstevel@tonic-gate { 15037c478bd9Sstevel@tonic-gate uid = ca->q_uid; 15047c478bd9Sstevel@tonic-gate gid = ca->q_gid; 15057c478bd9Sstevel@tonic-gate user = ca->q_user; 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate #if MAILER_SETUID_METHOD != USE_SETUID 15087c478bd9Sstevel@tonic-gate saveduid = geteuid(); 15097c478bd9Sstevel@tonic-gate savedgid = getegid(); 15107c478bd9Sstevel@tonic-gate if (saveduid == 0) 15117c478bd9Sstevel@tonic-gate { 15127c478bd9Sstevel@tonic-gate if (!DontInitGroups) 15137c478bd9Sstevel@tonic-gate { 15147c478bd9Sstevel@tonic-gate if (initgroups(user, gid) == -1) 15157c478bd9Sstevel@tonic-gate { 15167c478bd9Sstevel@tonic-gate rval = EAGAIN; 15177c478bd9Sstevel@tonic-gate syserr("include: initgroups(%s, %d) failed", 15187c478bd9Sstevel@tonic-gate user, gid); 15197c478bd9Sstevel@tonic-gate goto resetuid; 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate else 15237c478bd9Sstevel@tonic-gate { 15247c478bd9Sstevel@tonic-gate GIDSET_T gidset[1]; 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate gidset[0] = gid; 15277c478bd9Sstevel@tonic-gate if (setgroups(1, gidset) == -1) 15287c478bd9Sstevel@tonic-gate { 15297c478bd9Sstevel@tonic-gate rval = EAGAIN; 15307c478bd9Sstevel@tonic-gate syserr("include: setgroups() failed"); 15317c478bd9Sstevel@tonic-gate goto resetuid; 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate if (gid != 0 && setgid(gid) < -1) 15367c478bd9Sstevel@tonic-gate { 15377c478bd9Sstevel@tonic-gate rval = EAGAIN; 15387c478bd9Sstevel@tonic-gate syserr("setgid(%d) failure", gid); 15397c478bd9Sstevel@tonic-gate goto resetuid; 15407c478bd9Sstevel@tonic-gate } 15417c478bd9Sstevel@tonic-gate if (uid != 0) 15427c478bd9Sstevel@tonic-gate { 15437c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETEUID 15447c478bd9Sstevel@tonic-gate if (seteuid(uid) < 0) 15457c478bd9Sstevel@tonic-gate { 15467c478bd9Sstevel@tonic-gate rval = EAGAIN; 15477c478bd9Sstevel@tonic-gate syserr("seteuid(%d) failure (real=%d, eff=%d)", 15487c478bd9Sstevel@tonic-gate uid, (int) getuid(), (int) geteuid()); 15497c478bd9Sstevel@tonic-gate goto resetuid; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETEUID */ 15527c478bd9Sstevel@tonic-gate # if MAILER_SETUID_METHOD == USE_SETREUID 15537c478bd9Sstevel@tonic-gate if (setreuid(0, uid) < 0) 15547c478bd9Sstevel@tonic-gate { 15557c478bd9Sstevel@tonic-gate rval = EAGAIN; 15567c478bd9Sstevel@tonic-gate syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 15577c478bd9Sstevel@tonic-gate uid, (int) getuid(), (int) geteuid()); 15587c478bd9Sstevel@tonic-gate goto resetuid; 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate # endif /* MAILER_SETUID_METHOD == USE_SETREUID */ 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate #endif /* MAILER_SETUID_METHOD != USE_SETUID */ 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate if (tTd(27, 9)) 15667c478bd9Sstevel@tonic-gate sm_dprintf("include: new uid = %d/%d\n", 15677c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate ** If home directory is remote mounted but server is down, 15717c478bd9Sstevel@tonic-gate ** this can hang or give errors; use a timeout to avoid this 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if (setjmp(CtxIncludeTimeout) != 0) 15757c478bd9Sstevel@tonic-gate { 15767c478bd9Sstevel@tonic-gate ctladdr->q_state = QS_QUEUEUP; 15777c478bd9Sstevel@tonic-gate errno = 0; 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate /* return pseudo-error code */ 15807c478bd9Sstevel@tonic-gate rval = E_SM_OPENTIMEOUT; 15817c478bd9Sstevel@tonic-gate goto resetuid; 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate if (TimeOuts.to_fileopen > 0) 15847c478bd9Sstevel@tonic-gate ev = sm_setevent(TimeOuts.to_fileopen, includetimeout, 0); 15857c478bd9Sstevel@tonic-gate else 15867c478bd9Sstevel@tonic-gate ev = NULL; 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* check for writable parent directory */ 15907c478bd9Sstevel@tonic-gate p = strrchr(fname, '/'); 15917c478bd9Sstevel@tonic-gate if (p != NULL) 15927c478bd9Sstevel@tonic-gate { 15937c478bd9Sstevel@tonic-gate int ret; 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate *p = '\0'; 15967c478bd9Sstevel@tonic-gate ret = safedirpath(fname, uid, gid, user, 15977c478bd9Sstevel@tonic-gate sfflags|SFF_SAFEDIRPATH, 0, 0); 15987c478bd9Sstevel@tonic-gate if (ret == 0) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate /* in safe directory: relax chown & link rules */ 16017c478bd9Sstevel@tonic-gate safedir = true; 16027c478bd9Sstevel@tonic-gate sfflags |= SFF_NOPATHCHECK; 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate else 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate if (bitnset((forwarding ? 16077c478bd9Sstevel@tonic-gate DBS_FORWARDFILEINUNSAFEDIRPATH : 16087c478bd9Sstevel@tonic-gate DBS_INCLUDEFILEINUNSAFEDIRPATH), 16097c478bd9Sstevel@tonic-gate DontBlameSendmail)) 16107c478bd9Sstevel@tonic-gate sfflags |= SFF_NOPATHCHECK; 16117c478bd9Sstevel@tonic-gate else if (bitnset((forwarding ? 16127c478bd9Sstevel@tonic-gate DBS_FORWARDFILEINGROUPWRITABLEDIRPATH : 16137c478bd9Sstevel@tonic-gate DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH), 16147c478bd9Sstevel@tonic-gate DontBlameSendmail) && 16157c478bd9Sstevel@tonic-gate ret == E_SM_GWDIR) 16167c478bd9Sstevel@tonic-gate { 16177c478bd9Sstevel@tonic-gate setbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 16187c478bd9Sstevel@tonic-gate DontBlameSendmail); 16197c478bd9Sstevel@tonic-gate ret = safedirpath(fname, uid, gid, user, 16207c478bd9Sstevel@tonic-gate sfflags|SFF_SAFEDIRPATH, 16217c478bd9Sstevel@tonic-gate 0, 0); 16227c478bd9Sstevel@tonic-gate clrbitn(DBS_GROUPWRITABLEDIRPATHSAFE, 16237c478bd9Sstevel@tonic-gate DontBlameSendmail); 16247c478bd9Sstevel@tonic-gate if (ret == 0) 16257c478bd9Sstevel@tonic-gate sfflags |= SFF_NOPATHCHECK; 16267c478bd9Sstevel@tonic-gate else 16277c478bd9Sstevel@tonic-gate sfflags |= SFF_SAFEDIRPATH; 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate else 16307c478bd9Sstevel@tonic-gate sfflags |= SFF_SAFEDIRPATH; 16317c478bd9Sstevel@tonic-gate if (ret > E_PSEUDOBASE && 16327c478bd9Sstevel@tonic-gate !bitnset((forwarding ? 16337c478bd9Sstevel@tonic-gate DBS_FORWARDFILEINUNSAFEDIRPATHSAFE : 16347c478bd9Sstevel@tonic-gate DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE), 16357c478bd9Sstevel@tonic-gate DontBlameSendmail)) 16367c478bd9Sstevel@tonic-gate { 16377c478bd9Sstevel@tonic-gate if (LogLevel > 11) 16387c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 16397c478bd9Sstevel@tonic-gate "%s: unsafe directory path, marked unsafe", 16407c478bd9Sstevel@tonic-gate shortenstring(fname, MAXSHORTSTR)); 16417c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QUNSAFEADDR; 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate *p = '/'; 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* allow links only in unwritable directories */ 16487c478bd9Sstevel@tonic-gate if (!safedir && 16497c478bd9Sstevel@tonic-gate !bitnset((forwarding ? 16507c478bd9Sstevel@tonic-gate DBS_LINKEDFORWARDFILEINWRITABLEDIR : 16517c478bd9Sstevel@tonic-gate DBS_LINKEDINCLUDEFILEINWRITABLEDIR), 16527c478bd9Sstevel@tonic-gate DontBlameSendmail)) 16537c478bd9Sstevel@tonic-gate sfflags |= SFF_NOLINK; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate rval = safefile(fname, uid, gid, user, sfflags, S_IREAD, &st); 16567c478bd9Sstevel@tonic-gate if (rval != 0) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate /* don't use this :include: file */ 16597c478bd9Sstevel@tonic-gate if (tTd(27, 4)) 16607c478bd9Sstevel@tonic-gate sm_dprintf("include: not safe (uid=%d): %s\n", 16617c478bd9Sstevel@tonic-gate (int) uid, sm_errstring(rval)); 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate else if ((fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, fname, 16647c478bd9Sstevel@tonic-gate SM_IO_RDONLY, NULL)) == NULL) 16657c478bd9Sstevel@tonic-gate { 16667c478bd9Sstevel@tonic-gate rval = errno; 16677c478bd9Sstevel@tonic-gate if (tTd(27, 4)) 16687c478bd9Sstevel@tonic-gate sm_dprintf("include: open: %s\n", sm_errstring(rval)); 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate else if (filechanged(fname, sm_io_getinfo(fp,SM_IO_WHAT_FD, NULL), &st)) 16717c478bd9Sstevel@tonic-gate { 16727c478bd9Sstevel@tonic-gate rval = E_SM_FILECHANGE; 16737c478bd9Sstevel@tonic-gate if (tTd(27, 4)) 16747c478bd9Sstevel@tonic-gate sm_dprintf("include: file changed after open\n"); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate if (ev != NULL) 16777c478bd9Sstevel@tonic-gate sm_clrevent(ev); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate resetuid: 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate #if HASSETREUID || USESETEUID 16827c478bd9Sstevel@tonic-gate if (saveduid == 0) 16837c478bd9Sstevel@tonic-gate { 16847c478bd9Sstevel@tonic-gate if (uid != 0) 16857c478bd9Sstevel@tonic-gate { 16867c478bd9Sstevel@tonic-gate # if USESETEUID 16877c478bd9Sstevel@tonic-gate if (seteuid(0) < 0) 16887c478bd9Sstevel@tonic-gate syserr("!seteuid(0) failure (real=%d, eff=%d)", 16897c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 16907c478bd9Sstevel@tonic-gate # else /* USESETEUID */ 16917c478bd9Sstevel@tonic-gate if (setreuid(-1, 0) < 0) 16927c478bd9Sstevel@tonic-gate syserr("!setreuid(-1, 0) failure (real=%d, eff=%d)", 16937c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 16947c478bd9Sstevel@tonic-gate if (setreuid(RealUid, 0) < 0) 16957c478bd9Sstevel@tonic-gate syserr("!setreuid(%d, 0) failure (real=%d, eff=%d)", 16967c478bd9Sstevel@tonic-gate (int) RealUid, (int) getuid(), 16977c478bd9Sstevel@tonic-gate (int) geteuid()); 16987c478bd9Sstevel@tonic-gate # endif /* USESETEUID */ 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate if (setgid(savedgid) < 0) 17017c478bd9Sstevel@tonic-gate syserr("!setgid(%d) failure (real=%d eff=%d)", 17027c478bd9Sstevel@tonic-gate (int) savedgid, (int) getgid(), 17037c478bd9Sstevel@tonic-gate (int) getegid()); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate #endif /* HASSETREUID || USESETEUID */ 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate if (tTd(27, 9)) 17087c478bd9Sstevel@tonic-gate sm_dprintf("include: reset uid = %d/%d\n", 17097c478bd9Sstevel@tonic-gate (int) getuid(), (int) geteuid()); 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate if (rval == E_SM_OPENTIMEOUT) 17127c478bd9Sstevel@tonic-gate usrerr("451 4.4.1 open timeout on %s", fname); 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate if (fp == NULL) 17157c478bd9Sstevel@tonic-gate return rval; 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate if (fstat(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), &st) < 0) 17187c478bd9Sstevel@tonic-gate { 17197c478bd9Sstevel@tonic-gate rval = errno; 17207c478bd9Sstevel@tonic-gate syserr("Cannot fstat %s!", fname); 17217c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT); 17227c478bd9Sstevel@tonic-gate return rval; 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate /* if path was writable, check to avoid file giveaway tricks */ 17267c478bd9Sstevel@tonic-gate safechown = chownsafe(sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL), safedir); 17277c478bd9Sstevel@tonic-gate if (tTd(27, 6)) 17287c478bd9Sstevel@tonic-gate sm_dprintf("include: parent of %s is %s, chown is %ssafe\n", 17297c478bd9Sstevel@tonic-gate fname, safedir ? "safe" : "dangerous", 17307c478bd9Sstevel@tonic-gate safechown ? "" : "un"); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* if no controlling user or coming from an alias delivery */ 17337c478bd9Sstevel@tonic-gate if (safechown && 17347c478bd9Sstevel@tonic-gate (ca == NULL || 17357c478bd9Sstevel@tonic-gate (ca->q_uid == DefUid && ca->q_gid == 0))) 17367c478bd9Sstevel@tonic-gate { 17377c478bd9Sstevel@tonic-gate ctladdr->q_uid = st.st_uid; 17387c478bd9Sstevel@tonic-gate ctladdr->q_gid = st.st_gid; 17397c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QGOODUID; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate if (ca != NULL && ca->q_uid == st.st_uid) 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate /* optimization -- avoid getpwuid if we already have info */ 17447c478bd9Sstevel@tonic-gate ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 17457c478bd9Sstevel@tonic-gate ctladdr->q_ruser = ca->q_ruser; 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate else if (!forwarding) 17487c478bd9Sstevel@tonic-gate { 17497c478bd9Sstevel@tonic-gate register struct passwd *pw; 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate pw = sm_getpwuid(st.st_uid); 17527c478bd9Sstevel@tonic-gate if (pw == NULL) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate ctladdr->q_uid = st.st_uid; 17557c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QBOGUSSHELL; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate else 17587c478bd9Sstevel@tonic-gate { 17597c478bd9Sstevel@tonic-gate char *sh; 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate ctladdr->q_ruser = sm_rpool_strdup_x(e->e_rpool, 17627c478bd9Sstevel@tonic-gate pw->pw_name); 17637c478bd9Sstevel@tonic-gate if (safechown) 17647c478bd9Sstevel@tonic-gate sh = pw->pw_shell; 17657c478bd9Sstevel@tonic-gate else 17667c478bd9Sstevel@tonic-gate sh = "/SENDMAIL/ANY/SHELL/"; 17677c478bd9Sstevel@tonic-gate if (!usershellok(pw->pw_name, sh)) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate if (LogLevel > 11) 17707c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 17717c478bd9Sstevel@tonic-gate "%s: user %s has bad shell %s, marked %s", 17727c478bd9Sstevel@tonic-gate shortenstring(fname, 17737c478bd9Sstevel@tonic-gate MAXSHORTSTR), 17747c478bd9Sstevel@tonic-gate pw->pw_name, sh, 17757c478bd9Sstevel@tonic-gate safechown ? "bogus" : "unsafe"); 17767c478bd9Sstevel@tonic-gate if (safechown) 17777c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QBOGUSSHELL; 17787c478bd9Sstevel@tonic-gate else 17797c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QUNSAFEADDR; 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate if (bitset(EF_VRFYONLY, e->e_flags)) 17857c478bd9Sstevel@tonic-gate { 17867c478bd9Sstevel@tonic-gate /* don't do any more now */ 17877c478bd9Sstevel@tonic-gate ctladdr->q_state = QS_VERIFIED; 17887c478bd9Sstevel@tonic-gate e->e_nrcpts++; 17897c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT); 17907c478bd9Sstevel@tonic-gate return rval; 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate ** Check to see if some bad guy can write this file 17957c478bd9Sstevel@tonic-gate ** 17967c478bd9Sstevel@tonic-gate ** Group write checking could be more clever, e.g., 17977c478bd9Sstevel@tonic-gate ** guessing as to which groups are actually safe ("sys" 17987c478bd9Sstevel@tonic-gate ** may be; "user" probably is not). 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate mode = S_IWOTH; 18027c478bd9Sstevel@tonic-gate if (!bitnset((forwarding ? 18037c478bd9Sstevel@tonic-gate DBS_GROUPWRITABLEFORWARDFILESAFE : 18047c478bd9Sstevel@tonic-gate DBS_GROUPWRITABLEINCLUDEFILESAFE), 18057c478bd9Sstevel@tonic-gate DontBlameSendmail)) 18067c478bd9Sstevel@tonic-gate mode |= S_IWGRP; 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate if (bitset(mode, st.st_mode)) 18097c478bd9Sstevel@tonic-gate { 18107c478bd9Sstevel@tonic-gate if (tTd(27, 6)) 18117c478bd9Sstevel@tonic-gate sm_dprintf("include: %s is %s writable, marked unsafe\n", 18127c478bd9Sstevel@tonic-gate shortenstring(fname, MAXSHORTSTR), 18137c478bd9Sstevel@tonic-gate bitset(S_IWOTH, st.st_mode) ? "world" 18147c478bd9Sstevel@tonic-gate : "group"); 18157c478bd9Sstevel@tonic-gate if (LogLevel > 11) 18167c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 18177c478bd9Sstevel@tonic-gate "%s: %s writable %s file, marked unsafe", 18187c478bd9Sstevel@tonic-gate shortenstring(fname, MAXSHORTSTR), 18197c478bd9Sstevel@tonic-gate bitset(S_IWOTH, st.st_mode) ? "world" : "group", 18207c478bd9Sstevel@tonic-gate forwarding ? "forward" : ":include:"); 18217c478bd9Sstevel@tonic-gate ctladdr->q_flags |= QUNSAFEADDR; 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate /* read the file -- each line is a comma-separated list. */ 18257c478bd9Sstevel@tonic-gate FileName = fname; 18267c478bd9Sstevel@tonic-gate LineNumber = 0; 18277c478bd9Sstevel@tonic-gate ctladdr->q_flags &= ~QSELFREF; 18287c478bd9Sstevel@tonic-gate nincludes = 0; 1829058561cbSjbeck while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL && 18307c478bd9Sstevel@tonic-gate !maxreached) 18317c478bd9Sstevel@tonic-gate { 18327c478bd9Sstevel@tonic-gate fixcrlf(buf, true); 18337c478bd9Sstevel@tonic-gate LineNumber++; 18347c478bd9Sstevel@tonic-gate if (buf[0] == '#' || buf[0] == '\0') 18357c478bd9Sstevel@tonic-gate continue; 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate /* <sp>#@# introduces a comment anywhere */ 18387c478bd9Sstevel@tonic-gate /* for Japanese character sets */ 18397c478bd9Sstevel@tonic-gate for (p = buf; (p = strchr(++p, '#')) != NULL; ) 18407c478bd9Sstevel@tonic-gate { 18417c478bd9Sstevel@tonic-gate if (p[1] == '@' && p[2] == '#' && 18427c478bd9Sstevel@tonic-gate isascii(p[-1]) && isspace(p[-1]) && 18437c478bd9Sstevel@tonic-gate (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) 18447c478bd9Sstevel@tonic-gate { 18457c478bd9Sstevel@tonic-gate --p; 18467c478bd9Sstevel@tonic-gate while (p > buf && isascii(p[-1]) && 18477c478bd9Sstevel@tonic-gate isspace(p[-1])) 18487c478bd9Sstevel@tonic-gate --p; 18497c478bd9Sstevel@tonic-gate p[0] = '\0'; 18507c478bd9Sstevel@tonic-gate break; 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate if (buf[0] == '\0') 18547c478bd9Sstevel@tonic-gate continue; 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate e->e_to = NULL; 18577c478bd9Sstevel@tonic-gate message("%s to %s", 18587c478bd9Sstevel@tonic-gate forwarding ? "forwarding" : "sending", buf); 18597c478bd9Sstevel@tonic-gate if (forwarding && LogLevel > 10) 18607c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 18617c478bd9Sstevel@tonic-gate "forward %.200s => %s", 18627c478bd9Sstevel@tonic-gate oldto, shortenstring(buf, MAXSHORTSTR)); 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate if (forwarding && 18677c478bd9Sstevel@tonic-gate MaxForwardEntries > 0 && 18687c478bd9Sstevel@tonic-gate nincludes >= MaxForwardEntries) 18697c478bd9Sstevel@tonic-gate { 18707c478bd9Sstevel@tonic-gate /* just stop reading and processing further entries */ 18717c478bd9Sstevel@tonic-gate #if 0 18727c478bd9Sstevel@tonic-gate /* additional: (?) */ 18737c478bd9Sstevel@tonic-gate ctladdr->q_state = QS_DONTSEND; 18747c478bd9Sstevel@tonic-gate #endif /* 0 */ 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate syserr("Attempt to forward to more than %d addresses (in %s)!", 18777c478bd9Sstevel@tonic-gate MaxForwardEntries, fname); 18787c478bd9Sstevel@tonic-gate maxreached = true; 18797c478bd9Sstevel@tonic-gate } 18807c478bd9Sstevel@tonic-gate } 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate if (sm_io_error(fp) && tTd(27, 3)) 18837c478bd9Sstevel@tonic-gate sm_dprintf("include: read error: %s\n", sm_errstring(errno)); 18847c478bd9Sstevel@tonic-gate if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 18857c478bd9Sstevel@tonic-gate { 18864aac33d3Sjbeck if (aliaslevel <= MaxAliasRecursion || 18874aac33d3Sjbeck ctladdr->q_state != QS_BADADDR) 18887c478bd9Sstevel@tonic-gate { 18894aac33d3Sjbeck ctladdr->q_state = QS_DONTSEND; 18904aac33d3Sjbeck if (tTd(27, 5)) 18914aac33d3Sjbeck { 18924aac33d3Sjbeck sm_dprintf("include: QS_DONTSEND "); 18934aac33d3Sjbeck printaddr(sm_debug_file(), ctladdr, false); 18944aac33d3Sjbeck } 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate (void) sm_io_close(fp, SM_TIME_DEFAULT); 18997c478bd9Sstevel@tonic-gate FileName = oldfilename; 19007c478bd9Sstevel@tonic-gate LineNumber = oldlinenumber; 19017c478bd9Sstevel@tonic-gate e->e_to = oldto; 19027c478bd9Sstevel@tonic-gate return rval; 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate static void 19067c478bd9Sstevel@tonic-gate includetimeout(ignore) 19077c478bd9Sstevel@tonic-gate int ignore; 19087c478bd9Sstevel@tonic-gate { 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 19117c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 19127c478bd9Sstevel@tonic-gate ** DOING. 19137c478bd9Sstevel@tonic-gate */ 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 19167c478bd9Sstevel@tonic-gate longjmp(CtxIncludeTimeout, 1); 19177c478bd9Sstevel@tonic-gate } 1918058561cbSjbeck 19197c478bd9Sstevel@tonic-gate /* 19207c478bd9Sstevel@tonic-gate ** SENDTOARGV -- send to an argument vector. 19217c478bd9Sstevel@tonic-gate ** 19227c478bd9Sstevel@tonic-gate ** Parameters: 19237c478bd9Sstevel@tonic-gate ** argv -- argument vector to send to. 19247c478bd9Sstevel@tonic-gate ** e -- the current envelope. 19257c478bd9Sstevel@tonic-gate ** 19267c478bd9Sstevel@tonic-gate ** Returns: 19277c478bd9Sstevel@tonic-gate ** none. 19287c478bd9Sstevel@tonic-gate ** 19297c478bd9Sstevel@tonic-gate ** Side Effects: 19307c478bd9Sstevel@tonic-gate ** puts all addresses on the argument vector onto the 19317c478bd9Sstevel@tonic-gate ** send queue. 19327c478bd9Sstevel@tonic-gate */ 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate void 19357c478bd9Sstevel@tonic-gate sendtoargv(argv, e) 19367c478bd9Sstevel@tonic-gate register char **argv; 19377c478bd9Sstevel@tonic-gate register ENVELOPE *e; 19387c478bd9Sstevel@tonic-gate { 19397c478bd9Sstevel@tonic-gate register char *p; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate while ((p = *argv++) != NULL) 19427c478bd9Sstevel@tonic-gate (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 19437c478bd9Sstevel@tonic-gate } 1944058561cbSjbeck 19457c478bd9Sstevel@tonic-gate /* 19467c478bd9Sstevel@tonic-gate ** GETCTLADDR -- get controlling address from an address header. 19477c478bd9Sstevel@tonic-gate ** 19487c478bd9Sstevel@tonic-gate ** If none, get one corresponding to the effective userid. 19497c478bd9Sstevel@tonic-gate ** 19507c478bd9Sstevel@tonic-gate ** Parameters: 19517c478bd9Sstevel@tonic-gate ** a -- the address to find the controller of. 19527c478bd9Sstevel@tonic-gate ** 19537c478bd9Sstevel@tonic-gate ** Returns: 19547c478bd9Sstevel@tonic-gate ** the controlling address. 19557c478bd9Sstevel@tonic-gate */ 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate ADDRESS * 19587c478bd9Sstevel@tonic-gate getctladdr(a) 19597c478bd9Sstevel@tonic-gate register ADDRESS *a; 19607c478bd9Sstevel@tonic-gate { 19617c478bd9Sstevel@tonic-gate while (a != NULL && !bitset(QGOODUID, a->q_flags)) 19627c478bd9Sstevel@tonic-gate a = a->q_alias; 19637c478bd9Sstevel@tonic-gate return a; 19647c478bd9Sstevel@tonic-gate } 1965058561cbSjbeck 19667c478bd9Sstevel@tonic-gate /* 19677c478bd9Sstevel@tonic-gate ** SELF_REFERENCE -- check to see if an address references itself 19687c478bd9Sstevel@tonic-gate ** 19697c478bd9Sstevel@tonic-gate ** The check is done through a chain of aliases. If it is part of 19707c478bd9Sstevel@tonic-gate ** a loop, break the loop at the "best" address, that is, the one 19717c478bd9Sstevel@tonic-gate ** that exists as a real user. 19727c478bd9Sstevel@tonic-gate ** 19737c478bd9Sstevel@tonic-gate ** This is to handle the case of: 19747c478bd9Sstevel@tonic-gate ** awc: Andrew.Chang 19757c478bd9Sstevel@tonic-gate ** Andrew.Chang: awc@mail.server 19767c478bd9Sstevel@tonic-gate ** which is a problem only on mail.server. 19777c478bd9Sstevel@tonic-gate ** 19787c478bd9Sstevel@tonic-gate ** Parameters: 19797c478bd9Sstevel@tonic-gate ** a -- the address to check. 19807c478bd9Sstevel@tonic-gate ** 19817c478bd9Sstevel@tonic-gate ** Returns: 19827c478bd9Sstevel@tonic-gate ** The address that should be retained. 19837c478bd9Sstevel@tonic-gate */ 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate static ADDRESS * 19867c478bd9Sstevel@tonic-gate self_reference(a) 19877c478bd9Sstevel@tonic-gate ADDRESS *a; 19887c478bd9Sstevel@tonic-gate { 19897c478bd9Sstevel@tonic-gate ADDRESS *b; /* top entry in self ref loop */ 19907c478bd9Sstevel@tonic-gate ADDRESS *c; /* entry that point to a real mail box */ 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate if (tTd(27, 1)) 19937c478bd9Sstevel@tonic-gate sm_dprintf("self_reference(%s)\n", a->q_paddr); 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate for (b = a->q_alias; b != NULL; b = b->q_alias) 19967c478bd9Sstevel@tonic-gate { 19977c478bd9Sstevel@tonic-gate if (sameaddr(a, b)) 19987c478bd9Sstevel@tonic-gate break; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate if (b == NULL) 20027c478bd9Sstevel@tonic-gate { 20037c478bd9Sstevel@tonic-gate if (tTd(27, 1)) 20047c478bd9Sstevel@tonic-gate sm_dprintf("\t... no self ref\n"); 20057c478bd9Sstevel@tonic-gate return NULL; 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate ** Pick the first address that resolved to a real mail box 20107c478bd9Sstevel@tonic-gate ** i.e has a mbdb entry. The returned value will be marked 20117c478bd9Sstevel@tonic-gate ** QSELFREF in recipient(), which in turn will disable alias() 20127c478bd9Sstevel@tonic-gate ** from marking it as QS_IS_DEAD(), which mean it will be used 20137c478bd9Sstevel@tonic-gate ** as a deliverable address. 20147c478bd9Sstevel@tonic-gate ** 20157c478bd9Sstevel@tonic-gate ** The 2 key thing to note here are: 20167c478bd9Sstevel@tonic-gate ** 1) we are in a recursive call sequence: 20177c478bd9Sstevel@tonic-gate ** alias->sendtolist->recipient->alias 20187c478bd9Sstevel@tonic-gate ** 2) normally, when we return back to alias(), the address 20197c478bd9Sstevel@tonic-gate ** will be marked QS_EXPANDED, since alias() assumes the 20207c478bd9Sstevel@tonic-gate ** expanded form will be used instead of the current address. 20217c478bd9Sstevel@tonic-gate ** This behaviour is turned off if the address is marked 20227c478bd9Sstevel@tonic-gate ** QSELFREF. We set QSELFREF when we return to recipient(). 20237c478bd9Sstevel@tonic-gate */ 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate c = a; 20267c478bd9Sstevel@tonic-gate while (c != NULL) 20277c478bd9Sstevel@tonic-gate { 20287c478bd9Sstevel@tonic-gate if (tTd(27, 10)) 20297c478bd9Sstevel@tonic-gate sm_dprintf(" %s", c->q_user); 20307c478bd9Sstevel@tonic-gate if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 20317c478bd9Sstevel@tonic-gate { 20327c478bd9Sstevel@tonic-gate SM_MBDB_T user; 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate if (tTd(27, 2)) 20357c478bd9Sstevel@tonic-gate sm_dprintf("\t... getpwnam(%s)... ", c->q_user); 20367c478bd9Sstevel@tonic-gate if (sm_mbdb_lookup(c->q_user, &user) == EX_OK) 20377c478bd9Sstevel@tonic-gate { 20387c478bd9Sstevel@tonic-gate if (tTd(27, 2)) 20397c478bd9Sstevel@tonic-gate sm_dprintf("found\n"); 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate /* ought to cache results here */ 20427c478bd9Sstevel@tonic-gate if (sameaddr(b, c)) 20437c478bd9Sstevel@tonic-gate return b; 20447c478bd9Sstevel@tonic-gate else 20457c478bd9Sstevel@tonic-gate return c; 20467c478bd9Sstevel@tonic-gate } 20477c478bd9Sstevel@tonic-gate if (tTd(27, 2)) 20487c478bd9Sstevel@tonic-gate sm_dprintf("failed\n"); 20497c478bd9Sstevel@tonic-gate } 20507c478bd9Sstevel@tonic-gate else 20517c478bd9Sstevel@tonic-gate { 20527c478bd9Sstevel@tonic-gate /* if local delivery, compare usernames */ 20537c478bd9Sstevel@tonic-gate if (bitnset(M_LOCALMAILER, c->q_mailer->m_flags) && 20547c478bd9Sstevel@tonic-gate b->q_mailer == c->q_mailer) 20557c478bd9Sstevel@tonic-gate { 20567c478bd9Sstevel@tonic-gate if (tTd(27, 2)) 20577c478bd9Sstevel@tonic-gate sm_dprintf("\t... local match (%s)\n", 20587c478bd9Sstevel@tonic-gate c->q_user); 20597c478bd9Sstevel@tonic-gate if (sameaddr(b, c)) 20607c478bd9Sstevel@tonic-gate return b; 20617c478bd9Sstevel@tonic-gate else 20627c478bd9Sstevel@tonic-gate return c; 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate if (tTd(27, 10)) 20667c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 20677c478bd9Sstevel@tonic-gate c = c->q_alias; 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate if (tTd(27, 1)) 20717c478bd9Sstevel@tonic-gate sm_dprintf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate return NULL; 20747c478bd9Sstevel@tonic-gate } 2075