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*68802Seric static char sccsid[] = "@(#)recipient.c 8.78 (Berkeley) 04/13/95"; 1133731Sbostic #endif /* not lint */ 1222710Sdist 1358332Seric # include "sendmail.h" 144174Seric 154174Seric /* 169622Seric ** SENDTOLIST -- Designate a send list. 174174Seric ** 184174Seric ** The parameter is a comma-separated list of people to send to. 194174Seric ** This routine arranges to send to all of them. 204174Seric ** 214174Seric ** Parameters: 224174Seric ** list -- the send list. 234399Seric ** ctladdr -- the address template for the person to 244399Seric ** send to -- effective uid/gid are important. 255006Seric ** This is typically the alias that caused this 265006Seric ** expansion. 275006Seric ** sendq -- a pointer to the head of a queue to put 285006Seric ** these people into. 2968481Seric ** aliaslevel -- the current alias nesting depth -- to 3068481Seric ** diagnose loops. 3158247Seric ** e -- the envelope in which to add these recipients. 324174Seric ** 334174Seric ** Returns: 3458082Seric ** The number of addresses actually on the list. 354174Seric ** 364174Seric ** Side Effects: 374174Seric ** none. 384174Seric */ 394174Seric 4068481Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 414174Seric 4268481Seric /* q_flags bits inherited from ctladdr */ 4368595Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) 4468481Seric 4568481Seric int 4668481Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 474174Seric char *list; 484399Seric ADDRESS *ctladdr; 495198Seric ADDRESS **sendq; 5068481Seric int aliaslevel; 5155012Seric register ENVELOPE *e; 524174Seric { 534174Seric register char *p; 548223Seric register ADDRESS *al; /* list of addresses to send to */ 554423Seric bool firstone; /* set on first address sent */ 5611446Seric char delimiter; /* the address delimiter */ 5758082Seric int naddrs; 5868392Seric int i; 5963847Seric char *oldto = e->e_to; 6068392Seric char *bufp; 6168271Seric char buf[MAXNAME + 1]; 624174Seric 6364131Seric if (list == NULL) 6464131Seric { 6564131Seric syserr("sendtolist: null list"); 6664131Seric return 0; 6764131Seric } 6864131Seric 697676Seric if (tTd(25, 1)) 704444Seric { 714444Seric printf("sendto: %s\n ctladdr=", list); 724444Seric printaddr(ctladdr, FALSE); 734444Seric } 744324Seric 758223Seric /* heuristic to determine old versus new style addresses */ 768230Seric if (ctladdr == NULL && 7756795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 7856795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 7955012Seric e->e_flags &= ~EF_OLDSTYLE; 8011446Seric delimiter = ' '; 8155012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 8211446Seric delimiter = ','; 838223Seric 844423Seric firstone = TRUE; 854324Seric al = NULL; 8658082Seric naddrs = 0; 878223Seric 8868392Seric /* make sure we have enough space to copy the string */ 8968392Seric i = strlen(list) + 1; 9068392Seric if (i <= sizeof buf) 9168271Seric bufp = buf; 9268392Seric else 9368392Seric bufp = xalloc(i); 9468478Seric strcpy(bufp, denlstring(list, FALSE, TRUE)); 9568271Seric 9668271Seric for (p = bufp; *p != '\0'; ) 9768271Seric { 9858333Seric auto char *delimptr; 998081Seric register ADDRESS *a; 1004319Seric 1018081Seric /* parse the address */ 10258050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1034174Seric p++; 10464284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10558333Seric p = delimptr; 1069297Seric if (a == NULL) 1074174Seric continue; 1084324Seric a->q_next = al; 1094399Seric a->q_alias = ctladdr; 1104444Seric 11168481Seric /* arrange to inherit attributes from parent */ 11268481Seric if (ctladdr != NULL) 11368481Seric { 11468481Seric /* self reference test */ 11568481Seric if (sameaddr(ctladdr, a)) 11668481Seric ctladdr->q_flags |= QSELFREF; 11768481Seric 11868481Seric /* full name */ 11968481Seric if (a->q_fullname == NULL) 12068481Seric a->q_fullname = ctladdr->q_fullname; 12168481Seric 12268481Seric /* various flag bits */ 12368481Seric a->q_flags &= ~QINHERITEDBITS; 12468481Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 12568481Seric 12668481Seric /* original recipient information */ 12768481Seric a->q_orcpt = ctladdr->q_orcpt; 12868481Seric } 12968481Seric 13057731Seric al = a; 1314423Seric firstone = FALSE; 1324324Seric } 1334324Seric 1344324Seric /* arrange to send to everyone on the local send list */ 1354324Seric while (al != NULL) 1364324Seric { 1374324Seric register ADDRESS *a = al; 1384324Seric 1394324Seric al = a->q_next; 14068481Seric a = recipient(a, sendq, aliaslevel, e); 14158082Seric naddrs++; 1424174Seric } 1434324Seric 14463847Seric e->e_to = oldto; 14568392Seric if (bufp != buf) 14668392Seric free(bufp); 14758082Seric return (naddrs); 1484174Seric } 1494174Seric /* 1504174Seric ** RECIPIENT -- Designate a message recipient 1514174Seric ** 1524174Seric ** Saves the named person for future mailing. 1534174Seric ** 1544174Seric ** Parameters: 1554174Seric ** a -- the (preparsed) address header for the recipient. 1565006Seric ** sendq -- a pointer to the head of a queue to put the 1575006Seric ** recipient in. Duplicate supression is done 1585006Seric ** in this queue. 15968481Seric ** aliaslevel -- the current alias nesting depth. 16057731Seric ** e -- the current envelope. 1614174Seric ** 1624174Seric ** Returns: 16312613Seric ** The actual address in the queue. This will be "a" if 16412613Seric ** the address is not a duplicate, else the original address. 1654174Seric ** 1664174Seric ** Side Effects: 1674174Seric ** none. 1684174Seric */ 1694174Seric 17012613Seric ADDRESS * 17168481Seric recipient(a, sendq, aliaslevel, e) 1724174Seric register ADDRESS *a; 1735006Seric register ADDRESS **sendq; 17468481Seric int aliaslevel; 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; 18368603Seric bool initialdontsend = bitset(QDONTSEND, a->q_flags); 18468481Seric int i; 18568481Seric char *buf; 18668528Seric char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 18758247Seric extern int safefile(); 1884174Seric 18955012Seric e->e_to = a->q_paddr; 1904600Seric m = a->q_mailer; 1914174Seric errno = 0; 19268603Seric if (aliaslevel == 0) 19368603Seric a->q_flags |= QPRIMARY; 1947676Seric if (tTd(26, 1)) 1954444Seric { 19668603Seric printf("\nrecipient (%d): ", aliaslevel); 1974444Seric printaddr(a, FALSE); 1984444Seric } 1994174Seric 20064146Seric /* if this is primary, add it to the original recipient list */ 20164146Seric if (a->q_alias == NULL) 20264146Seric { 20364146Seric if (e->e_origrcpt == NULL) 20464146Seric e->e_origrcpt = a->q_paddr; 20564146Seric else if (e->e_origrcpt != a->q_paddr) 20664146Seric e->e_origrcpt = ""; 20764146Seric } 20864146Seric 2094174Seric /* break aliasing loops */ 21068481Seric if (aliaslevel > MAXRCRSN) 2114174Seric { 21268481Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 21368481Seric aliaslevel, MAXRCRSN); 21412613Seric return (a); 2154174Seric } 2164174Seric 2174174Seric /* 2184627Seric ** Finish setting up address structure. 2194174Seric */ 2204174Seric 22116160Seric /* get unquoted user for file, program or user.name check */ 22268481Seric i = strlen(a->q_user); 22368528Seric if (i >= sizeof buf0) 22468481Seric buf = xalloc(i + 1); 22568481Seric else 22668481Seric buf = buf0; 2279210Seric (void) strcpy(buf, a->q_user); 2289210Seric for (p = buf; *p != '\0' && !quoted; p++) 2299210Seric { 23054993Seric if (*p == '\\') 2319210Seric quoted = TRUE; 2329210Seric } 23354983Seric stripquotes(buf); 2349210Seric 23557402Seric /* check for direct mailing to restricted mailers */ 23665496Seric if (m == ProgMailer) 2374174Seric { 23865496Seric if (a->q_alias == NULL) 23965496Seric { 24065496Seric a->q_flags |= QBADADDR; 24165496Seric usrerr("550 Cannot mail directly to programs"); 24265496Seric } 24365496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24465496Seric { 24565496Seric a->q_flags |= QBADADDR; 24665496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 24765496Seric a->q_alias->q_ruser, MyHostName); 24865496Seric } 24965496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25065496Seric { 25165496Seric a->q_flags |= QBADADDR; 25265496Seric usrerr("550 Address %s is unsafe for mailing to programs", 25365496Seric a->q_alias->q_paddr); 25465496Seric } 2554174Seric } 2564174Seric 2574174Seric /* 2584419Seric ** Look up this person in the recipient list. 2594419Seric ** If they are there already, return, otherwise continue. 2604419Seric ** If the list is empty, just add it. Notice the cute 2614419Seric ** hack to make from addresses suppress things correctly: 2624419Seric ** the QDONTSEND bit will be set in the send list. 2634419Seric ** [Please note: the emphasis is on "hack."] 2644174Seric */ 2654174Seric 2665006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2674174Seric { 26858294Seric if (sameaddr(q, a)) 2694174Seric { 2707676Seric if (tTd(26, 1)) 2714444Seric { 2724444Seric printf("%s in sendq: ", a->q_paddr); 2734444Seric printaddr(q, FALSE); 2744444Seric } 27565593Seric if (!bitset(QPRIMARY, q->q_flags)) 27658065Seric { 27765593Seric if (!bitset(QDONTSEND, a->q_flags)) 27858151Seric message("duplicate suppressed"); 27965593Seric q->q_flags |= a->q_flags; 28065593Seric } 28165593Seric else if (bitset(QSELFREF, q->q_flags)) 28265579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 28363847Seric a = q; 28468481Seric goto done; 2854174Seric } 2864319Seric } 2874174Seric 2884319Seric /* add address on list */ 28958884Seric *pq = a; 29058884Seric a->q_next = NULL; 2914174Seric 2924174Seric /* 29357402Seric ** Alias the name and handle special mailer types. 2944174Seric */ 2954174Seric 29653735Seric trylocaluser: 29755354Seric if (tTd(29, 7)) 29855354Seric printf("at trylocaluser %s\n", a->q_user); 29955354Seric 30058680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30163847Seric goto testselfdestruct; 30257402Seric 30357402Seric if (m == InclMailer) 3044174Seric { 30557402Seric a->q_flags |= QDONTSEND; 30664761Seric if (a->q_alias == NULL) 3074174Seric { 30858680Seric a->q_flags |= QBADADDR; 30958151Seric usrerr("550 Cannot mail directly to :include:s"); 3104174Seric } 3114174Seric else 31250556Seric { 31359563Seric int ret; 31458247Seric 31558151Seric message("including file %s", a->q_user); 31668481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 31759563Seric if (transienterror(ret)) 31859563Seric { 31959563Seric #ifdef LOG 32059563Seric if (LogLevel > 2) 32166239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 32266284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 32366284Seric a->q_user, errstring(ret)); 32459563Seric #endif 32563853Seric a->q_flags |= QQUEUEUP; 32665215Seric a->q_flags &= ~QDONTSEND; 32759563Seric usrerr("451 Cannot open %s: %s", 32859563Seric a->q_user, errstring(ret)); 32959563Seric } 33059563Seric else if (ret != 0) 33159563Seric { 33263938Seric a->q_flags |= QBADADDR; 33359563Seric usrerr("550 Cannot open %s: %s", 33459563Seric a->q_user, errstring(ret)); 33559563Seric } 33650556Seric } 3374174Seric } 33857642Seric else if (m == FileMailer) 3394174Seric { 3404329Seric extern bool writable(); 3414174Seric 34251317Seric /* check if writable or creatable */ 34364761Seric if (a->q_alias == NULL) 3444174Seric { 34558680Seric a->q_flags |= QBADADDR; 34658151Seric usrerr("550 Cannot mail directly to files"); 3474174Seric } 34865496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 34965496Seric { 35065496Seric a->q_flags |= QBADADDR; 35165496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 35265496Seric a->q_alias->q_ruser, MyHostName); 35365496Seric } 35465496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 35565496Seric { 35665496Seric a->q_flags |= QBADADDR; 35765496Seric usrerr("550 Address %s is unsafe for mailing to files", 35865496Seric a->q_alias->q_paddr); 35965496Seric } 36068494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT)) 36151317Seric { 36258680Seric a->q_flags |= QBADADDR; 36368481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 36468481Seric (time_t) 0, e); 36551317Seric } 36651317Seric } 36751317Seric 36857402Seric /* try aliasing */ 36968481Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 37068481Seric alias(a, sendq, aliaslevel, e); 37157402Seric 37257402Seric # ifdef USERDB 37357402Seric /* if not aliased, look it up in the user database */ 37468481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 37568481Seric bitnset(M_CHECKUDB, m->m_flags)) 37657402Seric { 37757402Seric extern int udbexpand(); 37857402Seric 37968481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38057402Seric { 38163853Seric a->q_flags |= QQUEUEUP; 38257402Seric if (e->e_message == NULL) 38357402Seric e->e_message = newstr("Deferred: user database error"); 38457402Seric # ifdef LOG 38558020Seric if (LogLevel > 8) 38659623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 38766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 38866284Seric errstring(errno)); 38957402Seric # endif 39059615Seric message("queued (user database error): %s", 39159615Seric errstring(errno)); 39257642Seric e->e_nrcpts++; 39363847Seric goto testselfdestruct; 39457402Seric } 39557402Seric } 39657402Seric # endif 39757402Seric 39851317Seric /* 39951317Seric ** If we have a level two config file, then pass the name through 40051317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 40151317Seric ** to send rewrite it to another mailer. This gives us a hook 40251317Seric ** after local aliasing has been done. 40351317Seric */ 40451317Seric 40551317Seric if (tTd(29, 5)) 40651317Seric { 40751317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 40851317Seric ConfigLevel, RewriteRules[5]); 40951317Seric printaddr(a, FALSE); 41051317Seric } 41168481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 41268481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 41368481Seric bitnset(M_TRYRULESET5, m->m_flags)) 41451317Seric { 41568603Seric maplocaluser(a, sendq, aliaslevel + 1, e); 41651317Seric } 41751317Seric 41851317Seric /* 41951317Seric ** If it didn't get rewritten to another mailer, go ahead 42051317Seric ** and deliver it. 42151317Seric */ 42251317Seric 42368481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 42468481Seric bitnset(M_HASPWENT, m->m_flags)) 42551317Seric { 42655354Seric auto bool fuzzy; 42751317Seric register struct passwd *pw; 42851317Seric extern struct passwd *finduser(); 42951317Seric 43051317Seric /* warning -- finduser may trash buf */ 43155354Seric pw = finduser(buf, &fuzzy); 43251317Seric if (pw == NULL) 43351317Seric { 43458680Seric a->q_flags |= QBADADDR; 43568481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 43668481Seric (time_t) 0, e); 43751317Seric } 4384174Seric else 4394174Seric { 44068528Seric char nbuf[MAXNAME + 1]; 4414373Seric 44255354Seric if (fuzzy) 4434174Seric { 44453735Seric /* name was a fuzzy match */ 44551317Seric a->q_user = newstr(pw->pw_name); 44653735Seric if (findusercount++ > 3) 44753735Seric { 44858680Seric a->q_flags |= QBADADDR; 44958151Seric usrerr("554 aliasing/forwarding loop for %s broken", 45053735Seric pw->pw_name); 45168481Seric goto done; 45253735Seric } 45353735Seric 45453735Seric /* see if it aliases */ 45551317Seric (void) strcpy(buf, pw->pw_name); 45653735Seric goto trylocaluser; 4574174Seric } 45865822Seric if (strcmp(pw->pw_dir, "/") == 0) 45965822Seric a->q_home = ""; 46065822Seric else 46165822Seric a->q_home = newstr(pw->pw_dir); 46251317Seric a->q_uid = pw->pw_uid; 46351317Seric a->q_gid = pw->pw_gid; 46459083Seric a->q_ruser = newstr(pw->pw_name); 46551317Seric a->q_flags |= QGOODUID; 46651317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 46751317Seric if (nbuf[0] != '\0') 46851317Seric a->q_fullname = newstr(nbuf); 46965211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 47065211Seric !usershellok(pw->pw_shell)) 47165206Seric { 47265211Seric a->q_flags |= QBOGUSSHELL; 47365206Seric } 47451317Seric if (!quoted) 47568481Seric forward(a, sendq, aliaslevel, e); 4764174Seric } 4774174Seric } 47857642Seric if (!bitset(QDONTSEND, a->q_flags)) 47957642Seric e->e_nrcpts++; 48063847Seric 48163847Seric testselfdestruct: 48268603Seric a->q_flags |= QTHISPASS; 48363978Seric if (tTd(26, 8)) 48463847Seric { 48563978Seric printf("testselfdestruct: "); 48668603Seric printaddr(a, FALSE); 48768603Seric if (tTd(26, 10)) 48868603Seric { 48968603Seric printf("SENDQ:\n"); 49068603Seric printaddr(*sendq, TRUE); 49168603Seric printf("----\n"); 49268603Seric } 49363978Seric } 49463978Seric if (a->q_alias == NULL && a != &e->e_from && 49563978Seric bitset(QDONTSEND, a->q_flags)) 49663978Seric { 49768603Seric for (q = *sendq; q != NULL; q = q->q_next) 49868603Seric { 49968603Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags) && 50068603Seric bitset(QTHISPASS, q->q_flags)) 50168603Seric break; 50268603Seric } 50363978Seric if (q == NULL) 50463847Seric { 50563847Seric a->q_flags |= QBADADDR; 50663847Seric usrerr("554 aliasing/forwarding loop broken"); 50763847Seric } 50863847Seric } 50968481Seric 51068481Seric done: 51168603Seric a->q_flags |= QTHISPASS; 51268481Seric if (buf != buf0) 51368481Seric free(buf); 51468603Seric 51568603Seric /* 51668603Seric ** If we are at the top level, check to see if this has 51768603Seric ** expanded to exactly one address. If so, it can inherit 51868603Seric ** the primaryness of the address. 51968603Seric ** 52068603Seric ** While we're at it, clear the QTHISPASS bits. 52168603Seric */ 52268603Seric 52368603Seric if (aliaslevel == 0) 52468603Seric { 52568603Seric int nrcpts = 0; 52668603Seric ADDRESS *only; 52768603Seric 52868603Seric for (q = *sendq; q != NULL; q = q->q_next) 52968603Seric { 53068603Seric if (bitset(QTHISPASS, q->q_flags) && 53168603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags)) 53268603Seric { 53368603Seric nrcpts++; 53468603Seric only = q; 53568603Seric } 53668603Seric q->q_flags &= ~QTHISPASS; 53768603Seric } 53868603Seric if (nrcpts == 1) 53968603Seric only->q_flags |= QPRIMARY; 54068603Seric else if (!initialdontsend) 54168603Seric { 54268603Seric /* arrange for return receipt */ 54368603Seric e->e_flags |= EF_SENDRECEIPT; 54468603Seric a->q_flags |= QEXPLODED; 54568603Seric if (e->e_xfp != NULL) 54668603Seric fprintf(e->e_xfp, 54768603Seric "%s... expanded to multiple addresses\n", 54868603Seric a->q_paddr); 54968603Seric } 55068603Seric } 55168603Seric 55212613Seric return (a); 5534174Seric } 5544174Seric /* 5554373Seric ** FINDUSER -- find the password entry for a user. 5564373Seric ** 5574373Seric ** This looks a lot like getpwnam, except that it may want to 5584373Seric ** do some fancier pattern matching in /etc/passwd. 5594373Seric ** 5609379Seric ** This routine contains most of the time of many sendmail runs. 5619379Seric ** It deserves to be optimized. 5629379Seric ** 5634373Seric ** Parameters: 5644373Seric ** name -- the name to match against. 56555354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 56655354Seric ** was found using the fuzzy matching algorithm; 56755354Seric ** set to FALSE otherwise. 5684373Seric ** 5694373Seric ** Returns: 5704373Seric ** A pointer to a pw struct. 5714373Seric ** NULL if name is unknown or ambiguous. 5724373Seric ** 5734373Seric ** Side Effects: 5744407Seric ** may modify name. 5754373Seric */ 5764373Seric 5774373Seric struct passwd * 57855354Seric finduser(name, fuzzyp) 5794373Seric char *name; 58055354Seric bool *fuzzyp; 5814373Seric { 5824376Seric register struct passwd *pw; 5834407Seric register char *p; 5844373Seric 58555354Seric if (tTd(29, 4)) 58655354Seric printf("finduser(%s): ", name); 58755354Seric 58855354Seric *fuzzyp = FALSE; 5894407Seric 59068481Seric #ifdef HESIOD 59164673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 59264673Seric for (p = name; *p != '\0'; p++) 59364673Seric if (!isascii(*p) || !isdigit(*p)) 59464673Seric break; 59564673Seric if (*p == '\0') 59664673Seric { 59764673Seric if (tTd(29, 4)) 59864673Seric printf("failed (numeric input)\n"); 59964673Seric return NULL; 60064673Seric } 60168481Seric #endif 60264673Seric 60325777Seric /* look up this login name using fast path */ 60468693Seric if ((pw = sm_getpwnam(name)) != NULL) 60555354Seric { 60655354Seric if (tTd(29, 4)) 60755354Seric printf("found (non-fuzzy)\n"); 60812634Seric return (pw); 60955354Seric } 61012634Seric 61153735Seric #ifdef MATCHGECOS 61253735Seric /* see if fuzzy matching allowed */ 61353735Seric if (!MatchGecos) 61455354Seric { 61555354Seric if (tTd(29, 4)) 61655354Seric printf("not found (fuzzy disabled)\n"); 61753735Seric return NULL; 61855354Seric } 61953735Seric 62012634Seric /* search for a matching full name instead */ 62125777Seric for (p = name; *p != '\0'; p++) 62225777Seric { 62325777Seric if (*p == (SpaceSub & 0177) || *p == '_') 62425777Seric *p = ' '; 62525777Seric } 62623107Seric (void) setpwent(); 6274376Seric while ((pw = getpwent()) != NULL) 6284376Seric { 62968528Seric char buf[MAXNAME + 1]; 6304376Seric 6314998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 63256795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 6334381Seric { 63455354Seric if (tTd(29, 4)) 63555354Seric printf("fuzzy matches %s\n", pw->pw_name); 63658151Seric message("sending to login name %s", pw->pw_name); 63755354Seric *fuzzyp = TRUE; 6384376Seric return (pw); 6394377Seric } 6404376Seric } 64155354Seric if (tTd(29, 4)) 64255354Seric printf("no fuzzy match found\n"); 64359015Seric #else 64459015Seric if (tTd(29, 4)) 64559015Seric printf("not found (fuzzy disabled)\n"); 64659015Seric #endif 6474376Seric return (NULL); 6484373Seric } 6494373Seric /* 6504329Seric ** WRITABLE -- predicate returning if the file is writable. 6514329Seric ** 6524329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6534329Seric ** Unfortunately, we cannot use the access call since we 6544329Seric ** won't necessarily be the real uid when we try to 6554329Seric ** actually open the file. 6564329Seric ** 6574329Seric ** Notice that ANY file with ANY execute bit is automatically 6584329Seric ** not writable. This is also enforced by mailfile. 6594329Seric ** 6604329Seric ** Parameters: 66165064Seric ** filename -- the file name to check. 66265112Seric ** ctladdr -- the controlling address for this file. 66365064Seric ** flags -- SFF_* flags to control the function. 6644329Seric ** 6654329Seric ** Returns: 6664329Seric ** TRUE -- if we will be able to write this file. 6674329Seric ** FALSE -- if we cannot write this file. 6684329Seric ** 6694329Seric ** Side Effects: 6704329Seric ** none. 6714329Seric */ 6724329Seric 6734329Seric bool 67465112Seric writable(filename, ctladdr, flags) 67564819Seric char *filename; 67665112Seric ADDRESS *ctladdr; 67765064Seric int flags; 6784329Seric { 67955372Seric uid_t euid; 68055372Seric gid_t egid; 6814329Seric int bits; 68264944Seric register char *p; 68364944Seric char *uname; 6844329Seric 68564819Seric if (tTd(29, 5)) 686*68802Seric printf("writable(%s, 0x%x)\n", filename, flags); 68764944Seric 68865225Seric #ifdef SUID_ROOT_FILES_OK 68965225Seric /* really ought to be passed down -- and not a good idea */ 69065225Seric flags |= SFF_ROOTOK; 69165225Seric #endif 69265225Seric 69364944Seric /* 69464944Seric ** File does exist -- check that it is writable. 69564944Seric */ 69664944Seric 69765112Seric if (ctladdr != NULL && geteuid() == 0) 69864944Seric { 69965112Seric euid = ctladdr->q_uid; 70065112Seric egid = ctladdr->q_gid; 70165112Seric uname = ctladdr->q_user; 70264944Seric } 703*68802Seric else if (bitset(SFF_RUNASREALUID, flags)) 70465112Seric { 70568494Seric extern char RealUserName[]; 70668494Seric 70765112Seric euid = RealUid; 70865112Seric egid = RealGid; 70965112Seric uname = RealUserName; 71065112Seric } 71168481Seric else if (FileMailer != NULL) 71268481Seric { 71368481Seric euid = FileMailer->m_uid; 71468481Seric egid = FileMailer->m_gid; 71568481Seric } 71668481Seric else 71768481Seric { 71868481Seric euid = egid = 0; 71968481Seric } 72065138Seric if (euid == 0) 72165138Seric { 72265138Seric euid = DefUid; 72365138Seric uname = DefUser; 72465138Seric } 72565138Seric if (egid == 0) 72665138Seric egid = DefGid; 7274329Seric if (geteuid() == 0) 72868494Seric flags |= SFF_SETUIDOK; 7294329Seric 73068494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); 73165067Seric return errno == 0; 7324329Seric } 7334329Seric /* 7344174Seric ** INCLUDE -- handle :include: specification. 7354174Seric ** 7364174Seric ** Parameters: 7374174Seric ** fname -- filename to include. 73853037Seric ** forwarding -- if TRUE, we are reading a .forward file. 73953037Seric ** if FALSE, it's a :include: file. 7404399Seric ** ctladdr -- address template to use to fill in these 7414399Seric ** addresses -- effective user/group id are 7424399Seric ** the important things. 7435006Seric ** sendq -- a pointer to the head of the send queue 7445006Seric ** to put these addresses in. 74568481Seric ** aliaslevel -- the alias nesting depth. 74668481Seric ** e -- the current envelope. 7474174Seric ** 7484174Seric ** Returns: 74957136Seric ** open error status 7504174Seric ** 7514174Seric ** Side Effects: 7524174Seric ** reads the :include: file and sends to everyone 7534174Seric ** listed in that file. 75465909Seric ** 75565909Seric ** Security Note: 75665909Seric ** If you have restricted chown (that is, you can't 75765909Seric ** give a file away), it is reasonable to allow programs 75865909Seric ** and files called from this :include: file to be to be 75965909Seric ** run as the owner of the :include: file. This is bogus 76065909Seric ** if there is any chance of someone giving away a file. 76165909Seric ** We assume that pre-POSIX systems can give away files. 76265909Seric ** 76365909Seric ** There is an additional restriction that if you 76465909Seric ** forward to a :include: file, it will not take on 76565909Seric ** the ownership of the :include: file. This may not 76665909Seric ** be necessary, but shouldn't hurt. 7674174Seric */ 7684174Seric 76953037Seric static jmp_buf CtxIncludeTimeout; 77068481Seric static void includetimeout(); 77153037Seric 77257136Seric int 77368481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7744174Seric char *fname; 77553037Seric bool forwarding; 7764399Seric ADDRESS *ctladdr; 7775006Seric ADDRESS **sendq; 77868481Seric int aliaslevel; 77955012Seric ENVELOPE *e; 7804174Seric { 78168481Seric FILE *fp = NULL; 78255012Seric char *oldto = e->e_to; 7839379Seric char *oldfilename = FileName; 7849379Seric int oldlinenumber = LineNumber; 78553037Seric register EVENT *ev = NULL; 78658082Seric int nincludes; 78764325Seric register ADDRESS *ca; 78864325Seric uid_t saveduid, uid; 78964325Seric gid_t savedgid, gid; 79064083Seric char *uname; 79164325Seric int rval = 0; 79268513Seric int sfflags = SFF_REGONLY; 79365496Seric struct stat st; 79465948Seric char buf[MAXLINE]; 79565909Seric #ifdef _POSIX_CHOWN_RESTRICTED 79665948Seric # if _POSIX_CHOWN_RESTRICTED == -1 79765948Seric # define safechown FALSE 79865948Seric # else 79965948Seric # define safechown TRUE 80065948Seric # endif 80165948Seric #else 80265948Seric # ifdef _PC_CHOWN_RESTRICTED 80365909Seric bool safechown; 80465948Seric # else 80565948Seric # ifdef BSD 80665948Seric # define safechown TRUE 80765948Seric # else 80865948Seric # define safechown FALSE 80965948Seric # endif 81065948Seric # endif 81165909Seric #endif 81265948Seric extern bool chownsafe(); 8134174Seric 81457186Seric if (tTd(27, 2)) 81557186Seric printf("include(%s)\n", fname); 81663902Seric if (tTd(27, 4)) 81763902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 81863581Seric if (tTd(27, 14)) 81963581Seric { 82063581Seric printf("ctladdr "); 82163581Seric printaddr(ctladdr, FALSE); 82263581Seric } 82357186Seric 82464325Seric if (tTd(27, 9)) 82564325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 82653037Seric 82768513Seric if (forwarding) 82868513Seric sfflags |= SFF_MUSTOWN; 82968513Seric 83063581Seric ca = getctladdr(ctladdr); 83163581Seric if (ca == NULL) 83264083Seric { 83364846Seric uid = DefUid; 83464846Seric gid = DefGid; 83564846Seric uname = DefUser; 83664083Seric } 83763581Seric else 83864083Seric { 83963581Seric uid = ca->q_uid; 84064083Seric gid = ca->q_gid; 84164083Seric uname = ca->q_user; 84268481Seric } 84364325Seric #ifdef HASSETREUID 84468481Seric saveduid = geteuid(); 84568481Seric savedgid = getegid(); 84668481Seric if (saveduid == 0) 84768481Seric { 84868481Seric initgroups(uname, gid); 84968481Seric if (uid != 0) 85064325Seric { 85168481Seric if (setreuid(0, uid) < 0) 85268481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 85368481Seric uid, getuid(), geteuid()); 85468481Seric else 85568481Seric sfflags |= SFF_NOPATHCHECK; 85664325Seric } 85768481Seric } 85868478Seric #endif 85963581Seric 86064325Seric if (tTd(27, 9)) 86164325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 86264325Seric 86364325Seric /* 86464325Seric ** If home directory is remote mounted but server is down, 86564325Seric ** this can hang or give errors; use a timeout to avoid this 86664325Seric */ 86764325Seric 86853037Seric if (setjmp(CtxIncludeTimeout) != 0) 86953037Seric { 87063853Seric ctladdr->q_flags |= QQUEUEUP; 87153037Seric errno = 0; 87263993Seric 87363993Seric /* return pseudo-error code */ 87464325Seric rval = EOPENTIMEOUT; 87564325Seric goto resetuid; 87653037Seric } 87768481Seric if (TimeOuts.to_fileopen > 0) 87868481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 87968481Seric else 88068481Seric ev = NULL; 88153037Seric 88263581Seric /* the input file must be marked safe */ 88368494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); 88464329Seric if (rval != 0) 88553037Seric { 88664325Seric /* don't use this :include: file */ 88757186Seric if (tTd(27, 4)) 88858247Seric printf("include: not safe (uid=%d): %s\n", 88964329Seric uid, errstring(rval)); 89053037Seric } 89165496Seric else 8924174Seric { 89365496Seric fp = fopen(fname, "r"); 89465496Seric if (fp == NULL) 89558061Seric { 89664329Seric rval = errno; 89765496Seric if (tTd(27, 4)) 89865496Seric printf("include: open: %s\n", errstring(rval)); 89958061Seric } 9004406Seric } 90168481Seric if (ev != NULL) 90268481Seric clrevent(ev); 90353037Seric 90464570Seric resetuid: 90564570Seric 90664570Seric #ifdef HASSETREUID 90764570Seric if (saveduid == 0) 90864570Seric { 90964570Seric if (uid != 0) 91068481Seric { 91168481Seric if (setreuid(-1, 0) < 0) 91268481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 91368481Seric getuid(), geteuid()); 91468481Seric if (setreuid(RealUid, 0) < 0) 91564570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 91664570Seric RealUid, getuid(), geteuid()); 91768481Seric } 91864570Seric setgid(savedgid); 91964570Seric } 92064570Seric #endif 92164570Seric 92264570Seric if (tTd(27, 9)) 92364570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 92464570Seric 92565593Seric if (rval == EOPENTIMEOUT) 92665593Seric usrerr("451 open timeout on %s", fname); 92765593Seric 92864570Seric if (fp == NULL) 92964570Seric return rval; 93064570Seric 93165496Seric if (fstat(fileno(fp), &st) < 0) 93265496Seric { 93365496Seric rval = errno; 93465496Seric syserr("Cannot fstat %s!", fname); 93565496Seric return rval; 93665496Seric } 93765496Seric 93865948Seric #ifndef safechown 93965948Seric safechown = chownsafe(fileno(fp)); 94065948Seric #endif 94165909Seric if (ca == NULL && safechown) 94265496Seric { 94365496Seric ctladdr->q_uid = st.st_uid; 94465496Seric ctladdr->q_gid = st.st_gid; 94565496Seric ctladdr->q_flags |= QGOODUID; 94665496Seric } 94765496Seric if (ca != NULL && ca->q_uid == st.st_uid) 94865496Seric { 94965496Seric /* optimization -- avoid getpwuid if we already have info */ 95065496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 95165496Seric ctladdr->q_ruser = ca->q_ruser; 95265496Seric } 95365496Seric else 95465496Seric { 95565496Seric register struct passwd *pw; 95665496Seric 95768693Seric pw = sm_getpwuid(st.st_uid); 95868481Seric if (pw == NULL) 95968481Seric ctladdr->q_flags |= QBOGUSSHELL; 96068481Seric else 96168478Seric { 96268481Seric char *sh; 96368481Seric 96468478Seric ctladdr->q_ruser = newstr(pw->pw_name); 96568478Seric if (safechown) 96668478Seric sh = pw->pw_shell; 96765909Seric else 96868481Seric sh = "/SENDMAIL/ANY/SHELL/"; 96968481Seric if (!usershellok(sh)) 97068481Seric { 97168481Seric if (safechown) 97268481Seric ctladdr->q_flags |= QBOGUSSHELL; 97368481Seric else 97468481Seric ctladdr->q_flags |= QUNSAFEADDR; 97568481Seric } 97665496Seric } 97765496Seric } 97865496Seric 97958092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 98058092Seric { 98158092Seric /* don't do any more now */ 98258868Seric ctladdr->q_flags |= QVERIFIED; 98358884Seric e->e_nrcpts++; 98458680Seric xfclose(fp, "include", fname); 98564570Seric return rval; 98658092Seric } 98758092Seric 98865496Seric /* 98965496Seric ** Check to see if some bad guy can write this file 99065496Seric ** 99165496Seric ** This should really do something clever with group 99265496Seric ** permissions; currently we just view world writable 99365496Seric ** as unsafe. Also, we don't check for writable 99465496Seric ** directories in the path. We've got to leave 99565496Seric ** something for the local sysad to do. 99665496Seric */ 99765496Seric 99865496Seric if (bitset(S_IWOTH, st.st_mode)) 99965496Seric ctladdr->q_flags |= QUNSAFEADDR; 100065496Seric 10014174Seric /* read the file -- each line is a comma-separated list. */ 10029379Seric FileName = fname; 10039379Seric LineNumber = 0; 100458082Seric ctladdr->q_flags &= ~QSELFREF; 100558082Seric nincludes = 0; 10064174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10074174Seric { 100856795Seric register char *p = strchr(buf, '\n'); 10094174Seric 101040963Sbostic LineNumber++; 10114174Seric if (p != NULL) 10124174Seric *p = '\0'; 101357186Seric if (buf[0] == '#' || buf[0] == '\0') 101457139Seric continue; 101568787Seric 101668787Seric /* <sp>#@# introduces a comment anywhere */ 101768787Seric /* for Japanese character sets */ 101868787Seric for (p = buf; (p = strchr(++p, '#')) != NULL; ) 101968787Seric { 102068787Seric if (p[1] == '@' && p[2] == '#' && 102168787Seric isascii(p[-1]) && isspace(p[-1]) && 102268787Seric isascii(p[3]) && isspace(p[3])) 102368787Seric { 102468787Seric p[-1] = '\0'; 102568787Seric break; 102668787Seric } 102768787Seric } 102868787Seric if (buf[0] == '\0') 102968787Seric continue; 103068787Seric 103158008Seric e->e_to = NULL; 103258151Seric message("%s to %s", 103353037Seric forwarding ? "forwarding" : "sending", buf); 103457977Seric #ifdef LOG 103558020Seric if (forwarding && LogLevel > 9) 103657977Seric syslog(LOG_INFO, "%s: forward %s => %s", 103766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 103866284Seric oldto, buf); 103957977Seric #endif 104057977Seric 104168481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10424174Seric } 104363902Seric 104463902Seric if (ferror(fp) && tTd(27, 3)) 104563902Seric printf("include: read error: %s\n", errstring(errno)); 104658082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 104758065Seric { 104858065Seric if (tTd(27, 5)) 104958065Seric { 105058065Seric printf("include: QDONTSEND "); 105158065Seric printaddr(ctladdr, FALSE); 105258065Seric } 105358065Seric ctladdr->q_flags |= QDONTSEND; 105458065Seric } 10554174Seric 105658680Seric (void) xfclose(fp, "include", fname); 10579379Seric FileName = oldfilename; 10589379Seric LineNumber = oldlinenumber; 105963847Seric e->e_to = oldto; 106064325Seric return rval; 10614174Seric } 106253037Seric 106368481Seric static void 106453037Seric includetimeout() 106553037Seric { 106653037Seric longjmp(CtxIncludeTimeout, 1); 106753037Seric } 10684324Seric /* 10694324Seric ** SENDTOARGV -- send to an argument vector. 10704324Seric ** 10714324Seric ** Parameters: 10724324Seric ** argv -- argument vector to send to. 107358247Seric ** e -- the current envelope. 10744324Seric ** 10754324Seric ** Returns: 10764324Seric ** none. 10774324Seric ** 10784324Seric ** Side Effects: 10794324Seric ** puts all addresses on the argument vector onto the 10804324Seric ** send queue. 10814324Seric */ 10824324Seric 108355012Seric sendtoargv(argv, e) 10844324Seric register char **argv; 108555012Seric register ENVELOPE *e; 10864324Seric { 10874324Seric register char *p; 10884324Seric 10894324Seric while ((p = *argv++) != NULL) 10904324Seric { 109168481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 10924324Seric } 10934324Seric } 10944399Seric /* 10954399Seric ** GETCTLADDR -- get controlling address from an address header. 10964399Seric ** 10974399Seric ** If none, get one corresponding to the effective userid. 10984399Seric ** 10994399Seric ** Parameters: 11004399Seric ** a -- the address to find the controller of. 11014399Seric ** 11024399Seric ** Returns: 11034399Seric ** the controlling address. 11044399Seric ** 11054399Seric ** Side Effects: 11064399Seric ** none. 11074399Seric */ 11084399Seric 11094399Seric ADDRESS * 11104399Seric getctladdr(a) 11114399Seric register ADDRESS *a; 11124399Seric { 11134404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11144399Seric a = a->q_alias; 11154399Seric return (a); 11164399Seric } 1117