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*68285Seric static char sccsid[] = "@(#)recipient.c 8.63 (Berkeley) 02/11/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. 3068284Seric ** aliaslevel -- the current alias nesting depth -- to 3168284Seric ** 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 4168284Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 424174Seric 4368284Seric /* q_flags bits inherited from ctladdr */ 4468284Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHAS_RET_PARAM|QRET_HDRS) 4568284Seric 4668284Seric int 4768284Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 484174Seric char *list; 494399Seric ADDRESS *ctladdr; 505198Seric ADDRESS **sendq; 5168284Seric 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; 5963847Seric char *oldto = e->e_to; 6068271Seric static char *bufp = NULL; 6168271Seric static int buflen; 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 8968271Seric if (buf == NULL) 904174Seric { 9168271Seric bufp = buf; 9268271Seric buflen = sizeof buf - 1; 9368271Seric } 9468271Seric if (strlen(list) > buflen) 9568271Seric { 9668271Seric /* allocate additional space */ 9768271Seric if (bufp != buf) 9868271Seric free(bufp); 9968271Seric buflen = strlen(list); 10068271Seric bufp = malloc(buflen + 1); 10168271Seric } 10268271Seric strcpy(bufp, list); 10368271Seric 10468271Seric for (p = bufp; *p != '\0'; ) 10568271Seric { 10658333Seric auto char *delimptr; 1078081Seric register ADDRESS *a; 1084319Seric 1098081Seric /* parse the address */ 11058050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1114174Seric p++; 11264284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 11358333Seric p = delimptr; 1149297Seric if (a == NULL) 1154174Seric continue; 1164324Seric a->q_next = al; 1174399Seric a->q_alias = ctladdr; 1184444Seric 1194444Seric /* see if this should be marked as a primary address */ 1204423Seric if (ctladdr == NULL || 1218081Seric (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 1224423Seric a->q_flags |= QPRIMARY; 1234444Seric 12468284Seric /* arrange to inherit attributes from parent */ 12568284Seric if (ctladdr != NULL) 12668284Seric { 12768284Seric /* self reference test */ 12868284Seric if (sameaddr(ctladdr, a)) 12968284Seric ctladdr->q_flags |= QSELFREF; 13068284Seric 13168284Seric /* full name */ 13268284Seric if (a->q_fullname == NULL) 13368284Seric a->q_fullname = ctladdr->q_fullname; 13468284Seric 13568284Seric /* various flag bits */ 13668284Seric a->q_flags &= ~QINHERITEDBITS; 13768284Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 13868284Seric 13968284Seric /* original recipient information */ 14068284Seric a->q_orcpt = ctladdr->q_orcpt; 14168284Seric } 14268284Seric 14357731Seric al = a; 1444423Seric firstone = FALSE; 1454324Seric } 1464324Seric 1474324Seric /* arrange to send to everyone on the local send list */ 1484324Seric while (al != NULL) 1494324Seric { 1504324Seric register ADDRESS *a = al; 1514324Seric 1524324Seric al = a->q_next; 15368284Seric a = recipient(a, sendq, aliaslevel, e); 15458082Seric naddrs++; 1554174Seric } 1564324Seric 15763847Seric e->e_to = oldto; 15858082Seric return (naddrs); 1594174Seric } 1604174Seric /* 1614174Seric ** RECIPIENT -- Designate a message recipient 1624174Seric ** 1634174Seric ** Saves the named person for future mailing. 1644174Seric ** 1654174Seric ** Parameters: 1664174Seric ** a -- the (preparsed) address header for the recipient. 1675006Seric ** sendq -- a pointer to the head of a queue to put the 1685006Seric ** recipient in. Duplicate supression is done 1695006Seric ** in this queue. 17068284Seric ** aliaslevel -- the current alias nesting depth. 17157731Seric ** e -- the current envelope. 1724174Seric ** 1734174Seric ** Returns: 17412613Seric ** The actual address in the queue. This will be "a" if 17512613Seric ** the address is not a duplicate, else the original address. 1764174Seric ** 1774174Seric ** Side Effects: 1784174Seric ** none. 1794174Seric */ 1804174Seric 18112613Seric ADDRESS * 18268284Seric recipient(a, sendq, aliaslevel, e) 1834174Seric register ADDRESS *a; 1845006Seric register ADDRESS **sendq; 18568284Seric int aliaslevel; 18655012Seric register ENVELOPE *e; 1874174Seric { 1884174Seric register ADDRESS *q; 1894319Seric ADDRESS **pq; 1904174Seric register struct mailer *m; 1919210Seric register char *p; 1929210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 19353735Seric int findusercount = 0; 19468284Seric int i; 19568284Seric char *buf; 19668284Seric char buf0[MAXNAME]; /* unquoted image of the user name */ 19758247Seric extern int safefile(); 1984174Seric 19955012Seric e->e_to = a->q_paddr; 2004600Seric m = a->q_mailer; 2014174Seric errno = 0; 2027676Seric if (tTd(26, 1)) 2034444Seric { 2044444Seric printf("\nrecipient: "); 2054444Seric printaddr(a, FALSE); 2064444Seric } 2074174Seric 20864146Seric /* if this is primary, add it to the original recipient list */ 20964146Seric if (a->q_alias == NULL) 21064146Seric { 21164146Seric if (e->e_origrcpt == NULL) 21264146Seric e->e_origrcpt = a->q_paddr; 21364146Seric else if (e->e_origrcpt != a->q_paddr) 21464146Seric e->e_origrcpt = ""; 21564146Seric } 21664146Seric 2174174Seric /* break aliasing loops */ 21868284Seric if (aliaslevel > MAXRCRSN) 2194174Seric { 22068284Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 22168284Seric aliaslevel, MAXRCRSN); 22212613Seric return (a); 2234174Seric } 2244174Seric 2254174Seric /* 2264627Seric ** Finish setting up address structure. 2274174Seric */ 2284174Seric 22916160Seric /* get unquoted user for file, program or user.name check */ 23068284Seric i = strlen(a->q_user); 23168284Seric if (i >= sizeof buf) 23268284Seric buf = xalloc(i + 1); 23368284Seric else 23468284Seric buf = buf0; 2359210Seric (void) strcpy(buf, a->q_user); 2369210Seric for (p = buf; *p != '\0' && !quoted; p++) 2379210Seric { 23854993Seric if (*p == '\\') 2399210Seric quoted = TRUE; 2409210Seric } 24154983Seric stripquotes(buf); 2429210Seric 24357402Seric /* check for direct mailing to restricted mailers */ 24465496Seric if (m == ProgMailer) 2454174Seric { 24665496Seric if (a->q_alias == NULL) 24765496Seric { 24865496Seric a->q_flags |= QBADADDR; 24965496Seric usrerr("550 Cannot mail directly to programs"); 25065496Seric } 25165496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 25265496Seric { 25365496Seric a->q_flags |= QBADADDR; 25465496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 25565496Seric a->q_alias->q_ruser, MyHostName); 25665496Seric } 25765496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25865496Seric { 25965496Seric a->q_flags |= QBADADDR; 26065496Seric usrerr("550 Address %s is unsafe for mailing to programs", 26165496Seric a->q_alias->q_paddr); 26265496Seric } 2634174Seric } 2644174Seric 2654174Seric /* 2664419Seric ** Look up this person in the recipient list. 2674419Seric ** If they are there already, return, otherwise continue. 2684419Seric ** If the list is empty, just add it. Notice the cute 2694419Seric ** hack to make from addresses suppress things correctly: 2704419Seric ** the QDONTSEND bit will be set in the send list. 2714419Seric ** [Please note: the emphasis is on "hack."] 2724174Seric */ 2734174Seric 2745006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2754174Seric { 27658294Seric if (sameaddr(q, a)) 2774174Seric { 2787676Seric if (tTd(26, 1)) 2794444Seric { 2804444Seric printf("%s in sendq: ", a->q_paddr); 2814444Seric printaddr(q, FALSE); 2824444Seric } 28365593Seric if (!bitset(QPRIMARY, q->q_flags)) 28458065Seric { 28565593Seric if (!bitset(QDONTSEND, a->q_flags)) 28658151Seric message("duplicate suppressed"); 28765593Seric q->q_flags |= a->q_flags; 28865593Seric } 28965593Seric else if (bitset(QSELFREF, q->q_flags)) 29065579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 29163847Seric a = q; 29268284Seric goto done; 2934174Seric } 2944319Seric } 2954174Seric 2964319Seric /* add address on list */ 29758884Seric *pq = a; 29858884Seric a->q_next = NULL; 2994174Seric 3004174Seric /* 30157402Seric ** Alias the name and handle special mailer types. 3024174Seric */ 3034174Seric 30453735Seric trylocaluser: 30555354Seric if (tTd(29, 7)) 30655354Seric printf("at trylocaluser %s\n", a->q_user); 30755354Seric 30858680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30963847Seric goto testselfdestruct; 31057402Seric 31157402Seric if (m == InclMailer) 3124174Seric { 31357402Seric a->q_flags |= QDONTSEND; 31464761Seric if (a->q_alias == NULL) 3154174Seric { 31658680Seric a->q_flags |= QBADADDR; 31758151Seric usrerr("550 Cannot mail directly to :include:s"); 3184174Seric } 3194174Seric else 32050556Seric { 32159563Seric int ret; 32258247Seric 32358151Seric message("including file %s", a->q_user); 32468284Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 32559563Seric if (transienterror(ret)) 32659563Seric { 32759563Seric #ifdef LOG 32859563Seric if (LogLevel > 2) 32966239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 33066284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 33166284Seric a->q_user, errstring(ret)); 33259563Seric #endif 33363853Seric a->q_flags |= QQUEUEUP; 33465215Seric a->q_flags &= ~QDONTSEND; 33559563Seric usrerr("451 Cannot open %s: %s", 33659563Seric a->q_user, errstring(ret)); 33759563Seric } 33859563Seric else if (ret != 0) 33959563Seric { 34063938Seric a->q_flags |= QBADADDR; 34159563Seric usrerr("550 Cannot open %s: %s", 34259563Seric a->q_user, errstring(ret)); 34359563Seric } 34450556Seric } 3454174Seric } 34657642Seric else if (m == FileMailer) 3474174Seric { 3484329Seric extern bool writable(); 3494174Seric 35051317Seric /* check if writable or creatable */ 35164761Seric if (a->q_alias == NULL) 3524174Seric { 35358680Seric a->q_flags |= QBADADDR; 35458151Seric usrerr("550 Cannot mail directly to files"); 3554174Seric } 35665496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 35765496Seric { 35865496Seric a->q_flags |= QBADADDR; 35965496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 36065496Seric a->q_alias->q_ruser, MyHostName); 36165496Seric } 36265496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 36365496Seric { 36465496Seric a->q_flags |= QBADADDR; 36565496Seric usrerr("550 Address %s is unsafe for mailing to files", 36665496Seric a->q_alias->q_paddr); 36765496Seric } 36865112Seric else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) 36951317Seric { 37058680Seric a->q_flags |= QBADADDR; 37168284Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 37268284Seric (time_t) 0, e); 37351317Seric } 37451317Seric } 37551317Seric 37657402Seric /* try aliasing */ 37768284Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 37868284Seric alias(a, sendq, aliaslevel, e); 37957402Seric 38057402Seric # ifdef USERDB 38157402Seric /* if not aliased, look it up in the user database */ 38268284Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 38368284Seric bitnset(M_CHECKUDB, m->m_flags)) 38457402Seric { 38557402Seric extern int udbexpand(); 38657402Seric 38768284Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38857402Seric { 38963853Seric a->q_flags |= QQUEUEUP; 39057402Seric if (e->e_message == NULL) 39157402Seric e->e_message = newstr("Deferred: user database error"); 39257402Seric # ifdef LOG 39358020Seric if (LogLevel > 8) 39459623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 39566284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 39666284Seric errstring(errno)); 39757402Seric # endif 39859615Seric message("queued (user database error): %s", 39959615Seric errstring(errno)); 40057642Seric e->e_nrcpts++; 40163847Seric goto testselfdestruct; 40257402Seric } 40357402Seric } 40457402Seric # endif 40557402Seric 40651317Seric /* 40751317Seric ** If we have a level two config file, then pass the name through 40851317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 40951317Seric ** to send rewrite it to another mailer. This gives us a hook 41051317Seric ** after local aliasing has been done. 41151317Seric */ 41251317Seric 41351317Seric if (tTd(29, 5)) 41451317Seric { 41551317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 41651317Seric ConfigLevel, RewriteRules[5]); 41751317Seric printaddr(a, FALSE); 41851317Seric } 41968284Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 42068284Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 42168284Seric bitnset(M_TRYRULESET5, m->m_flags)) 42251317Seric { 42368284Seric maplocaluser(a, sendq, aliaslevel, e); 42451317Seric } 42551317Seric 42651317Seric /* 42751317Seric ** If it didn't get rewritten to another mailer, go ahead 42851317Seric ** and deliver it. 42951317Seric */ 43051317Seric 43168284Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 43268284Seric bitnset(M_HASPWENT, m->m_flags)) 43351317Seric { 43455354Seric auto bool fuzzy; 43551317Seric register struct passwd *pw; 43651317Seric extern struct passwd *finduser(); 43751317Seric 43851317Seric /* warning -- finduser may trash buf */ 43955354Seric pw = finduser(buf, &fuzzy); 44051317Seric if (pw == NULL) 44151317Seric { 44258680Seric a->q_flags |= QBADADDR; 44368284Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 44468284Seric (time_t) 0, e); 44551317Seric } 4464174Seric else 4474174Seric { 44851317Seric char nbuf[MAXNAME]; 4494373Seric 45055354Seric if (fuzzy) 4514174Seric { 45253735Seric /* name was a fuzzy match */ 45351317Seric a->q_user = newstr(pw->pw_name); 45453735Seric if (findusercount++ > 3) 45553735Seric { 45658680Seric a->q_flags |= QBADADDR; 45758151Seric usrerr("554 aliasing/forwarding loop for %s broken", 45853735Seric pw->pw_name); 45968284Seric goto done; 46053735Seric } 46153735Seric 46253735Seric /* see if it aliases */ 46351317Seric (void) strcpy(buf, pw->pw_name); 46453735Seric goto trylocaluser; 4654174Seric } 46665822Seric if (strcmp(pw->pw_dir, "/") == 0) 46765822Seric a->q_home = ""; 46865822Seric else 46965822Seric a->q_home = newstr(pw->pw_dir); 47051317Seric a->q_uid = pw->pw_uid; 47151317Seric a->q_gid = pw->pw_gid; 47259083Seric a->q_ruser = newstr(pw->pw_name); 47351317Seric a->q_flags |= QGOODUID; 47451317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 47551317Seric if (nbuf[0] != '\0') 47651317Seric a->q_fullname = newstr(nbuf); 47765211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 47865211Seric !usershellok(pw->pw_shell)) 47965206Seric { 48065211Seric a->q_flags |= QBOGUSSHELL; 48165206Seric } 48251317Seric if (!quoted) 48368284Seric forward(a, sendq, aliaslevel, e); 4844174Seric } 4854174Seric } 48657642Seric if (!bitset(QDONTSEND, a->q_flags)) 48757642Seric e->e_nrcpts++; 48863847Seric 48963847Seric testselfdestruct: 49063978Seric if (tTd(26, 8)) 49163847Seric { 49263978Seric printf("testselfdestruct: "); 49363978Seric printaddr(a, TRUE); 49463978Seric } 49563978Seric if (a->q_alias == NULL && a != &e->e_from && 49663978Seric bitset(QDONTSEND, a->q_flags)) 49763978Seric { 49863978Seric q = *sendq; 49963965Seric while (q != NULL && bitset(QDONTSEND, q->q_flags)) 50063847Seric q = q->q_next; 50163978Seric if (q == NULL) 50263847Seric { 50363847Seric a->q_flags |= QBADADDR; 50463847Seric usrerr("554 aliasing/forwarding loop broken"); 50563847Seric } 50663847Seric } 50768284Seric 50868284Seric done: 50968284Seric if (buf != buf0) 51068284Seric free(buf); 51112613Seric return (a); 5124174Seric } 5134174Seric /* 5144373Seric ** FINDUSER -- find the password entry for a user. 5154373Seric ** 5164373Seric ** This looks a lot like getpwnam, except that it may want to 5174373Seric ** do some fancier pattern matching in /etc/passwd. 5184373Seric ** 5199379Seric ** This routine contains most of the time of many sendmail runs. 5209379Seric ** It deserves to be optimized. 5219379Seric ** 5224373Seric ** Parameters: 5234373Seric ** name -- the name to match against. 52455354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 52555354Seric ** was found using the fuzzy matching algorithm; 52655354Seric ** set to FALSE otherwise. 5274373Seric ** 5284373Seric ** Returns: 5294373Seric ** A pointer to a pw struct. 5304373Seric ** NULL if name is unknown or ambiguous. 5314373Seric ** 5324373Seric ** Side Effects: 5334407Seric ** may modify name. 5344373Seric */ 5354373Seric 5364373Seric struct passwd * 53755354Seric finduser(name, fuzzyp) 5384373Seric char *name; 53955354Seric bool *fuzzyp; 5404373Seric { 5414376Seric register struct passwd *pw; 5424407Seric register char *p; 54315325Seric extern struct passwd *getpwent(); 54415325Seric extern struct passwd *getpwnam(); 5454373Seric 54655354Seric if (tTd(29, 4)) 54755354Seric printf("finduser(%s): ", name); 54855354Seric 54955354Seric *fuzzyp = FALSE; 5504407Seric 55168284Seric #ifdef HESIOD 55264673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 55364673Seric for (p = name; *p != '\0'; p++) 55464673Seric if (!isascii(*p) || !isdigit(*p)) 55564673Seric break; 55664673Seric if (*p == '\0') 55764673Seric { 55864673Seric if (tTd(29, 4)) 55964673Seric printf("failed (numeric input)\n"); 56064673Seric return NULL; 56164673Seric } 56268284Seric #endif 56364673Seric 56425777Seric /* look up this login name using fast path */ 56512634Seric if ((pw = getpwnam(name)) != NULL) 56655354Seric { 56755354Seric if (tTd(29, 4)) 56855354Seric printf("found (non-fuzzy)\n"); 56912634Seric return (pw); 57055354Seric } 57112634Seric 57253735Seric #ifdef MATCHGECOS 57353735Seric /* see if fuzzy matching allowed */ 57453735Seric if (!MatchGecos) 57555354Seric { 57655354Seric if (tTd(29, 4)) 57755354Seric printf("not found (fuzzy disabled)\n"); 57853735Seric return NULL; 57955354Seric } 58053735Seric 58112634Seric /* search for a matching full name instead */ 58225777Seric for (p = name; *p != '\0'; p++) 58325777Seric { 58425777Seric if (*p == (SpaceSub & 0177) || *p == '_') 58525777Seric *p = ' '; 58625777Seric } 58723107Seric (void) setpwent(); 5884376Seric while ((pw = getpwent()) != NULL) 5894376Seric { 5904998Seric char buf[MAXNAME]; 5914376Seric 5924998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 59356795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 5944381Seric { 59555354Seric if (tTd(29, 4)) 59655354Seric printf("fuzzy matches %s\n", pw->pw_name); 59758151Seric message("sending to login name %s", pw->pw_name); 59855354Seric *fuzzyp = TRUE; 5994376Seric return (pw); 6004377Seric } 6014376Seric } 60255354Seric if (tTd(29, 4)) 60355354Seric printf("no fuzzy match found\n"); 60459015Seric #else 60559015Seric if (tTd(29, 4)) 60659015Seric printf("not found (fuzzy disabled)\n"); 60759015Seric #endif 6084376Seric return (NULL); 6094373Seric } 6104373Seric /* 6114329Seric ** WRITABLE -- predicate returning if the file is writable. 6124329Seric ** 6134329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6144329Seric ** Unfortunately, we cannot use the access call since we 6154329Seric ** won't necessarily be the real uid when we try to 6164329Seric ** actually open the file. 6174329Seric ** 6184329Seric ** Notice that ANY file with ANY execute bit is automatically 6194329Seric ** not writable. This is also enforced by mailfile. 6204329Seric ** 6214329Seric ** Parameters: 62265064Seric ** filename -- the file name to check. 62365112Seric ** ctladdr -- the controlling address for this file. 62465064Seric ** flags -- SFF_* flags to control the function. 6254329Seric ** 6264329Seric ** Returns: 6274329Seric ** TRUE -- if we will be able to write this file. 6284329Seric ** FALSE -- if we cannot write this file. 6294329Seric ** 6304329Seric ** Side Effects: 6314329Seric ** none. 6324329Seric */ 6334329Seric 6344329Seric bool 63565112Seric writable(filename, ctladdr, flags) 63664819Seric char *filename; 63765112Seric ADDRESS *ctladdr; 63865064Seric int flags; 6394329Seric { 64055372Seric uid_t euid; 64155372Seric gid_t egid; 6424329Seric int bits; 64364944Seric register char *p; 64464944Seric char *uname; 64564944Seric struct stat stb; 64664944Seric extern char RealUserName[]; 6474329Seric 64864819Seric if (tTd(29, 5)) 64965064Seric printf("writable(%s, %x)\n", filename, flags); 65064944Seric 65164944Seric #ifdef HASLSTAT 65265064Seric if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) 65365064Seric : stat(filename, &stb)) < 0) 65464944Seric #else 65564944Seric if (stat(filename, &stb) < 0) 65664944Seric #endif 65764944Seric { 65864944Seric /* file does not exist -- see if directory is safe */ 65964944Seric p = strrchr(filename, '/'); 66064944Seric if (p == NULL) 66164944Seric { 66265067Seric errno = ENOTDIR; 66364944Seric return FALSE; 66464944Seric } 66565067Seric *p = '\0'; 66665067Seric errno = safefile(filename, RealUid, RealGid, RealUserName, 66765067Seric SFF_MUSTOWN, S_IWRITE|S_IEXEC); 66864944Seric *p = '/'; 66965067Seric return errno == 0; 67064944Seric } 67164944Seric 67265225Seric #ifdef SUID_ROOT_FILES_OK 67365225Seric /* really ought to be passed down -- and not a good idea */ 67465225Seric flags |= SFF_ROOTOK; 67565225Seric #endif 67665225Seric 67764944Seric /* 67864944Seric ** File does exist -- check that it is writable. 67964944Seric */ 68064944Seric 68164944Seric if (bitset(0111, stb.st_mode)) 68265022Seric { 68365022Seric if (tTd(29, 5)) 68465022Seric printf("failed (mode %o: x bits)\n", stb.st_mode); 68565067Seric errno = EPERM; 6864329Seric return (FALSE); 68765022Seric } 68864944Seric 68965112Seric if (ctladdr != NULL && geteuid() == 0) 69064944Seric { 69165112Seric euid = ctladdr->q_uid; 69265112Seric egid = ctladdr->q_gid; 69365112Seric uname = ctladdr->q_user; 69464944Seric } 69568284Seric #ifdef RUN_AS_REAL_UID 69665112Seric else 69765112Seric { 69865112Seric euid = RealUid; 69965112Seric egid = RealGid; 70065112Seric uname = RealUserName; 70165112Seric } 70268284Seric #else 70368284Seric else if (FileMailer != NULL) 70468284Seric { 70568284Seric euid = FileMailer->m_uid; 70668284Seric egid = FileMailer->m_gid; 70768284Seric } 70868284Seric else 70968284Seric { 71068284Seric euid = egid = 0; 71168284Seric } 71268284Seric #endif 71365138Seric if (euid == 0) 71465138Seric { 71565138Seric euid = DefUid; 71665138Seric uname = DefUser; 71765138Seric } 71865138Seric if (egid == 0) 71965138Seric egid = DefGid; 7204329Seric if (geteuid() == 0) 7214329Seric { 72265225Seric if (bitset(S_ISUID, stb.st_mode) && 72365225Seric (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) 72464944Seric { 72564944Seric euid = stb.st_uid; 72664944Seric uname = NULL; 72764944Seric } 72865225Seric if (bitset(S_ISGID, stb.st_mode) && 72965225Seric (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) 73064944Seric egid = stb.st_gid; 7314329Seric } 7324329Seric 73364819Seric if (tTd(29, 5)) 73464819Seric printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", 73564944Seric euid, egid, stb.st_uid, stb.st_gid); 73664819Seric 73765067Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); 73865067Seric return errno == 0; 7394329Seric } 7404329Seric /* 7414174Seric ** INCLUDE -- handle :include: specification. 7424174Seric ** 7434174Seric ** Parameters: 7444174Seric ** fname -- filename to include. 74553037Seric ** forwarding -- if TRUE, we are reading a .forward file. 74653037Seric ** if FALSE, it's a :include: file. 7474399Seric ** ctladdr -- address template to use to fill in these 7484399Seric ** addresses -- effective user/group id are 7494399Seric ** the important things. 7505006Seric ** sendq -- a pointer to the head of the send queue 7515006Seric ** to put these addresses in. 75268284Seric ** aliaslevel -- the alias nesting depth. 75368284Seric ** e -- the current envelope. 7544174Seric ** 7554174Seric ** Returns: 75657136Seric ** open error status 7574174Seric ** 7584174Seric ** Side Effects: 7594174Seric ** reads the :include: file and sends to everyone 7604174Seric ** listed in that file. 76165909Seric ** 76265909Seric ** Security Note: 76365909Seric ** If you have restricted chown (that is, you can't 76465909Seric ** give a file away), it is reasonable to allow programs 76565909Seric ** and files called from this :include: file to be to be 76665909Seric ** run as the owner of the :include: file. This is bogus 76765909Seric ** if there is any chance of someone giving away a file. 76865909Seric ** We assume that pre-POSIX systems can give away files. 76965909Seric ** 77065909Seric ** There is an additional restriction that if you 77165909Seric ** forward to a :include: file, it will not take on 77265909Seric ** the ownership of the :include: file. This may not 77365909Seric ** be necessary, but shouldn't hurt. 7744174Seric */ 7754174Seric 77653037Seric static jmp_buf CtxIncludeTimeout; 77763937Seric static int includetimeout(); 77853037Seric 77965496Seric #ifndef S_IWOTH 78065496Seric # define S_IWOTH (S_IWRITE >> 6) 78165496Seric #endif 78265496Seric 78357136Seric int 78468284Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7854174Seric char *fname; 78653037Seric bool forwarding; 7874399Seric ADDRESS *ctladdr; 7885006Seric ADDRESS **sendq; 78968284Seric int aliaslevel; 79055012Seric ENVELOPE *e; 7914174Seric { 79264570Seric register FILE *fp = NULL; 79355012Seric char *oldto = e->e_to; 7949379Seric char *oldfilename = FileName; 7959379Seric int oldlinenumber = LineNumber; 79653037Seric register EVENT *ev = NULL; 79758082Seric int nincludes; 79864325Seric register ADDRESS *ca; 79964325Seric uid_t saveduid, uid; 80064325Seric gid_t savedgid, gid; 80164083Seric char *uname; 80264325Seric int rval = 0; 80365064Seric int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; 80465496Seric struct stat st; 80565948Seric char buf[MAXLINE]; 80665909Seric #ifdef _POSIX_CHOWN_RESTRICTED 80765948Seric # if _POSIX_CHOWN_RESTRICTED == -1 80865948Seric # define safechown FALSE 80965948Seric # else 81065948Seric # define safechown TRUE 81165948Seric # endif 81265948Seric #else 81365948Seric # ifdef _PC_CHOWN_RESTRICTED 81465909Seric bool safechown; 81565948Seric # else 81665948Seric # ifdef BSD 81765948Seric # define safechown TRUE 81865948Seric # else 81965948Seric # define safechown FALSE 82065948Seric # endif 82165948Seric # endif 82265909Seric #endif 82365948Seric extern bool chownsafe(); 8244174Seric 82557186Seric if (tTd(27, 2)) 82657186Seric printf("include(%s)\n", fname); 82763902Seric if (tTd(27, 4)) 82863902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 82963581Seric if (tTd(27, 14)) 83063581Seric { 83163581Seric printf("ctladdr "); 83263581Seric printaddr(ctladdr, FALSE); 83363581Seric } 83457186Seric 83564325Seric if (tTd(27, 9)) 83664325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 83753037Seric 83863581Seric ca = getctladdr(ctladdr); 83963581Seric if (ca == NULL) 84064083Seric { 84164846Seric uid = DefUid; 84264846Seric gid = DefGid; 84364846Seric uname = DefUser; 84464083Seric } 84563581Seric else 84664083Seric { 84763581Seric uid = ca->q_uid; 84864083Seric gid = ca->q_gid; 84964083Seric uname = ca->q_user; 850*68285Seric } 85164325Seric #ifdef HASSETREUID 852*68285Seric saveduid = geteuid(); 853*68285Seric savedgid = getegid(); 854*68285Seric if (saveduid == 0) 855*68285Seric { 856*68285Seric initgroups(uname, gid); 857*68285Seric if (uid != 0) 85864325Seric { 859*68285Seric if (setreuid(0, uid) < 0) 860*68285Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 861*68285Seric uid, getuid(), geteuid()); 862*68285Seric else 863*68285Seric sfflags |= SFF_NOPATHCHECK; 86464325Seric } 865*68285Seric } 86664325Seric #endif 86763581Seric 86864325Seric if (tTd(27, 9)) 86964325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 87064325Seric 87164325Seric /* 87264325Seric ** If home directory is remote mounted but server is down, 87364325Seric ** this can hang or give errors; use a timeout to avoid this 87464325Seric */ 87564325Seric 87653037Seric if (setjmp(CtxIncludeTimeout) != 0) 87753037Seric { 87863853Seric ctladdr->q_flags |= QQUEUEUP; 87953037Seric errno = 0; 88063993Seric 88163993Seric /* return pseudo-error code */ 88264325Seric rval = EOPENTIMEOUT; 88364325Seric goto resetuid; 88453037Seric } 88568284Seric if (TimeOuts.to_fileopen > 0) 88668284Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 88768284Seric else 88868284Seric ev = NULL; 88953037Seric 89063581Seric /* the input file must be marked safe */ 89164944Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); 89264329Seric if (rval != 0) 89353037Seric { 89464325Seric /* don't use this :include: file */ 89557186Seric if (tTd(27, 4)) 89658247Seric printf("include: not safe (uid=%d): %s\n", 89764329Seric uid, errstring(rval)); 89853037Seric } 89965496Seric else 9004174Seric { 90165496Seric fp = fopen(fname, "r"); 90265496Seric if (fp == NULL) 90358061Seric { 90464329Seric rval = errno; 90565496Seric if (tTd(27, 4)) 90665496Seric printf("include: open: %s\n", errstring(rval)); 90758061Seric } 9084406Seric } 90968284Seric if (ev != NULL) 91068284Seric clrevent(ev); 91153037Seric 91264570Seric resetuid: 91364570Seric 91464570Seric #ifdef HASSETREUID 91564570Seric if (saveduid == 0) 91664570Seric { 91764570Seric if (uid != 0) 91868284Seric { 91968284Seric if (setreuid(-1, 0) < 0) 92068284Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 92168284Seric getuid(), geteuid()); 92268284Seric if (setreuid(RealUid, 0) < 0) 92364570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 92464570Seric RealUid, getuid(), geteuid()); 92568284Seric } 92664570Seric setgid(savedgid); 92764570Seric } 92864570Seric #endif 92964570Seric 93064570Seric if (tTd(27, 9)) 93164570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 93264570Seric 93365593Seric if (rval == EOPENTIMEOUT) 93465593Seric usrerr("451 open timeout on %s", fname); 93565593Seric 93664570Seric if (fp == NULL) 93764570Seric return rval; 93864570Seric 93965496Seric if (fstat(fileno(fp), &st) < 0) 94065496Seric { 94165496Seric rval = errno; 94265496Seric syserr("Cannot fstat %s!", fname); 94365496Seric return rval; 94465496Seric } 94565496Seric 94665948Seric #ifndef safechown 94765948Seric safechown = chownsafe(fileno(fp)); 94865948Seric #endif 94965909Seric if (ca == NULL && safechown) 95065496Seric { 95165496Seric ctladdr->q_uid = st.st_uid; 95265496Seric ctladdr->q_gid = st.st_gid; 95365496Seric ctladdr->q_flags |= QGOODUID; 95465496Seric } 95565496Seric if (ca != NULL && ca->q_uid == st.st_uid) 95665496Seric { 95765496Seric /* optimization -- avoid getpwuid if we already have info */ 95865496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 95965496Seric ctladdr->q_ruser = ca->q_ruser; 96065496Seric } 96165496Seric else 96265496Seric { 96365496Seric register struct passwd *pw; 96465496Seric 96565496Seric pw = getpwuid(st.st_uid); 96668284Seric if (pw == NULL) 96768284Seric ctladdr->q_flags |= QBOGUSSHELL; 96868284Seric else 96968268Seric { 97068284Seric char *sh; 97168284Seric 97268268Seric ctladdr->q_ruser = newstr(pw->pw_name); 97368268Seric if (safechown) 97468268Seric sh = pw->pw_shell; 97565909Seric else 97668284Seric sh = "/SENDMAIL/ANY/SHELL/"; 97768284Seric if (!usershellok(sh)) 97868284Seric { 97968284Seric if (safechown) 98068284Seric ctladdr->q_flags |= QBOGUSSHELL; 98168284Seric else 98268284Seric ctladdr->q_flags |= QUNSAFEADDR; 98368284Seric } 98465496Seric } 98565496Seric } 98665496Seric 98758092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 98858092Seric { 98958092Seric /* don't do any more now */ 99058868Seric ctladdr->q_flags |= QVERIFIED; 99158884Seric e->e_nrcpts++; 99258680Seric xfclose(fp, "include", fname); 99364570Seric return rval; 99458092Seric } 99558092Seric 99665496Seric /* 99765496Seric ** Check to see if some bad guy can write this file 99865496Seric ** 99965496Seric ** This should really do something clever with group 100065496Seric ** permissions; currently we just view world writable 100165496Seric ** as unsafe. Also, we don't check for writable 100265496Seric ** directories in the path. We've got to leave 100365496Seric ** something for the local sysad to do. 100465496Seric */ 100565496Seric 100665496Seric if (bitset(S_IWOTH, st.st_mode)) 100765496Seric ctladdr->q_flags |= QUNSAFEADDR; 100865496Seric 10094174Seric /* read the file -- each line is a comma-separated list. */ 10109379Seric FileName = fname; 10119379Seric LineNumber = 0; 101258082Seric ctladdr->q_flags &= ~QSELFREF; 101358082Seric nincludes = 0; 10144174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10154174Seric { 101656795Seric register char *p = strchr(buf, '\n'); 10174174Seric 101840963Sbostic LineNumber++; 10194174Seric if (p != NULL) 10204174Seric *p = '\0'; 102157186Seric if (buf[0] == '#' || buf[0] == '\0') 102257139Seric continue; 102358008Seric e->e_to = NULL; 102458151Seric message("%s to %s", 102553037Seric forwarding ? "forwarding" : "sending", buf); 102657977Seric #ifdef LOG 102758020Seric if (forwarding && LogLevel > 9) 102857977Seric syslog(LOG_INFO, "%s: forward %s => %s", 102966284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 103066284Seric oldto, buf); 103157977Seric #endif 103257977Seric 103368284Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10344174Seric } 103563902Seric 103663902Seric if (ferror(fp) && tTd(27, 3)) 103763902Seric printf("include: read error: %s\n", errstring(errno)); 103858082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 103958065Seric { 104058065Seric if (tTd(27, 5)) 104158065Seric { 104258065Seric printf("include: QDONTSEND "); 104358065Seric printaddr(ctladdr, FALSE); 104458065Seric } 104558065Seric ctladdr->q_flags |= QDONTSEND; 104658065Seric } 10474174Seric 104858680Seric (void) xfclose(fp, "include", fname); 10499379Seric FileName = oldfilename; 10509379Seric LineNumber = oldlinenumber; 105163847Seric e->e_to = oldto; 105264325Seric return rval; 10534174Seric } 105453037Seric 105553037Seric static 105653037Seric includetimeout() 105753037Seric { 105853037Seric longjmp(CtxIncludeTimeout, 1); 105953037Seric } 10604324Seric /* 10614324Seric ** SENDTOARGV -- send to an argument vector. 10624324Seric ** 10634324Seric ** Parameters: 10644324Seric ** argv -- argument vector to send to. 106558247Seric ** e -- the current envelope. 10664324Seric ** 10674324Seric ** Returns: 10684324Seric ** none. 10694324Seric ** 10704324Seric ** Side Effects: 10714324Seric ** puts all addresses on the argument vector onto the 10724324Seric ** send queue. 10734324Seric */ 10744324Seric 107555012Seric sendtoargv(argv, e) 10764324Seric register char **argv; 107755012Seric register ENVELOPE *e; 10784324Seric { 10794324Seric register char *p; 10804324Seric 10814324Seric while ((p = *argv++) != NULL) 10824324Seric { 108368284Seric (void) sendtolist(denlstring(p), NULLADDR, 108468284Seric &e->e_sendqueue, 0, e); 10854324Seric } 10864324Seric } 10874399Seric /* 10884399Seric ** GETCTLADDR -- get controlling address from an address header. 10894399Seric ** 10904399Seric ** If none, get one corresponding to the effective userid. 10914399Seric ** 10924399Seric ** Parameters: 10934399Seric ** a -- the address to find the controller of. 10944399Seric ** 10954399Seric ** Returns: 10964399Seric ** the controlling address. 10974399Seric ** 10984399Seric ** Side Effects: 10994399Seric ** none. 11004399Seric */ 11014399Seric 11024399Seric ADDRESS * 11034399Seric getctladdr(a) 11044399Seric register ADDRESS *a; 11054399Seric { 11064404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11074399Seric a = a->q_alias; 11084399Seric return (a); 11094399Seric } 1110