122710Sdist /* 268839Seric * Copyright (c) 1983, 1995 Eric P. Allman 363589Sbostic * Copyright (c) 1988, 1993 463589Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822710Sdist 922710Sdist #ifndef lint 10*69544Seric static char sccsid[] = "@(#)recipient.c 8.84 (Berkeley) 05/18/95"; 1133731Sbostic #endif /* not lint */ 1222710Sdist 1358332Seric # include "sendmail.h" 144174Seric 154174Seric /* 169622Seric ** SENDTOLIST -- Designate a send list. 174174Seric ** 184174Seric ** The parameter is a comma-separated list of people to send to. 194174Seric ** This routine arranges to send to all of them. 204174Seric ** 214174Seric ** Parameters: 224174Seric ** list -- the send list. 234399Seric ** ctladdr -- the address template for the person to 244399Seric ** send to -- effective uid/gid are important. 255006Seric ** This is typically the alias that caused this 265006Seric ** expansion. 275006Seric ** sendq -- a pointer to the head of a queue to put 285006Seric ** these people into. 2968481Seric ** aliaslevel -- the current alias nesting depth -- to 3068481Seric ** diagnose loops. 3158247Seric ** e -- the envelope in which to add these recipients. 324174Seric ** 334174Seric ** Returns: 3458082Seric ** The number of addresses actually on the list. 354174Seric ** 364174Seric ** Side Effects: 374174Seric ** none. 384174Seric */ 394174Seric 4068481Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 414174Seric 4268481Seric /* q_flags bits inherited from ctladdr */ 4368595Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) 4468481Seric 4568481Seric int 4668481Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 474174Seric char *list; 484399Seric ADDRESS *ctladdr; 495198Seric ADDRESS **sendq; 5068481Seric int aliaslevel; 5155012Seric register ENVELOPE *e; 524174Seric { 534174Seric register char *p; 548223Seric register ADDRESS *al; /* list of addresses to send to */ 554423Seric bool firstone; /* set on first address sent */ 5611446Seric char delimiter; /* the address delimiter */ 5758082Seric int naddrs; 5868392Seric int i; 5963847Seric char *oldto = e->e_to; 6068392Seric char *bufp; 6168271Seric char buf[MAXNAME + 1]; 624174Seric 6364131Seric if (list == NULL) 6464131Seric { 6564131Seric syserr("sendtolist: null list"); 6664131Seric return 0; 6764131Seric } 6864131Seric 697676Seric if (tTd(25, 1)) 704444Seric { 714444Seric printf("sendto: %s\n ctladdr=", list); 724444Seric printaddr(ctladdr, FALSE); 734444Seric } 744324Seric 758223Seric /* heuristic to determine old versus new style addresses */ 768230Seric if (ctladdr == NULL && 7756795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 7856795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 7955012Seric e->e_flags &= ~EF_OLDSTYLE; 8011446Seric delimiter = ' '; 8155012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 8211446Seric delimiter = ','; 838223Seric 844423Seric firstone = TRUE; 854324Seric al = NULL; 8658082Seric naddrs = 0; 878223Seric 8868392Seric /* make sure we have enough space to copy the string */ 8968392Seric i = strlen(list) + 1; 9068392Seric if (i <= sizeof buf) 9168271Seric bufp = buf; 9268392Seric else 9368392Seric bufp = xalloc(i); 9468478Seric strcpy(bufp, denlstring(list, FALSE, TRUE)); 9568271Seric 9668271Seric for (p = bufp; *p != '\0'; ) 9768271Seric { 9858333Seric auto char *delimptr; 998081Seric register ADDRESS *a; 1004319Seric 1018081Seric /* parse the address */ 10258050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1034174Seric p++; 10464284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10558333Seric p = delimptr; 1069297Seric if (a == NULL) 1074174Seric continue; 1084324Seric a->q_next = al; 1094399Seric a->q_alias = ctladdr; 1104444Seric 11168481Seric /* arrange to inherit attributes from parent */ 11268481Seric if (ctladdr != NULL) 11368481Seric { 114*69544Seric ADDRESS *b; 115*69544Seric extern ADDRESS *self_reference(); 116*69544Seric 117*69544Seric #if 0 11868481Seric /* self reference test */ 11968481Seric if (sameaddr(ctladdr, a)) 12068481Seric ctladdr->q_flags |= QSELFREF; 121*69544Seric #endif 12268481Seric 123*69544Seric /* check for address loops */ 124*69544Seric b = self_reference(a, e); 125*69544Seric if (b != NULL) 126*69544Seric { 127*69544Seric b->q_flags |= QSELFREF; 128*69544Seric if (a != b) 129*69544Seric { 130*69544Seric a->q_flags |= QDONTSEND; 131*69544Seric continue; 132*69544Seric } 133*69544Seric } 134*69544Seric 13568481Seric /* full name */ 13668481Seric if (a->q_fullname == NULL) 13768481Seric a->q_fullname = ctladdr->q_fullname; 13868481Seric 13968481Seric /* various flag bits */ 14068481Seric a->q_flags &= ~QINHERITEDBITS; 14168481Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 14268481Seric 14368481Seric /* original recipient information */ 14468481Seric a->q_orcpt = ctladdr->q_orcpt; 14568481Seric } 14668481Seric 14757731Seric al = a; 1484423Seric firstone = FALSE; 1494324Seric } 1504324Seric 1514324Seric /* arrange to send to everyone on the local send list */ 1524324Seric while (al != NULL) 1534324Seric { 1544324Seric register ADDRESS *a = al; 1554324Seric 1564324Seric al = a->q_next; 15768481Seric a = recipient(a, sendq, aliaslevel, e); 15858082Seric naddrs++; 1594174Seric } 1604324Seric 16163847Seric e->e_to = oldto; 16268392Seric if (bufp != buf) 16368392Seric free(bufp); 16458082Seric return (naddrs); 1654174Seric } 1664174Seric /* 1674174Seric ** RECIPIENT -- Designate a message recipient 1684174Seric ** 1694174Seric ** Saves the named person for future mailing. 1704174Seric ** 1714174Seric ** Parameters: 1724174Seric ** a -- the (preparsed) address header for the recipient. 1735006Seric ** sendq -- a pointer to the head of a queue to put the 1745006Seric ** recipient in. Duplicate supression is done 1755006Seric ** in this queue. 17668481Seric ** aliaslevel -- the current alias nesting depth. 17757731Seric ** e -- the current envelope. 1784174Seric ** 1794174Seric ** Returns: 18012613Seric ** The actual address in the queue. This will be "a" if 18112613Seric ** the address is not a duplicate, else the original address. 1824174Seric ** 1834174Seric ** Side Effects: 1844174Seric ** none. 1854174Seric */ 1864174Seric 18712613Seric ADDRESS * 18868481Seric recipient(a, sendq, aliaslevel, e) 1894174Seric register ADDRESS *a; 1905006Seric register ADDRESS **sendq; 19168481Seric int aliaslevel; 19255012Seric register ENVELOPE *e; 1934174Seric { 1944174Seric register ADDRESS *q; 1954319Seric ADDRESS **pq; 1964174Seric register struct mailer *m; 1979210Seric register char *p; 1989210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 19953735Seric int findusercount = 0; 20068603Seric bool initialdontsend = bitset(QDONTSEND, a->q_flags); 20168481Seric int i; 20268481Seric char *buf; 20368528Seric char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 20458247Seric extern int safefile(); 2054174Seric 20655012Seric e->e_to = a->q_paddr; 2074600Seric m = a->q_mailer; 2084174Seric errno = 0; 20968603Seric if (aliaslevel == 0) 21068603Seric a->q_flags |= QPRIMARY; 2117676Seric if (tTd(26, 1)) 2124444Seric { 21368603Seric printf("\nrecipient (%d): ", aliaslevel); 2144444Seric printaddr(a, FALSE); 2154444Seric } 2164174Seric 21764146Seric /* if this is primary, add it to the original recipient list */ 21864146Seric if (a->q_alias == NULL) 21964146Seric { 22064146Seric if (e->e_origrcpt == NULL) 22164146Seric e->e_origrcpt = a->q_paddr; 22264146Seric else if (e->e_origrcpt != a->q_paddr) 22364146Seric e->e_origrcpt = ""; 22464146Seric } 22564146Seric 2264174Seric /* break aliasing loops */ 22768481Seric if (aliaslevel > MAXRCRSN) 2284174Seric { 22968857Seric a->q_status = "5.4.6"; 23068481Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 23168481Seric aliaslevel, MAXRCRSN); 23212613Seric return (a); 2334174Seric } 2344174Seric 2354174Seric /* 2364627Seric ** Finish setting up address structure. 2374174Seric */ 2384174Seric 23916160Seric /* get unquoted user for file, program or user.name check */ 24068481Seric i = strlen(a->q_user); 24168528Seric if (i >= sizeof buf0) 24268481Seric buf = xalloc(i + 1); 24368481Seric else 24468481Seric buf = buf0; 2459210Seric (void) strcpy(buf, a->q_user); 2469210Seric for (p = buf; *p != '\0' && !quoted; p++) 2479210Seric { 24854993Seric if (*p == '\\') 2499210Seric quoted = TRUE; 2509210Seric } 25154983Seric stripquotes(buf); 2529210Seric 25357402Seric /* check for direct mailing to restricted mailers */ 25465496Seric if (m == ProgMailer) 2554174Seric { 25665496Seric if (a->q_alias == NULL) 25765496Seric { 25865496Seric a->q_flags |= QBADADDR; 25968857Seric a->q_status = "5.7.1"; 26065496Seric usrerr("550 Cannot mail directly to programs"); 26165496Seric } 26265496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 26365496Seric { 26465496Seric a->q_flags |= QBADADDR; 26568857Seric a->q_status = "5.7.1"; 26665496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 26765496Seric a->q_alias->q_ruser, MyHostName); 26865496Seric } 26965496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 27065496Seric { 27165496Seric a->q_flags |= QBADADDR; 27268857Seric a->q_status = "5.7.1"; 27365496Seric usrerr("550 Address %s is unsafe for mailing to programs", 27465496Seric a->q_alias->q_paddr); 27565496Seric } 2764174Seric } 2774174Seric 2784174Seric /* 2794419Seric ** Look up this person in the recipient list. 2804419Seric ** If they are there already, return, otherwise continue. 2814419Seric ** If the list is empty, just add it. Notice the cute 2824419Seric ** hack to make from addresses suppress things correctly: 2834419Seric ** the QDONTSEND bit will be set in the send list. 2844419Seric ** [Please note: the emphasis is on "hack."] 2854174Seric */ 2864174Seric 2875006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2884174Seric { 28958294Seric if (sameaddr(q, a)) 2904174Seric { 2917676Seric if (tTd(26, 1)) 2924444Seric { 2934444Seric printf("%s in sendq: ", a->q_paddr); 2944444Seric printaddr(q, FALSE); 2954444Seric } 29665593Seric if (!bitset(QPRIMARY, q->q_flags)) 29758065Seric { 29865593Seric if (!bitset(QDONTSEND, a->q_flags)) 29958151Seric message("duplicate suppressed"); 30065593Seric q->q_flags |= a->q_flags; 30165593Seric } 30265593Seric else if (bitset(QSELFREF, q->q_flags)) 30365579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 30463847Seric a = q; 30568481Seric goto done; 3064174Seric } 3074319Seric } 3084174Seric 3094319Seric /* add address on list */ 31058884Seric *pq = a; 31158884Seric a->q_next = NULL; 3124174Seric 3134174Seric /* 31457402Seric ** Alias the name and handle special mailer types. 3154174Seric */ 3164174Seric 31753735Seric trylocaluser: 31855354Seric if (tTd(29, 7)) 31955354Seric printf("at trylocaluser %s\n", a->q_user); 32055354Seric 32158680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 32263847Seric goto testselfdestruct; 32357402Seric 32457402Seric if (m == InclMailer) 3254174Seric { 32657402Seric a->q_flags |= QDONTSEND; 32764761Seric if (a->q_alias == NULL) 3284174Seric { 32958680Seric a->q_flags |= QBADADDR; 33068857Seric a->q_status = "5.7.1"; 33158151Seric usrerr("550 Cannot mail directly to :include:s"); 3324174Seric } 3334174Seric else 33450556Seric { 33559563Seric int ret; 33658247Seric 33758151Seric message("including file %s", a->q_user); 33868481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 33959563Seric if (transienterror(ret)) 34059563Seric { 34159563Seric #ifdef LOG 34259563Seric if (LogLevel > 2) 34366239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 34466284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 34566284Seric a->q_user, errstring(ret)); 34659563Seric #endif 34763853Seric a->q_flags |= QQUEUEUP; 34865215Seric a->q_flags &= ~QDONTSEND; 34959563Seric usrerr("451 Cannot open %s: %s", 35059563Seric a->q_user, errstring(ret)); 35159563Seric } 35259563Seric else if (ret != 0) 35359563Seric { 35463938Seric a->q_flags |= QBADADDR; 35568857Seric a->q_status = "5.2.4"; 35659563Seric usrerr("550 Cannot open %s: %s", 35759563Seric a->q_user, errstring(ret)); 35859563Seric } 35950556Seric } 3604174Seric } 36157642Seric else if (m == FileMailer) 3624174Seric { 3634329Seric extern bool writable(); 3644174Seric 36551317Seric /* check if writable or creatable */ 36664761Seric if (a->q_alias == NULL) 3674174Seric { 36858680Seric a->q_flags |= QBADADDR; 36968857Seric a->q_status = "5.7.1"; 37058151Seric usrerr("550 Cannot mail directly to files"); 3714174Seric } 37265496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 37365496Seric { 37465496Seric a->q_flags |= QBADADDR; 37568857Seric a->q_status = "5.7.1"; 37665496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 37765496Seric a->q_alias->q_ruser, MyHostName); 37865496Seric } 37965496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 38065496Seric { 38165496Seric a->q_flags |= QBADADDR; 38268857Seric a->q_status = "5.7.1"; 38365496Seric usrerr("550 Address %s is unsafe for mailing to files", 38465496Seric a->q_alias->q_paddr); 38565496Seric } 38668494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT)) 38751317Seric { 38858680Seric a->q_flags |= QBADADDR; 38968481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 39068481Seric (time_t) 0, e); 39151317Seric } 39251317Seric } 39351317Seric 39457402Seric /* try aliasing */ 39568481Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 39668481Seric alias(a, sendq, aliaslevel, e); 39757402Seric 39857402Seric # ifdef USERDB 39957402Seric /* if not aliased, look it up in the user database */ 40068481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 40168481Seric bitnset(M_CHECKUDB, m->m_flags)) 40257402Seric { 40357402Seric extern int udbexpand(); 40457402Seric 40568481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 40657402Seric { 40763853Seric a->q_flags |= QQUEUEUP; 40857402Seric if (e->e_message == NULL) 40957402Seric e->e_message = newstr("Deferred: user database error"); 41057402Seric # ifdef LOG 41158020Seric if (LogLevel > 8) 41259623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 41366284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 41466284Seric errstring(errno)); 41557402Seric # endif 41659615Seric message("queued (user database error): %s", 41759615Seric errstring(errno)); 41857642Seric e->e_nrcpts++; 41963847Seric goto testselfdestruct; 42057402Seric } 42157402Seric } 42257402Seric # endif 42357402Seric 42451317Seric /* 42551317Seric ** If we have a level two config file, then pass the name through 42651317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 42751317Seric ** to send rewrite it to another mailer. This gives us a hook 42851317Seric ** after local aliasing has been done. 42951317Seric */ 43051317Seric 43151317Seric if (tTd(29, 5)) 43251317Seric { 43351317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 43451317Seric ConfigLevel, RewriteRules[5]); 43551317Seric printaddr(a, FALSE); 43651317Seric } 43768481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 43868481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 43968481Seric bitnset(M_TRYRULESET5, m->m_flags)) 44051317Seric { 44168603Seric maplocaluser(a, sendq, aliaslevel + 1, e); 44251317Seric } 44351317Seric 44451317Seric /* 44551317Seric ** If it didn't get rewritten to another mailer, go ahead 44651317Seric ** and deliver it. 44751317Seric */ 44851317Seric 44968481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 45068481Seric bitnset(M_HASPWENT, m->m_flags)) 45151317Seric { 45255354Seric auto bool fuzzy; 45351317Seric register struct passwd *pw; 45451317Seric extern struct passwd *finduser(); 45551317Seric 45651317Seric /* warning -- finduser may trash buf */ 45755354Seric pw = finduser(buf, &fuzzy); 45851317Seric if (pw == NULL) 45951317Seric { 46058680Seric a->q_flags |= QBADADDR; 46168857Seric a->q_status = "5.1.1"; 46268481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 46368481Seric (time_t) 0, e); 46451317Seric } 4654174Seric else 4664174Seric { 46768528Seric char nbuf[MAXNAME + 1]; 4684373Seric 46955354Seric if (fuzzy) 4704174Seric { 47153735Seric /* name was a fuzzy match */ 47251317Seric a->q_user = newstr(pw->pw_name); 47353735Seric if (findusercount++ > 3) 47453735Seric { 47558680Seric a->q_flags |= QBADADDR; 47668857Seric a->q_status = "5.4.6"; 47758151Seric usrerr("554 aliasing/forwarding loop for %s broken", 47853735Seric pw->pw_name); 47968481Seric goto done; 48053735Seric } 48153735Seric 48253735Seric /* see if it aliases */ 48351317Seric (void) strcpy(buf, pw->pw_name); 48453735Seric goto trylocaluser; 4854174Seric } 48665822Seric if (strcmp(pw->pw_dir, "/") == 0) 48765822Seric a->q_home = ""; 48865822Seric else 48965822Seric a->q_home = newstr(pw->pw_dir); 49051317Seric a->q_uid = pw->pw_uid; 49151317Seric a->q_gid = pw->pw_gid; 49259083Seric a->q_ruser = newstr(pw->pw_name); 49351317Seric a->q_flags |= QGOODUID; 49451317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 49551317Seric if (nbuf[0] != '\0') 49651317Seric a->q_fullname = newstr(nbuf); 49765211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 49865211Seric !usershellok(pw->pw_shell)) 49965206Seric { 50065211Seric a->q_flags |= QBOGUSSHELL; 50165206Seric } 50251317Seric if (!quoted) 50368481Seric forward(a, sendq, aliaslevel, e); 5044174Seric } 5054174Seric } 50657642Seric if (!bitset(QDONTSEND, a->q_flags)) 50757642Seric e->e_nrcpts++; 50863847Seric 50963847Seric testselfdestruct: 51068603Seric a->q_flags |= QTHISPASS; 51163978Seric if (tTd(26, 8)) 51263847Seric { 51363978Seric printf("testselfdestruct: "); 51468603Seric printaddr(a, FALSE); 51568603Seric if (tTd(26, 10)) 51668603Seric { 51768603Seric printf("SENDQ:\n"); 51868603Seric printaddr(*sendq, TRUE); 51968603Seric printf("----\n"); 52068603Seric } 52163978Seric } 52263978Seric if (a->q_alias == NULL && a != &e->e_from && 52363978Seric bitset(QDONTSEND, a->q_flags)) 52463978Seric { 52568603Seric for (q = *sendq; q != NULL; q = q->q_next) 52668603Seric { 52768603Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags) && 52868603Seric bitset(QTHISPASS, q->q_flags)) 52968603Seric break; 53068603Seric } 53163978Seric if (q == NULL) 53263847Seric { 53363847Seric a->q_flags |= QBADADDR; 53468858Seric a->q_status = "5.4.6"; 53563847Seric usrerr("554 aliasing/forwarding loop broken"); 53663847Seric } 53763847Seric } 53868481Seric 53968481Seric done: 54068603Seric a->q_flags |= QTHISPASS; 54168481Seric if (buf != buf0) 54268481Seric free(buf); 54368603Seric 54468603Seric /* 54568603Seric ** If we are at the top level, check to see if this has 54668603Seric ** expanded to exactly one address. If so, it can inherit 54768603Seric ** the primaryness of the address. 54868603Seric ** 54968603Seric ** While we're at it, clear the QTHISPASS bits. 55068603Seric */ 55168603Seric 55268603Seric if (aliaslevel == 0) 55368603Seric { 55468603Seric int nrcpts = 0; 55568603Seric ADDRESS *only; 55668603Seric 55768603Seric for (q = *sendq; q != NULL; q = q->q_next) 55868603Seric { 55968603Seric if (bitset(QTHISPASS, q->q_flags) && 56068603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags)) 56168603Seric { 56268603Seric nrcpts++; 56368603Seric only = q; 56468603Seric } 56568603Seric q->q_flags &= ~QTHISPASS; 56668603Seric } 56768603Seric if (nrcpts == 1) 56868603Seric { 56968867Seric /* check to see if this actually got a new owner */ 57068867Seric q = only; 57168867Seric while ((q = q->q_alias) != NULL) 57268867Seric { 57368867Seric if (q->q_owner != NULL) 57468867Seric break; 57568867Seric } 57668867Seric if (q == NULL) 57768867Seric only->q_flags |= QPRIMARY; 57868867Seric } 57968867Seric else if (!initialdontsend && nrcpts > 0) 58068867Seric { 58168603Seric /* arrange for return receipt */ 58268603Seric e->e_flags |= EF_SENDRECEIPT; 58368867Seric a->q_flags |= QEXPANDED; 58468603Seric if (e->e_xfp != NULL) 58568603Seric fprintf(e->e_xfp, 58668603Seric "%s... expanded to multiple addresses\n", 58768603Seric a->q_paddr); 58868603Seric } 58968603Seric } 59068603Seric 59112613Seric return (a); 5924174Seric } 5934174Seric /* 5944373Seric ** FINDUSER -- find the password entry for a user. 5954373Seric ** 5964373Seric ** This looks a lot like getpwnam, except that it may want to 5974373Seric ** do some fancier pattern matching in /etc/passwd. 5984373Seric ** 5999379Seric ** This routine contains most of the time of many sendmail runs. 6009379Seric ** It deserves to be optimized. 6019379Seric ** 6024373Seric ** Parameters: 6034373Seric ** name -- the name to match against. 60455354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 60555354Seric ** was found using the fuzzy matching algorithm; 60655354Seric ** set to FALSE otherwise. 6074373Seric ** 6084373Seric ** Returns: 6094373Seric ** A pointer to a pw struct. 6104373Seric ** NULL if name is unknown or ambiguous. 6114373Seric ** 6124373Seric ** Side Effects: 6134407Seric ** may modify name. 6144373Seric */ 6154373Seric 6164373Seric struct passwd * 61755354Seric finduser(name, fuzzyp) 6184373Seric char *name; 61955354Seric bool *fuzzyp; 6204373Seric { 6214376Seric register struct passwd *pw; 6224407Seric register char *p; 6234373Seric 62455354Seric if (tTd(29, 4)) 62555354Seric printf("finduser(%s): ", name); 62655354Seric 62755354Seric *fuzzyp = FALSE; 6284407Seric 62968481Seric #ifdef HESIOD 63064673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 63164673Seric for (p = name; *p != '\0'; p++) 63264673Seric if (!isascii(*p) || !isdigit(*p)) 63364673Seric break; 63464673Seric if (*p == '\0') 63564673Seric { 63664673Seric if (tTd(29, 4)) 63764673Seric printf("failed (numeric input)\n"); 63864673Seric return NULL; 63964673Seric } 64068481Seric #endif 64164673Seric 64225777Seric /* look up this login name using fast path */ 64368693Seric if ((pw = sm_getpwnam(name)) != NULL) 64455354Seric { 64555354Seric if (tTd(29, 4)) 64655354Seric printf("found (non-fuzzy)\n"); 64712634Seric return (pw); 64855354Seric } 64912634Seric 65053735Seric #ifdef MATCHGECOS 65153735Seric /* see if fuzzy matching allowed */ 65253735Seric if (!MatchGecos) 65355354Seric { 65455354Seric if (tTd(29, 4)) 65555354Seric printf("not found (fuzzy disabled)\n"); 65653735Seric return NULL; 65755354Seric } 65853735Seric 65912634Seric /* search for a matching full name instead */ 66025777Seric for (p = name; *p != '\0'; p++) 66125777Seric { 66225777Seric if (*p == (SpaceSub & 0177) || *p == '_') 66325777Seric *p = ' '; 66425777Seric } 66523107Seric (void) setpwent(); 6664376Seric while ((pw = getpwent()) != NULL) 6674376Seric { 66868528Seric char buf[MAXNAME + 1]; 6694376Seric 6704998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 67156795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 6724381Seric { 67355354Seric if (tTd(29, 4)) 67455354Seric printf("fuzzy matches %s\n", pw->pw_name); 67558151Seric message("sending to login name %s", pw->pw_name); 67655354Seric *fuzzyp = TRUE; 6774376Seric return (pw); 6784377Seric } 6794376Seric } 68055354Seric if (tTd(29, 4)) 68155354Seric printf("no fuzzy match found\n"); 68259015Seric #else 68359015Seric if (tTd(29, 4)) 68459015Seric printf("not found (fuzzy disabled)\n"); 68559015Seric #endif 6864376Seric return (NULL); 6874373Seric } 6884373Seric /* 6894329Seric ** WRITABLE -- predicate returning if the file is writable. 6904329Seric ** 6914329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6924329Seric ** Unfortunately, we cannot use the access call since we 6934329Seric ** won't necessarily be the real uid when we try to 6944329Seric ** actually open the file. 6954329Seric ** 6964329Seric ** Notice that ANY file with ANY execute bit is automatically 6974329Seric ** not writable. This is also enforced by mailfile. 6984329Seric ** 6994329Seric ** Parameters: 70065064Seric ** filename -- the file name to check. 70165112Seric ** ctladdr -- the controlling address for this file. 70265064Seric ** flags -- SFF_* flags to control the function. 7034329Seric ** 7044329Seric ** Returns: 7054329Seric ** TRUE -- if we will be able to write this file. 7064329Seric ** FALSE -- if we cannot write this file. 7074329Seric ** 7084329Seric ** Side Effects: 7094329Seric ** none. 7104329Seric */ 7114329Seric 7124329Seric bool 71365112Seric writable(filename, ctladdr, flags) 71464819Seric char *filename; 71565112Seric ADDRESS *ctladdr; 71665064Seric int flags; 7174329Seric { 71855372Seric uid_t euid; 71955372Seric gid_t egid; 7204329Seric int bits; 72164944Seric register char *p; 72264944Seric char *uname; 7234329Seric 72464819Seric if (tTd(29, 5)) 72568802Seric printf("writable(%s, 0x%x)\n", filename, flags); 72664944Seric 72765225Seric #ifdef SUID_ROOT_FILES_OK 72865225Seric /* really ought to be passed down -- and not a good idea */ 72965225Seric flags |= SFF_ROOTOK; 73065225Seric #endif 73165225Seric 73264944Seric /* 73364944Seric ** File does exist -- check that it is writable. 73464944Seric */ 73564944Seric 73665112Seric if (ctladdr != NULL && geteuid() == 0) 73764944Seric { 73865112Seric euid = ctladdr->q_uid; 73965112Seric egid = ctladdr->q_gid; 74065112Seric uname = ctladdr->q_user; 74164944Seric } 74268802Seric else if (bitset(SFF_RUNASREALUID, flags)) 74365112Seric { 74468494Seric extern char RealUserName[]; 74568494Seric 74665112Seric euid = RealUid; 74765112Seric egid = RealGid; 74865112Seric uname = RealUserName; 74965112Seric } 75068481Seric else if (FileMailer != NULL) 75168481Seric { 75268481Seric euid = FileMailer->m_uid; 75368481Seric egid = FileMailer->m_gid; 75468481Seric } 75568481Seric else 75668481Seric { 75768481Seric euid = egid = 0; 75868481Seric } 75965138Seric if (euid == 0) 76065138Seric { 76165138Seric euid = DefUid; 76265138Seric uname = DefUser; 76365138Seric } 76465138Seric if (egid == 0) 76565138Seric egid = DefGid; 7664329Seric if (geteuid() == 0) 76768494Seric flags |= SFF_SETUIDOK; 7684329Seric 76968494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); 77065067Seric return errno == 0; 7714329Seric } 7724329Seric /* 7734174Seric ** INCLUDE -- handle :include: specification. 7744174Seric ** 7754174Seric ** Parameters: 7764174Seric ** fname -- filename to include. 77753037Seric ** forwarding -- if TRUE, we are reading a .forward file. 77853037Seric ** if FALSE, it's a :include: file. 7794399Seric ** ctladdr -- address template to use to fill in these 7804399Seric ** addresses -- effective user/group id are 7814399Seric ** the important things. 7825006Seric ** sendq -- a pointer to the head of the send queue 7835006Seric ** to put these addresses in. 78468481Seric ** aliaslevel -- the alias nesting depth. 78568481Seric ** e -- the current envelope. 7864174Seric ** 7874174Seric ** Returns: 78857136Seric ** open error status 7894174Seric ** 7904174Seric ** Side Effects: 7914174Seric ** reads the :include: file and sends to everyone 7924174Seric ** listed in that file. 79365909Seric ** 79465909Seric ** Security Note: 79565909Seric ** If you have restricted chown (that is, you can't 79665909Seric ** give a file away), it is reasonable to allow programs 79765909Seric ** and files called from this :include: file to be to be 79865909Seric ** run as the owner of the :include: file. This is bogus 79965909Seric ** if there is any chance of someone giving away a file. 80065909Seric ** We assume that pre-POSIX systems can give away files. 80165909Seric ** 80265909Seric ** There is an additional restriction that if you 80365909Seric ** forward to a :include: file, it will not take on 80465909Seric ** the ownership of the :include: file. This may not 80565909Seric ** be necessary, but shouldn't hurt. 8064174Seric */ 8074174Seric 80853037Seric static jmp_buf CtxIncludeTimeout; 80968481Seric static void includetimeout(); 81053037Seric 81157136Seric int 81268481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 8134174Seric char *fname; 81453037Seric bool forwarding; 8154399Seric ADDRESS *ctladdr; 8165006Seric ADDRESS **sendq; 81768481Seric int aliaslevel; 81855012Seric ENVELOPE *e; 8194174Seric { 82068481Seric FILE *fp = NULL; 82155012Seric char *oldto = e->e_to; 8229379Seric char *oldfilename = FileName; 8239379Seric int oldlinenumber = LineNumber; 82453037Seric register EVENT *ev = NULL; 82558082Seric int nincludes; 82664325Seric register ADDRESS *ca; 82764325Seric uid_t saveduid, uid; 82864325Seric gid_t savedgid, gid; 82964083Seric char *uname; 83064325Seric int rval = 0; 83168513Seric int sfflags = SFF_REGONLY; 83265496Seric struct stat st; 83365948Seric char buf[MAXLINE]; 83465909Seric #ifdef _POSIX_CHOWN_RESTRICTED 83565948Seric # if _POSIX_CHOWN_RESTRICTED == -1 83665948Seric # define safechown FALSE 83765948Seric # else 83865948Seric # define safechown TRUE 83965948Seric # endif 84065948Seric #else 84165948Seric # ifdef _PC_CHOWN_RESTRICTED 84265909Seric bool safechown; 84365948Seric # else 84465948Seric # ifdef BSD 84565948Seric # define safechown TRUE 84665948Seric # else 84765948Seric # define safechown FALSE 84865948Seric # endif 84965948Seric # endif 85065909Seric #endif 85165948Seric extern bool chownsafe(); 8524174Seric 85357186Seric if (tTd(27, 2)) 85457186Seric printf("include(%s)\n", fname); 85563902Seric if (tTd(27, 4)) 85663902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 85763581Seric if (tTd(27, 14)) 85863581Seric { 85963581Seric printf("ctladdr "); 86063581Seric printaddr(ctladdr, FALSE); 86163581Seric } 86257186Seric 86364325Seric if (tTd(27, 9)) 86464325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 86553037Seric 86668513Seric if (forwarding) 86769306Seric sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK; 86868513Seric 86963581Seric ca = getctladdr(ctladdr); 87063581Seric if (ca == NULL) 87164083Seric { 87264846Seric uid = DefUid; 87364846Seric gid = DefGid; 87464846Seric uname = DefUser; 87564083Seric } 87663581Seric else 87764083Seric { 87863581Seric uid = ca->q_uid; 87964083Seric gid = ca->q_gid; 88064083Seric uname = ca->q_user; 88168481Seric } 88264325Seric #ifdef HASSETREUID 88368481Seric saveduid = geteuid(); 88468481Seric savedgid = getegid(); 88568481Seric if (saveduid == 0) 88668481Seric { 88768481Seric initgroups(uname, gid); 88868481Seric if (uid != 0) 88964325Seric { 89068481Seric if (setreuid(0, uid) < 0) 89168481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 89268481Seric uid, getuid(), geteuid()); 89368481Seric else 89468481Seric sfflags |= SFF_NOPATHCHECK; 89564325Seric } 89668481Seric } 897*69544Seric #endif 89863581Seric 89964325Seric if (tTd(27, 9)) 90064325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 90164325Seric 90264325Seric /* 90364325Seric ** If home directory is remote mounted but server is down, 90464325Seric ** this can hang or give errors; use a timeout to avoid this 90564325Seric */ 90664325Seric 90753037Seric if (setjmp(CtxIncludeTimeout) != 0) 90853037Seric { 90963853Seric ctladdr->q_flags |= QQUEUEUP; 91053037Seric errno = 0; 91163993Seric 91263993Seric /* return pseudo-error code */ 91364325Seric rval = EOPENTIMEOUT; 91464325Seric goto resetuid; 91553037Seric } 91668481Seric if (TimeOuts.to_fileopen > 0) 91768481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 91868481Seric else 91968481Seric ev = NULL; 92053037Seric 92163581Seric /* the input file must be marked safe */ 92268494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); 92364329Seric if (rval != 0) 92453037Seric { 92564325Seric /* don't use this :include: file */ 92657186Seric if (tTd(27, 4)) 92758247Seric printf("include: not safe (uid=%d): %s\n", 92864329Seric uid, errstring(rval)); 92953037Seric } 93065496Seric else 9314174Seric { 93265496Seric fp = fopen(fname, "r"); 93365496Seric if (fp == NULL) 93458061Seric { 93564329Seric rval = errno; 93665496Seric if (tTd(27, 4)) 93765496Seric printf("include: open: %s\n", errstring(rval)); 93858061Seric } 9394406Seric } 94068481Seric if (ev != NULL) 94168481Seric clrevent(ev); 94253037Seric 94364570Seric resetuid: 94464570Seric 94564570Seric #ifdef HASSETREUID 94664570Seric if (saveduid == 0) 94764570Seric { 94864570Seric if (uid != 0) 94968481Seric { 95068481Seric if (setreuid(-1, 0) < 0) 95168481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 95268481Seric getuid(), geteuid()); 95368481Seric if (setreuid(RealUid, 0) < 0) 95464570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 95564570Seric RealUid, getuid(), geteuid()); 95668481Seric } 95764570Seric setgid(savedgid); 95864570Seric } 95964570Seric #endif 96064570Seric 96164570Seric if (tTd(27, 9)) 96264570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 96364570Seric 96465593Seric if (rval == EOPENTIMEOUT) 96565593Seric usrerr("451 open timeout on %s", fname); 96665593Seric 96764570Seric if (fp == NULL) 96864570Seric return rval; 96964570Seric 97065496Seric if (fstat(fileno(fp), &st) < 0) 97165496Seric { 97265496Seric rval = errno; 97365496Seric syserr("Cannot fstat %s!", fname); 97465496Seric return rval; 97565496Seric } 97665496Seric 97765948Seric #ifndef safechown 97865948Seric safechown = chownsafe(fileno(fp)); 97965948Seric #endif 98065909Seric if (ca == NULL && safechown) 98165496Seric { 98265496Seric ctladdr->q_uid = st.st_uid; 98365496Seric ctladdr->q_gid = st.st_gid; 98465496Seric ctladdr->q_flags |= QGOODUID; 98565496Seric } 98665496Seric if (ca != NULL && ca->q_uid == st.st_uid) 98765496Seric { 98865496Seric /* optimization -- avoid getpwuid if we already have info */ 98965496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 99065496Seric ctladdr->q_ruser = ca->q_ruser; 99165496Seric } 99265496Seric else 99365496Seric { 99465496Seric register struct passwd *pw; 99565496Seric 99668693Seric pw = sm_getpwuid(st.st_uid); 99768481Seric if (pw == NULL) 99868481Seric ctladdr->q_flags |= QBOGUSSHELL; 99968481Seric else 100068478Seric { 100168481Seric char *sh; 100268481Seric 100368478Seric ctladdr->q_ruser = newstr(pw->pw_name); 100468478Seric if (safechown) 100568478Seric sh = pw->pw_shell; 100665909Seric else 100768481Seric sh = "/SENDMAIL/ANY/SHELL/"; 100868481Seric if (!usershellok(sh)) 100968481Seric { 101068481Seric if (safechown) 101168481Seric ctladdr->q_flags |= QBOGUSSHELL; 101268481Seric else 101368481Seric ctladdr->q_flags |= QUNSAFEADDR; 101468481Seric } 101565496Seric } 101665496Seric } 101765496Seric 101858092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 101958092Seric { 102058092Seric /* don't do any more now */ 102158868Seric ctladdr->q_flags |= QVERIFIED; 102258884Seric e->e_nrcpts++; 102358680Seric xfclose(fp, "include", fname); 102464570Seric return rval; 102558092Seric } 102658092Seric 102765496Seric /* 102865496Seric ** Check to see if some bad guy can write this file 102965496Seric ** 103065496Seric ** This should really do something clever with group 103165496Seric ** permissions; currently we just view world writable 103265496Seric ** as unsafe. Also, we don't check for writable 103365496Seric ** directories in the path. We've got to leave 103465496Seric ** something for the local sysad to do. 103565496Seric */ 103665496Seric 103765496Seric if (bitset(S_IWOTH, st.st_mode)) 103865496Seric ctladdr->q_flags |= QUNSAFEADDR; 103965496Seric 10404174Seric /* read the file -- each line is a comma-separated list. */ 10419379Seric FileName = fname; 10429379Seric LineNumber = 0; 104358082Seric ctladdr->q_flags &= ~QSELFREF; 104458082Seric nincludes = 0; 10454174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10464174Seric { 104756795Seric register char *p = strchr(buf, '\n'); 10484174Seric 104940963Sbostic LineNumber++; 10504174Seric if (p != NULL) 10514174Seric *p = '\0'; 105257186Seric if (buf[0] == '#' || buf[0] == '\0') 105357139Seric continue; 105468787Seric 105568787Seric /* <sp>#@# introduces a comment anywhere */ 105668787Seric /* for Japanese character sets */ 105768787Seric for (p = buf; (p = strchr(++p, '#')) != NULL; ) 105868787Seric { 105968787Seric if (p[1] == '@' && p[2] == '#' && 106068787Seric isascii(p[-1]) && isspace(p[-1]) && 106168787Seric isascii(p[3]) && isspace(p[3])) 106268787Seric { 106368787Seric p[-1] = '\0'; 106468787Seric break; 106568787Seric } 106668787Seric } 106768787Seric if (buf[0] == '\0') 106868787Seric continue; 106968787Seric 107058008Seric e->e_to = NULL; 107158151Seric message("%s to %s", 107253037Seric forwarding ? "forwarding" : "sending", buf); 107357977Seric #ifdef LOG 107458020Seric if (forwarding && LogLevel > 9) 107557977Seric syslog(LOG_INFO, "%s: forward %s => %s", 107666284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 107766284Seric oldto, buf); 107857977Seric #endif 107957977Seric 108068481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10814174Seric } 108263902Seric 108363902Seric if (ferror(fp) && tTd(27, 3)) 108463902Seric printf("include: read error: %s\n", errstring(errno)); 108558082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 108658065Seric { 108758065Seric if (tTd(27, 5)) 108858065Seric { 108958065Seric printf("include: QDONTSEND "); 109058065Seric printaddr(ctladdr, FALSE); 109158065Seric } 109258065Seric ctladdr->q_flags |= QDONTSEND; 109358065Seric } 10944174Seric 109558680Seric (void) xfclose(fp, "include", fname); 10969379Seric FileName = oldfilename; 10979379Seric LineNumber = oldlinenumber; 109863847Seric e->e_to = oldto; 109964325Seric return rval; 11004174Seric } 110153037Seric 110268481Seric static void 110353037Seric includetimeout() 110453037Seric { 110553037Seric longjmp(CtxIncludeTimeout, 1); 110653037Seric } 11074324Seric /* 11084324Seric ** SENDTOARGV -- send to an argument vector. 11094324Seric ** 11104324Seric ** Parameters: 11114324Seric ** argv -- argument vector to send to. 111258247Seric ** e -- the current envelope. 11134324Seric ** 11144324Seric ** Returns: 11154324Seric ** none. 11164324Seric ** 11174324Seric ** Side Effects: 11184324Seric ** puts all addresses on the argument vector onto the 11194324Seric ** send queue. 11204324Seric */ 11214324Seric 112255012Seric sendtoargv(argv, e) 11234324Seric register char **argv; 112455012Seric register ENVELOPE *e; 11254324Seric { 11264324Seric register char *p; 11274324Seric 11284324Seric while ((p = *argv++) != NULL) 11294324Seric { 113068481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 11314324Seric } 11324324Seric } 11334399Seric /* 11344399Seric ** GETCTLADDR -- get controlling address from an address header. 11354399Seric ** 11364399Seric ** If none, get one corresponding to the effective userid. 11374399Seric ** 11384399Seric ** Parameters: 11394399Seric ** a -- the address to find the controller of. 11404399Seric ** 11414399Seric ** Returns: 11424399Seric ** the controlling address. 11434399Seric ** 11444399Seric ** Side Effects: 11454399Seric ** none. 11464399Seric */ 11474399Seric 11484399Seric ADDRESS * 11494399Seric getctladdr(a) 11504399Seric register ADDRESS *a; 11514399Seric { 11524404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11534399Seric a = a->q_alias; 11544399Seric return (a); 11554399Seric } 1156*69544Seric /* 1157*69544Seric ** SELF_REFERENCE -- check to see if an address references itself 1158*69544Seric ** 1159*69544Seric ** The check is done through a chain of aliases. If it is part of 1160*69544Seric ** a loop, break the loop at the "best" address, that is, the one 1161*69544Seric ** that exists as a real user. 1162*69544Seric ** 1163*69544Seric ** This is to handle the case of: 1164*69544Seric ** Andrew.Chang: awc 1165*69544Seric ** awc: Andrew.Chang@mail.server. 1166*69544Seric ** which is a problem only on mail.server. 1167*69544Seric ** 1168*69544Seric ** Parameters: 1169*69544Seric ** a -- the address to check. 1170*69544Seric ** e -- the current envelope. 1171*69544Seric ** 1172*69544Seric ** Returns: 1173*69544Seric ** The address that should be retained. 1174*69544Seric */ 1175*69544Seric 1176*69544Seric ADDRESS * 1177*69544Seric self_reference(a, e) 1178*69544Seric ADDRESS *a; 1179*69544Seric ENVELOPE *e; 1180*69544Seric { 1181*69544Seric ADDRESS *b; /* top entry in self ref loop */ 1182*69544Seric ADDRESS *c; /* entry that point to a real mail box */ 1183*69544Seric 1184*69544Seric if (tTd(27, 1)) 1185*69544Seric printf("self_reference(%s)\n", a->q_paddr); 1186*69544Seric 1187*69544Seric for (b = a->q_alias; b != NULL; b = b->q_alias) 1188*69544Seric { 1189*69544Seric if (sameaddr(a, b)) 1190*69544Seric break; 1191*69544Seric } 1192*69544Seric 1193*69544Seric if (b == NULL) 1194*69544Seric { 1195*69544Seric if (tTd(27, 1)) 1196*69544Seric printf("\t... no self ref\n"); 1197*69544Seric return NULL; 1198*69544Seric } 1199*69544Seric 1200*69544Seric /* 1201*69544Seric ** Pick the first address that resolved to a real mail box 1202*69544Seric ** i.e has a pw entry. The returned value will be marked 1203*69544Seric ** QSELFREF in recipient(), which in turn will disable alias() 1204*69544Seric ** from marking it QDONTSEND, which mean it will be used 1205*69544Seric ** as a deliverable address. 1206*69544Seric ** 1207*69544Seric ** The 2 key thing to note here are: 1208*69544Seric ** 1) we are in a recursive call sequence: 1209*69544Seric ** alias->sentolist->recipient->alias 1210*69544Seric ** 2) normally, when we return back to alias(), the address 1211*69544Seric ** will be marked QDONTSEND, since alias() assumes the 1212*69544Seric ** expanded form will be used instead of the current address. 1213*69544Seric ** This behaviour is turned off if the address is marked 1214*69544Seric ** QSELFREF We set QSELFREF when we return to recipient(). 1215*69544Seric */ 1216*69544Seric 1217*69544Seric c = a; 1218*69544Seric while (c != NULL) 1219*69544Seric { 1220*69544Seric if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 1221*69544Seric { 1222*69544Seric if (tTd(27, 2)) 1223*69544Seric printf("\t... getpwnam(%s)... ", c->q_user); 1224*69544Seric if (sm_getpwnam(c->q_user) != NULL) 1225*69544Seric { 1226*69544Seric if (tTd(27, 2)) 1227*69544Seric printf("found\n"); 1228*69544Seric 1229*69544Seric /* ought to cache results here */ 1230*69544Seric return c; 1231*69544Seric } 1232*69544Seric if (tTd(27, 2)) 1233*69544Seric printf("failed\n"); 1234*69544Seric } 1235*69544Seric c = c->q_alias; 1236*69544Seric } 1237*69544Seric 1238*69544Seric if (tTd(27, 1)) 1239*69544Seric printf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 1240*69544Seric 1241*69544Seric return NULL; 1242*69544Seric } 1243