122710Sdist /* 268839Seric * Copyright (c) 1983, 1995 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*68858Seric static char sccsid[] = "@(#)recipient.c 8.81 (Berkeley) 04/22/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 { 21268857Seric a->q_status = "5.4.6"; 21368481Seric usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", 21468481Seric aliaslevel, MAXRCRSN); 21512613Seric return (a); 2164174Seric } 2174174Seric 2184174Seric /* 2194627Seric ** Finish setting up address structure. 2204174Seric */ 2214174Seric 22216160Seric /* get unquoted user for file, program or user.name check */ 22368481Seric i = strlen(a->q_user); 22468528Seric if (i >= sizeof buf0) 22568481Seric buf = xalloc(i + 1); 22668481Seric else 22768481Seric buf = buf0; 2289210Seric (void) strcpy(buf, a->q_user); 2299210Seric for (p = buf; *p != '\0' && !quoted; p++) 2309210Seric { 23154993Seric if (*p == '\\') 2329210Seric quoted = TRUE; 2339210Seric } 23454983Seric stripquotes(buf); 2359210Seric 23657402Seric /* check for direct mailing to restricted mailers */ 23765496Seric if (m == ProgMailer) 2384174Seric { 23965496Seric if (a->q_alias == NULL) 24065496Seric { 24165496Seric a->q_flags |= QBADADDR; 24268857Seric a->q_status = "5.7.1"; 24365496Seric usrerr("550 Cannot mail directly to programs"); 24465496Seric } 24565496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24665496Seric { 24765496Seric a->q_flags |= QBADADDR; 24868857Seric a->q_status = "5.7.1"; 24965496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 25065496Seric a->q_alias->q_ruser, MyHostName); 25165496Seric } 25265496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25365496Seric { 25465496Seric a->q_flags |= QBADADDR; 25568857Seric a->q_status = "5.7.1"; 25665496Seric usrerr("550 Address %s is unsafe for mailing to programs", 25765496Seric a->q_alias->q_paddr); 25865496Seric } 2594174Seric } 2604174Seric 2614174Seric /* 2624419Seric ** Look up this person in the recipient list. 2634419Seric ** If they are there already, return, otherwise continue. 2644419Seric ** If the list is empty, just add it. Notice the cute 2654419Seric ** hack to make from addresses suppress things correctly: 2664419Seric ** the QDONTSEND bit will be set in the send list. 2674419Seric ** [Please note: the emphasis is on "hack."] 2684174Seric */ 2694174Seric 2705006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2714174Seric { 27258294Seric if (sameaddr(q, a)) 2734174Seric { 2747676Seric if (tTd(26, 1)) 2754444Seric { 2764444Seric printf("%s in sendq: ", a->q_paddr); 2774444Seric printaddr(q, FALSE); 2784444Seric } 27965593Seric if (!bitset(QPRIMARY, q->q_flags)) 28058065Seric { 28165593Seric if (!bitset(QDONTSEND, a->q_flags)) 28258151Seric message("duplicate suppressed"); 28365593Seric q->q_flags |= a->q_flags; 28465593Seric } 28565593Seric else if (bitset(QSELFREF, q->q_flags)) 28665579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 28763847Seric a = q; 28868481Seric goto done; 2894174Seric } 2904319Seric } 2914174Seric 2924319Seric /* add address on list */ 29358884Seric *pq = a; 29458884Seric a->q_next = NULL; 2954174Seric 2964174Seric /* 29757402Seric ** Alias the name and handle special mailer types. 2984174Seric */ 2994174Seric 30053735Seric trylocaluser: 30155354Seric if (tTd(29, 7)) 30255354Seric printf("at trylocaluser %s\n", a->q_user); 30355354Seric 30458680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30563847Seric goto testselfdestruct; 30657402Seric 30757402Seric if (m == InclMailer) 3084174Seric { 30957402Seric a->q_flags |= QDONTSEND; 31064761Seric if (a->q_alias == NULL) 3114174Seric { 31258680Seric a->q_flags |= QBADADDR; 31368857Seric a->q_status = "5.7.1"; 31458151Seric usrerr("550 Cannot mail directly to :include:s"); 3154174Seric } 3164174Seric else 31750556Seric { 31859563Seric int ret; 31958247Seric 32058151Seric message("including file %s", a->q_user); 32168481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 32259563Seric if (transienterror(ret)) 32359563Seric { 32459563Seric #ifdef LOG 32559563Seric if (LogLevel > 2) 32666239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 32766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 32866284Seric a->q_user, errstring(ret)); 32959563Seric #endif 33063853Seric a->q_flags |= QQUEUEUP; 33165215Seric a->q_flags &= ~QDONTSEND; 33259563Seric usrerr("451 Cannot open %s: %s", 33359563Seric a->q_user, errstring(ret)); 33459563Seric } 33559563Seric else if (ret != 0) 33659563Seric { 33763938Seric a->q_flags |= QBADADDR; 33868857Seric a->q_status = "5.2.4"; 33959563Seric usrerr("550 Cannot open %s: %s", 34059563Seric a->q_user, errstring(ret)); 34159563Seric } 34250556Seric } 3434174Seric } 34457642Seric else if (m == FileMailer) 3454174Seric { 3464329Seric extern bool writable(); 3474174Seric 34851317Seric /* check if writable or creatable */ 34964761Seric if (a->q_alias == NULL) 3504174Seric { 35158680Seric a->q_flags |= QBADADDR; 35268857Seric a->q_status = "5.7.1"; 35358151Seric usrerr("550 Cannot mail directly to files"); 3544174Seric } 35565496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 35665496Seric { 35765496Seric a->q_flags |= QBADADDR; 35868857Seric a->q_status = "5.7.1"; 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; 36568857Seric a->q_status = "5.7.1"; 36665496Seric usrerr("550 Address %s is unsafe for mailing to files", 36765496Seric a->q_alias->q_paddr); 36865496Seric } 36968494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT)) 37051317Seric { 37158680Seric a->q_flags |= QBADADDR; 37268481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 37368481Seric (time_t) 0, e); 37451317Seric } 37551317Seric } 37651317Seric 37757402Seric /* try aliasing */ 37868481Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 37968481Seric alias(a, sendq, aliaslevel, e); 38057402Seric 38157402Seric # ifdef USERDB 38257402Seric /* if not aliased, look it up in the user database */ 38368481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 38468481Seric bitnset(M_CHECKUDB, m->m_flags)) 38557402Seric { 38657402Seric extern int udbexpand(); 38757402Seric 38868481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38957402Seric { 39063853Seric a->q_flags |= QQUEUEUP; 39157402Seric if (e->e_message == NULL) 39257402Seric e->e_message = newstr("Deferred: user database error"); 39357402Seric # ifdef LOG 39458020Seric if (LogLevel > 8) 39559623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 39666284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 39766284Seric errstring(errno)); 39857402Seric # endif 39959615Seric message("queued (user database error): %s", 40059615Seric errstring(errno)); 40157642Seric e->e_nrcpts++; 40263847Seric goto testselfdestruct; 40357402Seric } 40457402Seric } 40557402Seric # endif 40657402Seric 40751317Seric /* 40851317Seric ** If we have a level two config file, then pass the name through 40951317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 41051317Seric ** to send rewrite it to another mailer. This gives us a hook 41151317Seric ** after local aliasing has been done. 41251317Seric */ 41351317Seric 41451317Seric if (tTd(29, 5)) 41551317Seric { 41651317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 41751317Seric ConfigLevel, RewriteRules[5]); 41851317Seric printaddr(a, FALSE); 41951317Seric } 42068481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 42168481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 42268481Seric bitnset(M_TRYRULESET5, m->m_flags)) 42351317Seric { 42468603Seric maplocaluser(a, sendq, aliaslevel + 1, e); 42551317Seric } 42651317Seric 42751317Seric /* 42851317Seric ** If it didn't get rewritten to another mailer, go ahead 42951317Seric ** and deliver it. 43051317Seric */ 43151317Seric 43268481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 43368481Seric bitnset(M_HASPWENT, m->m_flags)) 43451317Seric { 43555354Seric auto bool fuzzy; 43651317Seric register struct passwd *pw; 43751317Seric extern struct passwd *finduser(); 43851317Seric 43951317Seric /* warning -- finduser may trash buf */ 44055354Seric pw = finduser(buf, &fuzzy); 44151317Seric if (pw == NULL) 44251317Seric { 44358680Seric a->q_flags |= QBADADDR; 44468857Seric a->q_status = "5.1.1"; 44568481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 44668481Seric (time_t) 0, e); 44751317Seric } 4484174Seric else 4494174Seric { 45068528Seric char nbuf[MAXNAME + 1]; 4514373Seric 45255354Seric if (fuzzy) 4534174Seric { 45453735Seric /* name was a fuzzy match */ 45551317Seric a->q_user = newstr(pw->pw_name); 45653735Seric if (findusercount++ > 3) 45753735Seric { 45858680Seric a->q_flags |= QBADADDR; 45968857Seric a->q_status = "5.4.6"; 46058151Seric usrerr("554 aliasing/forwarding loop for %s broken", 46153735Seric pw->pw_name); 46268481Seric goto done; 46353735Seric } 46453735Seric 46553735Seric /* see if it aliases */ 46651317Seric (void) strcpy(buf, pw->pw_name); 46753735Seric goto trylocaluser; 4684174Seric } 46965822Seric if (strcmp(pw->pw_dir, "/") == 0) 47065822Seric a->q_home = ""; 47165822Seric else 47265822Seric a->q_home = newstr(pw->pw_dir); 47351317Seric a->q_uid = pw->pw_uid; 47451317Seric a->q_gid = pw->pw_gid; 47559083Seric a->q_ruser = newstr(pw->pw_name); 47651317Seric a->q_flags |= QGOODUID; 47751317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 47851317Seric if (nbuf[0] != '\0') 47951317Seric a->q_fullname = newstr(nbuf); 48065211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 48165211Seric !usershellok(pw->pw_shell)) 48265206Seric { 48365211Seric a->q_flags |= QBOGUSSHELL; 48465206Seric } 48551317Seric if (!quoted) 48668481Seric forward(a, sendq, aliaslevel, e); 4874174Seric } 4884174Seric } 48957642Seric if (!bitset(QDONTSEND, a->q_flags)) 49057642Seric e->e_nrcpts++; 49163847Seric 49263847Seric testselfdestruct: 49368603Seric a->q_flags |= QTHISPASS; 49463978Seric if (tTd(26, 8)) 49563847Seric { 49663978Seric printf("testselfdestruct: "); 49768603Seric printaddr(a, FALSE); 49868603Seric if (tTd(26, 10)) 49968603Seric { 50068603Seric printf("SENDQ:\n"); 50168603Seric printaddr(*sendq, TRUE); 50268603Seric printf("----\n"); 50368603Seric } 50463978Seric } 50563978Seric if (a->q_alias == NULL && a != &e->e_from && 50663978Seric bitset(QDONTSEND, a->q_flags)) 50763978Seric { 50868603Seric for (q = *sendq; q != NULL; q = q->q_next) 50968603Seric { 51068603Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags) && 51168603Seric bitset(QTHISPASS, q->q_flags)) 51268603Seric break; 51368603Seric } 51463978Seric if (q == NULL) 51563847Seric { 51663847Seric a->q_flags |= QBADADDR; 517*68858Seric a->q_status = "5.4.6"; 51863847Seric usrerr("554 aliasing/forwarding loop broken"); 51963847Seric } 52063847Seric } 52168481Seric 52268481Seric done: 52368603Seric a->q_flags |= QTHISPASS; 52468481Seric if (buf != buf0) 52568481Seric free(buf); 52668603Seric 52768603Seric /* 52868603Seric ** If we are at the top level, check to see if this has 52968603Seric ** expanded to exactly one address. If so, it can inherit 53068603Seric ** the primaryness of the address. 53168603Seric ** 53268603Seric ** While we're at it, clear the QTHISPASS bits. 53368603Seric */ 53468603Seric 53568603Seric if (aliaslevel == 0) 53668603Seric { 53768603Seric int nrcpts = 0; 53868603Seric ADDRESS *only; 53968603Seric 54068603Seric for (q = *sendq; q != NULL; q = q->q_next) 54168603Seric { 54268603Seric if (bitset(QTHISPASS, q->q_flags) && 54368603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags)) 54468603Seric { 54568603Seric nrcpts++; 54668603Seric only = q; 54768603Seric } 54868603Seric q->q_flags &= ~QTHISPASS; 54968603Seric } 55068603Seric if (nrcpts == 1) 55168603Seric only->q_flags |= QPRIMARY; 55268603Seric else if (!initialdontsend) 55368603Seric { 55468603Seric /* arrange for return receipt */ 55568603Seric e->e_flags |= EF_SENDRECEIPT; 55668603Seric a->q_flags |= QEXPLODED; 55768603Seric if (e->e_xfp != NULL) 55868603Seric fprintf(e->e_xfp, 55968603Seric "%s... expanded to multiple addresses\n", 56068603Seric a->q_paddr); 56168603Seric } 56268603Seric } 56368603Seric 56412613Seric return (a); 5654174Seric } 5664174Seric /* 5674373Seric ** FINDUSER -- find the password entry for a user. 5684373Seric ** 5694373Seric ** This looks a lot like getpwnam, except that it may want to 5704373Seric ** do some fancier pattern matching in /etc/passwd. 5714373Seric ** 5729379Seric ** This routine contains most of the time of many sendmail runs. 5739379Seric ** It deserves to be optimized. 5749379Seric ** 5754373Seric ** Parameters: 5764373Seric ** name -- the name to match against. 57755354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 57855354Seric ** was found using the fuzzy matching algorithm; 57955354Seric ** set to FALSE otherwise. 5804373Seric ** 5814373Seric ** Returns: 5824373Seric ** A pointer to a pw struct. 5834373Seric ** NULL if name is unknown or ambiguous. 5844373Seric ** 5854373Seric ** Side Effects: 5864407Seric ** may modify name. 5874373Seric */ 5884373Seric 5894373Seric struct passwd * 59055354Seric finduser(name, fuzzyp) 5914373Seric char *name; 59255354Seric bool *fuzzyp; 5934373Seric { 5944376Seric register struct passwd *pw; 5954407Seric register char *p; 5964373Seric 59755354Seric if (tTd(29, 4)) 59855354Seric printf("finduser(%s): ", name); 59955354Seric 60055354Seric *fuzzyp = FALSE; 6014407Seric 60268481Seric #ifdef HESIOD 60364673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 60464673Seric for (p = name; *p != '\0'; p++) 60564673Seric if (!isascii(*p) || !isdigit(*p)) 60664673Seric break; 60764673Seric if (*p == '\0') 60864673Seric { 60964673Seric if (tTd(29, 4)) 61064673Seric printf("failed (numeric input)\n"); 61164673Seric return NULL; 61264673Seric } 61368481Seric #endif 61464673Seric 61525777Seric /* look up this login name using fast path */ 61668693Seric if ((pw = sm_getpwnam(name)) != NULL) 61755354Seric { 61855354Seric if (tTd(29, 4)) 61955354Seric printf("found (non-fuzzy)\n"); 62012634Seric return (pw); 62155354Seric } 62212634Seric 62353735Seric #ifdef MATCHGECOS 62453735Seric /* see if fuzzy matching allowed */ 62553735Seric if (!MatchGecos) 62655354Seric { 62755354Seric if (tTd(29, 4)) 62855354Seric printf("not found (fuzzy disabled)\n"); 62953735Seric return NULL; 63055354Seric } 63153735Seric 63212634Seric /* search for a matching full name instead */ 63325777Seric for (p = name; *p != '\0'; p++) 63425777Seric { 63525777Seric if (*p == (SpaceSub & 0177) || *p == '_') 63625777Seric *p = ' '; 63725777Seric } 63823107Seric (void) setpwent(); 6394376Seric while ((pw = getpwent()) != NULL) 6404376Seric { 64168528Seric char buf[MAXNAME + 1]; 6424376Seric 6434998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 64456795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 6454381Seric { 64655354Seric if (tTd(29, 4)) 64755354Seric printf("fuzzy matches %s\n", pw->pw_name); 64858151Seric message("sending to login name %s", pw->pw_name); 64955354Seric *fuzzyp = TRUE; 6504376Seric return (pw); 6514377Seric } 6524376Seric } 65355354Seric if (tTd(29, 4)) 65455354Seric printf("no fuzzy match found\n"); 65559015Seric #else 65659015Seric if (tTd(29, 4)) 65759015Seric printf("not found (fuzzy disabled)\n"); 65859015Seric #endif 6594376Seric return (NULL); 6604373Seric } 6614373Seric /* 6624329Seric ** WRITABLE -- predicate returning if the file is writable. 6634329Seric ** 6644329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6654329Seric ** Unfortunately, we cannot use the access call since we 6664329Seric ** won't necessarily be the real uid when we try to 6674329Seric ** actually open the file. 6684329Seric ** 6694329Seric ** Notice that ANY file with ANY execute bit is automatically 6704329Seric ** not writable. This is also enforced by mailfile. 6714329Seric ** 6724329Seric ** Parameters: 67365064Seric ** filename -- the file name to check. 67465112Seric ** ctladdr -- the controlling address for this file. 67565064Seric ** flags -- SFF_* flags to control the function. 6764329Seric ** 6774329Seric ** Returns: 6784329Seric ** TRUE -- if we will be able to write this file. 6794329Seric ** FALSE -- if we cannot write this file. 6804329Seric ** 6814329Seric ** Side Effects: 6824329Seric ** none. 6834329Seric */ 6844329Seric 6854329Seric bool 68665112Seric writable(filename, ctladdr, flags) 68764819Seric char *filename; 68865112Seric ADDRESS *ctladdr; 68965064Seric int flags; 6904329Seric { 69155372Seric uid_t euid; 69255372Seric gid_t egid; 6934329Seric int bits; 69464944Seric register char *p; 69564944Seric char *uname; 6964329Seric 69764819Seric if (tTd(29, 5)) 69868802Seric printf("writable(%s, 0x%x)\n", filename, flags); 69964944Seric 70065225Seric #ifdef SUID_ROOT_FILES_OK 70165225Seric /* really ought to be passed down -- and not a good idea */ 70265225Seric flags |= SFF_ROOTOK; 70365225Seric #endif 70465225Seric 70564944Seric /* 70664944Seric ** File does exist -- check that it is writable. 70764944Seric */ 70864944Seric 70965112Seric if (ctladdr != NULL && geteuid() == 0) 71064944Seric { 71165112Seric euid = ctladdr->q_uid; 71265112Seric egid = ctladdr->q_gid; 71365112Seric uname = ctladdr->q_user; 71464944Seric } 71568802Seric else if (bitset(SFF_RUNASREALUID, flags)) 71665112Seric { 71768494Seric extern char RealUserName[]; 71868494Seric 71965112Seric euid = RealUid; 72065112Seric egid = RealGid; 72165112Seric uname = RealUserName; 72265112Seric } 72368481Seric else if (FileMailer != NULL) 72468481Seric { 72568481Seric euid = FileMailer->m_uid; 72668481Seric egid = FileMailer->m_gid; 72768481Seric } 72868481Seric else 72968481Seric { 73068481Seric euid = egid = 0; 73168481Seric } 73265138Seric if (euid == 0) 73365138Seric { 73465138Seric euid = DefUid; 73565138Seric uname = DefUser; 73665138Seric } 73765138Seric if (egid == 0) 73865138Seric egid = DefGid; 7394329Seric if (geteuid() == 0) 74068494Seric flags |= SFF_SETUIDOK; 7414329Seric 74268494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); 74365067Seric return errno == 0; 7444329Seric } 7454329Seric /* 7464174Seric ** INCLUDE -- handle :include: specification. 7474174Seric ** 7484174Seric ** Parameters: 7494174Seric ** fname -- filename to include. 75053037Seric ** forwarding -- if TRUE, we are reading a .forward file. 75153037Seric ** if FALSE, it's a :include: file. 7524399Seric ** ctladdr -- address template to use to fill in these 7534399Seric ** addresses -- effective user/group id are 7544399Seric ** the important things. 7555006Seric ** sendq -- a pointer to the head of the send queue 7565006Seric ** to put these addresses in. 75768481Seric ** aliaslevel -- the alias nesting depth. 75868481Seric ** e -- the current envelope. 7594174Seric ** 7604174Seric ** Returns: 76157136Seric ** open error status 7624174Seric ** 7634174Seric ** Side Effects: 7644174Seric ** reads the :include: file and sends to everyone 7654174Seric ** listed in that file. 76665909Seric ** 76765909Seric ** Security Note: 76865909Seric ** If you have restricted chown (that is, you can't 76965909Seric ** give a file away), it is reasonable to allow programs 77065909Seric ** and files called from this :include: file to be to be 77165909Seric ** run as the owner of the :include: file. This is bogus 77265909Seric ** if there is any chance of someone giving away a file. 77365909Seric ** We assume that pre-POSIX systems can give away files. 77465909Seric ** 77565909Seric ** There is an additional restriction that if you 77665909Seric ** forward to a :include: file, it will not take on 77765909Seric ** the ownership of the :include: file. This may not 77865909Seric ** be necessary, but shouldn't hurt. 7794174Seric */ 7804174Seric 78153037Seric static jmp_buf CtxIncludeTimeout; 78268481Seric static void includetimeout(); 78353037Seric 78457136Seric int 78568481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7864174Seric char *fname; 78753037Seric bool forwarding; 7884399Seric ADDRESS *ctladdr; 7895006Seric ADDRESS **sendq; 79068481Seric int aliaslevel; 79155012Seric ENVELOPE *e; 7924174Seric { 79368481Seric FILE *fp = NULL; 79455012Seric char *oldto = e->e_to; 7959379Seric char *oldfilename = FileName; 7969379Seric int oldlinenumber = LineNumber; 79753037Seric register EVENT *ev = NULL; 79858082Seric int nincludes; 79964325Seric register ADDRESS *ca; 80064325Seric uid_t saveduid, uid; 80164325Seric gid_t savedgid, gid; 80264083Seric char *uname; 80364325Seric int rval = 0; 80468513Seric int sfflags = SFF_REGONLY; 80565496Seric struct stat st; 80665948Seric char buf[MAXLINE]; 80765909Seric #ifdef _POSIX_CHOWN_RESTRICTED 80865948Seric # if _POSIX_CHOWN_RESTRICTED == -1 80965948Seric # define safechown FALSE 81065948Seric # else 81165948Seric # define safechown TRUE 81265948Seric # endif 81365948Seric #else 81465948Seric # ifdef _PC_CHOWN_RESTRICTED 81565909Seric bool safechown; 81665948Seric # else 81765948Seric # ifdef BSD 81865948Seric # define safechown TRUE 81965948Seric # else 82065948Seric # define safechown FALSE 82165948Seric # endif 82265948Seric # endif 82365909Seric #endif 82465948Seric extern bool chownsafe(); 8254174Seric 82657186Seric if (tTd(27, 2)) 82757186Seric printf("include(%s)\n", fname); 82863902Seric if (tTd(27, 4)) 82963902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 83063581Seric if (tTd(27, 14)) 83163581Seric { 83263581Seric printf("ctladdr "); 83363581Seric printaddr(ctladdr, FALSE); 83463581Seric } 83557186Seric 83664325Seric if (tTd(27, 9)) 83764325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 83853037Seric 83968513Seric if (forwarding) 84068513Seric sfflags |= SFF_MUSTOWN; 84168513Seric 84263581Seric ca = getctladdr(ctladdr); 84363581Seric if (ca == NULL) 84464083Seric { 84564846Seric uid = DefUid; 84664846Seric gid = DefGid; 84764846Seric uname = DefUser; 84864083Seric } 84963581Seric else 85064083Seric { 85163581Seric uid = ca->q_uid; 85264083Seric gid = ca->q_gid; 85364083Seric uname = ca->q_user; 85468481Seric } 85564325Seric #ifdef HASSETREUID 85668481Seric saveduid = geteuid(); 85768481Seric savedgid = getegid(); 85868481Seric if (saveduid == 0) 85968481Seric { 86068481Seric initgroups(uname, gid); 86168481Seric if (uid != 0) 86264325Seric { 86368481Seric if (setreuid(0, uid) < 0) 86468481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 86568481Seric uid, getuid(), geteuid()); 86668481Seric else 86768481Seric sfflags |= SFF_NOPATHCHECK; 86864325Seric } 86968481Seric } 87068478Seric #endif 87163581Seric 87264325Seric if (tTd(27, 9)) 87364325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 87464325Seric 87564325Seric /* 87664325Seric ** If home directory is remote mounted but server is down, 87764325Seric ** this can hang or give errors; use a timeout to avoid this 87864325Seric */ 87964325Seric 88053037Seric if (setjmp(CtxIncludeTimeout) != 0) 88153037Seric { 88263853Seric ctladdr->q_flags |= QQUEUEUP; 88353037Seric errno = 0; 88463993Seric 88563993Seric /* return pseudo-error code */ 88664325Seric rval = EOPENTIMEOUT; 88764325Seric goto resetuid; 88853037Seric } 88968481Seric if (TimeOuts.to_fileopen > 0) 89068481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 89168481Seric else 89268481Seric ev = NULL; 89353037Seric 89463581Seric /* the input file must be marked safe */ 89568494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); 89664329Seric if (rval != 0) 89753037Seric { 89864325Seric /* don't use this :include: file */ 89957186Seric if (tTd(27, 4)) 90058247Seric printf("include: not safe (uid=%d): %s\n", 90164329Seric uid, errstring(rval)); 90253037Seric } 90365496Seric else 9044174Seric { 90565496Seric fp = fopen(fname, "r"); 90665496Seric if (fp == NULL) 90758061Seric { 90864329Seric rval = errno; 90965496Seric if (tTd(27, 4)) 91065496Seric printf("include: open: %s\n", errstring(rval)); 91158061Seric } 9124406Seric } 91368481Seric if (ev != NULL) 91468481Seric clrevent(ev); 91553037Seric 91664570Seric resetuid: 91764570Seric 91864570Seric #ifdef HASSETREUID 91964570Seric if (saveduid == 0) 92064570Seric { 92164570Seric if (uid != 0) 92268481Seric { 92368481Seric if (setreuid(-1, 0) < 0) 92468481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 92568481Seric getuid(), geteuid()); 92668481Seric if (setreuid(RealUid, 0) < 0) 92764570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 92864570Seric RealUid, getuid(), geteuid()); 92968481Seric } 93064570Seric setgid(savedgid); 93164570Seric } 93264570Seric #endif 93364570Seric 93464570Seric if (tTd(27, 9)) 93564570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 93664570Seric 93765593Seric if (rval == EOPENTIMEOUT) 93865593Seric usrerr("451 open timeout on %s", fname); 93965593Seric 94064570Seric if (fp == NULL) 94164570Seric return rval; 94264570Seric 94365496Seric if (fstat(fileno(fp), &st) < 0) 94465496Seric { 94565496Seric rval = errno; 94665496Seric syserr("Cannot fstat %s!", fname); 94765496Seric return rval; 94865496Seric } 94965496Seric 95065948Seric #ifndef safechown 95165948Seric safechown = chownsafe(fileno(fp)); 95265948Seric #endif 95365909Seric if (ca == NULL && safechown) 95465496Seric { 95565496Seric ctladdr->q_uid = st.st_uid; 95665496Seric ctladdr->q_gid = st.st_gid; 95765496Seric ctladdr->q_flags |= QGOODUID; 95865496Seric } 95965496Seric if (ca != NULL && ca->q_uid == st.st_uid) 96065496Seric { 96165496Seric /* optimization -- avoid getpwuid if we already have info */ 96265496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 96365496Seric ctladdr->q_ruser = ca->q_ruser; 96465496Seric } 96565496Seric else 96665496Seric { 96765496Seric register struct passwd *pw; 96865496Seric 96968693Seric pw = sm_getpwuid(st.st_uid); 97068481Seric if (pw == NULL) 97168481Seric ctladdr->q_flags |= QBOGUSSHELL; 97268481Seric else 97368478Seric { 97468481Seric char *sh; 97568481Seric 97668478Seric ctladdr->q_ruser = newstr(pw->pw_name); 97768478Seric if (safechown) 97868478Seric sh = pw->pw_shell; 97965909Seric else 98068481Seric sh = "/SENDMAIL/ANY/SHELL/"; 98168481Seric if (!usershellok(sh)) 98268481Seric { 98368481Seric if (safechown) 98468481Seric ctladdr->q_flags |= QBOGUSSHELL; 98568481Seric else 98668481Seric ctladdr->q_flags |= QUNSAFEADDR; 98768481Seric } 98865496Seric } 98965496Seric } 99065496Seric 99158092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 99258092Seric { 99358092Seric /* don't do any more now */ 99458868Seric ctladdr->q_flags |= QVERIFIED; 99558884Seric e->e_nrcpts++; 99658680Seric xfclose(fp, "include", fname); 99764570Seric return rval; 99858092Seric } 99958092Seric 100065496Seric /* 100165496Seric ** Check to see if some bad guy can write this file 100265496Seric ** 100365496Seric ** This should really do something clever with group 100465496Seric ** permissions; currently we just view world writable 100565496Seric ** as unsafe. Also, we don't check for writable 100665496Seric ** directories in the path. We've got to leave 100765496Seric ** something for the local sysad to do. 100865496Seric */ 100965496Seric 101065496Seric if (bitset(S_IWOTH, st.st_mode)) 101165496Seric ctladdr->q_flags |= QUNSAFEADDR; 101265496Seric 10134174Seric /* read the file -- each line is a comma-separated list. */ 10149379Seric FileName = fname; 10159379Seric LineNumber = 0; 101658082Seric ctladdr->q_flags &= ~QSELFREF; 101758082Seric nincludes = 0; 10184174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10194174Seric { 102056795Seric register char *p = strchr(buf, '\n'); 10214174Seric 102240963Sbostic LineNumber++; 10234174Seric if (p != NULL) 10244174Seric *p = '\0'; 102557186Seric if (buf[0] == '#' || buf[0] == '\0') 102657139Seric continue; 102768787Seric 102868787Seric /* <sp>#@# introduces a comment anywhere */ 102968787Seric /* for Japanese character sets */ 103068787Seric for (p = buf; (p = strchr(++p, '#')) != NULL; ) 103168787Seric { 103268787Seric if (p[1] == '@' && p[2] == '#' && 103368787Seric isascii(p[-1]) && isspace(p[-1]) && 103468787Seric isascii(p[3]) && isspace(p[3])) 103568787Seric { 103668787Seric p[-1] = '\0'; 103768787Seric break; 103868787Seric } 103968787Seric } 104068787Seric if (buf[0] == '\0') 104168787Seric continue; 104268787Seric 104358008Seric e->e_to = NULL; 104458151Seric message("%s to %s", 104553037Seric forwarding ? "forwarding" : "sending", buf); 104657977Seric #ifdef LOG 104758020Seric if (forwarding && LogLevel > 9) 104857977Seric syslog(LOG_INFO, "%s: forward %s => %s", 104966284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 105066284Seric oldto, buf); 105157977Seric #endif 105257977Seric 105368481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10544174Seric } 105563902Seric 105663902Seric if (ferror(fp) && tTd(27, 3)) 105763902Seric printf("include: read error: %s\n", errstring(errno)); 105858082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 105958065Seric { 106058065Seric if (tTd(27, 5)) 106158065Seric { 106258065Seric printf("include: QDONTSEND "); 106358065Seric printaddr(ctladdr, FALSE); 106458065Seric } 106558065Seric ctladdr->q_flags |= QDONTSEND; 106658065Seric } 10674174Seric 106858680Seric (void) xfclose(fp, "include", fname); 10699379Seric FileName = oldfilename; 10709379Seric LineNumber = oldlinenumber; 107163847Seric e->e_to = oldto; 107264325Seric return rval; 10734174Seric } 107453037Seric 107568481Seric static void 107653037Seric includetimeout() 107753037Seric { 107853037Seric longjmp(CtxIncludeTimeout, 1); 107953037Seric } 10804324Seric /* 10814324Seric ** SENDTOARGV -- send to an argument vector. 10824324Seric ** 10834324Seric ** Parameters: 10844324Seric ** argv -- argument vector to send to. 108558247Seric ** e -- the current envelope. 10864324Seric ** 10874324Seric ** Returns: 10884324Seric ** none. 10894324Seric ** 10904324Seric ** Side Effects: 10914324Seric ** puts all addresses on the argument vector onto the 10924324Seric ** send queue. 10934324Seric */ 10944324Seric 109555012Seric sendtoargv(argv, e) 10964324Seric register char **argv; 109755012Seric register ENVELOPE *e; 10984324Seric { 10994324Seric register char *p; 11004324Seric 11014324Seric while ((p = *argv++) != NULL) 11024324Seric { 110368481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 11044324Seric } 11054324Seric } 11064399Seric /* 11074399Seric ** GETCTLADDR -- get controlling address from an address header. 11084399Seric ** 11094399Seric ** If none, get one corresponding to the effective userid. 11104399Seric ** 11114399Seric ** Parameters: 11124399Seric ** a -- the address to find the controller of. 11134399Seric ** 11144399Seric ** Returns: 11154399Seric ** the controlling address. 11164399Seric ** 11174399Seric ** Side Effects: 11184399Seric ** none. 11194399Seric */ 11204399Seric 11214399Seric ADDRESS * 11224399Seric getctladdr(a) 11234399Seric register ADDRESS *a; 11244399Seric { 11254404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11264399Seric a = a->q_alias; 11274399Seric return (a); 11284399Seric } 1129