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*68464Seric static char sccsid[] = "@(#)recipient.c 8.68 (Berkeley) 02/28/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*68464Seric ** aliaslevel -- the current alias nesting depth -- to 31*68464Seric ** 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*68464Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 424174Seric 43*68464Seric /* q_flags bits inherited from ctladdr */ 44*68464Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHAS_RET_PARAM|QRET_HDRS) 45*68464Seric 46*68464Seric int 47*68464Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 484174Seric char *list; 494399Seric ADDRESS *ctladdr; 505198Seric ADDRESS **sendq; 51*68464Seric 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 8968392Seric /* make sure we have enough space to copy the string */ 9068392Seric i = strlen(list) + 1; 9168392Seric if (i <= sizeof buf) 9268271Seric bufp = buf; 9368392Seric else 9468392Seric bufp = xalloc(i); 9568457Seric strcpy(bufp, denlstring(list, FALSE)); 9668271Seric 9768271Seric for (p = bufp; *p != '\0'; ) 9868271Seric { 9958333Seric auto char *delimptr; 1008081Seric register ADDRESS *a; 1014319Seric 1028081Seric /* parse the address */ 10358050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1044174Seric p++; 10564284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10658333Seric p = delimptr; 1079297Seric if (a == NULL) 1084174Seric continue; 1094324Seric a->q_next = al; 1104399Seric a->q_alias = ctladdr; 1114444Seric 1124444Seric /* see if this should be marked as a primary address */ 1134423Seric if (ctladdr == NULL || 1148081Seric (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 1154423Seric a->q_flags |= QPRIMARY; 1164444Seric 117*68464Seric /* arrange to inherit attributes from parent */ 118*68464Seric if (ctladdr != NULL) 119*68464Seric { 120*68464Seric /* self reference test */ 121*68464Seric if (sameaddr(ctladdr, a)) 122*68464Seric ctladdr->q_flags |= QSELFREF; 123*68464Seric 124*68464Seric /* full name */ 125*68464Seric if (a->q_fullname == NULL) 126*68464Seric a->q_fullname = ctladdr->q_fullname; 127*68464Seric 128*68464Seric /* various flag bits */ 129*68464Seric a->q_flags &= ~QINHERITEDBITS; 130*68464Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 131*68464Seric 132*68464Seric /* original recipient information */ 133*68464Seric a->q_orcpt = ctladdr->q_orcpt; 134*68464Seric } 135*68464Seric 13657731Seric al = a; 1374423Seric firstone = FALSE; 1384324Seric } 1394324Seric 1404324Seric /* arrange to send to everyone on the local send list */ 1414324Seric while (al != NULL) 1424324Seric { 1434324Seric register ADDRESS *a = al; 1444324Seric 1454324Seric al = a->q_next; 146*68464Seric a = recipient(a, sendq, aliaslevel, e); 14758082Seric naddrs++; 1484174Seric } 1494324Seric 15063847Seric e->e_to = oldto; 15168392Seric if (bufp != buf) 15268392Seric free(bufp); 15358082Seric return (naddrs); 1544174Seric } 1554174Seric /* 1564174Seric ** RECIPIENT -- Designate a message recipient 1574174Seric ** 1584174Seric ** Saves the named person for future mailing. 1594174Seric ** 1604174Seric ** Parameters: 1614174Seric ** a -- the (preparsed) address header for the recipient. 1625006Seric ** sendq -- a pointer to the head of a queue to put the 1635006Seric ** recipient in. Duplicate supression is done 1645006Seric ** in this queue. 165*68464Seric ** aliaslevel -- the current alias nesting depth. 16657731Seric ** e -- the current envelope. 1674174Seric ** 1684174Seric ** Returns: 16912613Seric ** The actual address in the queue. This will be "a" if 17012613Seric ** the address is not a duplicate, else the original address. 1714174Seric ** 1724174Seric ** Side Effects: 1734174Seric ** none. 1744174Seric */ 1754174Seric 17612613Seric ADDRESS * 177*68464Seric recipient(a, sendq, aliaslevel, e) 1784174Seric register ADDRESS *a; 1795006Seric register ADDRESS **sendq; 180*68464Seric int aliaslevel; 18155012Seric register ENVELOPE *e; 1824174Seric { 1834174Seric register ADDRESS *q; 1844319Seric ADDRESS **pq; 1854174Seric register struct mailer *m; 1869210Seric register char *p; 1879210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 18853735Seric int findusercount = 0; 189*68464Seric int i; 190*68464Seric char *buf; 191*68464Seric char buf0[MAXNAME]; /* unquoted image of the user name */ 19258247Seric extern int safefile(); 1934174Seric 19455012Seric e->e_to = a->q_paddr; 1954600Seric m = a->q_mailer; 1964174Seric errno = 0; 1977676Seric if (tTd(26, 1)) 1984444Seric { 1994444Seric printf("\nrecipient: "); 2004444Seric printaddr(a, FALSE); 2014444Seric } 2024174Seric 20364146Seric /* if this is primary, add it to the original recipient list */ 20464146Seric if (a->q_alias == NULL) 20564146Seric { 20664146Seric if (e->e_origrcpt == NULL) 20764146Seric e->e_origrcpt = a->q_paddr; 20864146Seric else if (e->e_origrcpt != a->q_paddr) 20964146Seric e->e_origrcpt = ""; 21064146Seric } 21164146Seric 2124174Seric /* break aliasing loops */ 213*68464Seric if (aliaslevel > MAXRCRSN) 2144174Seric { 215*68464Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 216*68464Seric aliaslevel, MAXRCRSN); 21712613Seric return (a); 2184174Seric } 2194174Seric 2204174Seric /* 2214627Seric ** Finish setting up address structure. 2224174Seric */ 2234174Seric 22416160Seric /* get unquoted user for file, program or user.name check */ 225*68464Seric i = strlen(a->q_user); 226*68464Seric if (i >= sizeof buf) 227*68464Seric buf = xalloc(i + 1); 228*68464Seric else 229*68464Seric buf = buf0; 2309210Seric (void) strcpy(buf, a->q_user); 2319210Seric for (p = buf; *p != '\0' && !quoted; p++) 2329210Seric { 23354993Seric if (*p == '\\') 2349210Seric quoted = TRUE; 2359210Seric } 23654983Seric stripquotes(buf); 2379210Seric 23857402Seric /* check for direct mailing to restricted mailers */ 23965496Seric if (m == ProgMailer) 2404174Seric { 24165496Seric if (a->q_alias == NULL) 24265496Seric { 24365496Seric a->q_flags |= QBADADDR; 24465496Seric usrerr("550 Cannot mail directly to programs"); 24565496Seric } 24665496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24765496Seric { 24865496Seric a->q_flags |= QBADADDR; 24965496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 25065496Seric a->q_alias->q_ruser, MyHostName); 25165496Seric } 25265496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25365496Seric { 25465496Seric a->q_flags |= QBADADDR; 25565496Seric usrerr("550 Address %s is unsafe for mailing to programs", 25665496Seric a->q_alias->q_paddr); 25765496Seric } 2584174Seric } 2594174Seric 2604174Seric /* 2614419Seric ** Look up this person in the recipient list. 2624419Seric ** If they are there already, return, otherwise continue. 2634419Seric ** If the list is empty, just add it. Notice the cute 2644419Seric ** hack to make from addresses suppress things correctly: 2654419Seric ** the QDONTSEND bit will be set in the send list. 2664419Seric ** [Please note: the emphasis is on "hack."] 2674174Seric */ 2684174Seric 2695006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2704174Seric { 27158294Seric if (sameaddr(q, a)) 2724174Seric { 2737676Seric if (tTd(26, 1)) 2744444Seric { 2754444Seric printf("%s in sendq: ", a->q_paddr); 2764444Seric printaddr(q, FALSE); 2774444Seric } 27865593Seric if (!bitset(QPRIMARY, q->q_flags)) 27958065Seric { 28065593Seric if (!bitset(QDONTSEND, a->q_flags)) 28158151Seric message("duplicate suppressed"); 28265593Seric q->q_flags |= a->q_flags; 28365593Seric } 28465593Seric else if (bitset(QSELFREF, q->q_flags)) 28565579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 28663847Seric a = q; 287*68464Seric goto done; 2884174Seric } 2894319Seric } 2904174Seric 2914319Seric /* add address on list */ 29258884Seric *pq = a; 29358884Seric a->q_next = NULL; 2944174Seric 2954174Seric /* 29657402Seric ** Alias the name and handle special mailer types. 2974174Seric */ 2984174Seric 29953735Seric trylocaluser: 30055354Seric if (tTd(29, 7)) 30155354Seric printf("at trylocaluser %s\n", a->q_user); 30255354Seric 30358680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30463847Seric goto testselfdestruct; 30557402Seric 30657402Seric if (m == InclMailer) 3074174Seric { 30857402Seric a->q_flags |= QDONTSEND; 30964761Seric if (a->q_alias == NULL) 3104174Seric { 31158680Seric a->q_flags |= QBADADDR; 31258151Seric usrerr("550 Cannot mail directly to :include:s"); 3134174Seric } 3144174Seric else 31550556Seric { 31659563Seric int ret; 31758247Seric 31858151Seric message("including file %s", a->q_user); 319*68464Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 32059563Seric if (transienterror(ret)) 32159563Seric { 32259563Seric #ifdef LOG 32359563Seric if (LogLevel > 2) 32466239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 32566284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 32666284Seric a->q_user, errstring(ret)); 32759563Seric #endif 32863853Seric a->q_flags |= QQUEUEUP; 32965215Seric a->q_flags &= ~QDONTSEND; 33059563Seric usrerr("451 Cannot open %s: %s", 33159563Seric a->q_user, errstring(ret)); 33259563Seric } 33359563Seric else if (ret != 0) 33459563Seric { 33563938Seric a->q_flags |= QBADADDR; 33659563Seric usrerr("550 Cannot open %s: %s", 33759563Seric a->q_user, errstring(ret)); 33859563Seric } 33950556Seric } 3404174Seric } 34157642Seric else if (m == FileMailer) 3424174Seric { 3434329Seric extern bool writable(); 3444174Seric 34551317Seric /* check if writable or creatable */ 34664761Seric if (a->q_alias == NULL) 3474174Seric { 34858680Seric a->q_flags |= QBADADDR; 34958151Seric usrerr("550 Cannot mail directly to files"); 3504174Seric } 35165496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 35265496Seric { 35365496Seric a->q_flags |= QBADADDR; 35465496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 35565496Seric a->q_alias->q_ruser, MyHostName); 35665496Seric } 35765496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 35865496Seric { 35965496Seric a->q_flags |= QBADADDR; 36065496Seric usrerr("550 Address %s is unsafe for mailing to files", 36165496Seric a->q_alias->q_paddr); 36265496Seric } 36365112Seric else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) 36451317Seric { 36558680Seric a->q_flags |= QBADADDR; 366*68464Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 367*68464Seric (time_t) 0, e); 36851317Seric } 36951317Seric } 37051317Seric 37157402Seric /* try aliasing */ 372*68464Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 373*68464Seric alias(a, sendq, aliaslevel, e); 37457402Seric 37557402Seric # ifdef USERDB 37657402Seric /* if not aliased, look it up in the user database */ 377*68464Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 378*68464Seric bitnset(M_CHECKUDB, m->m_flags)) 37957402Seric { 38057402Seric extern int udbexpand(); 38157402Seric 382*68464Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38357402Seric { 38463853Seric a->q_flags |= QQUEUEUP; 38557402Seric if (e->e_message == NULL) 38657402Seric e->e_message = newstr("Deferred: user database error"); 38757402Seric # ifdef LOG 38858020Seric if (LogLevel > 8) 38959623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 39066284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 39166284Seric errstring(errno)); 39257402Seric # endif 39359615Seric message("queued (user database error): %s", 39459615Seric errstring(errno)); 39557642Seric e->e_nrcpts++; 39663847Seric goto testselfdestruct; 39757402Seric } 39857402Seric } 39957402Seric # endif 40057402Seric 40151317Seric /* 40251317Seric ** If we have a level two config file, then pass the name through 40351317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 40451317Seric ** to send rewrite it to another mailer. This gives us a hook 40551317Seric ** after local aliasing has been done. 40651317Seric */ 40751317Seric 40851317Seric if (tTd(29, 5)) 40951317Seric { 41051317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 41151317Seric ConfigLevel, RewriteRules[5]); 41251317Seric printaddr(a, FALSE); 41351317Seric } 414*68464Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 415*68464Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 416*68464Seric bitnset(M_TRYRULESET5, m->m_flags)) 41751317Seric { 418*68464Seric maplocaluser(a, sendq, aliaslevel, e); 41951317Seric } 42051317Seric 42151317Seric /* 42251317Seric ** If it didn't get rewritten to another mailer, go ahead 42351317Seric ** and deliver it. 42451317Seric */ 42551317Seric 426*68464Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 427*68464Seric bitnset(M_HASPWENT, m->m_flags)) 42851317Seric { 42955354Seric auto bool fuzzy; 43051317Seric register struct passwd *pw; 43151317Seric extern struct passwd *finduser(); 43251317Seric 43351317Seric /* warning -- finduser may trash buf */ 43455354Seric pw = finduser(buf, &fuzzy); 43551317Seric if (pw == NULL) 43651317Seric { 43758680Seric a->q_flags |= QBADADDR; 438*68464Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 439*68464Seric (time_t) 0, e); 44051317Seric } 4414174Seric else 4424174Seric { 44351317Seric char nbuf[MAXNAME]; 4444373Seric 44555354Seric if (fuzzy) 4464174Seric { 44753735Seric /* name was a fuzzy match */ 44851317Seric a->q_user = newstr(pw->pw_name); 44953735Seric if (findusercount++ > 3) 45053735Seric { 45158680Seric a->q_flags |= QBADADDR; 45258151Seric usrerr("554 aliasing/forwarding loop for %s broken", 45353735Seric pw->pw_name); 454*68464Seric goto done; 45553735Seric } 45653735Seric 45753735Seric /* see if it aliases */ 45851317Seric (void) strcpy(buf, pw->pw_name); 45953735Seric goto trylocaluser; 4604174Seric } 46165822Seric if (strcmp(pw->pw_dir, "/") == 0) 46265822Seric a->q_home = ""; 46365822Seric else 46465822Seric a->q_home = newstr(pw->pw_dir); 46551317Seric a->q_uid = pw->pw_uid; 46651317Seric a->q_gid = pw->pw_gid; 46759083Seric a->q_ruser = newstr(pw->pw_name); 46851317Seric a->q_flags |= QGOODUID; 46951317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 47051317Seric if (nbuf[0] != '\0') 47151317Seric a->q_fullname = newstr(nbuf); 47265211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 47365211Seric !usershellok(pw->pw_shell)) 47465206Seric { 47565211Seric a->q_flags |= QBOGUSSHELL; 47665206Seric } 47751317Seric if (!quoted) 478*68464Seric forward(a, sendq, aliaslevel, e); 4794174Seric } 4804174Seric } 48157642Seric if (!bitset(QDONTSEND, a->q_flags)) 48257642Seric e->e_nrcpts++; 48363847Seric 48463847Seric testselfdestruct: 48563978Seric if (tTd(26, 8)) 48663847Seric { 48763978Seric printf("testselfdestruct: "); 48863978Seric printaddr(a, TRUE); 48963978Seric } 49063978Seric if (a->q_alias == NULL && a != &e->e_from && 49163978Seric bitset(QDONTSEND, a->q_flags)) 49263978Seric { 49363978Seric q = *sendq; 49463965Seric while (q != NULL && bitset(QDONTSEND, q->q_flags)) 49563847Seric q = q->q_next; 49663978Seric if (q == NULL) 49763847Seric { 49863847Seric a->q_flags |= QBADADDR; 49963847Seric usrerr("554 aliasing/forwarding loop broken"); 50063847Seric } 50163847Seric } 502*68464Seric 503*68464Seric done: 504*68464Seric if (buf != buf0) 505*68464Seric free(buf); 50612613Seric return (a); 5074174Seric } 5084174Seric /* 5094373Seric ** FINDUSER -- find the password entry for a user. 5104373Seric ** 5114373Seric ** This looks a lot like getpwnam, except that it may want to 5124373Seric ** do some fancier pattern matching in /etc/passwd. 5134373Seric ** 5149379Seric ** This routine contains most of the time of many sendmail runs. 5159379Seric ** It deserves to be optimized. 5169379Seric ** 5174373Seric ** Parameters: 5184373Seric ** name -- the name to match against. 51955354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 52055354Seric ** was found using the fuzzy matching algorithm; 52155354Seric ** set to FALSE otherwise. 5224373Seric ** 5234373Seric ** Returns: 5244373Seric ** A pointer to a pw struct. 5254373Seric ** NULL if name is unknown or ambiguous. 5264373Seric ** 5274373Seric ** Side Effects: 5284407Seric ** may modify name. 5294373Seric */ 5304373Seric 5314373Seric struct passwd * 53255354Seric finduser(name, fuzzyp) 5334373Seric char *name; 53455354Seric bool *fuzzyp; 5354373Seric { 5364376Seric register struct passwd *pw; 5374407Seric register char *p; 53815325Seric extern struct passwd *getpwent(); 53915325Seric extern struct passwd *getpwnam(); 5404373Seric 54155354Seric if (tTd(29, 4)) 54255354Seric printf("finduser(%s): ", name); 54355354Seric 54455354Seric *fuzzyp = FALSE; 5454407Seric 546*68464Seric #ifdef HESIOD 54764673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 54864673Seric for (p = name; *p != '\0'; p++) 54964673Seric if (!isascii(*p) || !isdigit(*p)) 55064673Seric break; 55164673Seric if (*p == '\0') 55264673Seric { 55364673Seric if (tTd(29, 4)) 55464673Seric printf("failed (numeric input)\n"); 55564673Seric return NULL; 55664673Seric } 557*68464Seric #endif 55864673Seric 55925777Seric /* look up this login name using fast path */ 56012634Seric if ((pw = getpwnam(name)) != NULL) 56155354Seric { 56255354Seric if (tTd(29, 4)) 56355354Seric printf("found (non-fuzzy)\n"); 56412634Seric return (pw); 56555354Seric } 56612634Seric 56753735Seric #ifdef MATCHGECOS 56853735Seric /* see if fuzzy matching allowed */ 56953735Seric if (!MatchGecos) 57055354Seric { 57155354Seric if (tTd(29, 4)) 57255354Seric printf("not found (fuzzy disabled)\n"); 57353735Seric return NULL; 57455354Seric } 57553735Seric 57612634Seric /* search for a matching full name instead */ 57725777Seric for (p = name; *p != '\0'; p++) 57825777Seric { 57925777Seric if (*p == (SpaceSub & 0177) || *p == '_') 58025777Seric *p = ' '; 58125777Seric } 58223107Seric (void) setpwent(); 5834376Seric while ((pw = getpwent()) != NULL) 5844376Seric { 5854998Seric char buf[MAXNAME]; 5864376Seric 5874998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 58856795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 5894381Seric { 59055354Seric if (tTd(29, 4)) 59155354Seric printf("fuzzy matches %s\n", pw->pw_name); 59258151Seric message("sending to login name %s", pw->pw_name); 59355354Seric *fuzzyp = TRUE; 5944376Seric return (pw); 5954377Seric } 5964376Seric } 59755354Seric if (tTd(29, 4)) 59855354Seric printf("no fuzzy match found\n"); 59959015Seric #else 60059015Seric if (tTd(29, 4)) 60159015Seric printf("not found (fuzzy disabled)\n"); 60259015Seric #endif 6034376Seric return (NULL); 6044373Seric } 6054373Seric /* 6064329Seric ** WRITABLE -- predicate returning if the file is writable. 6074329Seric ** 6084329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6094329Seric ** Unfortunately, we cannot use the access call since we 6104329Seric ** won't necessarily be the real uid when we try to 6114329Seric ** actually open the file. 6124329Seric ** 6134329Seric ** Notice that ANY file with ANY execute bit is automatically 6144329Seric ** not writable. This is also enforced by mailfile. 6154329Seric ** 6164329Seric ** Parameters: 61765064Seric ** filename -- the file name to check. 61865112Seric ** ctladdr -- the controlling address for this file. 61965064Seric ** flags -- SFF_* flags to control the function. 6204329Seric ** 6214329Seric ** Returns: 6224329Seric ** TRUE -- if we will be able to write this file. 6234329Seric ** FALSE -- if we cannot write this file. 6244329Seric ** 6254329Seric ** Side Effects: 6264329Seric ** none. 6274329Seric */ 6284329Seric 6294329Seric bool 63065112Seric writable(filename, ctladdr, flags) 63164819Seric char *filename; 63265112Seric ADDRESS *ctladdr; 63365064Seric int flags; 6344329Seric { 63555372Seric uid_t euid; 63655372Seric gid_t egid; 6374329Seric int bits; 63864944Seric register char *p; 63964944Seric char *uname; 64064944Seric struct stat stb; 64164944Seric extern char RealUserName[]; 6424329Seric 64364819Seric if (tTd(29, 5)) 64465064Seric printf("writable(%s, %x)\n", filename, flags); 64564944Seric 64664944Seric #ifdef HASLSTAT 64765064Seric if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) 64865064Seric : stat(filename, &stb)) < 0) 64964944Seric #else 65064944Seric if (stat(filename, &stb) < 0) 65164944Seric #endif 65264944Seric { 65364944Seric /* file does not exist -- see if directory is safe */ 65464944Seric p = strrchr(filename, '/'); 65564944Seric if (p == NULL) 65664944Seric { 65765067Seric errno = ENOTDIR; 65864944Seric return FALSE; 65964944Seric } 66065067Seric *p = '\0'; 66165067Seric errno = safefile(filename, RealUid, RealGid, RealUserName, 66265067Seric SFF_MUSTOWN, S_IWRITE|S_IEXEC); 66364944Seric *p = '/'; 66465067Seric return errno == 0; 66564944Seric } 66664944Seric 66765225Seric #ifdef SUID_ROOT_FILES_OK 66865225Seric /* really ought to be passed down -- and not a good idea */ 66965225Seric flags |= SFF_ROOTOK; 67065225Seric #endif 67165225Seric 67264944Seric /* 67364944Seric ** File does exist -- check that it is writable. 67464944Seric */ 67564944Seric 67664944Seric if (bitset(0111, stb.st_mode)) 67765022Seric { 67865022Seric if (tTd(29, 5)) 67965022Seric printf("failed (mode %o: x bits)\n", stb.st_mode); 68065067Seric errno = EPERM; 6814329Seric return (FALSE); 68265022Seric } 68364944Seric 68465112Seric if (ctladdr != NULL && geteuid() == 0) 68564944Seric { 68665112Seric euid = ctladdr->q_uid; 68765112Seric egid = ctladdr->q_gid; 68865112Seric uname = ctladdr->q_user; 68964944Seric } 690*68464Seric #ifdef RUN_AS_REAL_UID 69165112Seric else 69265112Seric { 69365112Seric euid = RealUid; 69465112Seric egid = RealGid; 69565112Seric uname = RealUserName; 69665112Seric } 697*68464Seric #else 698*68464Seric else if (FileMailer != NULL) 699*68464Seric { 700*68464Seric euid = FileMailer->m_uid; 701*68464Seric egid = FileMailer->m_gid; 702*68464Seric } 703*68464Seric else 704*68464Seric { 705*68464Seric euid = egid = 0; 706*68464Seric } 707*68464Seric #endif 70865138Seric if (euid == 0) 70965138Seric { 71065138Seric euid = DefUid; 71165138Seric uname = DefUser; 71265138Seric } 71365138Seric if (egid == 0) 71465138Seric egid = DefGid; 7154329Seric if (geteuid() == 0) 7164329Seric { 71765225Seric if (bitset(S_ISUID, stb.st_mode) && 71865225Seric (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) 71964944Seric { 72064944Seric euid = stb.st_uid; 72164944Seric uname = NULL; 72264944Seric } 72365225Seric if (bitset(S_ISGID, stb.st_mode) && 72465225Seric (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) 72564944Seric egid = stb.st_gid; 7264329Seric } 7274329Seric 72864819Seric if (tTd(29, 5)) 72964819Seric printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", 73064944Seric euid, egid, stb.st_uid, stb.st_gid); 73164819Seric 73265067Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); 73365067Seric return errno == 0; 7344329Seric } 7354329Seric /* 7364174Seric ** INCLUDE -- handle :include: specification. 7374174Seric ** 7384174Seric ** Parameters: 7394174Seric ** fname -- filename to include. 74053037Seric ** forwarding -- if TRUE, we are reading a .forward file. 74153037Seric ** if FALSE, it's a :include: file. 7424399Seric ** ctladdr -- address template to use to fill in these 7434399Seric ** addresses -- effective user/group id are 7444399Seric ** the important things. 7455006Seric ** sendq -- a pointer to the head of the send queue 7465006Seric ** to put these addresses in. 747*68464Seric ** aliaslevel -- the alias nesting depth. 748*68464Seric ** e -- the current envelope. 7494174Seric ** 7504174Seric ** Returns: 75157136Seric ** open error status 7524174Seric ** 7534174Seric ** Side Effects: 7544174Seric ** reads the :include: file and sends to everyone 7554174Seric ** listed in that file. 75665909Seric ** 75765909Seric ** Security Note: 75865909Seric ** If you have restricted chown (that is, you can't 75965909Seric ** give a file away), it is reasonable to allow programs 76065909Seric ** and files called from this :include: file to be to be 76165909Seric ** run as the owner of the :include: file. This is bogus 76265909Seric ** if there is any chance of someone giving away a file. 76365909Seric ** We assume that pre-POSIX systems can give away files. 76465909Seric ** 76565909Seric ** There is an additional restriction that if you 76665909Seric ** forward to a :include: file, it will not take on 76765909Seric ** the ownership of the :include: file. This may not 76865909Seric ** be necessary, but shouldn't hurt. 7694174Seric */ 7704174Seric 77153037Seric static jmp_buf CtxIncludeTimeout; 772*68464Seric static void includetimeout(); 77353037Seric 77465496Seric #ifndef S_IWOTH 77565496Seric # define S_IWOTH (S_IWRITE >> 6) 77665496Seric #endif 77765496Seric 77857136Seric int 779*68464Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7804174Seric char *fname; 78153037Seric bool forwarding; 7824399Seric ADDRESS *ctladdr; 7835006Seric ADDRESS **sendq; 784*68464Seric int aliaslevel; 78555012Seric ENVELOPE *e; 7864174Seric { 787*68464Seric FILE *fp = NULL; 78855012Seric char *oldto = e->e_to; 7899379Seric char *oldfilename = FileName; 7909379Seric int oldlinenumber = LineNumber; 79153037Seric register EVENT *ev = NULL; 79258082Seric int nincludes; 79364325Seric register ADDRESS *ca; 79464325Seric uid_t saveduid, uid; 79564325Seric gid_t savedgid, gid; 79664083Seric char *uname; 79764325Seric int rval = 0; 79865064Seric int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; 79965496Seric struct stat st; 80065948Seric char buf[MAXLINE]; 80165909Seric #ifdef _POSIX_CHOWN_RESTRICTED 80265948Seric # if _POSIX_CHOWN_RESTRICTED == -1 80365948Seric # define safechown FALSE 80465948Seric # else 80565948Seric # define safechown TRUE 80665948Seric # endif 80765948Seric #else 80865948Seric # ifdef _PC_CHOWN_RESTRICTED 80965909Seric bool safechown; 81065948Seric # else 81165948Seric # ifdef BSD 81265948Seric # define safechown TRUE 81365948Seric # else 81465948Seric # define safechown FALSE 81565948Seric # endif 81665948Seric # endif 81765909Seric #endif 81865948Seric extern bool chownsafe(); 8194174Seric 82057186Seric if (tTd(27, 2)) 82157186Seric printf("include(%s)\n", fname); 82263902Seric if (tTd(27, 4)) 82363902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 82463581Seric if (tTd(27, 14)) 82563581Seric { 82663581Seric printf("ctladdr "); 82763581Seric printaddr(ctladdr, FALSE); 82863581Seric } 82957186Seric 83064325Seric if (tTd(27, 9)) 83164325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 83253037Seric 83363581Seric ca = getctladdr(ctladdr); 83463581Seric if (ca == NULL) 83564083Seric { 83664846Seric uid = DefUid; 83764846Seric gid = DefGid; 83864846Seric uname = DefUser; 83964083Seric } 84063581Seric else 84164083Seric { 84263581Seric uid = ca->q_uid; 84364083Seric gid = ca->q_gid; 84464083Seric uname = ca->q_user; 845*68464Seric } 84664325Seric #ifdef HASSETREUID 847*68464Seric saveduid = geteuid(); 848*68464Seric savedgid = getegid(); 849*68464Seric if (saveduid == 0) 850*68464Seric { 851*68464Seric initgroups(uname, gid); 852*68464Seric if (uid != 0) 85364325Seric { 854*68464Seric if (setreuid(0, uid) < 0) 855*68464Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 856*68464Seric uid, getuid(), geteuid()); 857*68464Seric else 858*68464Seric sfflags |= SFF_NOPATHCHECK; 85964325Seric } 860*68464Seric } 86168457Seric #endif 86263581Seric 86364325Seric if (tTd(27, 9)) 86464325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 86564325Seric 86664325Seric /* 86764325Seric ** If home directory is remote mounted but server is down, 86864325Seric ** this can hang or give errors; use a timeout to avoid this 86964325Seric */ 87064325Seric 87153037Seric if (setjmp(CtxIncludeTimeout) != 0) 87253037Seric { 87363853Seric ctladdr->q_flags |= QQUEUEUP; 87453037Seric errno = 0; 87563993Seric 87663993Seric /* return pseudo-error code */ 87764325Seric rval = EOPENTIMEOUT; 87864325Seric goto resetuid; 87953037Seric } 880*68464Seric if (TimeOuts.to_fileopen > 0) 881*68464Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 882*68464Seric else 883*68464Seric ev = NULL; 88453037Seric 88563581Seric /* the input file must be marked safe */ 88664944Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); 88764329Seric if (rval != 0) 88853037Seric { 88964325Seric /* don't use this :include: file */ 89057186Seric if (tTd(27, 4)) 89158247Seric printf("include: not safe (uid=%d): %s\n", 89264329Seric uid, errstring(rval)); 89353037Seric } 89465496Seric else 8954174Seric { 89665496Seric fp = fopen(fname, "r"); 89765496Seric if (fp == NULL) 89858061Seric { 89964329Seric rval = errno; 90065496Seric if (tTd(27, 4)) 90165496Seric printf("include: open: %s\n", errstring(rval)); 90258061Seric } 9034406Seric } 904*68464Seric if (ev != NULL) 905*68464Seric clrevent(ev); 90653037Seric 90764570Seric resetuid: 90864570Seric 90964570Seric #ifdef HASSETREUID 91064570Seric if (saveduid == 0) 91164570Seric { 91264570Seric if (uid != 0) 913*68464Seric { 914*68464Seric if (setreuid(-1, 0) < 0) 915*68464Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 916*68464Seric getuid(), geteuid()); 917*68464Seric if (setreuid(RealUid, 0) < 0) 91864570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 91964570Seric RealUid, getuid(), geteuid()); 920*68464Seric } 92164570Seric setgid(savedgid); 92264570Seric } 92364570Seric #endif 92464570Seric 92564570Seric if (tTd(27, 9)) 92664570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 92764570Seric 92865593Seric if (rval == EOPENTIMEOUT) 92965593Seric usrerr("451 open timeout on %s", fname); 93065593Seric 93164570Seric if (fp == NULL) 93264570Seric return rval; 93364570Seric 93465496Seric if (fstat(fileno(fp), &st) < 0) 93565496Seric { 93665496Seric rval = errno; 93765496Seric syserr("Cannot fstat %s!", fname); 93865496Seric return rval; 93965496Seric } 94065496Seric 94165948Seric #ifndef safechown 94265948Seric safechown = chownsafe(fileno(fp)); 94365948Seric #endif 94465909Seric if (ca == NULL && safechown) 94565496Seric { 94665496Seric ctladdr->q_uid = st.st_uid; 94765496Seric ctladdr->q_gid = st.st_gid; 94865496Seric ctladdr->q_flags |= QGOODUID; 94965496Seric } 95065496Seric if (ca != NULL && ca->q_uid == st.st_uid) 95165496Seric { 95265496Seric /* optimization -- avoid getpwuid if we already have info */ 95365496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 95465496Seric ctladdr->q_ruser = ca->q_ruser; 95565496Seric } 95665496Seric else 95765496Seric { 95865496Seric register struct passwd *pw; 95965496Seric 96065496Seric pw = getpwuid(st.st_uid); 961*68464Seric if (pw == NULL) 962*68464Seric ctladdr->q_flags |= QBOGUSSHELL; 963*68464Seric else 96468457Seric { 965*68464Seric char *sh; 966*68464Seric 96768457Seric ctladdr->q_ruser = newstr(pw->pw_name); 96868457Seric if (safechown) 96968457Seric sh = pw->pw_shell; 97065909Seric else 971*68464Seric sh = "/SENDMAIL/ANY/SHELL/"; 972*68464Seric if (!usershellok(sh)) 973*68464Seric { 974*68464Seric if (safechown) 975*68464Seric ctladdr->q_flags |= QBOGUSSHELL; 976*68464Seric else 977*68464Seric ctladdr->q_flags |= QUNSAFEADDR; 978*68464Seric } 97965496Seric } 98065496Seric } 98165496Seric 98258092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 98358092Seric { 98458092Seric /* don't do any more now */ 98558868Seric ctladdr->q_flags |= QVERIFIED; 98658884Seric e->e_nrcpts++; 98758680Seric xfclose(fp, "include", fname); 98864570Seric return rval; 98958092Seric } 99058092Seric 99165496Seric /* 99265496Seric ** Check to see if some bad guy can write this file 99365496Seric ** 99465496Seric ** This should really do something clever with group 99565496Seric ** permissions; currently we just view world writable 99665496Seric ** as unsafe. Also, we don't check for writable 99765496Seric ** directories in the path. We've got to leave 99865496Seric ** something for the local sysad to do. 99965496Seric */ 100065496Seric 100165496Seric if (bitset(S_IWOTH, st.st_mode)) 100265496Seric ctladdr->q_flags |= QUNSAFEADDR; 100365496Seric 10044174Seric /* read the file -- each line is a comma-separated list. */ 10059379Seric FileName = fname; 10069379Seric LineNumber = 0; 100758082Seric ctladdr->q_flags &= ~QSELFREF; 100858082Seric nincludes = 0; 10094174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10104174Seric { 101156795Seric register char *p = strchr(buf, '\n'); 10124174Seric 101340963Sbostic LineNumber++; 10144174Seric if (p != NULL) 10154174Seric *p = '\0'; 101657186Seric if (buf[0] == '#' || buf[0] == '\0') 101757139Seric continue; 101858008Seric e->e_to = NULL; 101958151Seric message("%s to %s", 102053037Seric forwarding ? "forwarding" : "sending", buf); 102157977Seric #ifdef LOG 102258020Seric if (forwarding && LogLevel > 9) 102357977Seric syslog(LOG_INFO, "%s: forward %s => %s", 102466284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 102566284Seric oldto, buf); 102657977Seric #endif 102757977Seric 1028*68464Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10294174Seric } 103063902Seric 103163902Seric if (ferror(fp) && tTd(27, 3)) 103263902Seric printf("include: read error: %s\n", errstring(errno)); 103358082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 103458065Seric { 103558065Seric if (tTd(27, 5)) 103658065Seric { 103758065Seric printf("include: QDONTSEND "); 103858065Seric printaddr(ctladdr, FALSE); 103958065Seric } 104058065Seric ctladdr->q_flags |= QDONTSEND; 104158065Seric } 10424174Seric 104358680Seric (void) xfclose(fp, "include", fname); 10449379Seric FileName = oldfilename; 10459379Seric LineNumber = oldlinenumber; 104663847Seric e->e_to = oldto; 104764325Seric return rval; 10484174Seric } 104953037Seric 1050*68464Seric static void 105153037Seric includetimeout() 105253037Seric { 105353037Seric longjmp(CtxIncludeTimeout, 1); 105453037Seric } 10554324Seric /* 10564324Seric ** SENDTOARGV -- send to an argument vector. 10574324Seric ** 10584324Seric ** Parameters: 10594324Seric ** argv -- argument vector to send to. 106058247Seric ** e -- the current envelope. 10614324Seric ** 10624324Seric ** Returns: 10634324Seric ** none. 10644324Seric ** 10654324Seric ** Side Effects: 10664324Seric ** puts all addresses on the argument vector onto the 10674324Seric ** send queue. 10684324Seric */ 10694324Seric 107055012Seric sendtoargv(argv, e) 10714324Seric register char **argv; 107255012Seric register ENVELOPE *e; 10734324Seric { 10744324Seric register char *p; 10754324Seric 10764324Seric while ((p = *argv++) != NULL) 10774324Seric { 1078*68464Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 10794324Seric } 10804324Seric } 10814399Seric /* 10824399Seric ** GETCTLADDR -- get controlling address from an address header. 10834399Seric ** 10844399Seric ** If none, get one corresponding to the effective userid. 10854399Seric ** 10864399Seric ** Parameters: 10874399Seric ** a -- the address to find the controller of. 10884399Seric ** 10894399Seric ** Returns: 10904399Seric ** the controlling address. 10914399Seric ** 10924399Seric ** Side Effects: 10934399Seric ** none. 10944399Seric */ 10954399Seric 10964399Seric ADDRESS * 10974399Seric getctladdr(a) 10984399Seric register ADDRESS *a; 10994399Seric { 11004404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11014399Seric a = a->q_alias; 11024399Seric return (a); 11034399Seric } 1104