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*67940Seric static char sccsid[] = "@(#)recipient.c 8.53 (Berkeley) 11/20/94"; 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. 3058247Seric ** e -- the envelope in which to add these recipients. 314174Seric ** 324174Seric ** Returns: 3358082Seric ** The number of addresses actually on the list. 344174Seric ** 354174Seric ** Side Effects: 364174Seric ** none. 374174Seric */ 384174Seric 3967880Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 404174Seric 4167880Seric /* q_flags bits inherited from ctladdr */ 4267880Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASRETPARAM|QNOBODYRETURN) 4367880Seric 4455012Seric sendtolist(list, ctladdr, sendq, e) 454174Seric char *list; 464399Seric ADDRESS *ctladdr; 475198Seric ADDRESS **sendq; 4855012Seric register ENVELOPE *e; 494174Seric { 504174Seric register char *p; 518223Seric register ADDRESS *al; /* list of addresses to send to */ 524423Seric bool firstone; /* set on first address sent */ 5311446Seric char delimiter; /* the address delimiter */ 5458082Seric int naddrs; 5563847Seric char *oldto = e->e_to; 5667894Seric static char *bufp = NULL; 5767894Seric static int buflen; 5867894Seric char buf[MAXNAME + 1]; 594174Seric 6064131Seric if (list == NULL) 6164131Seric { 6264131Seric syserr("sendtolist: null list"); 6364131Seric return 0; 6464131Seric } 6564131Seric 667676Seric if (tTd(25, 1)) 674444Seric { 684444Seric printf("sendto: %s\n ctladdr=", list); 694444Seric printaddr(ctladdr, FALSE); 704444Seric } 714324Seric 728223Seric /* heuristic to determine old versus new style addresses */ 738230Seric if (ctladdr == NULL && 7456795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 7556795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 7655012Seric e->e_flags &= ~EF_OLDSTYLE; 7711446Seric delimiter = ' '; 7855012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 7911446Seric delimiter = ','; 808223Seric 814423Seric firstone = TRUE; 824324Seric al = NULL; 8358082Seric naddrs = 0; 848223Seric 8567894Seric if (buf == NULL) 864174Seric { 8767894Seric bufp = buf; 8867894Seric buflen = sizeof buf - 1; 8967894Seric } 9067894Seric if (strlen(list) > buflen) 9167894Seric { 9267894Seric /* allocate additional space */ 9367894Seric if (bufp != buf) 9467894Seric free(bufp); 9567894Seric buflen = strlen(list); 9667894Seric bufp = malloc(buflen + 1); 9767894Seric } 9867894Seric strcpy(bufp, list); 9967894Seric 10067894Seric for (p = bufp; *p != '\0'; ) 10167894Seric { 10258333Seric auto char *delimptr; 1038081Seric register ADDRESS *a; 1044319Seric 1058081Seric /* parse the address */ 10658050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1074174Seric p++; 10864284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10958333Seric p = delimptr; 1109297Seric if (a == NULL) 1114174Seric continue; 1124324Seric a->q_next = al; 1134399Seric a->q_alias = ctladdr; 1144444Seric 1154444Seric /* see if this should be marked as a primary address */ 1164423Seric if (ctladdr == NULL || 1178081Seric (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 1184423Seric a->q_flags |= QPRIMARY; 1194444Seric 1209379Seric if (ctladdr != NULL && sameaddr(ctladdr, a)) 12158061Seric ctladdr->q_flags |= QSELFREF; 12257731Seric al = a; 1234423Seric firstone = FALSE; 1244324Seric } 1254324Seric 1264324Seric /* arrange to send to everyone on the local send list */ 1274324Seric while (al != NULL) 1284324Seric { 1294324Seric register ADDRESS *a = al; 1304324Seric 1314324Seric al = a->q_next; 13255012Seric a = recipient(a, sendq, e); 1334993Seric 13467880Seric /* arrange to inherit attributes from parent */ 13567880Seric if (ctladdr != NULL) 13667880Seric { 13767880Seric /* full name */ 13867880Seric if (a->q_fullname == NULL) 13967880Seric a->q_fullname = ctladdr->q_fullname; 14067880Seric 14167880Seric /* various flag bits */ 14267880Seric a->q_flags &= ~QINHERITEDBITS; 14367880Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 14467880Seric } 14558082Seric naddrs++; 1464174Seric } 1474324Seric 14863847Seric e->e_to = oldto; 14958082Seric return (naddrs); 1504174Seric } 1514174Seric /* 1524174Seric ** RECIPIENT -- Designate a message recipient 1534174Seric ** 1544174Seric ** Saves the named person for future mailing. 1554174Seric ** 1564174Seric ** Parameters: 1574174Seric ** a -- the (preparsed) address header for the recipient. 1585006Seric ** sendq -- a pointer to the head of a queue to put the 1595006Seric ** recipient in. Duplicate supression is done 1605006Seric ** in this queue. 16157731Seric ** e -- the current envelope. 1624174Seric ** 1634174Seric ** Returns: 16412613Seric ** The actual address in the queue. This will be "a" if 16512613Seric ** the address is not a duplicate, else the original address. 1664174Seric ** 1674174Seric ** Side Effects: 1684174Seric ** none. 1694174Seric */ 1704174Seric 17112613Seric ADDRESS * 17255012Seric recipient(a, sendq, e) 1734174Seric register ADDRESS *a; 1745006Seric register ADDRESS **sendq; 17555012Seric register ENVELOPE *e; 1764174Seric { 1774174Seric register ADDRESS *q; 1784319Seric ADDRESS **pq; 1794174Seric register struct mailer *m; 1809210Seric register char *p; 1819210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 18253735Seric int findusercount = 0; 18367264Seric int i; 18467264Seric char *buf; 18567264Seric char buf0[MAXNAME]; /* unquoted image of the user name */ 18658247Seric extern int safefile(); 1874174Seric 18855012Seric e->e_to = a->q_paddr; 1894600Seric m = a->q_mailer; 1904174Seric errno = 0; 1917676Seric if (tTd(26, 1)) 1924444Seric { 1934444Seric printf("\nrecipient: "); 1944444Seric printaddr(a, FALSE); 1954444Seric } 1964174Seric 19764146Seric /* if this is primary, add it to the original recipient list */ 19864146Seric if (a->q_alias == NULL) 19964146Seric { 20064146Seric if (e->e_origrcpt == NULL) 20164146Seric e->e_origrcpt = a->q_paddr; 20264146Seric else if (e->e_origrcpt != a->q_paddr) 20364146Seric e->e_origrcpt = ""; 20464146Seric } 20564146Seric 2064174Seric /* break aliasing loops */ 2074174Seric if (AliasLevel > MAXRCRSN) 2084174Seric { 20958151Seric usrerr("554 aliasing/forwarding loop broken"); 21012613Seric return (a); 2114174Seric } 2124174Seric 2134174Seric /* 2144627Seric ** Finish setting up address structure. 2154174Seric */ 2164174Seric 21716160Seric /* get unquoted user for file, program or user.name check */ 21867264Seric i = strlen(a->q_user); 21967264Seric if (i >= sizeof buf) 22067264Seric buf = xalloc(i + 1); 22167264Seric else 22267264Seric buf = buf0; 2239210Seric (void) strcpy(buf, a->q_user); 2249210Seric for (p = buf; *p != '\0' && !quoted; p++) 2259210Seric { 22654993Seric if (*p == '\\') 2279210Seric quoted = TRUE; 2289210Seric } 22954983Seric stripquotes(buf); 2309210Seric 23157402Seric /* check for direct mailing to restricted mailers */ 23265496Seric if (m == ProgMailer) 2334174Seric { 23465496Seric if (a->q_alias == NULL) 23565496Seric { 23665496Seric a->q_flags |= QBADADDR; 23765496Seric usrerr("550 Cannot mail directly to programs"); 23865496Seric } 23965496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24065496Seric { 24165496Seric a->q_flags |= QBADADDR; 24265496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 24365496Seric a->q_alias->q_ruser, MyHostName); 24465496Seric } 24565496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 24665496Seric { 24765496Seric a->q_flags |= QBADADDR; 24865496Seric usrerr("550 Address %s is unsafe for mailing to programs", 24965496Seric a->q_alias->q_paddr); 25065496Seric } 2514174Seric } 2524174Seric 2534174Seric /* 2544419Seric ** Look up this person in the recipient list. 2554419Seric ** If they are there already, return, otherwise continue. 2564419Seric ** If the list is empty, just add it. Notice the cute 2574419Seric ** hack to make from addresses suppress things correctly: 2584419Seric ** the QDONTSEND bit will be set in the send list. 2594419Seric ** [Please note: the emphasis is on "hack."] 2604174Seric */ 2614174Seric 2625006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2634174Seric { 26458294Seric if (sameaddr(q, a)) 2654174Seric { 2667676Seric if (tTd(26, 1)) 2674444Seric { 2684444Seric printf("%s in sendq: ", a->q_paddr); 2694444Seric printaddr(q, FALSE); 2704444Seric } 27165593Seric if (!bitset(QPRIMARY, q->q_flags)) 27258065Seric { 27365593Seric if (!bitset(QDONTSEND, a->q_flags)) 27458151Seric message("duplicate suppressed"); 27565593Seric q->q_flags |= a->q_flags; 27665593Seric } 27765593Seric else if (bitset(QSELFREF, q->q_flags)) 27865579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 27963847Seric a = q; 28063847Seric goto testselfdestruct; 2814174Seric } 2824319Seric } 2834174Seric 2844319Seric /* add address on list */ 28558884Seric *pq = a; 28658884Seric a->q_next = NULL; 2874174Seric 2884174Seric /* 28957402Seric ** Alias the name and handle special mailer types. 2904174Seric */ 2914174Seric 29253735Seric trylocaluser: 29355354Seric if (tTd(29, 7)) 29455354Seric printf("at trylocaluser %s\n", a->q_user); 29555354Seric 29658680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 29763847Seric goto testselfdestruct; 29857402Seric 29957402Seric if (m == InclMailer) 3004174Seric { 30157402Seric a->q_flags |= QDONTSEND; 30264761Seric if (a->q_alias == NULL) 3034174Seric { 30458680Seric a->q_flags |= QBADADDR; 30558151Seric usrerr("550 Cannot mail directly to :include:s"); 3064174Seric } 3074174Seric else 30850556Seric { 30959563Seric int ret; 31058247Seric 31158151Seric message("including file %s", a->q_user); 31259563Seric ret = include(a->q_user, FALSE, a, sendq, e); 31359563Seric if (transienterror(ret)) 31459563Seric { 31559563Seric #ifdef LOG 31659563Seric if (LogLevel > 2) 31766239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 31866284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 31966284Seric a->q_user, errstring(ret)); 32059563Seric #endif 32163853Seric a->q_flags |= QQUEUEUP; 32265215Seric a->q_flags &= ~QDONTSEND; 32359563Seric usrerr("451 Cannot open %s: %s", 32459563Seric a->q_user, errstring(ret)); 32559563Seric } 32659563Seric else if (ret != 0) 32759563Seric { 32863938Seric a->q_flags |= QBADADDR; 32959563Seric usrerr("550 Cannot open %s: %s", 33059563Seric a->q_user, errstring(ret)); 33159563Seric } 33250556Seric } 3334174Seric } 33457642Seric else if (m == FileMailer) 3354174Seric { 3364329Seric extern bool writable(); 3374174Seric 33851317Seric /* check if writable or creatable */ 33964761Seric if (a->q_alias == NULL) 3404174Seric { 34158680Seric a->q_flags |= QBADADDR; 34258151Seric usrerr("550 Cannot mail directly to files"); 3434174Seric } 34465496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 34565496Seric { 34665496Seric a->q_flags |= QBADADDR; 34765496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 34865496Seric a->q_alias->q_ruser, MyHostName); 34965496Seric } 35065496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 35165496Seric { 35265496Seric a->q_flags |= QBADADDR; 35365496Seric usrerr("550 Address %s is unsafe for mailing to files", 35465496Seric a->q_alias->q_paddr); 35565496Seric } 35665112Seric else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) 35751317Seric { 35858680Seric a->q_flags |= QBADADDR; 35964771Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, e); 36051317Seric } 36151317Seric } 36251317Seric 36357402Seric /* try aliasing */ 36467472Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 36567472Seric alias(a, sendq, e); 36657402Seric 36757402Seric # ifdef USERDB 36857402Seric /* if not aliased, look it up in the user database */ 36967472Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 37067472Seric bitnset(M_CHECKUDB, m->m_flags)) 37157402Seric { 37257402Seric extern int udbexpand(); 37357402Seric 37457402Seric if (udbexpand(a, sendq, e) == EX_TEMPFAIL) 37557402Seric { 37663853Seric a->q_flags |= QQUEUEUP; 37757402Seric if (e->e_message == NULL) 37857402Seric e->e_message = newstr("Deferred: user database error"); 37957402Seric # ifdef LOG 38058020Seric if (LogLevel > 8) 38159623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 38266284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 38366284Seric errstring(errno)); 38457402Seric # endif 38559615Seric message("queued (user database error): %s", 38659615Seric errstring(errno)); 38757642Seric e->e_nrcpts++; 38863847Seric goto testselfdestruct; 38957402Seric } 39057402Seric } 39157402Seric # endif 39257402Seric 39351317Seric /* 39451317Seric ** If we have a level two config file, then pass the name through 39551317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 39651317Seric ** to send rewrite it to another mailer. This gives us a hook 39751317Seric ** after local aliasing has been done. 39851317Seric */ 39951317Seric 40051317Seric if (tTd(29, 5)) 40151317Seric { 40251317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 40351317Seric ConfigLevel, RewriteRules[5]); 40451317Seric printaddr(a, FALSE); 40551317Seric } 40667472Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 40767472Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 40867472Seric bitnset(M_TRYRULESET5, m->m_flags)) 40951317Seric { 41055012Seric maplocaluser(a, sendq, e); 41151317Seric } 41251317Seric 41351317Seric /* 41451317Seric ** If it didn't get rewritten to another mailer, go ahead 41551317Seric ** and deliver it. 41651317Seric */ 41751317Seric 41867472Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 41967472Seric bitnset(M_HASPWENT, m->m_flags)) 42051317Seric { 42155354Seric auto bool fuzzy; 42251317Seric register struct passwd *pw; 42351317Seric extern struct passwd *finduser(); 42451317Seric 42551317Seric /* warning -- finduser may trash buf */ 42655354Seric pw = finduser(buf, &fuzzy); 42751317Seric if (pw == NULL) 42851317Seric { 42958680Seric a->q_flags |= QBADADDR; 43064771Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, e); 43151317Seric } 4324174Seric else 4334174Seric { 43451317Seric char nbuf[MAXNAME]; 4354373Seric 43655354Seric if (fuzzy) 4374174Seric { 43853735Seric /* name was a fuzzy match */ 43951317Seric a->q_user = newstr(pw->pw_name); 44053735Seric if (findusercount++ > 3) 44153735Seric { 44258680Seric a->q_flags |= QBADADDR; 44358151Seric usrerr("554 aliasing/forwarding loop for %s broken", 44453735Seric pw->pw_name); 44567264Seric goto done; 44653735Seric } 44753735Seric 44853735Seric /* see if it aliases */ 44951317Seric (void) strcpy(buf, pw->pw_name); 45053735Seric goto trylocaluser; 4514174Seric } 45265822Seric if (strcmp(pw->pw_dir, "/") == 0) 45365822Seric a->q_home = ""; 45465822Seric else 45565822Seric a->q_home = newstr(pw->pw_dir); 45651317Seric a->q_uid = pw->pw_uid; 45751317Seric a->q_gid = pw->pw_gid; 45859083Seric a->q_ruser = newstr(pw->pw_name); 45951317Seric a->q_flags |= QGOODUID; 46051317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 46151317Seric if (nbuf[0] != '\0') 46251317Seric a->q_fullname = newstr(nbuf); 46365211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 46465211Seric !usershellok(pw->pw_shell)) 46565206Seric { 46665211Seric a->q_flags |= QBOGUSSHELL; 46765206Seric } 46851317Seric if (!quoted) 46955012Seric forward(a, sendq, e); 4704174Seric } 4714174Seric } 47257642Seric if (!bitset(QDONTSEND, a->q_flags)) 47357642Seric e->e_nrcpts++; 47463847Seric 47563847Seric testselfdestruct: 47663978Seric if (tTd(26, 8)) 47763847Seric { 47863978Seric printf("testselfdestruct: "); 47963978Seric printaddr(a, TRUE); 48063978Seric } 48163978Seric if (a->q_alias == NULL && a != &e->e_from && 48263978Seric bitset(QDONTSEND, a->q_flags)) 48363978Seric { 48463978Seric q = *sendq; 48563965Seric while (q != NULL && bitset(QDONTSEND, q->q_flags)) 48663847Seric q = q->q_next; 48763978Seric if (q == NULL) 48863847Seric { 48963847Seric a->q_flags |= QBADADDR; 49063847Seric usrerr("554 aliasing/forwarding loop broken"); 49163847Seric } 49263847Seric } 49367264Seric 49467264Seric done: 49567264Seric if (buf != buf0) 49667264Seric free(buf); 49712613Seric return (a); 4984174Seric } 4994174Seric /* 5004373Seric ** FINDUSER -- find the password entry for a user. 5014373Seric ** 5024373Seric ** This looks a lot like getpwnam, except that it may want to 5034373Seric ** do some fancier pattern matching in /etc/passwd. 5044373Seric ** 5059379Seric ** This routine contains most of the time of many sendmail runs. 5069379Seric ** It deserves to be optimized. 5079379Seric ** 5084373Seric ** Parameters: 5094373Seric ** name -- the name to match against. 51055354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 51155354Seric ** was found using the fuzzy matching algorithm; 51255354Seric ** set to FALSE otherwise. 5134373Seric ** 5144373Seric ** Returns: 5154373Seric ** A pointer to a pw struct. 5164373Seric ** NULL if name is unknown or ambiguous. 5174373Seric ** 5184373Seric ** Side Effects: 5194407Seric ** may modify name. 5204373Seric */ 5214373Seric 5224373Seric struct passwd * 52355354Seric finduser(name, fuzzyp) 5244373Seric char *name; 52555354Seric bool *fuzzyp; 5264373Seric { 5274376Seric register struct passwd *pw; 5284407Seric register char *p; 52915325Seric extern struct passwd *getpwent(); 53015325Seric extern struct passwd *getpwnam(); 5314373Seric 53255354Seric if (tTd(29, 4)) 53355354Seric printf("finduser(%s): ", name); 53455354Seric 53555354Seric *fuzzyp = FALSE; 5364407Seric 53767839Seric #ifdef HESIOD 53864673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 53964673Seric for (p = name; *p != '\0'; p++) 54064673Seric if (!isascii(*p) || !isdigit(*p)) 54164673Seric break; 54264673Seric if (*p == '\0') 54364673Seric { 54464673Seric if (tTd(29, 4)) 54564673Seric printf("failed (numeric input)\n"); 54664673Seric return NULL; 54764673Seric } 54867839Seric #endif 54964673Seric 55025777Seric /* look up this login name using fast path */ 55112634Seric if ((pw = getpwnam(name)) != NULL) 55255354Seric { 55355354Seric if (tTd(29, 4)) 55455354Seric printf("found (non-fuzzy)\n"); 55512634Seric return (pw); 55655354Seric } 55712634Seric 55853735Seric #ifdef MATCHGECOS 55953735Seric /* see if fuzzy matching allowed */ 56053735Seric if (!MatchGecos) 56155354Seric { 56255354Seric if (tTd(29, 4)) 56355354Seric printf("not found (fuzzy disabled)\n"); 56453735Seric return NULL; 56555354Seric } 56653735Seric 56712634Seric /* search for a matching full name instead */ 56825777Seric for (p = name; *p != '\0'; p++) 56925777Seric { 57025777Seric if (*p == (SpaceSub & 0177) || *p == '_') 57125777Seric *p = ' '; 57225777Seric } 57323107Seric (void) setpwent(); 5744376Seric while ((pw = getpwent()) != NULL) 5754376Seric { 5764998Seric char buf[MAXNAME]; 5774376Seric 5784998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 57956795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 5804381Seric { 58155354Seric if (tTd(29, 4)) 58255354Seric printf("fuzzy matches %s\n", pw->pw_name); 58358151Seric message("sending to login name %s", pw->pw_name); 58455354Seric *fuzzyp = TRUE; 5854376Seric return (pw); 5864377Seric } 5874376Seric } 58855354Seric if (tTd(29, 4)) 58955354Seric printf("no fuzzy match found\n"); 59059015Seric #else 59159015Seric if (tTd(29, 4)) 59259015Seric printf("not found (fuzzy disabled)\n"); 59359015Seric #endif 5944376Seric return (NULL); 5954373Seric } 5964373Seric /* 5974329Seric ** WRITABLE -- predicate returning if the file is writable. 5984329Seric ** 5994329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6004329Seric ** Unfortunately, we cannot use the access call since we 6014329Seric ** won't necessarily be the real uid when we try to 6024329Seric ** actually open the file. 6034329Seric ** 6044329Seric ** Notice that ANY file with ANY execute bit is automatically 6054329Seric ** not writable. This is also enforced by mailfile. 6064329Seric ** 6074329Seric ** Parameters: 60865064Seric ** filename -- the file name to check. 60965112Seric ** ctladdr -- the controlling address for this file. 61065064Seric ** flags -- SFF_* flags to control the function. 6114329Seric ** 6124329Seric ** Returns: 6134329Seric ** TRUE -- if we will be able to write this file. 6144329Seric ** FALSE -- if we cannot write this file. 6154329Seric ** 6164329Seric ** Side Effects: 6174329Seric ** none. 6184329Seric */ 6194329Seric 6204329Seric bool 62165112Seric writable(filename, ctladdr, flags) 62264819Seric char *filename; 62365112Seric ADDRESS *ctladdr; 62465064Seric int flags; 6254329Seric { 62655372Seric uid_t euid; 62755372Seric gid_t egid; 6284329Seric int bits; 62964944Seric register char *p; 63064944Seric char *uname; 63164944Seric struct stat stb; 63264944Seric extern char RealUserName[]; 6334329Seric 63464819Seric if (tTd(29, 5)) 63565064Seric printf("writable(%s, %x)\n", filename, flags); 63664944Seric 63764944Seric #ifdef HASLSTAT 63865064Seric if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) 63965064Seric : stat(filename, &stb)) < 0) 64064944Seric #else 64164944Seric if (stat(filename, &stb) < 0) 64264944Seric #endif 64364944Seric { 64464944Seric /* file does not exist -- see if directory is safe */ 64564944Seric p = strrchr(filename, '/'); 64664944Seric if (p == NULL) 64764944Seric { 64865067Seric errno = ENOTDIR; 64964944Seric return FALSE; 65064944Seric } 65165067Seric *p = '\0'; 65265067Seric errno = safefile(filename, RealUid, RealGid, RealUserName, 65365067Seric SFF_MUSTOWN, S_IWRITE|S_IEXEC); 65464944Seric *p = '/'; 65565067Seric return errno == 0; 65664944Seric } 65764944Seric 65865225Seric #ifdef SUID_ROOT_FILES_OK 65965225Seric /* really ought to be passed down -- and not a good idea */ 66065225Seric flags |= SFF_ROOTOK; 66165225Seric #endif 66265225Seric 66364944Seric /* 66464944Seric ** File does exist -- check that it is writable. 66564944Seric */ 66664944Seric 66764944Seric if (bitset(0111, stb.st_mode)) 66865022Seric { 66965022Seric if (tTd(29, 5)) 67065022Seric printf("failed (mode %o: x bits)\n", stb.st_mode); 67165067Seric errno = EPERM; 6724329Seric return (FALSE); 67365022Seric } 67464944Seric 67565112Seric if (ctladdr != NULL && geteuid() == 0) 67664944Seric { 67765112Seric euid = ctladdr->q_uid; 67865112Seric egid = ctladdr->q_gid; 67965112Seric uname = ctladdr->q_user; 68064944Seric } 681*67940Seric #ifdef RUN_AS_REAL_UID 68265112Seric else 68365112Seric { 68465112Seric euid = RealUid; 68565112Seric egid = RealGid; 68665112Seric uname = RealUserName; 68765112Seric } 688*67940Seric #else 689*67940Seric else if (FileMailer != NULL) 690*67940Seric { 691*67940Seric euid = FileMailer->m_uid; 692*67940Seric egid = FileMailer->m_gid; 693*67940Seric } 694*67940Seric else 695*67940Seric { 696*67940Seric euid = egid = 0; 697*67940Seric } 698*67940Seric #endif 69965138Seric if (euid == 0) 70065138Seric { 70165138Seric euid = DefUid; 70265138Seric uname = DefUser; 70365138Seric } 70465138Seric if (egid == 0) 70565138Seric egid = DefGid; 7064329Seric if (geteuid() == 0) 7074329Seric { 70865225Seric if (bitset(S_ISUID, stb.st_mode) && 70965225Seric (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) 71064944Seric { 71164944Seric euid = stb.st_uid; 71264944Seric uname = NULL; 71364944Seric } 71465225Seric if (bitset(S_ISGID, stb.st_mode) && 71565225Seric (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) 71664944Seric egid = stb.st_gid; 7174329Seric } 7184329Seric 71964819Seric if (tTd(29, 5)) 72064819Seric printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", 72164944Seric euid, egid, stb.st_uid, stb.st_gid); 72264819Seric 72365067Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); 72465067Seric return errno == 0; 7254329Seric } 7264329Seric /* 7274174Seric ** INCLUDE -- handle :include: specification. 7284174Seric ** 7294174Seric ** Parameters: 7304174Seric ** fname -- filename to include. 73153037Seric ** forwarding -- if TRUE, we are reading a .forward file. 73253037Seric ** if FALSE, it's a :include: file. 7334399Seric ** ctladdr -- address template to use to fill in these 7344399Seric ** addresses -- effective user/group id are 7354399Seric ** the important things. 7365006Seric ** sendq -- a pointer to the head of the send queue 7375006Seric ** to put these addresses in. 7384174Seric ** 7394174Seric ** Returns: 74057136Seric ** open error status 7414174Seric ** 7424174Seric ** Side Effects: 7434174Seric ** reads the :include: file and sends to everyone 7444174Seric ** listed in that file. 74565909Seric ** 74665909Seric ** Security Note: 74765909Seric ** If you have restricted chown (that is, you can't 74865909Seric ** give a file away), it is reasonable to allow programs 74965909Seric ** and files called from this :include: file to be to be 75065909Seric ** run as the owner of the :include: file. This is bogus 75165909Seric ** if there is any chance of someone giving away a file. 75265909Seric ** We assume that pre-POSIX systems can give away files. 75365909Seric ** 75465909Seric ** There is an additional restriction that if you 75565909Seric ** forward to a :include: file, it will not take on 75665909Seric ** the ownership of the :include: file. This may not 75765909Seric ** be necessary, but shouldn't hurt. 7584174Seric */ 7594174Seric 76053037Seric static jmp_buf CtxIncludeTimeout; 76163937Seric static int includetimeout(); 76253037Seric 76365496Seric #ifndef S_IWOTH 76465496Seric # define S_IWOTH (S_IWRITE >> 6) 76565496Seric #endif 76665496Seric 76757136Seric int 76855012Seric include(fname, forwarding, ctladdr, sendq, e) 7694174Seric char *fname; 77053037Seric bool forwarding; 7714399Seric ADDRESS *ctladdr; 7725006Seric ADDRESS **sendq; 77355012Seric ENVELOPE *e; 7744174Seric { 77564570Seric register FILE *fp = NULL; 77655012Seric char *oldto = e->e_to; 7779379Seric char *oldfilename = FileName; 7789379Seric int oldlinenumber = LineNumber; 77953037Seric register EVENT *ev = NULL; 78058082Seric int nincludes; 78164325Seric register ADDRESS *ca; 78264325Seric uid_t saveduid, uid; 78364325Seric gid_t savedgid, gid; 78464083Seric char *uname; 78564325Seric int rval = 0; 78665064Seric int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; 78765496Seric struct stat st; 78865948Seric char buf[MAXLINE]; 78965909Seric #ifdef _POSIX_CHOWN_RESTRICTED 79065948Seric # if _POSIX_CHOWN_RESTRICTED == -1 79165948Seric # define safechown FALSE 79265948Seric # else 79365948Seric # define safechown TRUE 79465948Seric # endif 79565948Seric #else 79665948Seric # ifdef _PC_CHOWN_RESTRICTED 79765909Seric bool safechown; 79865948Seric # else 79965948Seric # ifdef BSD 80065948Seric # define safechown TRUE 80165948Seric # else 80265948Seric # define safechown FALSE 80365948Seric # endif 80465948Seric # endif 80565909Seric #endif 80665948Seric extern bool chownsafe(); 8074174Seric 80857186Seric if (tTd(27, 2)) 80957186Seric printf("include(%s)\n", fname); 81063902Seric if (tTd(27, 4)) 81163902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 81263581Seric if (tTd(27, 14)) 81363581Seric { 81463581Seric printf("ctladdr "); 81563581Seric printaddr(ctladdr, FALSE); 81663581Seric } 81757186Seric 81864325Seric if (tTd(27, 9)) 81964325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 82053037Seric 82163581Seric ca = getctladdr(ctladdr); 82263581Seric if (ca == NULL) 82364083Seric { 82464846Seric uid = DefUid; 82564846Seric gid = DefGid; 82664846Seric uname = DefUser; 82764325Seric saveduid = -1; 82864083Seric } 82963581Seric else 83064083Seric { 83163581Seric uid = ca->q_uid; 83264083Seric gid = ca->q_gid; 83364083Seric uname = ca->q_user; 83464325Seric #ifdef HASSETREUID 83564325Seric saveduid = geteuid(); 83664325Seric savedgid = getegid(); 83764325Seric if (saveduid == 0) 83864325Seric { 83964325Seric initgroups(uname, gid); 84064325Seric if (uid != 0) 84167827Seric { 84267827Seric if (setreuid(0, uid) < 0) 84367827Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 84467827Seric uid, getuid(), geteuid()); 84567827Seric } 84664325Seric } 84764325Seric #endif 84864083Seric } 84963581Seric 85064325Seric if (tTd(27, 9)) 85164325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 85264325Seric 85364325Seric /* 85464325Seric ** If home directory is remote mounted but server is down, 85564325Seric ** this can hang or give errors; use a timeout to avoid this 85664325Seric */ 85764325Seric 85853037Seric if (setjmp(CtxIncludeTimeout) != 0) 85953037Seric { 86063853Seric ctladdr->q_flags |= QQUEUEUP; 86153037Seric errno = 0; 86263993Seric 86363993Seric /* return pseudo-error code */ 86464325Seric rval = EOPENTIMEOUT; 86564325Seric goto resetuid; 86653037Seric } 86767711Seric if (TimeOuts.to_fileopen > 0) 86867711Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 86967711Seric else 87067711Seric ev = NULL; 87153037Seric 87263581Seric /* the input file must be marked safe */ 87364944Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); 87464329Seric if (rval != 0) 87553037Seric { 87664325Seric /* don't use this :include: file */ 87757186Seric if (tTd(27, 4)) 87858247Seric printf("include: not safe (uid=%d): %s\n", 87964329Seric uid, errstring(rval)); 88053037Seric } 88165496Seric else 8824174Seric { 88365496Seric fp = fopen(fname, "r"); 88465496Seric if (fp == NULL) 88558061Seric { 88664329Seric rval = errno; 88765496Seric if (tTd(27, 4)) 88865496Seric printf("include: open: %s\n", errstring(rval)); 88958061Seric } 8904406Seric } 89167711Seric if (ev != NULL) 89267711Seric clrevent(ev); 89353037Seric 89464570Seric resetuid: 89564570Seric 89664570Seric #ifdef HASSETREUID 89764570Seric if (saveduid == 0) 89864570Seric { 89964570Seric if (uid != 0) 90067827Seric { 90167827Seric if (setreuid(-1, 0) < 0) 90267827Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 90367827Seric getuid(), geteuid()); 90467827Seric if (setreuid(RealUid, 0) < 0) 90564570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 90664570Seric RealUid, getuid(), geteuid()); 90767827Seric } 90864570Seric setgid(savedgid); 90964570Seric } 91064570Seric #endif 91164570Seric 91264570Seric if (tTd(27, 9)) 91364570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 91464570Seric 91565593Seric if (rval == EOPENTIMEOUT) 91665593Seric usrerr("451 open timeout on %s", fname); 91765593Seric 91864570Seric if (fp == NULL) 91964570Seric return rval; 92064570Seric 92165496Seric if (fstat(fileno(fp), &st) < 0) 92265496Seric { 92365496Seric rval = errno; 92465496Seric syserr("Cannot fstat %s!", fname); 92565496Seric return rval; 92665496Seric } 92765496Seric 92865948Seric #ifndef safechown 92965948Seric safechown = chownsafe(fileno(fp)); 93065948Seric #endif 93165909Seric if (ca == NULL && safechown) 93265496Seric { 93365496Seric ctladdr->q_uid = st.st_uid; 93465496Seric ctladdr->q_gid = st.st_gid; 93565496Seric ctladdr->q_flags |= QGOODUID; 93665496Seric } 93765496Seric if (ca != NULL && ca->q_uid == st.st_uid) 93865496Seric { 93965496Seric /* optimization -- avoid getpwuid if we already have info */ 94065496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 94165496Seric ctladdr->q_ruser = ca->q_ruser; 94265496Seric } 94365496Seric else 94465496Seric { 94565496Seric register struct passwd *pw; 94665496Seric 94765496Seric pw = getpwuid(st.st_uid); 948*67940Seric if (pw == NULL) 949*67940Seric ctladdr->q_flags |= QBOGUSSHELL; 950*67940Seric else 95165496Seric { 952*67940Seric char *sh; 953*67940Seric 95465496Seric ctladdr->q_ruser = newstr(pw->pw_name); 95565909Seric if (safechown) 95665909Seric sh = pw->pw_shell; 95765909Seric else 958*67940Seric sh = "/SENDMAIL/ANY/SHELL/"; 959*67940Seric if (!usershellok(sh)) 960*67940Seric { 961*67940Seric if (safechown) 962*67940Seric ctladdr->q_flags |= QBOGUSSHELL; 963*67940Seric else 964*67940Seric ctladdr->q_flags |= QUNSAFEADDR; 965*67940Seric } 96665496Seric } 96765496Seric } 96865496Seric 96958092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 97058092Seric { 97158092Seric /* don't do any more now */ 97258868Seric ctladdr->q_flags |= QVERIFIED; 97358884Seric e->e_nrcpts++; 97458680Seric xfclose(fp, "include", fname); 97564570Seric return rval; 97658092Seric } 97758092Seric 97865496Seric /* 97965496Seric ** Check to see if some bad guy can write this file 98065496Seric ** 98165496Seric ** This should really do something clever with group 98265496Seric ** permissions; currently we just view world writable 98365496Seric ** as unsafe. Also, we don't check for writable 98465496Seric ** directories in the path. We've got to leave 98565496Seric ** something for the local sysad to do. 98665496Seric */ 98765496Seric 98865496Seric if (bitset(S_IWOTH, st.st_mode)) 98965496Seric ctladdr->q_flags |= QUNSAFEADDR; 99065496Seric 9914174Seric /* read the file -- each line is a comma-separated list. */ 9929379Seric FileName = fname; 9939379Seric LineNumber = 0; 99458082Seric ctladdr->q_flags &= ~QSELFREF; 99558082Seric nincludes = 0; 9964174Seric while (fgets(buf, sizeof buf, fp) != NULL) 9974174Seric { 99856795Seric register char *p = strchr(buf, '\n'); 9994174Seric 100040963Sbostic LineNumber++; 10014174Seric if (p != NULL) 10024174Seric *p = '\0'; 100357186Seric if (buf[0] == '#' || buf[0] == '\0') 100457139Seric continue; 100558008Seric e->e_to = NULL; 100658151Seric message("%s to %s", 100753037Seric forwarding ? "forwarding" : "sending", buf); 100857977Seric #ifdef LOG 100958020Seric if (forwarding && LogLevel > 9) 101057977Seric syslog(LOG_INFO, "%s: forward %s => %s", 101166284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 101266284Seric oldto, buf); 101357977Seric #endif 101457977Seric 10154176Seric AliasLevel++; 101658082Seric nincludes += sendtolist(buf, ctladdr, sendq, e); 10174176Seric AliasLevel--; 10184174Seric } 101963902Seric 102063902Seric if (ferror(fp) && tTd(27, 3)) 102163902Seric printf("include: read error: %s\n", errstring(errno)); 102258082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 102358065Seric { 102458065Seric if (tTd(27, 5)) 102558065Seric { 102658065Seric printf("include: QDONTSEND "); 102758065Seric printaddr(ctladdr, FALSE); 102858065Seric } 102958065Seric ctladdr->q_flags |= QDONTSEND; 103058065Seric } 10314174Seric 103258680Seric (void) xfclose(fp, "include", fname); 10339379Seric FileName = oldfilename; 10349379Seric LineNumber = oldlinenumber; 103563847Seric e->e_to = oldto; 103664325Seric return rval; 10374174Seric } 103853037Seric 103953037Seric static 104053037Seric includetimeout() 104153037Seric { 104253037Seric longjmp(CtxIncludeTimeout, 1); 104353037Seric } 10444324Seric /* 10454324Seric ** SENDTOARGV -- send to an argument vector. 10464324Seric ** 10474324Seric ** Parameters: 10484324Seric ** argv -- argument vector to send to. 104958247Seric ** e -- the current envelope. 10504324Seric ** 10514324Seric ** Returns: 10524324Seric ** none. 10534324Seric ** 10544324Seric ** Side Effects: 10554324Seric ** puts all addresses on the argument vector onto the 10564324Seric ** send queue. 10574324Seric */ 10584324Seric 105955012Seric sendtoargv(argv, e) 10604324Seric register char **argv; 106155012Seric register ENVELOPE *e; 10624324Seric { 10634324Seric register char *p; 10644324Seric 10654324Seric while ((p = *argv++) != NULL) 10664324Seric { 106764284Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, e); 10684324Seric } 10694324Seric } 10704399Seric /* 10714399Seric ** GETCTLADDR -- get controlling address from an address header. 10724399Seric ** 10734399Seric ** If none, get one corresponding to the effective userid. 10744399Seric ** 10754399Seric ** Parameters: 10764399Seric ** a -- the address to find the controller of. 10774399Seric ** 10784399Seric ** Returns: 10794399Seric ** the controlling address. 10804399Seric ** 10814399Seric ** Side Effects: 10824399Seric ** none. 10834399Seric */ 10844399Seric 10854399Seric ADDRESS * 10864399Seric getctladdr(a) 10874399Seric register ADDRESS *a; 10884399Seric { 10894404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 10904399Seric a = a->q_alias; 10914399Seric return (a); 10924399Seric } 1093