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*69898Seric static char sccsid[] = "@(#)recipient.c 8.95 (Berkeley) 06/15/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 { 11469544Seric ADDRESS *b; 11569544Seric extern ADDRESS *self_reference(); 11669544Seric 11768481Seric /* self reference test */ 11868481Seric if (sameaddr(ctladdr, a)) 11969561Seric { 12069561Seric if (tTd(27, 5)) 12169561Seric { 12269561Seric printf("sendtolist: QSELFREF "); 12369561Seric printaddr(ctladdr, FALSE); 12469561Seric } 12568481Seric ctladdr->q_flags |= QSELFREF; 12669561Seric } 12768481Seric 12869544Seric /* check for address loops */ 12969544Seric b = self_reference(a, e); 13069544Seric if (b != NULL) 13169544Seric { 13269544Seric b->q_flags |= QSELFREF; 13369561Seric if (tTd(27, 5)) 13469561Seric { 13569561Seric printf("sendtolist: QSELFREF "); 13669561Seric printaddr(b, FALSE); 13769561Seric } 13869544Seric if (a != b) 13969544Seric { 14069561Seric if (tTd(27, 5)) 14169561Seric { 14269561Seric printf("sendtolist: QDONTSEND "); 14369561Seric printaddr(a, FALSE); 14469561Seric } 14569544Seric a->q_flags |= QDONTSEND; 14669544Seric continue; 14769544Seric } 14869544Seric } 14969544Seric 15068481Seric /* full name */ 15168481Seric if (a->q_fullname == NULL) 15268481Seric a->q_fullname = ctladdr->q_fullname; 15368481Seric 15468481Seric /* various flag bits */ 15568481Seric a->q_flags &= ~QINHERITEDBITS; 15668481Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 15768481Seric 15868481Seric /* original recipient information */ 15968481Seric a->q_orcpt = ctladdr->q_orcpt; 16068481Seric } 16168481Seric 16257731Seric al = a; 1634423Seric firstone = FALSE; 1644324Seric } 1654324Seric 1664324Seric /* arrange to send to everyone on the local send list */ 1674324Seric while (al != NULL) 1684324Seric { 1694324Seric register ADDRESS *a = al; 1704324Seric 1714324Seric al = a->q_next; 17268481Seric a = recipient(a, sendq, aliaslevel, e); 17358082Seric naddrs++; 1744174Seric } 1754324Seric 17663847Seric e->e_to = oldto; 17768392Seric if (bufp != buf) 17868392Seric free(bufp); 17958082Seric return (naddrs); 1804174Seric } 1814174Seric /* 1824174Seric ** RECIPIENT -- Designate a message recipient 1834174Seric ** 1844174Seric ** Saves the named person for future mailing. 1854174Seric ** 1864174Seric ** Parameters: 1874174Seric ** a -- the (preparsed) address header for the recipient. 1885006Seric ** sendq -- a pointer to the head of a queue to put the 1895006Seric ** recipient in. Duplicate supression is done 1905006Seric ** in this queue. 19168481Seric ** aliaslevel -- the current alias nesting depth. 19257731Seric ** e -- the current envelope. 1934174Seric ** 1944174Seric ** Returns: 19512613Seric ** The actual address in the queue. This will be "a" if 19612613Seric ** the address is not a duplicate, else the original address. 1974174Seric ** 1984174Seric ** Side Effects: 1994174Seric ** none. 2004174Seric */ 2014174Seric 20212613Seric ADDRESS * 20368481Seric recipient(a, sendq, aliaslevel, e) 2044174Seric register ADDRESS *a; 2055006Seric register ADDRESS **sendq; 20668481Seric int aliaslevel; 20755012Seric register ENVELOPE *e; 2084174Seric { 2094174Seric register ADDRESS *q; 2104319Seric ADDRESS **pq; 2114174Seric register struct mailer *m; 2129210Seric register char *p; 2139210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 21453735Seric int findusercount = 0; 21568603Seric bool initialdontsend = bitset(QDONTSEND, a->q_flags); 21668481Seric int i; 21768481Seric char *buf; 21868528Seric char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 21958247Seric extern int safefile(); 2204174Seric 22155012Seric e->e_to = a->q_paddr; 2224600Seric m = a->q_mailer; 2234174Seric errno = 0; 22468603Seric if (aliaslevel == 0) 22568603Seric a->q_flags |= QPRIMARY; 2267676Seric if (tTd(26, 1)) 2274444Seric { 22868603Seric printf("\nrecipient (%d): ", aliaslevel); 2294444Seric printaddr(a, FALSE); 2304444Seric } 2314174Seric 23264146Seric /* if this is primary, add it to the original recipient list */ 23364146Seric if (a->q_alias == NULL) 23464146Seric { 23564146Seric if (e->e_origrcpt == NULL) 23664146Seric e->e_origrcpt = a->q_paddr; 23764146Seric else if (e->e_origrcpt != a->q_paddr) 23864146Seric e->e_origrcpt = ""; 23964146Seric } 24064146Seric 2414174Seric /* break aliasing loops */ 24268481Seric if (aliaslevel > MAXRCRSN) 2434174Seric { 24468857Seric a->q_status = "5.4.6"; 24568481Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 24668481Seric aliaslevel, MAXRCRSN); 24712613Seric return (a); 2484174Seric } 2494174Seric 2504174Seric /* 2514627Seric ** Finish setting up address structure. 2524174Seric */ 2534174Seric 25416160Seric /* get unquoted user for file, program or user.name check */ 25568481Seric i = strlen(a->q_user); 25668528Seric if (i >= sizeof buf0) 25768481Seric buf = xalloc(i + 1); 25868481Seric else 25968481Seric buf = buf0; 2609210Seric (void) strcpy(buf, a->q_user); 2619210Seric for (p = buf; *p != '\0' && !quoted; p++) 2629210Seric { 26354993Seric if (*p == '\\') 2649210Seric quoted = TRUE; 2659210Seric } 26654983Seric stripquotes(buf); 2679210Seric 26857402Seric /* check for direct mailing to restricted mailers */ 26965496Seric if (m == ProgMailer) 2704174Seric { 27165496Seric if (a->q_alias == NULL) 27265496Seric { 27365496Seric a->q_flags |= QBADADDR; 27468857Seric a->q_status = "5.7.1"; 27565496Seric usrerr("550 Cannot mail directly to programs"); 27665496Seric } 27765496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 27865496Seric { 27965496Seric a->q_flags |= QBADADDR; 28068857Seric a->q_status = "5.7.1"; 28165496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 28265496Seric a->q_alias->q_ruser, MyHostName); 28365496Seric } 28465496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 28565496Seric { 28665496Seric a->q_flags |= QBADADDR; 28768857Seric a->q_status = "5.7.1"; 28865496Seric usrerr("550 Address %s is unsafe for mailing to programs", 28965496Seric a->q_alias->q_paddr); 29065496Seric } 2914174Seric } 2924174Seric 2934174Seric /* 2944419Seric ** Look up this person in the recipient list. 2954419Seric ** If they are there already, return, otherwise continue. 2964419Seric ** If the list is empty, just add it. Notice the cute 2974419Seric ** hack to make from addresses suppress things correctly: 2984419Seric ** the QDONTSEND bit will be set in the send list. 2994419Seric ** [Please note: the emphasis is on "hack."] 3004174Seric */ 3014174Seric 3025006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 3034174Seric { 30458294Seric if (sameaddr(q, a)) 3054174Seric { 3067676Seric if (tTd(26, 1)) 3074444Seric { 3084444Seric printf("%s in sendq: ", a->q_paddr); 3094444Seric printaddr(q, FALSE); 3104444Seric } 31165593Seric if (!bitset(QPRIMARY, q->q_flags)) 31258065Seric { 31365593Seric if (!bitset(QDONTSEND, a->q_flags)) 31458151Seric message("duplicate suppressed"); 31565593Seric q->q_flags |= a->q_flags; 31665593Seric } 31765593Seric else if (bitset(QSELFREF, q->q_flags)) 31865579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 31963847Seric a = q; 32068481Seric goto done; 3214174Seric } 3224319Seric } 3234174Seric 3244319Seric /* add address on list */ 32558884Seric *pq = a; 32658884Seric a->q_next = NULL; 3274174Seric 3284174Seric /* 32957402Seric ** Alias the name and handle special mailer types. 3304174Seric */ 3314174Seric 33253735Seric trylocaluser: 33355354Seric if (tTd(29, 7)) 33455354Seric printf("at trylocaluser %s\n", a->q_user); 33555354Seric 33658680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 33763847Seric goto testselfdestruct; 33857402Seric 33957402Seric if (m == InclMailer) 3404174Seric { 34157402Seric a->q_flags |= QDONTSEND; 34264761Seric if (a->q_alias == NULL) 3434174Seric { 34458680Seric a->q_flags |= QBADADDR; 34568857Seric a->q_status = "5.7.1"; 34658151Seric usrerr("550 Cannot mail directly to :include:s"); 3474174Seric } 3484174Seric else 34950556Seric { 35059563Seric int ret; 35158247Seric 35258151Seric message("including file %s", a->q_user); 35368481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 35459563Seric if (transienterror(ret)) 35559563Seric { 35659563Seric #ifdef LOG 35759563Seric if (LogLevel > 2) 35866239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 35966284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 36066284Seric a->q_user, errstring(ret)); 36159563Seric #endif 36263853Seric a->q_flags |= QQUEUEUP; 36365215Seric a->q_flags &= ~QDONTSEND; 36459563Seric usrerr("451 Cannot open %s: %s", 36559563Seric a->q_user, errstring(ret)); 36659563Seric } 36759563Seric else if (ret != 0) 36859563Seric { 36963938Seric a->q_flags |= QBADADDR; 37068857Seric a->q_status = "5.2.4"; 37159563Seric usrerr("550 Cannot open %s: %s", 37259563Seric a->q_user, errstring(ret)); 37359563Seric } 37450556Seric } 3754174Seric } 37657642Seric else if (m == FileMailer) 3774174Seric { 3784329Seric extern bool writable(); 3794174Seric 38051317Seric /* check if writable or creatable */ 38164761Seric if (a->q_alias == NULL) 3824174Seric { 38358680Seric a->q_flags |= QBADADDR; 38468857Seric a->q_status = "5.7.1"; 38558151Seric usrerr("550 Cannot mail directly to files"); 3864174Seric } 38765496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 38865496Seric { 38965496Seric a->q_flags |= QBADADDR; 39068857Seric a->q_status = "5.7.1"; 39165496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 39265496Seric a->q_alias->q_ruser, MyHostName); 39365496Seric } 39465496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 39565496Seric { 39665496Seric a->q_flags |= QBADADDR; 39768857Seric a->q_status = "5.7.1"; 39865496Seric usrerr("550 Address %s is unsafe for mailing to files", 39965496Seric a->q_alias->q_paddr); 40065496Seric } 40168494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT)) 40251317Seric { 40358680Seric a->q_flags |= QBADADDR; 40468481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 40568481Seric (time_t) 0, e); 40651317Seric } 40751317Seric } 40851317Seric 40957402Seric /* try aliasing */ 41068481Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 41168481Seric alias(a, sendq, aliaslevel, e); 41257402Seric 41369714Seric # if USERDB 41457402Seric /* if not aliased, look it up in the user database */ 41568481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 41668481Seric bitnset(M_CHECKUDB, m->m_flags)) 41757402Seric { 41857402Seric extern int udbexpand(); 41957402Seric 42068481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 42157402Seric { 42263853Seric a->q_flags |= QQUEUEUP; 42357402Seric if (e->e_message == NULL) 42457402Seric e->e_message = newstr("Deferred: user database error"); 42557402Seric # ifdef LOG 42658020Seric if (LogLevel > 8) 42759623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 42866284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 42966284Seric errstring(errno)); 43057402Seric # endif 43159615Seric message("queued (user database error): %s", 43259615Seric errstring(errno)); 43357642Seric e->e_nrcpts++; 43463847Seric goto testselfdestruct; 43557402Seric } 43657402Seric } 43757402Seric # endif 43857402Seric 43951317Seric /* 44051317Seric ** If we have a level two config file, then pass the name through 44151317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 44251317Seric ** to send rewrite it to another mailer. This gives us a hook 44351317Seric ** after local aliasing has been done. 44451317Seric */ 44551317Seric 44651317Seric if (tTd(29, 5)) 44751317Seric { 44851317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 44951317Seric ConfigLevel, RewriteRules[5]); 45051317Seric printaddr(a, FALSE); 45151317Seric } 45268481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 45368481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 45468481Seric bitnset(M_TRYRULESET5, m->m_flags)) 45551317Seric { 45668603Seric maplocaluser(a, sendq, aliaslevel + 1, e); 45751317Seric } 45851317Seric 45951317Seric /* 46051317Seric ** If it didn't get rewritten to another mailer, go ahead 46151317Seric ** and deliver it. 46251317Seric */ 46351317Seric 46468481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 46568481Seric bitnset(M_HASPWENT, m->m_flags)) 46651317Seric { 46755354Seric auto bool fuzzy; 46851317Seric register struct passwd *pw; 46951317Seric extern struct passwd *finduser(); 47051317Seric 47151317Seric /* warning -- finduser may trash buf */ 47255354Seric pw = finduser(buf, &fuzzy); 47351317Seric if (pw == NULL) 47451317Seric { 47558680Seric a->q_flags |= QBADADDR; 47668857Seric a->q_status = "5.1.1"; 47768481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 47868481Seric (time_t) 0, e); 47951317Seric } 4804174Seric else 4814174Seric { 48268528Seric char nbuf[MAXNAME + 1]; 4834373Seric 48455354Seric if (fuzzy) 4854174Seric { 48653735Seric /* name was a fuzzy match */ 48751317Seric a->q_user = newstr(pw->pw_name); 48853735Seric if (findusercount++ > 3) 48953735Seric { 49058680Seric a->q_flags |= QBADADDR; 49168857Seric a->q_status = "5.4.6"; 49258151Seric usrerr("554 aliasing/forwarding loop for %s broken", 49353735Seric pw->pw_name); 49468481Seric goto done; 49553735Seric } 49653735Seric 49753735Seric /* see if it aliases */ 49851317Seric (void) strcpy(buf, pw->pw_name); 49953735Seric goto trylocaluser; 5004174Seric } 50165822Seric if (strcmp(pw->pw_dir, "/") == 0) 50265822Seric a->q_home = ""; 50365822Seric else 50465822Seric a->q_home = newstr(pw->pw_dir); 50551317Seric a->q_uid = pw->pw_uid; 50651317Seric a->q_gid = pw->pw_gid; 50759083Seric a->q_ruser = newstr(pw->pw_name); 50851317Seric a->q_flags |= QGOODUID; 50951317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 51051317Seric if (nbuf[0] != '\0') 51151317Seric a->q_fullname = newstr(nbuf); 51269894Seric if (!usershellok(pw->pw_name, pw->pw_shell)) 51365206Seric { 51465211Seric a->q_flags |= QBOGUSSHELL; 51565206Seric } 51669619Seric if (bitset(EF_VRFYONLY, e->e_flags)) 51769619Seric { 51869619Seric /* don't do any more now */ 51969619Seric a->q_flags |= QVERIFIED; 52069619Seric } 52169619Seric else if (!quoted) 52268481Seric forward(a, sendq, aliaslevel, e); 5234174Seric } 5244174Seric } 52557642Seric if (!bitset(QDONTSEND, a->q_flags)) 52657642Seric e->e_nrcpts++; 52763847Seric 52863847Seric testselfdestruct: 52968603Seric a->q_flags |= QTHISPASS; 53063978Seric if (tTd(26, 8)) 53163847Seric { 53263978Seric printf("testselfdestruct: "); 53368603Seric printaddr(a, FALSE); 53468603Seric if (tTd(26, 10)) 53568603Seric { 53668603Seric printf("SENDQ:\n"); 53768603Seric printaddr(*sendq, TRUE); 53868603Seric printf("----\n"); 53968603Seric } 54063978Seric } 54163978Seric if (a->q_alias == NULL && a != &e->e_from && 54263978Seric bitset(QDONTSEND, a->q_flags)) 54363978Seric { 54468603Seric for (q = *sendq; q != NULL; q = q->q_next) 54568603Seric { 546*69898Seric if (!bitset(QDONTSEND, q->q_flags) && 54768603Seric bitset(QTHISPASS, q->q_flags)) 54868603Seric break; 54968603Seric } 55063978Seric if (q == NULL) 55163847Seric { 55263847Seric a->q_flags |= QBADADDR; 55368858Seric a->q_status = "5.4.6"; 55463847Seric usrerr("554 aliasing/forwarding loop broken"); 55563847Seric } 55663847Seric } 55768481Seric 55868481Seric done: 55968603Seric a->q_flags |= QTHISPASS; 56068481Seric if (buf != buf0) 56168481Seric free(buf); 56268603Seric 56368603Seric /* 56468603Seric ** If we are at the top level, check to see if this has 56568603Seric ** expanded to exactly one address. If so, it can inherit 56668603Seric ** the primaryness of the address. 56768603Seric ** 56868603Seric ** While we're at it, clear the QTHISPASS bits. 56968603Seric */ 57068603Seric 57168603Seric if (aliaslevel == 0) 57268603Seric { 57368603Seric int nrcpts = 0; 57468603Seric ADDRESS *only; 57568603Seric 57668603Seric for (q = *sendq; q != NULL; q = q->q_next) 57768603Seric { 57868603Seric if (bitset(QTHISPASS, q->q_flags) && 57968603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags)) 58068603Seric { 58168603Seric nrcpts++; 58268603Seric only = q; 58368603Seric } 58468603Seric q->q_flags &= ~QTHISPASS; 58568603Seric } 58668603Seric if (nrcpts == 1) 58768603Seric { 58868867Seric /* check to see if this actually got a new owner */ 58968867Seric q = only; 59068867Seric while ((q = q->q_alias) != NULL) 59168867Seric { 59268867Seric if (q->q_owner != NULL) 59368867Seric break; 59468867Seric } 59568867Seric if (q == NULL) 59668867Seric only->q_flags |= QPRIMARY; 59768867Seric } 59868867Seric else if (!initialdontsend && nrcpts > 0) 59968867Seric { 60068603Seric /* arrange for return receipt */ 60168603Seric e->e_flags |= EF_SENDRECEIPT; 60268867Seric a->q_flags |= QEXPANDED; 60368603Seric if (e->e_xfp != NULL) 60468603Seric fprintf(e->e_xfp, 60568603Seric "%s... expanded to multiple addresses\n", 60668603Seric a->q_paddr); 60768603Seric } 60868603Seric } 60968603Seric 61012613Seric return (a); 6114174Seric } 6124174Seric /* 6134373Seric ** FINDUSER -- find the password entry for a user. 6144373Seric ** 6154373Seric ** This looks a lot like getpwnam, except that it may want to 6164373Seric ** do some fancier pattern matching in /etc/passwd. 6174373Seric ** 6189379Seric ** This routine contains most of the time of many sendmail runs. 6199379Seric ** It deserves to be optimized. 6209379Seric ** 6214373Seric ** Parameters: 6224373Seric ** name -- the name to match against. 62355354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 62455354Seric ** was found using the fuzzy matching algorithm; 62555354Seric ** set to FALSE otherwise. 6264373Seric ** 6274373Seric ** Returns: 6284373Seric ** A pointer to a pw struct. 6294373Seric ** NULL if name is unknown or ambiguous. 6304373Seric ** 6314373Seric ** Side Effects: 6324407Seric ** may modify name. 6334373Seric */ 6344373Seric 6354373Seric struct passwd * 63655354Seric finduser(name, fuzzyp) 6374373Seric char *name; 63855354Seric bool *fuzzyp; 6394373Seric { 6404376Seric register struct passwd *pw; 6414407Seric register char *p; 6424373Seric 64355354Seric if (tTd(29, 4)) 64455354Seric printf("finduser(%s): ", name); 64555354Seric 64655354Seric *fuzzyp = FALSE; 6474407Seric 64868481Seric #ifdef HESIOD 64964673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 65064673Seric for (p = name; *p != '\0'; p++) 65164673Seric if (!isascii(*p) || !isdigit(*p)) 65264673Seric break; 65364673Seric if (*p == '\0') 65464673Seric { 65564673Seric if (tTd(29, 4)) 65664673Seric printf("failed (numeric input)\n"); 65764673Seric return NULL; 65864673Seric } 65968481Seric #endif 66064673Seric 66125777Seric /* look up this login name using fast path */ 66268693Seric if ((pw = sm_getpwnam(name)) != NULL) 66355354Seric { 66455354Seric if (tTd(29, 4)) 66555354Seric printf("found (non-fuzzy)\n"); 66612634Seric return (pw); 66755354Seric } 66812634Seric 66969881Seric #if MATCHGECOS 67053735Seric /* see if fuzzy matching allowed */ 67153735Seric if (!MatchGecos) 67255354Seric { 67355354Seric if (tTd(29, 4)) 67455354Seric printf("not found (fuzzy disabled)\n"); 67553735Seric return NULL; 67655354Seric } 67753735Seric 67812634Seric /* search for a matching full name instead */ 67925777Seric for (p = name; *p != '\0'; p++) 68025777Seric { 68125777Seric if (*p == (SpaceSub & 0177) || *p == '_') 68225777Seric *p = ' '; 68325777Seric } 68423107Seric (void) setpwent(); 6854376Seric while ((pw = getpwent()) != NULL) 6864376Seric { 68768528Seric char buf[MAXNAME + 1]; 6884376Seric 6894998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 69056795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 6914381Seric { 69255354Seric if (tTd(29, 4)) 69355354Seric printf("fuzzy matches %s\n", pw->pw_name); 69458151Seric message("sending to login name %s", pw->pw_name); 69555354Seric *fuzzyp = TRUE; 6964376Seric return (pw); 6974377Seric } 6984376Seric } 69955354Seric if (tTd(29, 4)) 70055354Seric printf("no fuzzy match found\n"); 70159015Seric #else 70259015Seric if (tTd(29, 4)) 70359015Seric printf("not found (fuzzy disabled)\n"); 70459015Seric #endif 7054376Seric return (NULL); 7064373Seric } 7074373Seric /* 7084329Seric ** WRITABLE -- predicate returning if the file is writable. 7094329Seric ** 7104329Seric ** This routine must duplicate the algorithm in sys/fio.c. 7114329Seric ** Unfortunately, we cannot use the access call since we 7124329Seric ** won't necessarily be the real uid when we try to 7134329Seric ** actually open the file. 7144329Seric ** 7154329Seric ** Notice that ANY file with ANY execute bit is automatically 7164329Seric ** not writable. This is also enforced by mailfile. 7174329Seric ** 7184329Seric ** Parameters: 71965064Seric ** filename -- the file name to check. 72065112Seric ** ctladdr -- the controlling address for this file. 72165064Seric ** flags -- SFF_* flags to control the function. 7224329Seric ** 7234329Seric ** Returns: 7244329Seric ** TRUE -- if we will be able to write this file. 7254329Seric ** FALSE -- if we cannot write this file. 7264329Seric ** 7274329Seric ** Side Effects: 7284329Seric ** none. 7294329Seric */ 7304329Seric 7314329Seric bool 73265112Seric writable(filename, ctladdr, flags) 73364819Seric char *filename; 73465112Seric ADDRESS *ctladdr; 73565064Seric int flags; 7364329Seric { 73755372Seric uid_t euid; 73855372Seric gid_t egid; 73964944Seric char *uname; 7404329Seric 74164819Seric if (tTd(29, 5)) 74268802Seric printf("writable(%s, 0x%x)\n", filename, flags); 74364944Seric 74465225Seric #ifdef SUID_ROOT_FILES_OK 74565225Seric /* really ought to be passed down -- and not a good idea */ 74665225Seric flags |= SFF_ROOTOK; 74765225Seric #endif 74865225Seric 74964944Seric /* 75064944Seric ** File does exist -- check that it is writable. 75164944Seric */ 75264944Seric 75365112Seric if (ctladdr != NULL && geteuid() == 0) 75464944Seric { 75565112Seric euid = ctladdr->q_uid; 75665112Seric egid = ctladdr->q_gid; 75765112Seric uname = ctladdr->q_user; 75864944Seric } 75968802Seric else if (bitset(SFF_RUNASREALUID, flags)) 76065112Seric { 76165112Seric euid = RealUid; 76265112Seric egid = RealGid; 76365112Seric uname = RealUserName; 76465112Seric } 76568481Seric else if (FileMailer != NULL) 76668481Seric { 76768481Seric euid = FileMailer->m_uid; 76868481Seric egid = FileMailer->m_gid; 76969748Seric uname = NULL; 77068481Seric } 77168481Seric else 77268481Seric { 77368481Seric euid = egid = 0; 77469748Seric uname = NULL; 77568481Seric } 77665138Seric if (euid == 0) 77765138Seric { 77865138Seric euid = DefUid; 77965138Seric uname = DefUser; 78065138Seric } 78165138Seric if (egid == 0) 78265138Seric egid = DefGid; 7834329Seric if (geteuid() == 0) 78468494Seric flags |= SFF_SETUIDOK; 7854329Seric 78668494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); 78765067Seric return errno == 0; 7884329Seric } 7894329Seric /* 7904174Seric ** INCLUDE -- handle :include: specification. 7914174Seric ** 7924174Seric ** Parameters: 7934174Seric ** fname -- filename to include. 79453037Seric ** forwarding -- if TRUE, we are reading a .forward file. 79553037Seric ** if FALSE, it's a :include: file. 7964399Seric ** ctladdr -- address template to use to fill in these 7974399Seric ** addresses -- effective user/group id are 7984399Seric ** the important things. 7995006Seric ** sendq -- a pointer to the head of the send queue 8005006Seric ** to put these addresses in. 80168481Seric ** aliaslevel -- the alias nesting depth. 80268481Seric ** e -- the current envelope. 8034174Seric ** 8044174Seric ** Returns: 80557136Seric ** open error status 8064174Seric ** 8074174Seric ** Side Effects: 8084174Seric ** reads the :include: file and sends to everyone 8094174Seric ** listed in that file. 81065909Seric ** 81165909Seric ** Security Note: 81265909Seric ** If you have restricted chown (that is, you can't 81365909Seric ** give a file away), it is reasonable to allow programs 81465909Seric ** and files called from this :include: file to be to be 81565909Seric ** run as the owner of the :include: file. This is bogus 81665909Seric ** if there is any chance of someone giving away a file. 81765909Seric ** We assume that pre-POSIX systems can give away files. 81865909Seric ** 81965909Seric ** There is an additional restriction that if you 82065909Seric ** forward to a :include: file, it will not take on 82165909Seric ** the ownership of the :include: file. This may not 82265909Seric ** be necessary, but shouldn't hurt. 8234174Seric */ 8244174Seric 82553037Seric static jmp_buf CtxIncludeTimeout; 82668481Seric static void includetimeout(); 82753037Seric 82857136Seric int 82968481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 8304174Seric char *fname; 83153037Seric bool forwarding; 8324399Seric ADDRESS *ctladdr; 8335006Seric ADDRESS **sendq; 83468481Seric int aliaslevel; 83555012Seric ENVELOPE *e; 8364174Seric { 83768481Seric FILE *fp = NULL; 83855012Seric char *oldto = e->e_to; 8399379Seric char *oldfilename = FileName; 8409379Seric int oldlinenumber = LineNumber; 84153037Seric register EVENT *ev = NULL; 84258082Seric int nincludes; 84364325Seric register ADDRESS *ca; 84464325Seric uid_t saveduid, uid; 84564325Seric gid_t savedgid, gid; 84664083Seric char *uname; 84764325Seric int rval = 0; 84868513Seric int sfflags = SFF_REGONLY; 84965496Seric struct stat st; 85065948Seric char buf[MAXLINE]; 85165909Seric #ifdef _POSIX_CHOWN_RESTRICTED 85265948Seric # if _POSIX_CHOWN_RESTRICTED == -1 85365948Seric # define safechown FALSE 85465948Seric # else 85565948Seric # define safechown TRUE 85665948Seric # endif 85765948Seric #else 85865948Seric # ifdef _PC_CHOWN_RESTRICTED 85965909Seric bool safechown; 86065948Seric # else 86165948Seric # ifdef BSD 86265948Seric # define safechown TRUE 86365948Seric # else 86465948Seric # define safechown FALSE 86565948Seric # endif 86665948Seric # endif 86765909Seric #endif 86865948Seric extern bool chownsafe(); 8694174Seric 87057186Seric if (tTd(27, 2)) 87157186Seric printf("include(%s)\n", fname); 87263902Seric if (tTd(27, 4)) 87363902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 87463581Seric if (tTd(27, 14)) 87563581Seric { 87663581Seric printf("ctladdr "); 87763581Seric printaddr(ctladdr, FALSE); 87863581Seric } 87957186Seric 88064325Seric if (tTd(27, 9)) 88164325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 88253037Seric 88368513Seric if (forwarding) 88469306Seric sfflags |= SFF_MUSTOWN|SFF_ROOTOK|SFF_NOSLINK; 88568513Seric 88663581Seric ca = getctladdr(ctladdr); 88763581Seric if (ca == NULL) 88864083Seric { 88964846Seric uid = DefUid; 89064846Seric gid = DefGid; 89164846Seric uname = DefUser; 89264083Seric } 89363581Seric else 89464083Seric { 89563581Seric uid = ca->q_uid; 89664083Seric gid = ca->q_gid; 89764083Seric uname = ca->q_user; 89868481Seric } 89969638Seric #if HASSETREUID || USESETEUID 90068481Seric saveduid = geteuid(); 90168481Seric savedgid = getegid(); 90268481Seric if (saveduid == 0) 90368481Seric { 90468481Seric initgroups(uname, gid); 90568481Seric if (uid != 0) 90664325Seric { 90769638Seric # if USESETEUID 90869638Seric if (seteuid(uid) < 0) 90969638Seric syserr("seteuid(%d) failure (real=%d, eff=%d)", 91069638Seric uid, getuid(), geteuid()); 91169638Seric # else 91268481Seric if (setreuid(0, uid) < 0) 91368481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 91468481Seric uid, getuid(), geteuid()); 91569638Seric # endif 91668481Seric else 91768481Seric sfflags |= SFF_NOPATHCHECK; 91864325Seric } 91968481Seric } 92069544Seric #endif 92163581Seric 92264325Seric if (tTd(27, 9)) 92364325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 92464325Seric 92564325Seric /* 92664325Seric ** If home directory is remote mounted but server is down, 92764325Seric ** this can hang or give errors; use a timeout to avoid this 92864325Seric */ 92964325Seric 93053037Seric if (setjmp(CtxIncludeTimeout) != 0) 93153037Seric { 93263853Seric ctladdr->q_flags |= QQUEUEUP; 93353037Seric errno = 0; 93463993Seric 93563993Seric /* return pseudo-error code */ 93664325Seric rval = EOPENTIMEOUT; 93764325Seric goto resetuid; 93853037Seric } 93968481Seric if (TimeOuts.to_fileopen > 0) 94068481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 94168481Seric else 94268481Seric ev = NULL; 94353037Seric 94463581Seric /* the input file must be marked safe */ 94568494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); 94664329Seric if (rval != 0) 94753037Seric { 94864325Seric /* don't use this :include: file */ 94957186Seric if (tTd(27, 4)) 95058247Seric printf("include: not safe (uid=%d): %s\n", 95164329Seric uid, errstring(rval)); 95253037Seric } 95365496Seric else 9544174Seric { 95565496Seric fp = fopen(fname, "r"); 95665496Seric if (fp == NULL) 95758061Seric { 95864329Seric rval = errno; 95965496Seric if (tTd(27, 4)) 96065496Seric printf("include: open: %s\n", errstring(rval)); 96158061Seric } 9624406Seric } 96368481Seric if (ev != NULL) 96468481Seric clrevent(ev); 96553037Seric 96664570Seric resetuid: 96764570Seric 96869638Seric #if HASSETREUID || USESETEUID 96964570Seric if (saveduid == 0) 97064570Seric { 97164570Seric if (uid != 0) 97268481Seric { 97369638Seric # if USESETEUID 97469638Seric if (seteuid(0) < 0) 97569638Seric syserr("seteuid(0) failure (real=%d, eff=%d)", 97669638Seric getuid(), geteuid()); 97769638Seric # else 97868481Seric if (setreuid(-1, 0) < 0) 97968481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 98068481Seric getuid(), geteuid()); 98168481Seric if (setreuid(RealUid, 0) < 0) 98264570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 98364570Seric RealUid, getuid(), geteuid()); 98469638Seric # endif 98568481Seric } 98664570Seric setgid(savedgid); 98764570Seric } 98864570Seric #endif 98964570Seric 99064570Seric if (tTd(27, 9)) 99164570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 99264570Seric 99365593Seric if (rval == EOPENTIMEOUT) 99465593Seric usrerr("451 open timeout on %s", fname); 99565593Seric 99664570Seric if (fp == NULL) 99764570Seric return rval; 99864570Seric 99965496Seric if (fstat(fileno(fp), &st) < 0) 100065496Seric { 100165496Seric rval = errno; 100265496Seric syserr("Cannot fstat %s!", fname); 100365496Seric return rval; 100465496Seric } 100565496Seric 100665948Seric #ifndef safechown 100765948Seric safechown = chownsafe(fileno(fp)); 100865948Seric #endif 100965909Seric if (ca == NULL && safechown) 101065496Seric { 101165496Seric ctladdr->q_uid = st.st_uid; 101265496Seric ctladdr->q_gid = st.st_gid; 101365496Seric ctladdr->q_flags |= QGOODUID; 101465496Seric } 101565496Seric if (ca != NULL && ca->q_uid == st.st_uid) 101665496Seric { 101765496Seric /* optimization -- avoid getpwuid if we already have info */ 101865496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 101965496Seric ctladdr->q_ruser = ca->q_ruser; 102065496Seric } 102165496Seric else 102265496Seric { 102365496Seric register struct passwd *pw; 102465496Seric 102568693Seric pw = sm_getpwuid(st.st_uid); 102668481Seric if (pw == NULL) 102768481Seric ctladdr->q_flags |= QBOGUSSHELL; 102868481Seric else 102968478Seric { 103068481Seric char *sh; 103168481Seric 103268478Seric ctladdr->q_ruser = newstr(pw->pw_name); 103368478Seric if (safechown) 103468478Seric sh = pw->pw_shell; 103565909Seric else 103668481Seric sh = "/SENDMAIL/ANY/SHELL/"; 103769894Seric if (!usershellok(pw->pw_name, sh)) 103868481Seric { 103968481Seric if (safechown) 104068481Seric ctladdr->q_flags |= QBOGUSSHELL; 104168481Seric else 104268481Seric ctladdr->q_flags |= QUNSAFEADDR; 104368481Seric } 104465496Seric } 104565496Seric } 104665496Seric 104758092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 104858092Seric { 104958092Seric /* don't do any more now */ 105058868Seric ctladdr->q_flags |= QVERIFIED; 105158884Seric e->e_nrcpts++; 105258680Seric xfclose(fp, "include", fname); 105364570Seric return rval; 105458092Seric } 105558092Seric 105665496Seric /* 105765496Seric ** Check to see if some bad guy can write this file 105865496Seric ** 105965496Seric ** This should really do something clever with group 106065496Seric ** permissions; currently we just view world writable 106165496Seric ** as unsafe. Also, we don't check for writable 106265496Seric ** directories in the path. We've got to leave 106365496Seric ** something for the local sysad to do. 106465496Seric */ 106565496Seric 106665496Seric if (bitset(S_IWOTH, st.st_mode)) 106765496Seric ctladdr->q_flags |= QUNSAFEADDR; 106865496Seric 10694174Seric /* read the file -- each line is a comma-separated list. */ 10709379Seric FileName = fname; 10719379Seric LineNumber = 0; 107258082Seric ctladdr->q_flags &= ~QSELFREF; 107358082Seric nincludes = 0; 10744174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10754174Seric { 107656795Seric register char *p = strchr(buf, '\n'); 10774174Seric 107840963Sbostic LineNumber++; 10794174Seric if (p != NULL) 10804174Seric *p = '\0'; 108157186Seric if (buf[0] == '#' || buf[0] == '\0') 108257139Seric continue; 108368787Seric 108468787Seric /* <sp>#@# introduces a comment anywhere */ 108568787Seric /* for Japanese character sets */ 108668787Seric for (p = buf; (p = strchr(++p, '#')) != NULL; ) 108768787Seric { 108868787Seric if (p[1] == '@' && p[2] == '#' && 108968787Seric isascii(p[-1]) && isspace(p[-1]) && 109069714Seric (p[3] == '\0' || (isascii(p[3]) && isspace(p[3])))) 109168787Seric { 109268787Seric p[-1] = '\0'; 109368787Seric break; 109468787Seric } 109568787Seric } 109668787Seric if (buf[0] == '\0') 109768787Seric continue; 109868787Seric 109958008Seric e->e_to = NULL; 110058151Seric message("%s to %s", 110153037Seric forwarding ? "forwarding" : "sending", buf); 110257977Seric #ifdef LOG 110358020Seric if (forwarding && LogLevel > 9) 110457977Seric syslog(LOG_INFO, "%s: forward %s => %s", 110566284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 110666284Seric oldto, buf); 110757977Seric #endif 110857977Seric 110968481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 11104174Seric } 111163902Seric 111263902Seric if (ferror(fp) && tTd(27, 3)) 111363902Seric printf("include: read error: %s\n", errstring(errno)); 111458082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 111558065Seric { 111658065Seric if (tTd(27, 5)) 111758065Seric { 111858065Seric printf("include: QDONTSEND "); 111958065Seric printaddr(ctladdr, FALSE); 112058065Seric } 112158065Seric ctladdr->q_flags |= QDONTSEND; 112258065Seric } 11234174Seric 112458680Seric (void) xfclose(fp, "include", fname); 11259379Seric FileName = oldfilename; 11269379Seric LineNumber = oldlinenumber; 112763847Seric e->e_to = oldto; 112864325Seric return rval; 11294174Seric } 113053037Seric 113168481Seric static void 113253037Seric includetimeout() 113353037Seric { 113453037Seric longjmp(CtxIncludeTimeout, 1); 113553037Seric } 11364324Seric /* 11374324Seric ** SENDTOARGV -- send to an argument vector. 11384324Seric ** 11394324Seric ** Parameters: 11404324Seric ** argv -- argument vector to send to. 114158247Seric ** e -- the current envelope. 11424324Seric ** 11434324Seric ** Returns: 11444324Seric ** none. 11454324Seric ** 11464324Seric ** Side Effects: 11474324Seric ** puts all addresses on the argument vector onto the 11484324Seric ** send queue. 11494324Seric */ 11504324Seric 115169748Seric void 115255012Seric sendtoargv(argv, e) 11534324Seric register char **argv; 115455012Seric register ENVELOPE *e; 11554324Seric { 11564324Seric register char *p; 11574324Seric 11584324Seric while ((p = *argv++) != NULL) 11594324Seric { 116068481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 11614324Seric } 11624324Seric } 11634399Seric /* 11644399Seric ** GETCTLADDR -- get controlling address from an address header. 11654399Seric ** 11664399Seric ** If none, get one corresponding to the effective userid. 11674399Seric ** 11684399Seric ** Parameters: 11694399Seric ** a -- the address to find the controller of. 11704399Seric ** 11714399Seric ** Returns: 11724399Seric ** the controlling address. 11734399Seric ** 11744399Seric ** Side Effects: 11754399Seric ** none. 11764399Seric */ 11774399Seric 11784399Seric ADDRESS * 11794399Seric getctladdr(a) 11804399Seric register ADDRESS *a; 11814399Seric { 11824404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11834399Seric a = a->q_alias; 11844399Seric return (a); 11854399Seric } 118669544Seric /* 118769544Seric ** SELF_REFERENCE -- check to see if an address references itself 118869544Seric ** 118969544Seric ** The check is done through a chain of aliases. If it is part of 119069544Seric ** a loop, break the loop at the "best" address, that is, the one 119169544Seric ** that exists as a real user. 119269544Seric ** 119369544Seric ** This is to handle the case of: 119469569Seric ** awc: Andrew.Chang 119569569Seric ** Andrew.Chang: awc@mail.server 119669544Seric ** which is a problem only on mail.server. 119769544Seric ** 119869544Seric ** Parameters: 119969544Seric ** a -- the address to check. 120069544Seric ** e -- the current envelope. 120169544Seric ** 120269544Seric ** Returns: 120369544Seric ** The address that should be retained. 120469544Seric */ 120569544Seric 120669544Seric ADDRESS * 120769544Seric self_reference(a, e) 120869544Seric ADDRESS *a; 120969544Seric ENVELOPE *e; 121069544Seric { 121169544Seric ADDRESS *b; /* top entry in self ref loop */ 121269544Seric ADDRESS *c; /* entry that point to a real mail box */ 121369544Seric 121469544Seric if (tTd(27, 1)) 121569544Seric printf("self_reference(%s)\n", a->q_paddr); 121669544Seric 121769544Seric for (b = a->q_alias; b != NULL; b = b->q_alias) 121869544Seric { 121969544Seric if (sameaddr(a, b)) 122069544Seric break; 122169544Seric } 122269544Seric 122369544Seric if (b == NULL) 122469544Seric { 122569544Seric if (tTd(27, 1)) 122669544Seric printf("\t... no self ref\n"); 122769544Seric return NULL; 122869544Seric } 122969544Seric 123069544Seric /* 123169544Seric ** Pick the first address that resolved to a real mail box 123269544Seric ** i.e has a pw entry. The returned value will be marked 123369544Seric ** QSELFREF in recipient(), which in turn will disable alias() 123469544Seric ** from marking it QDONTSEND, which mean it will be used 123569544Seric ** as a deliverable address. 123669544Seric ** 123769544Seric ** The 2 key thing to note here are: 123869544Seric ** 1) we are in a recursive call sequence: 123969544Seric ** alias->sentolist->recipient->alias 124069544Seric ** 2) normally, when we return back to alias(), the address 124169544Seric ** will be marked QDONTSEND, since alias() assumes the 124269544Seric ** expanded form will be used instead of the current address. 124369544Seric ** This behaviour is turned off if the address is marked 124469544Seric ** QSELFREF We set QSELFREF when we return to recipient(). 124569544Seric */ 124669544Seric 124769544Seric c = a; 124869544Seric while (c != NULL) 124969544Seric { 125069544Seric if (bitnset(M_HASPWENT, c->q_mailer->m_flags)) 125169544Seric { 125269544Seric if (tTd(27, 2)) 125369544Seric printf("\t... getpwnam(%s)... ", c->q_user); 125469544Seric if (sm_getpwnam(c->q_user) != NULL) 125569544Seric { 125669544Seric if (tTd(27, 2)) 125769544Seric printf("found\n"); 125869544Seric 125969544Seric /* ought to cache results here */ 126069621Seric if (sameaddr(b, c)) 126169621Seric return b; 126269621Seric else 126369621Seric return c; 126469544Seric } 126569544Seric if (tTd(27, 2)) 126669544Seric printf("failed\n"); 126769544Seric } 126869544Seric c = c->q_alias; 126969544Seric } 127069544Seric 127169544Seric if (tTd(27, 1)) 127269544Seric printf("\t... cannot break loop for \"%s\"\n", a->q_paddr); 127369544Seric 127469544Seric return NULL; 127569544Seric } 1276