122710Sdist /* 234921Sbostic * Copyright (c) 1983 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*68393Seric static char sccsid[] = "@(#)recipient.c 8.65 (Berkeley) 02/20/95"; 1133731Sbostic #endif /* not lint */ 1222710Sdist 1358332Seric # include "sendmail.h" 144174Seric # include <pwd.h> 154174Seric 164174Seric /* 179622Seric ** SENDTOLIST -- Designate a send list. 184174Seric ** 194174Seric ** The parameter is a comma-separated list of people to send to. 204174Seric ** This routine arranges to send to all of them. 214174Seric ** 224174Seric ** Parameters: 234174Seric ** list -- the send list. 244399Seric ** ctladdr -- the address template for the person to 254399Seric ** send to -- effective uid/gid are important. 265006Seric ** This is typically the alias that caused this 275006Seric ** expansion. 285006Seric ** sendq -- a pointer to the head of a queue to put 295006Seric ** these people into. 30*68393Seric ** aliaslevel -- the current alias nesting depth -- to 31*68393Seric ** diagnose loops. 3258247Seric ** e -- the envelope in which to add these recipients. 334174Seric ** 344174Seric ** Returns: 3558082Seric ** The number of addresses actually on the list. 364174Seric ** 374174Seric ** Side Effects: 384174Seric ** none. 394174Seric */ 404174Seric 41*68393Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 424174Seric 43*68393Seric /* q_flags bits inherited from ctladdr */ 44*68393Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHAS_RET_PARAM|QRET_HDRS) 45*68393Seric 46*68393Seric int 47*68393Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 484174Seric char *list; 494399Seric ADDRESS *ctladdr; 505198Seric ADDRESS **sendq; 51*68393Seric int aliaslevel; 5255012Seric register ENVELOPE *e; 534174Seric { 544174Seric register char *p; 558223Seric register ADDRESS *al; /* list of addresses to send to */ 564423Seric bool firstone; /* set on first address sent */ 5711446Seric char delimiter; /* the address delimiter */ 5858082Seric int naddrs; 5968392Seric int i; 6063847Seric char *oldto = e->e_to; 6168392Seric char *bufp; 6268271Seric char buf[MAXNAME + 1]; 634174Seric 6464131Seric if (list == NULL) 6564131Seric { 6664131Seric syserr("sendtolist: null list"); 6764131Seric return 0; 6864131Seric } 6964131Seric 707676Seric if (tTd(25, 1)) 714444Seric { 724444Seric printf("sendto: %s\n ctladdr=", list); 734444Seric printaddr(ctladdr, FALSE); 744444Seric } 754324Seric 768223Seric /* heuristic to determine old versus new style addresses */ 778230Seric if (ctladdr == NULL && 7856795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 7956795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 8055012Seric e->e_flags &= ~EF_OLDSTYLE; 8111446Seric delimiter = ' '; 8255012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 8311446Seric delimiter = ','; 848223Seric 854423Seric firstone = TRUE; 864324Seric al = NULL; 8758082Seric naddrs = 0; 888223Seric 89*68393Seric if (bufp == NULL) 9068392Seric /* make sure we have enough space to copy the string */ 9168392Seric i = strlen(list) + 1; 9268392Seric if (i <= sizeof buf) 9368271Seric bufp = buf; 9468392Seric else 9568392Seric bufp = xalloc(i); 9668392Seric strcpy(bufp, denlstring(list)); 9768271Seric 9868271Seric for (p = bufp; *p != '\0'; ) 9968271Seric { 10058333Seric auto char *delimptr; 1018081Seric register ADDRESS *a; 1024319Seric 1038081Seric /* parse the address */ 10458050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1054174Seric p++; 10664284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10758333Seric p = delimptr; 1089297Seric if (a == NULL) 1094174Seric continue; 1104324Seric a->q_next = al; 1114399Seric a->q_alias = ctladdr; 1124444Seric 1134444Seric /* see if this should be marked as a primary address */ 1144423Seric if (ctladdr == NULL || 1158081Seric (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 1164423Seric a->q_flags |= QPRIMARY; 1174444Seric 118*68393Seric /* arrange to inherit attributes from parent */ 119*68393Seric if (ctladdr != NULL) 120*68393Seric { 121*68393Seric /* self reference test */ 122*68393Seric if (sameaddr(ctladdr, a)) 123*68393Seric ctladdr->q_flags |= QSELFREF; 124*68393Seric 125*68393Seric /* full name */ 126*68393Seric if (a->q_fullname == NULL) 127*68393Seric a->q_fullname = ctladdr->q_fullname; 128*68393Seric 129*68393Seric /* various flag bits */ 130*68393Seric a->q_flags &= ~QINHERITEDBITS; 131*68393Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 132*68393Seric 133*68393Seric /* original recipient information */ 134*68393Seric a->q_orcpt = ctladdr->q_orcpt; 135*68393Seric } 136*68393Seric 13757731Seric al = a; 1384423Seric firstone = FALSE; 1394324Seric } 1404324Seric 1414324Seric /* arrange to send to everyone on the local send list */ 1424324Seric while (al != NULL) 1434324Seric { 1444324Seric register ADDRESS *a = al; 1454324Seric 1464324Seric al = a->q_next; 147*68393Seric a = recipient(a, sendq, aliaslevel, e); 14858082Seric naddrs++; 1494174Seric } 1504324Seric 15163847Seric e->e_to = oldto; 15268392Seric if (bufp != buf) 15368392Seric free(bufp); 15458082Seric return (naddrs); 1554174Seric } 1564174Seric /* 1574174Seric ** RECIPIENT -- Designate a message recipient 1584174Seric ** 1594174Seric ** Saves the named person for future mailing. 1604174Seric ** 1614174Seric ** Parameters: 1624174Seric ** a -- the (preparsed) address header for the recipient. 1635006Seric ** sendq -- a pointer to the head of a queue to put the 1645006Seric ** recipient in. Duplicate supression is done 1655006Seric ** in this queue. 166*68393Seric ** aliaslevel -- the current alias nesting depth. 16757731Seric ** e -- the current envelope. 1684174Seric ** 1694174Seric ** Returns: 17012613Seric ** The actual address in the queue. This will be "a" if 17112613Seric ** the address is not a duplicate, else the original address. 1724174Seric ** 1734174Seric ** Side Effects: 1744174Seric ** none. 1754174Seric */ 1764174Seric 17712613Seric ADDRESS * 178*68393Seric recipient(a, sendq, aliaslevel, e) 1794174Seric register ADDRESS *a; 1805006Seric register ADDRESS **sendq; 181*68393Seric int aliaslevel; 18255012Seric register ENVELOPE *e; 1834174Seric { 1844174Seric register ADDRESS *q; 1854319Seric ADDRESS **pq; 1864174Seric register struct mailer *m; 1879210Seric register char *p; 1889210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 18953735Seric int findusercount = 0; 190*68393Seric int i; 191*68393Seric char *buf; 192*68393Seric char buf0[MAXNAME]; /* unquoted image of the user name */ 19358247Seric extern int safefile(); 1944174Seric 19555012Seric e->e_to = a->q_paddr; 1964600Seric m = a->q_mailer; 1974174Seric errno = 0; 1987676Seric if (tTd(26, 1)) 1994444Seric { 2004444Seric printf("\nrecipient: "); 2014444Seric printaddr(a, FALSE); 2024444Seric } 2034174Seric 20464146Seric /* if this is primary, add it to the original recipient list */ 20564146Seric if (a->q_alias == NULL) 20664146Seric { 20764146Seric if (e->e_origrcpt == NULL) 20864146Seric e->e_origrcpt = a->q_paddr; 20964146Seric else if (e->e_origrcpt != a->q_paddr) 21064146Seric e->e_origrcpt = ""; 21164146Seric } 21264146Seric 2134174Seric /* break aliasing loops */ 214*68393Seric if (aliaslevel > MAXRCRSN) 2154174Seric { 216*68393Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 217*68393Seric aliaslevel, MAXRCRSN); 21812613Seric return (a); 2194174Seric } 2204174Seric 2214174Seric /* 2224627Seric ** Finish setting up address structure. 2234174Seric */ 2244174Seric 22516160Seric /* get unquoted user for file, program or user.name check */ 226*68393Seric i = strlen(a->q_user); 227*68393Seric if (i >= sizeof buf) 228*68393Seric buf = xalloc(i + 1); 229*68393Seric else 230*68393Seric buf = buf0; 2319210Seric (void) strcpy(buf, a->q_user); 2329210Seric for (p = buf; *p != '\0' && !quoted; p++) 2339210Seric { 23454993Seric if (*p == '\\') 2359210Seric quoted = TRUE; 2369210Seric } 23754983Seric stripquotes(buf); 2389210Seric 23957402Seric /* check for direct mailing to restricted mailers */ 24065496Seric if (m == ProgMailer) 2414174Seric { 24265496Seric if (a->q_alias == NULL) 24365496Seric { 24465496Seric a->q_flags |= QBADADDR; 24565496Seric usrerr("550 Cannot mail directly to programs"); 24665496Seric } 24765496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24865496Seric { 24965496Seric a->q_flags |= QBADADDR; 25065496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 25165496Seric a->q_alias->q_ruser, MyHostName); 25265496Seric } 25365496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25465496Seric { 25565496Seric a->q_flags |= QBADADDR; 25665496Seric usrerr("550 Address %s is unsafe for mailing to programs", 25765496Seric a->q_alias->q_paddr); 25865496Seric } 2594174Seric } 2604174Seric 2614174Seric /* 2624419Seric ** Look up this person in the recipient list. 2634419Seric ** If they are there already, return, otherwise continue. 2644419Seric ** If the list is empty, just add it. Notice the cute 2654419Seric ** hack to make from addresses suppress things correctly: 2664419Seric ** the QDONTSEND bit will be set in the send list. 2674419Seric ** [Please note: the emphasis is on "hack."] 2684174Seric */ 2694174Seric 2705006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2714174Seric { 27258294Seric if (sameaddr(q, a)) 2734174Seric { 2747676Seric if (tTd(26, 1)) 2754444Seric { 2764444Seric printf("%s in sendq: ", a->q_paddr); 2774444Seric printaddr(q, FALSE); 2784444Seric } 27965593Seric if (!bitset(QPRIMARY, q->q_flags)) 28058065Seric { 28165593Seric if (!bitset(QDONTSEND, a->q_flags)) 28258151Seric message("duplicate suppressed"); 28365593Seric q->q_flags |= a->q_flags; 28465593Seric } 28565593Seric else if (bitset(QSELFREF, q->q_flags)) 28665579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 28763847Seric a = q; 288*68393Seric goto done; 2894174Seric } 2904319Seric } 2914174Seric 2924319Seric /* add address on list */ 29358884Seric *pq = a; 29458884Seric a->q_next = NULL; 2954174Seric 2964174Seric /* 29757402Seric ** Alias the name and handle special mailer types. 2984174Seric */ 2994174Seric 30053735Seric trylocaluser: 30155354Seric if (tTd(29, 7)) 30255354Seric printf("at trylocaluser %s\n", a->q_user); 30355354Seric 30458680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30563847Seric goto testselfdestruct; 30657402Seric 30757402Seric if (m == InclMailer) 3084174Seric { 30957402Seric a->q_flags |= QDONTSEND; 31064761Seric if (a->q_alias == NULL) 3114174Seric { 31258680Seric a->q_flags |= QBADADDR; 31358151Seric usrerr("550 Cannot mail directly to :include:s"); 3144174Seric } 3154174Seric else 31650556Seric { 31759563Seric int ret; 31858247Seric 31958151Seric message("including file %s", a->q_user); 320*68393Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 32159563Seric if (transienterror(ret)) 32259563Seric { 32359563Seric #ifdef LOG 32459563Seric if (LogLevel > 2) 32566239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 32666284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 32766284Seric a->q_user, errstring(ret)); 32859563Seric #endif 32963853Seric a->q_flags |= QQUEUEUP; 33065215Seric a->q_flags &= ~QDONTSEND; 33159563Seric usrerr("451 Cannot open %s: %s", 33259563Seric a->q_user, errstring(ret)); 33359563Seric } 33459563Seric else if (ret != 0) 33559563Seric { 33663938Seric a->q_flags |= QBADADDR; 33759563Seric usrerr("550 Cannot open %s: %s", 33859563Seric a->q_user, errstring(ret)); 33959563Seric } 34050556Seric } 3414174Seric } 34257642Seric else if (m == FileMailer) 3434174Seric { 3444329Seric extern bool writable(); 3454174Seric 34651317Seric /* check if writable or creatable */ 34764761Seric if (a->q_alias == NULL) 3484174Seric { 34958680Seric a->q_flags |= QBADADDR; 35058151Seric usrerr("550 Cannot mail directly to files"); 3514174Seric } 35265496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 35365496Seric { 35465496Seric a->q_flags |= QBADADDR; 35565496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 35665496Seric a->q_alias->q_ruser, MyHostName); 35765496Seric } 35865496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 35965496Seric { 36065496Seric a->q_flags |= QBADADDR; 36165496Seric usrerr("550 Address %s is unsafe for mailing to files", 36265496Seric a->q_alias->q_paddr); 36365496Seric } 36465112Seric else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) 36551317Seric { 36658680Seric a->q_flags |= QBADADDR; 367*68393Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 368*68393Seric (time_t) 0, e); 36951317Seric } 37051317Seric } 37151317Seric 37257402Seric /* try aliasing */ 373*68393Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 374*68393Seric alias(a, sendq, aliaslevel, e); 37557402Seric 37657402Seric # ifdef USERDB 37757402Seric /* if not aliased, look it up in the user database */ 378*68393Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 379*68393Seric bitnset(M_CHECKUDB, m->m_flags)) 38057402Seric { 38157402Seric extern int udbexpand(); 38257402Seric 383*68393Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38457402Seric { 38563853Seric a->q_flags |= QQUEUEUP; 38657402Seric if (e->e_message == NULL) 38757402Seric e->e_message = newstr("Deferred: user database error"); 38857402Seric # ifdef LOG 38958020Seric if (LogLevel > 8) 39059623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 39166284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 39266284Seric errstring(errno)); 39357402Seric # endif 39459615Seric message("queued (user database error): %s", 39559615Seric errstring(errno)); 39657642Seric e->e_nrcpts++; 39763847Seric goto testselfdestruct; 39857402Seric } 39957402Seric } 40057402Seric # endif 40157402Seric 40251317Seric /* 40351317Seric ** If we have a level two config file, then pass the name through 40451317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 40551317Seric ** to send rewrite it to another mailer. This gives us a hook 40651317Seric ** after local aliasing has been done. 40751317Seric */ 40851317Seric 40951317Seric if (tTd(29, 5)) 41051317Seric { 41151317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 41251317Seric ConfigLevel, RewriteRules[5]); 41351317Seric printaddr(a, FALSE); 41451317Seric } 415*68393Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 416*68393Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 417*68393Seric bitnset(M_TRYRULESET5, m->m_flags)) 41851317Seric { 419*68393Seric maplocaluser(a, sendq, aliaslevel, e); 42051317Seric } 42151317Seric 42251317Seric /* 42351317Seric ** If it didn't get rewritten to another mailer, go ahead 42451317Seric ** and deliver it. 42551317Seric */ 42651317Seric 427*68393Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 428*68393Seric bitnset(M_HASPWENT, m->m_flags)) 42951317Seric { 43055354Seric auto bool fuzzy; 43151317Seric register struct passwd *pw; 43251317Seric extern struct passwd *finduser(); 43351317Seric 43451317Seric /* warning -- finduser may trash buf */ 43555354Seric pw = finduser(buf, &fuzzy); 43651317Seric if (pw == NULL) 43751317Seric { 43858680Seric a->q_flags |= QBADADDR; 439*68393Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 440*68393Seric (time_t) 0, e); 44151317Seric } 4424174Seric else 4434174Seric { 44451317Seric char nbuf[MAXNAME]; 4454373Seric 44655354Seric if (fuzzy) 4474174Seric { 44853735Seric /* name was a fuzzy match */ 44951317Seric a->q_user = newstr(pw->pw_name); 45053735Seric if (findusercount++ > 3) 45153735Seric { 45258680Seric a->q_flags |= QBADADDR; 45358151Seric usrerr("554 aliasing/forwarding loop for %s broken", 45453735Seric pw->pw_name); 455*68393Seric goto done; 45653735Seric } 45753735Seric 45853735Seric /* see if it aliases */ 45951317Seric (void) strcpy(buf, pw->pw_name); 46053735Seric goto trylocaluser; 4614174Seric } 46265822Seric if (strcmp(pw->pw_dir, "/") == 0) 46365822Seric a->q_home = ""; 46465822Seric else 46565822Seric a->q_home = newstr(pw->pw_dir); 46651317Seric a->q_uid = pw->pw_uid; 46751317Seric a->q_gid = pw->pw_gid; 46859083Seric a->q_ruser = newstr(pw->pw_name); 46951317Seric a->q_flags |= QGOODUID; 47051317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 47151317Seric if (nbuf[0] != '\0') 47251317Seric a->q_fullname = newstr(nbuf); 47365211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 47465211Seric !usershellok(pw->pw_shell)) 47565206Seric { 47665211Seric a->q_flags |= QBOGUSSHELL; 47765206Seric } 47851317Seric if (!quoted) 479*68393Seric forward(a, sendq, aliaslevel, e); 4804174Seric } 4814174Seric } 48257642Seric if (!bitset(QDONTSEND, a->q_flags)) 48357642Seric e->e_nrcpts++; 48463847Seric 48563847Seric testselfdestruct: 48663978Seric if (tTd(26, 8)) 48763847Seric { 48863978Seric printf("testselfdestruct: "); 48963978Seric printaddr(a, TRUE); 49063978Seric } 49163978Seric if (a->q_alias == NULL && a != &e->e_from && 49263978Seric bitset(QDONTSEND, a->q_flags)) 49363978Seric { 49463978Seric q = *sendq; 49563965Seric while (q != NULL && bitset(QDONTSEND, q->q_flags)) 49663847Seric q = q->q_next; 49763978Seric if (q == NULL) 49863847Seric { 49963847Seric a->q_flags |= QBADADDR; 50063847Seric usrerr("554 aliasing/forwarding loop broken"); 50163847Seric } 50263847Seric } 503*68393Seric 504*68393Seric done: 505*68393Seric if (buf != buf0) 506*68393Seric free(buf); 50712613Seric return (a); 5084174Seric } 5094174Seric /* 5104373Seric ** FINDUSER -- find the password entry for a user. 5114373Seric ** 5124373Seric ** This looks a lot like getpwnam, except that it may want to 5134373Seric ** do some fancier pattern matching in /etc/passwd. 5144373Seric ** 5159379Seric ** This routine contains most of the time of many sendmail runs. 5169379Seric ** It deserves to be optimized. 5179379Seric ** 5184373Seric ** Parameters: 5194373Seric ** name -- the name to match against. 52055354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 52155354Seric ** was found using the fuzzy matching algorithm; 52255354Seric ** set to FALSE otherwise. 5234373Seric ** 5244373Seric ** Returns: 5254373Seric ** A pointer to a pw struct. 5264373Seric ** NULL if name is unknown or ambiguous. 5274373Seric ** 5284373Seric ** Side Effects: 5294407Seric ** may modify name. 5304373Seric */ 5314373Seric 5324373Seric struct passwd * 53355354Seric finduser(name, fuzzyp) 5344373Seric char *name; 53555354Seric bool *fuzzyp; 5364373Seric { 5374376Seric register struct passwd *pw; 5384407Seric register char *p; 53915325Seric extern struct passwd *getpwent(); 54015325Seric extern struct passwd *getpwnam(); 5414373Seric 54255354Seric if (tTd(29, 4)) 54355354Seric printf("finduser(%s): ", name); 54455354Seric 54555354Seric *fuzzyp = FALSE; 5464407Seric 547*68393Seric #ifdef HESIOD 54864673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 54964673Seric for (p = name; *p != '\0'; p++) 55064673Seric if (!isascii(*p) || !isdigit(*p)) 55164673Seric break; 55264673Seric if (*p == '\0') 55364673Seric { 55464673Seric if (tTd(29, 4)) 55564673Seric printf("failed (numeric input)\n"); 55664673Seric return NULL; 55764673Seric } 558*68393Seric #endif 55964673Seric 56025777Seric /* look up this login name using fast path */ 56112634Seric if ((pw = getpwnam(name)) != NULL) 56255354Seric { 56355354Seric if (tTd(29, 4)) 56455354Seric printf("found (non-fuzzy)\n"); 56512634Seric return (pw); 56655354Seric } 56712634Seric 56853735Seric #ifdef MATCHGECOS 56953735Seric /* see if fuzzy matching allowed */ 57053735Seric if (!MatchGecos) 57155354Seric { 57255354Seric if (tTd(29, 4)) 57355354Seric printf("not found (fuzzy disabled)\n"); 57453735Seric return NULL; 57555354Seric } 57653735Seric 57712634Seric /* search for a matching full name instead */ 57825777Seric for (p = name; *p != '\0'; p++) 57925777Seric { 58025777Seric if (*p == (SpaceSub & 0177) || *p == '_') 58125777Seric *p = ' '; 58225777Seric } 58323107Seric (void) setpwent(); 5844376Seric while ((pw = getpwent()) != NULL) 5854376Seric { 5864998Seric char buf[MAXNAME]; 5874376Seric 5884998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 58956795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 5904381Seric { 59155354Seric if (tTd(29, 4)) 59255354Seric printf("fuzzy matches %s\n", pw->pw_name); 59358151Seric message("sending to login name %s", pw->pw_name); 59455354Seric *fuzzyp = TRUE; 5954376Seric return (pw); 5964377Seric } 5974376Seric } 59855354Seric if (tTd(29, 4)) 59955354Seric printf("no fuzzy match found\n"); 60059015Seric #else 60159015Seric if (tTd(29, 4)) 60259015Seric printf("not found (fuzzy disabled)\n"); 60359015Seric #endif 6044376Seric return (NULL); 6054373Seric } 6064373Seric /* 6074329Seric ** WRITABLE -- predicate returning if the file is writable. 6084329Seric ** 6094329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6104329Seric ** Unfortunately, we cannot use the access call since we 6114329Seric ** won't necessarily be the real uid when we try to 6124329Seric ** actually open the file. 6134329Seric ** 6144329Seric ** Notice that ANY file with ANY execute bit is automatically 6154329Seric ** not writable. This is also enforced by mailfile. 6164329Seric ** 6174329Seric ** Parameters: 61865064Seric ** filename -- the file name to check. 61965112Seric ** ctladdr -- the controlling address for this file. 62065064Seric ** flags -- SFF_* flags to control the function. 6214329Seric ** 6224329Seric ** Returns: 6234329Seric ** TRUE -- if we will be able to write this file. 6244329Seric ** FALSE -- if we cannot write this file. 6254329Seric ** 6264329Seric ** Side Effects: 6274329Seric ** none. 6284329Seric */ 6294329Seric 6304329Seric bool 63165112Seric writable(filename, ctladdr, flags) 63264819Seric char *filename; 63365112Seric ADDRESS *ctladdr; 63465064Seric int flags; 6354329Seric { 63655372Seric uid_t euid; 63755372Seric gid_t egid; 6384329Seric int bits; 63964944Seric register char *p; 64064944Seric char *uname; 64164944Seric struct stat stb; 64264944Seric extern char RealUserName[]; 6434329Seric 64464819Seric if (tTd(29, 5)) 64565064Seric printf("writable(%s, %x)\n", filename, flags); 64664944Seric 64764944Seric #ifdef HASLSTAT 64865064Seric if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) 64965064Seric : stat(filename, &stb)) < 0) 65064944Seric #else 65164944Seric if (stat(filename, &stb) < 0) 65264944Seric #endif 65364944Seric { 65464944Seric /* file does not exist -- see if directory is safe */ 65564944Seric p = strrchr(filename, '/'); 65664944Seric if (p == NULL) 65764944Seric { 65865067Seric errno = ENOTDIR; 65964944Seric return FALSE; 66064944Seric } 66165067Seric *p = '\0'; 66265067Seric errno = safefile(filename, RealUid, RealGid, RealUserName, 66365067Seric SFF_MUSTOWN, S_IWRITE|S_IEXEC); 66464944Seric *p = '/'; 66565067Seric return errno == 0; 66664944Seric } 66764944Seric 66865225Seric #ifdef SUID_ROOT_FILES_OK 66965225Seric /* really ought to be passed down -- and not a good idea */ 67065225Seric flags |= SFF_ROOTOK; 67165225Seric #endif 67265225Seric 67364944Seric /* 67464944Seric ** File does exist -- check that it is writable. 67564944Seric */ 67664944Seric 67764944Seric if (bitset(0111, stb.st_mode)) 67865022Seric { 67965022Seric if (tTd(29, 5)) 68065022Seric printf("failed (mode %o: x bits)\n", stb.st_mode); 68165067Seric errno = EPERM; 6824329Seric return (FALSE); 68365022Seric } 68464944Seric 68565112Seric if (ctladdr != NULL && geteuid() == 0) 68664944Seric { 68765112Seric euid = ctladdr->q_uid; 68865112Seric egid = ctladdr->q_gid; 68965112Seric uname = ctladdr->q_user; 69064944Seric } 691*68393Seric #ifdef RUN_AS_REAL_UID 69265112Seric else 69365112Seric { 69465112Seric euid = RealUid; 69565112Seric egid = RealGid; 69665112Seric uname = RealUserName; 69765112Seric } 698*68393Seric #else 699*68393Seric else if (FileMailer != NULL) 700*68393Seric { 701*68393Seric euid = FileMailer->m_uid; 702*68393Seric egid = FileMailer->m_gid; 703*68393Seric } 704*68393Seric else 705*68393Seric { 706*68393Seric euid = egid = 0; 707*68393Seric } 708*68393Seric #endif 70965138Seric if (euid == 0) 71065138Seric { 71165138Seric euid = DefUid; 71265138Seric uname = DefUser; 71365138Seric } 71465138Seric if (egid == 0) 71565138Seric egid = DefGid; 7164329Seric if (geteuid() == 0) 7174329Seric { 71865225Seric if (bitset(S_ISUID, stb.st_mode) && 71965225Seric (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) 72064944Seric { 72164944Seric euid = stb.st_uid; 72264944Seric uname = NULL; 72364944Seric } 72465225Seric if (bitset(S_ISGID, stb.st_mode) && 72565225Seric (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) 72664944Seric egid = stb.st_gid; 7274329Seric } 7284329Seric 72964819Seric if (tTd(29, 5)) 73064819Seric printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", 73164944Seric euid, egid, stb.st_uid, stb.st_gid); 73264819Seric 73365067Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); 73465067Seric return errno == 0; 7354329Seric } 7364329Seric /* 7374174Seric ** INCLUDE -- handle :include: specification. 7384174Seric ** 7394174Seric ** Parameters: 7404174Seric ** fname -- filename to include. 74153037Seric ** forwarding -- if TRUE, we are reading a .forward file. 74253037Seric ** if FALSE, it's a :include: file. 7434399Seric ** ctladdr -- address template to use to fill in these 7444399Seric ** addresses -- effective user/group id are 7454399Seric ** the important things. 7465006Seric ** sendq -- a pointer to the head of the send queue 7475006Seric ** to put these addresses in. 748*68393Seric ** aliaslevel -- the alias nesting depth. 749*68393Seric ** e -- the current envelope. 7504174Seric ** 7514174Seric ** Returns: 75257136Seric ** open error status 7534174Seric ** 7544174Seric ** Side Effects: 7554174Seric ** reads the :include: file and sends to everyone 7564174Seric ** listed in that file. 75765909Seric ** 75865909Seric ** Security Note: 75965909Seric ** If you have restricted chown (that is, you can't 76065909Seric ** give a file away), it is reasonable to allow programs 76165909Seric ** and files called from this :include: file to be to be 76265909Seric ** run as the owner of the :include: file. This is bogus 76365909Seric ** if there is any chance of someone giving away a file. 76465909Seric ** We assume that pre-POSIX systems can give away files. 76565909Seric ** 76665909Seric ** There is an additional restriction that if you 76765909Seric ** forward to a :include: file, it will not take on 76865909Seric ** the ownership of the :include: file. This may not 76965909Seric ** be necessary, but shouldn't hurt. 7704174Seric */ 7714174Seric 77253037Seric static jmp_buf CtxIncludeTimeout; 77363937Seric static int includetimeout(); 77453037Seric 77565496Seric #ifndef S_IWOTH 77665496Seric # define S_IWOTH (S_IWRITE >> 6) 77765496Seric #endif 77865496Seric 77957136Seric int 780*68393Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7814174Seric char *fname; 78253037Seric bool forwarding; 7834399Seric ADDRESS *ctladdr; 7845006Seric ADDRESS **sendq; 785*68393Seric int aliaslevel; 78655012Seric ENVELOPE *e; 7874174Seric { 78864570Seric register FILE *fp = NULL; 78955012Seric char *oldto = e->e_to; 7909379Seric char *oldfilename = FileName; 7919379Seric int oldlinenumber = LineNumber; 79253037Seric register EVENT *ev = NULL; 79358082Seric int nincludes; 79464325Seric register ADDRESS *ca; 79564325Seric uid_t saveduid, uid; 79664325Seric gid_t savedgid, gid; 79764083Seric char *uname; 79864325Seric int rval = 0; 79965064Seric int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; 80065496Seric struct stat st; 80165948Seric char buf[MAXLINE]; 80265909Seric #ifdef _POSIX_CHOWN_RESTRICTED 80365948Seric # if _POSIX_CHOWN_RESTRICTED == -1 80465948Seric # define safechown FALSE 80565948Seric # else 80665948Seric # define safechown TRUE 80765948Seric # endif 80865948Seric #else 80965948Seric # ifdef _PC_CHOWN_RESTRICTED 81065909Seric bool safechown; 81165948Seric # else 81265948Seric # ifdef BSD 81365948Seric # define safechown TRUE 81465948Seric # else 81565948Seric # define safechown FALSE 81665948Seric # endif 81765948Seric # endif 81865909Seric #endif 81965948Seric extern bool chownsafe(); 8204174Seric 82157186Seric if (tTd(27, 2)) 82257186Seric printf("include(%s)\n", fname); 82363902Seric if (tTd(27, 4)) 82463902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 82563581Seric if (tTd(27, 14)) 82663581Seric { 82763581Seric printf("ctladdr "); 82863581Seric printaddr(ctladdr, FALSE); 82963581Seric } 83057186Seric 83164325Seric if (tTd(27, 9)) 83264325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 83353037Seric 83463581Seric ca = getctladdr(ctladdr); 83563581Seric if (ca == NULL) 83664083Seric { 83764846Seric uid = DefUid; 83864846Seric gid = DefGid; 83964846Seric uname = DefUser; 84064083Seric } 84163581Seric else 84264083Seric { 84363581Seric uid = ca->q_uid; 84464083Seric gid = ca->q_gid; 84564083Seric uname = ca->q_user; 846*68393Seric } 84764325Seric #ifdef HASSETREUID 848*68393Seric saveduid = geteuid(); 849*68393Seric savedgid = getegid(); 850*68393Seric if (saveduid == 0) 851*68393Seric { 852*68393Seric initgroups(uname, gid); 853*68393Seric if (uid != 0) 85464325Seric { 855*68393Seric if (setreuid(0, uid) < 0) 856*68393Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 857*68393Seric uid, getuid(), geteuid()); 858*68393Seric else 859*68393Seric sfflags |= SFF_NOPATHCHECK; 86064325Seric } 861*68393Seric } 86268392Seric #endif 86363581Seric 86464325Seric if (tTd(27, 9)) 86564325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 86664325Seric 86764325Seric /* 86864325Seric ** If home directory is remote mounted but server is down, 86964325Seric ** this can hang or give errors; use a timeout to avoid this 87064325Seric */ 87164325Seric 87253037Seric if (setjmp(CtxIncludeTimeout) != 0) 87353037Seric { 87463853Seric ctladdr->q_flags |= QQUEUEUP; 87553037Seric errno = 0; 87663993Seric 87763993Seric /* return pseudo-error code */ 87864325Seric rval = EOPENTIMEOUT; 87964325Seric goto resetuid; 88053037Seric } 881*68393Seric if (TimeOuts.to_fileopen > 0) 882*68393Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 883*68393Seric else 884*68393Seric ev = NULL; 88553037Seric 88663581Seric /* the input file must be marked safe */ 88764944Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); 88864329Seric if (rval != 0) 88953037Seric { 89064325Seric /* don't use this :include: file */ 89157186Seric if (tTd(27, 4)) 89258247Seric printf("include: not safe (uid=%d): %s\n", 89364329Seric uid, errstring(rval)); 89453037Seric } 89565496Seric else 8964174Seric { 89765496Seric fp = fopen(fname, "r"); 89865496Seric if (fp == NULL) 89958061Seric { 90064329Seric rval = errno; 90165496Seric if (tTd(27, 4)) 90265496Seric printf("include: open: %s\n", errstring(rval)); 90358061Seric } 9044406Seric } 905*68393Seric if (ev != NULL) 906*68393Seric clrevent(ev); 90753037Seric 90864570Seric resetuid: 90964570Seric 91064570Seric #ifdef HASSETREUID 91164570Seric if (saveduid == 0) 91264570Seric { 91364570Seric if (uid != 0) 914*68393Seric { 915*68393Seric if (setreuid(-1, 0) < 0) 916*68393Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 917*68393Seric getuid(), geteuid()); 918*68393Seric if (setreuid(RealUid, 0) < 0) 91964570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 92064570Seric RealUid, getuid(), geteuid()); 921*68393Seric } 92264570Seric setgid(savedgid); 92364570Seric } 92464570Seric #endif 92564570Seric 92664570Seric if (tTd(27, 9)) 92764570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 92864570Seric 92965593Seric if (rval == EOPENTIMEOUT) 93065593Seric usrerr("451 open timeout on %s", fname); 93165593Seric 93264570Seric if (fp == NULL) 93364570Seric return rval; 93464570Seric 93565496Seric if (fstat(fileno(fp), &st) < 0) 93665496Seric { 93765496Seric rval = errno; 93865496Seric syserr("Cannot fstat %s!", fname); 93965496Seric return rval; 94065496Seric } 94165496Seric 94265948Seric #ifndef safechown 94365948Seric safechown = chownsafe(fileno(fp)); 94465948Seric #endif 94565909Seric if (ca == NULL && safechown) 94665496Seric { 94765496Seric ctladdr->q_uid = st.st_uid; 94865496Seric ctladdr->q_gid = st.st_gid; 94965496Seric ctladdr->q_flags |= QGOODUID; 95065496Seric } 95165496Seric if (ca != NULL && ca->q_uid == st.st_uid) 95265496Seric { 95365496Seric /* optimization -- avoid getpwuid if we already have info */ 95465496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 95565496Seric ctladdr->q_ruser = ca->q_ruser; 95665496Seric } 95765496Seric else 95865496Seric { 95965496Seric register struct passwd *pw; 96065496Seric 96165496Seric pw = getpwuid(st.st_uid); 962*68393Seric if (pw == NULL) 963*68393Seric ctladdr->q_flags |= QBOGUSSHELL; 964*68393Seric else 96568392Seric { 966*68393Seric char *sh; 967*68393Seric 96868392Seric ctladdr->q_ruser = newstr(pw->pw_name); 96968392Seric if (safechown) 97068392Seric sh = pw->pw_shell; 97165909Seric else 972*68393Seric sh = "/SENDMAIL/ANY/SHELL/"; 973*68393Seric if (!usershellok(sh)) 974*68393Seric { 975*68393Seric if (safechown) 976*68393Seric ctladdr->q_flags |= QBOGUSSHELL; 977*68393Seric else 978*68393Seric ctladdr->q_flags |= QUNSAFEADDR; 979*68393Seric } 98065496Seric } 98165496Seric } 98265496Seric 98358092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 98458092Seric { 98558092Seric /* don't do any more now */ 98658868Seric ctladdr->q_flags |= QVERIFIED; 98758884Seric e->e_nrcpts++; 98858680Seric xfclose(fp, "include", fname); 98964570Seric return rval; 99058092Seric } 99158092Seric 99265496Seric /* 99365496Seric ** Check to see if some bad guy can write this file 99465496Seric ** 99565496Seric ** This should really do something clever with group 99665496Seric ** permissions; currently we just view world writable 99765496Seric ** as unsafe. Also, we don't check for writable 99865496Seric ** directories in the path. We've got to leave 99965496Seric ** something for the local sysad to do. 100065496Seric */ 100165496Seric 100265496Seric if (bitset(S_IWOTH, st.st_mode)) 100365496Seric ctladdr->q_flags |= QUNSAFEADDR; 100465496Seric 10054174Seric /* read the file -- each line is a comma-separated list. */ 10069379Seric FileName = fname; 10079379Seric LineNumber = 0; 100858082Seric ctladdr->q_flags &= ~QSELFREF; 100958082Seric nincludes = 0; 10104174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10114174Seric { 101256795Seric register char *p = strchr(buf, '\n'); 10134174Seric 101440963Sbostic LineNumber++; 10154174Seric if (p != NULL) 10164174Seric *p = '\0'; 101757186Seric if (buf[0] == '#' || buf[0] == '\0') 101857139Seric continue; 101958008Seric e->e_to = NULL; 102058151Seric message("%s to %s", 102153037Seric forwarding ? "forwarding" : "sending", buf); 102257977Seric #ifdef LOG 102358020Seric if (forwarding && LogLevel > 9) 102457977Seric syslog(LOG_INFO, "%s: forward %s => %s", 102566284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 102666284Seric oldto, buf); 102757977Seric #endif 102857977Seric 1029*68393Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10304174Seric } 103163902Seric 103263902Seric if (ferror(fp) && tTd(27, 3)) 103363902Seric printf("include: read error: %s\n", errstring(errno)); 103458082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 103558065Seric { 103658065Seric if (tTd(27, 5)) 103758065Seric { 103858065Seric printf("include: QDONTSEND "); 103958065Seric printaddr(ctladdr, FALSE); 104058065Seric } 104158065Seric ctladdr->q_flags |= QDONTSEND; 104258065Seric } 10434174Seric 104458680Seric (void) xfclose(fp, "include", fname); 10459379Seric FileName = oldfilename; 10469379Seric LineNumber = oldlinenumber; 104763847Seric e->e_to = oldto; 104864325Seric return rval; 10494174Seric } 105053037Seric 105153037Seric static 105253037Seric includetimeout() 105353037Seric { 105453037Seric longjmp(CtxIncludeTimeout, 1); 105553037Seric } 10564324Seric /* 10574324Seric ** SENDTOARGV -- send to an argument vector. 10584324Seric ** 10594324Seric ** Parameters: 10604324Seric ** argv -- argument vector to send to. 106158247Seric ** e -- the current envelope. 10624324Seric ** 10634324Seric ** Returns: 10644324Seric ** none. 10654324Seric ** 10664324Seric ** Side Effects: 10674324Seric ** puts all addresses on the argument vector onto the 10684324Seric ** send queue. 10694324Seric */ 10704324Seric 107155012Seric sendtoargv(argv, e) 10724324Seric register char **argv; 107355012Seric register ENVELOPE *e; 10744324Seric { 10754324Seric register char *p; 10764324Seric 10774324Seric while ((p = *argv++) != NULL) 10784324Seric { 1079*68393Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 10804324Seric } 10814324Seric } 10824399Seric /* 10834399Seric ** GETCTLADDR -- get controlling address from an address header. 10844399Seric ** 10854399Seric ** If none, get one corresponding to the effective userid. 10864399Seric ** 10874399Seric ** Parameters: 10884399Seric ** a -- the address to find the controller of. 10894399Seric ** 10904399Seric ** Returns: 10914399Seric ** the controlling address. 10924399Seric ** 10934399Seric ** Side Effects: 10944399Seric ** none. 10954399Seric */ 10964399Seric 10974399Seric ADDRESS * 10984399Seric getctladdr(a) 10994399Seric register ADDRESS *a; 11004399Seric { 11014404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11024399Seric a = a->q_alias; 11034399Seric return (a); 11044399Seric } 1105