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