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*68603Seric static char sccsid[] = "@(#)recipient.c 8.75 (Berkeley) 03/27/95"; 1133731Sbostic #endif /* not lint */ 1222710Sdist 1358332Seric # include "sendmail.h" 144174Seric # include <pwd.h> 154174Seric 164174Seric /* 179622Seric ** SENDTOLIST -- Designate a send list. 184174Seric ** 194174Seric ** The parameter is a comma-separated list of people to send to. 204174Seric ** This routine arranges to send to all of them. 214174Seric ** 224174Seric ** Parameters: 234174Seric ** list -- the send list. 244399Seric ** ctladdr -- the address template for the person to 254399Seric ** send to -- effective uid/gid are important. 265006Seric ** This is typically the alias that caused this 275006Seric ** expansion. 285006Seric ** sendq -- a pointer to the head of a queue to put 295006Seric ** these people into. 3068481Seric ** aliaslevel -- the current alias nesting depth -- to 3168481Seric ** diagnose loops. 3258247Seric ** e -- the envelope in which to add these recipients. 334174Seric ** 344174Seric ** Returns: 3558082Seric ** The number of addresses actually on the list. 364174Seric ** 374174Seric ** Side Effects: 384174Seric ** none. 394174Seric */ 404174Seric 4168481Seric #define MAXRCRSN 10 /* maximum levels of alias recursion */ 424174Seric 4368481Seric /* q_flags bits inherited from ctladdr */ 4468595Seric #define QINHERITEDBITS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY) 4568481Seric 4668481Seric int 4768481Seric sendtolist(list, ctladdr, sendq, aliaslevel, e) 484174Seric char *list; 494399Seric ADDRESS *ctladdr; 505198Seric ADDRESS **sendq; 5168481Seric int aliaslevel; 5255012Seric register ENVELOPE *e; 534174Seric { 544174Seric register char *p; 558223Seric register ADDRESS *al; /* list of addresses to send to */ 564423Seric bool firstone; /* set on first address sent */ 5711446Seric char delimiter; /* the address delimiter */ 5858082Seric int naddrs; 5968392Seric int i; 6063847Seric char *oldto = e->e_to; 6168392Seric char *bufp; 6268271Seric char buf[MAXNAME + 1]; 634174Seric 6464131Seric if (list == NULL) 6564131Seric { 6664131Seric syserr("sendtolist: null list"); 6764131Seric return 0; 6864131Seric } 6964131Seric 707676Seric if (tTd(25, 1)) 714444Seric { 724444Seric printf("sendto: %s\n ctladdr=", list); 734444Seric printaddr(ctladdr, FALSE); 744444Seric } 754324Seric 768223Seric /* heuristic to determine old versus new style addresses */ 778230Seric if (ctladdr == NULL && 7856795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 7956795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 8055012Seric e->e_flags &= ~EF_OLDSTYLE; 8111446Seric delimiter = ' '; 8255012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 8311446Seric delimiter = ','; 848223Seric 854423Seric firstone = TRUE; 864324Seric al = NULL; 8758082Seric naddrs = 0; 888223Seric 8968392Seric /* make sure we have enough space to copy the string */ 9068392Seric i = strlen(list) + 1; 9168392Seric if (i <= sizeof buf) 9268271Seric bufp = buf; 9368392Seric else 9468392Seric bufp = xalloc(i); 9568478Seric strcpy(bufp, denlstring(list, FALSE, TRUE)); 9668271Seric 9768271Seric for (p = bufp; *p != '\0'; ) 9868271Seric { 9958333Seric auto char *delimptr; 1008081Seric register ADDRESS *a; 1014319Seric 1028081Seric /* parse the address */ 10358050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 1044174Seric p++; 10564284Seric a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); 10658333Seric p = delimptr; 1079297Seric if (a == NULL) 1084174Seric continue; 1094324Seric a->q_next = al; 1104399Seric a->q_alias = ctladdr; 1114444Seric 11268481Seric /* arrange to inherit attributes from parent */ 11368481Seric if (ctladdr != NULL) 11468481Seric { 11568481Seric /* self reference test */ 11668481Seric if (sameaddr(ctladdr, a)) 11768481Seric ctladdr->q_flags |= QSELFREF; 11868481Seric 11968481Seric /* full name */ 12068481Seric if (a->q_fullname == NULL) 12168481Seric a->q_fullname = ctladdr->q_fullname; 12268481Seric 12368481Seric /* various flag bits */ 12468481Seric a->q_flags &= ~QINHERITEDBITS; 12568481Seric a->q_flags |= ctladdr->q_flags & QINHERITEDBITS; 12668481Seric 12768481Seric /* original recipient information */ 12868481Seric a->q_orcpt = ctladdr->q_orcpt; 12968481Seric } 13068481Seric 13157731Seric al = a; 1324423Seric firstone = FALSE; 1334324Seric } 1344324Seric 1354324Seric /* arrange to send to everyone on the local send list */ 1364324Seric while (al != NULL) 1374324Seric { 1384324Seric register ADDRESS *a = al; 1394324Seric 1404324Seric al = a->q_next; 14168481Seric a = recipient(a, sendq, aliaslevel, e); 14258082Seric naddrs++; 1434174Seric } 1444324Seric 14563847Seric e->e_to = oldto; 14668392Seric if (bufp != buf) 14768392Seric free(bufp); 14858082Seric return (naddrs); 1494174Seric } 1504174Seric /* 1514174Seric ** RECIPIENT -- Designate a message recipient 1524174Seric ** 1534174Seric ** Saves the named person for future mailing. 1544174Seric ** 1554174Seric ** Parameters: 1564174Seric ** a -- the (preparsed) address header for the recipient. 1575006Seric ** sendq -- a pointer to the head of a queue to put the 1585006Seric ** recipient in. Duplicate supression is done 1595006Seric ** in this queue. 16068481Seric ** aliaslevel -- the current alias nesting depth. 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 * 17268481Seric recipient(a, sendq, aliaslevel, e) 1734174Seric register ADDRESS *a; 1745006Seric register ADDRESS **sendq; 17568481Seric int aliaslevel; 17655012Seric register ENVELOPE *e; 1774174Seric { 1784174Seric register ADDRESS *q; 1794319Seric ADDRESS **pq; 1804174Seric register struct mailer *m; 1819210Seric register char *p; 1829210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 18353735Seric int findusercount = 0; 184*68603Seric bool initialdontsend = bitset(QDONTSEND, a->q_flags); 18568481Seric int i; 18668481Seric char *buf; 18768528Seric char buf0[MAXNAME + 1]; /* unquoted image of the user name */ 18858247Seric extern int safefile(); 1894174Seric 19055012Seric e->e_to = a->q_paddr; 1914600Seric m = a->q_mailer; 1924174Seric errno = 0; 193*68603Seric if (aliaslevel == 0) 194*68603Seric a->q_flags |= QPRIMARY; 1957676Seric if (tTd(26, 1)) 1964444Seric { 197*68603Seric printf("\nrecipient (%d): ", aliaslevel); 1984444Seric printaddr(a, FALSE); 1994444Seric } 2004174Seric 20164146Seric /* if this is primary, add it to the original recipient list */ 20264146Seric if (a->q_alias == NULL) 20364146Seric { 20464146Seric if (e->e_origrcpt == NULL) 20564146Seric e->e_origrcpt = a->q_paddr; 20664146Seric else if (e->e_origrcpt != a->q_paddr) 20764146Seric e->e_origrcpt = ""; 20864146Seric } 20964146Seric 2104174Seric /* break aliasing loops */ 21168481Seric if (aliaslevel > MAXRCRSN) 2124174Seric { 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; 24265496Seric usrerr("550 Cannot mail directly to programs"); 24365496Seric } 24465496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 24565496Seric { 24665496Seric a->q_flags |= QBADADDR; 24765496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", 24865496Seric a->q_alias->q_ruser, MyHostName); 24965496Seric } 25065496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 25165496Seric { 25265496Seric a->q_flags |= QBADADDR; 25365496Seric usrerr("550 Address %s is unsafe for mailing to programs", 25465496Seric a->q_alias->q_paddr); 25565496Seric } 2564174Seric } 2574174Seric 2584174Seric /* 2594419Seric ** Look up this person in the recipient list. 2604419Seric ** If they are there already, return, otherwise continue. 2614419Seric ** If the list is empty, just add it. Notice the cute 2624419Seric ** hack to make from addresses suppress things correctly: 2634419Seric ** the QDONTSEND bit will be set in the send list. 2644419Seric ** [Please note: the emphasis is on "hack."] 2654174Seric */ 2664174Seric 2675006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2684174Seric { 26958294Seric if (sameaddr(q, a)) 2704174Seric { 2717676Seric if (tTd(26, 1)) 2724444Seric { 2734444Seric printf("%s in sendq: ", a->q_paddr); 2744444Seric printaddr(q, FALSE); 2754444Seric } 27665593Seric if (!bitset(QPRIMARY, q->q_flags)) 27758065Seric { 27865593Seric if (!bitset(QDONTSEND, a->q_flags)) 27958151Seric message("duplicate suppressed"); 28065593Seric q->q_flags |= a->q_flags; 28165593Seric } 28265593Seric else if (bitset(QSELFREF, q->q_flags)) 28365579Seric q->q_flags |= a->q_flags & ~QDONTSEND; 28463847Seric a = q; 28568481Seric goto done; 2864174Seric } 2874319Seric } 2884174Seric 2894319Seric /* add address on list */ 29058884Seric *pq = a; 29158884Seric a->q_next = NULL; 2924174Seric 2934174Seric /* 29457402Seric ** Alias the name and handle special mailer types. 2954174Seric */ 2964174Seric 29753735Seric trylocaluser: 29855354Seric if (tTd(29, 7)) 29955354Seric printf("at trylocaluser %s\n", a->q_user); 30055354Seric 30158680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 30263847Seric goto testselfdestruct; 30357402Seric 30457402Seric if (m == InclMailer) 3054174Seric { 30657402Seric a->q_flags |= QDONTSEND; 30764761Seric if (a->q_alias == NULL) 3084174Seric { 30958680Seric a->q_flags |= QBADADDR; 31058151Seric usrerr("550 Cannot mail directly to :include:s"); 3114174Seric } 3124174Seric else 31350556Seric { 31459563Seric int ret; 31558247Seric 31658151Seric message("including file %s", a->q_user); 31768481Seric ret = include(a->q_user, FALSE, a, sendq, aliaslevel, e); 31859563Seric if (transienterror(ret)) 31959563Seric { 32059563Seric #ifdef LOG 32159563Seric if (LogLevel > 2) 32266239Seric syslog(LOG_ERR, "%s: include %s: transient error: %s", 32366284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 32466284Seric a->q_user, errstring(ret)); 32559563Seric #endif 32663853Seric a->q_flags |= QQUEUEUP; 32765215Seric a->q_flags &= ~QDONTSEND; 32859563Seric usrerr("451 Cannot open %s: %s", 32959563Seric a->q_user, errstring(ret)); 33059563Seric } 33159563Seric else if (ret != 0) 33259563Seric { 33363938Seric a->q_flags |= QBADADDR; 33459563Seric usrerr("550 Cannot open %s: %s", 33559563Seric a->q_user, errstring(ret)); 33659563Seric } 33750556Seric } 3384174Seric } 33957642Seric else if (m == FileMailer) 3404174Seric { 3414329Seric extern bool writable(); 3424174Seric 34351317Seric /* check if writable or creatable */ 34464761Seric if (a->q_alias == NULL) 3454174Seric { 34658680Seric a->q_flags |= QBADADDR; 34758151Seric usrerr("550 Cannot mail directly to files"); 3484174Seric } 34965496Seric else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) 35065496Seric { 35165496Seric a->q_flags |= QBADADDR; 35265496Seric usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", 35365496Seric a->q_alias->q_ruser, MyHostName); 35465496Seric } 35565496Seric else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) 35665496Seric { 35765496Seric a->q_flags |= QBADADDR; 35865496Seric usrerr("550 Address %s is unsafe for mailing to files", 35965496Seric a->q_alias->q_paddr); 36065496Seric } 36168494Seric else if (!writable(buf, getctladdr(a), SFF_CREAT)) 36251317Seric { 36358680Seric a->q_flags |= QBADADDR; 36468481Seric giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, 36568481Seric (time_t) 0, e); 36651317Seric } 36751317Seric } 36851317Seric 36957402Seric /* try aliasing */ 37068481Seric if (!bitset(QDONTSEND, a->q_flags) && bitnset(M_ALIASABLE, m->m_flags)) 37168481Seric alias(a, sendq, aliaslevel, e); 37257402Seric 37357402Seric # ifdef USERDB 37457402Seric /* if not aliased, look it up in the user database */ 37568481Seric if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags) && 37668481Seric bitnset(M_CHECKUDB, m->m_flags)) 37757402Seric { 37857402Seric extern int udbexpand(); 37957402Seric 38068481Seric if (udbexpand(a, sendq, aliaslevel, e) == EX_TEMPFAIL) 38157402Seric { 38263853Seric a->q_flags |= QQUEUEUP; 38357402Seric if (e->e_message == NULL) 38457402Seric e->e_message = newstr("Deferred: user database error"); 38557402Seric # ifdef LOG 38658020Seric if (LogLevel > 8) 38759623Seric syslog(LOG_INFO, "%s: deferred: udbexpand: %s", 38866284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 38966284Seric errstring(errno)); 39057402Seric # endif 39159615Seric message("queued (user database error): %s", 39259615Seric errstring(errno)); 39357642Seric e->e_nrcpts++; 39463847Seric goto testselfdestruct; 39557402Seric } 39657402Seric } 39757402Seric # endif 39857402Seric 39951317Seric /* 40051317Seric ** If we have a level two config file, then pass the name through 40151317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 40251317Seric ** to send rewrite it to another mailer. This gives us a hook 40351317Seric ** after local aliasing has been done. 40451317Seric */ 40551317Seric 40651317Seric if (tTd(29, 5)) 40751317Seric { 40851317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 40951317Seric ConfigLevel, RewriteRules[5]); 41051317Seric printaddr(a, FALSE); 41151317Seric } 41268481Seric if (!bitset(QNOTREMOTE|QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 41368481Seric ConfigLevel >= 2 && RewriteRules[5] != NULL && 41468481Seric bitnset(M_TRYRULESET5, m->m_flags)) 41551317Seric { 416*68603Seric maplocaluser(a, sendq, aliaslevel + 1, e); 41751317Seric } 41851317Seric 41951317Seric /* 42051317Seric ** If it didn't get rewritten to another mailer, go ahead 42151317Seric ** and deliver it. 42251317Seric */ 42351317Seric 42468481Seric if (!bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags) && 42568481Seric bitnset(M_HASPWENT, m->m_flags)) 42651317Seric { 42755354Seric auto bool fuzzy; 42851317Seric register struct passwd *pw; 42951317Seric extern struct passwd *finduser(); 43051317Seric 43151317Seric /* warning -- finduser may trash buf */ 43255354Seric pw = finduser(buf, &fuzzy); 43351317Seric if (pw == NULL) 43451317Seric { 43558680Seric a->q_flags |= QBADADDR; 43668481Seric giveresponse(EX_NOUSER, m, NULL, a->q_alias, 43768481Seric (time_t) 0, e); 43851317Seric } 4394174Seric else 4404174Seric { 44168528Seric char nbuf[MAXNAME + 1]; 4424373Seric 44355354Seric if (fuzzy) 4444174Seric { 44553735Seric /* name was a fuzzy match */ 44651317Seric a->q_user = newstr(pw->pw_name); 44753735Seric if (findusercount++ > 3) 44853735Seric { 44958680Seric a->q_flags |= QBADADDR; 45058151Seric usrerr("554 aliasing/forwarding loop for %s broken", 45153735Seric pw->pw_name); 45268481Seric goto done; 45353735Seric } 45453735Seric 45553735Seric /* see if it aliases */ 45651317Seric (void) strcpy(buf, pw->pw_name); 45753735Seric goto trylocaluser; 4584174Seric } 45965822Seric if (strcmp(pw->pw_dir, "/") == 0) 46065822Seric a->q_home = ""; 46165822Seric else 46265822Seric a->q_home = newstr(pw->pw_dir); 46351317Seric a->q_uid = pw->pw_uid; 46451317Seric a->q_gid = pw->pw_gid; 46559083Seric a->q_ruser = newstr(pw->pw_name); 46651317Seric a->q_flags |= QGOODUID; 46751317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 46851317Seric if (nbuf[0] != '\0') 46951317Seric a->q_fullname = newstr(nbuf); 47065211Seric if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && 47165211Seric !usershellok(pw->pw_shell)) 47265206Seric { 47365211Seric a->q_flags |= QBOGUSSHELL; 47465206Seric } 47551317Seric if (!quoted) 47668481Seric forward(a, sendq, aliaslevel, e); 4774174Seric } 4784174Seric } 47957642Seric if (!bitset(QDONTSEND, a->q_flags)) 48057642Seric e->e_nrcpts++; 48163847Seric 48263847Seric testselfdestruct: 483*68603Seric a->q_flags |= QTHISPASS; 48463978Seric if (tTd(26, 8)) 48563847Seric { 48663978Seric printf("testselfdestruct: "); 487*68603Seric printaddr(a, FALSE); 488*68603Seric if (tTd(26, 10)) 489*68603Seric { 490*68603Seric printf("SENDQ:\n"); 491*68603Seric printaddr(*sendq, TRUE); 492*68603Seric printf("----\n"); 493*68603Seric } 49463978Seric } 49563978Seric if (a->q_alias == NULL && a != &e->e_from && 49663978Seric bitset(QDONTSEND, a->q_flags)) 49763978Seric { 498*68603Seric for (q = *sendq; q != NULL; q = q->q_next) 499*68603Seric { 500*68603Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags) && 501*68603Seric bitset(QTHISPASS, q->q_flags)) 502*68603Seric break; 503*68603Seric } 50463978Seric if (q == NULL) 50563847Seric { 50663847Seric a->q_flags |= QBADADDR; 50763847Seric usrerr("554 aliasing/forwarding loop broken"); 50863847Seric } 50963847Seric } 51068481Seric 51168481Seric done: 512*68603Seric a->q_flags |= QTHISPASS; 51368481Seric if (buf != buf0) 51468481Seric free(buf); 515*68603Seric 516*68603Seric /* 517*68603Seric ** If we are at the top level, check to see if this has 518*68603Seric ** expanded to exactly one address. If so, it can inherit 519*68603Seric ** the primaryness of the address. 520*68603Seric ** 521*68603Seric ** While we're at it, clear the QTHISPASS bits. 522*68603Seric */ 523*68603Seric 524*68603Seric if (aliaslevel == 0) 525*68603Seric { 526*68603Seric int nrcpts = 0; 527*68603Seric ADDRESS *only; 528*68603Seric 529*68603Seric for (q = *sendq; q != NULL; q = q->q_next) 530*68603Seric { 531*68603Seric if (bitset(QTHISPASS, q->q_flags) && 532*68603Seric !bitset(QDONTSEND|QBADADDR, q->q_flags)) 533*68603Seric { 534*68603Seric nrcpts++; 535*68603Seric only = q; 536*68603Seric } 537*68603Seric q->q_flags &= ~QTHISPASS; 538*68603Seric } 539*68603Seric if (nrcpts == 1) 540*68603Seric only->q_flags |= QPRIMARY; 541*68603Seric else if (!initialdontsend) 542*68603Seric { 543*68603Seric /* arrange for return receipt */ 544*68603Seric e->e_flags |= EF_SENDRECEIPT; 545*68603Seric a->q_flags |= QEXPLODED; 546*68603Seric if (e->e_xfp != NULL) 547*68603Seric fprintf(e->e_xfp, 548*68603Seric "%s... expanded to multiple addresses\n", 549*68603Seric a->q_paddr); 550*68603Seric } 551*68603Seric } 552*68603Seric 55312613Seric return (a); 5544174Seric } 5554174Seric /* 5564373Seric ** FINDUSER -- find the password entry for a user. 5574373Seric ** 5584373Seric ** This looks a lot like getpwnam, except that it may want to 5594373Seric ** do some fancier pattern matching in /etc/passwd. 5604373Seric ** 5619379Seric ** This routine contains most of the time of many sendmail runs. 5629379Seric ** It deserves to be optimized. 5639379Seric ** 5644373Seric ** Parameters: 5654373Seric ** name -- the name to match against. 56655354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 56755354Seric ** was found using the fuzzy matching algorithm; 56855354Seric ** set to FALSE otherwise. 5694373Seric ** 5704373Seric ** Returns: 5714373Seric ** A pointer to a pw struct. 5724373Seric ** NULL if name is unknown or ambiguous. 5734373Seric ** 5744373Seric ** Side Effects: 5754407Seric ** may modify name. 5764373Seric */ 5774373Seric 5784373Seric struct passwd * 57955354Seric finduser(name, fuzzyp) 5804373Seric char *name; 58155354Seric bool *fuzzyp; 5824373Seric { 5834376Seric register struct passwd *pw; 5844407Seric register char *p; 58515325Seric extern struct passwd *getpwent(); 58615325Seric extern struct passwd *getpwnam(); 5874373Seric 58855354Seric if (tTd(29, 4)) 58955354Seric printf("finduser(%s): ", name); 59055354Seric 59155354Seric *fuzzyp = FALSE; 5924407Seric 59368481Seric #ifdef HESIOD 59464673Seric /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 59564673Seric for (p = name; *p != '\0'; p++) 59664673Seric if (!isascii(*p) || !isdigit(*p)) 59764673Seric break; 59864673Seric if (*p == '\0') 59964673Seric { 60064673Seric if (tTd(29, 4)) 60164673Seric printf("failed (numeric input)\n"); 60264673Seric return NULL; 60364673Seric } 60468481Seric #endif 60564673Seric 60625777Seric /* look up this login name using fast path */ 60712634Seric if ((pw = getpwnam(name)) != NULL) 60855354Seric { 60955354Seric if (tTd(29, 4)) 61055354Seric printf("found (non-fuzzy)\n"); 61112634Seric return (pw); 61255354Seric } 61312634Seric 61453735Seric #ifdef MATCHGECOS 61553735Seric /* see if fuzzy matching allowed */ 61653735Seric if (!MatchGecos) 61755354Seric { 61855354Seric if (tTd(29, 4)) 61955354Seric printf("not found (fuzzy disabled)\n"); 62053735Seric return NULL; 62155354Seric } 62253735Seric 62312634Seric /* search for a matching full name instead */ 62425777Seric for (p = name; *p != '\0'; p++) 62525777Seric { 62625777Seric if (*p == (SpaceSub & 0177) || *p == '_') 62725777Seric *p = ' '; 62825777Seric } 62923107Seric (void) setpwent(); 6304376Seric while ((pw = getpwent()) != NULL) 6314376Seric { 63268528Seric char buf[MAXNAME + 1]; 6334376Seric 6344998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 63556795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 6364381Seric { 63755354Seric if (tTd(29, 4)) 63855354Seric printf("fuzzy matches %s\n", pw->pw_name); 63958151Seric message("sending to login name %s", pw->pw_name); 64055354Seric *fuzzyp = TRUE; 6414376Seric return (pw); 6424377Seric } 6434376Seric } 64455354Seric if (tTd(29, 4)) 64555354Seric printf("no fuzzy match found\n"); 64659015Seric #else 64759015Seric if (tTd(29, 4)) 64859015Seric printf("not found (fuzzy disabled)\n"); 64959015Seric #endif 6504376Seric return (NULL); 6514373Seric } 6524373Seric /* 6534329Seric ** WRITABLE -- predicate returning if the file is writable. 6544329Seric ** 6554329Seric ** This routine must duplicate the algorithm in sys/fio.c. 6564329Seric ** Unfortunately, we cannot use the access call since we 6574329Seric ** won't necessarily be the real uid when we try to 6584329Seric ** actually open the file. 6594329Seric ** 6604329Seric ** Notice that ANY file with ANY execute bit is automatically 6614329Seric ** not writable. This is also enforced by mailfile. 6624329Seric ** 6634329Seric ** Parameters: 66465064Seric ** filename -- the file name to check. 66565112Seric ** ctladdr -- the controlling address for this file. 66665064Seric ** flags -- SFF_* flags to control the function. 6674329Seric ** 6684329Seric ** Returns: 6694329Seric ** TRUE -- if we will be able to write this file. 6704329Seric ** FALSE -- if we cannot write this file. 6714329Seric ** 6724329Seric ** Side Effects: 6734329Seric ** none. 6744329Seric */ 6754329Seric 6764329Seric bool 67765112Seric writable(filename, ctladdr, flags) 67864819Seric char *filename; 67965112Seric ADDRESS *ctladdr; 68065064Seric int flags; 6814329Seric { 68255372Seric uid_t euid; 68355372Seric gid_t egid; 6844329Seric int bits; 68564944Seric register char *p; 68664944Seric char *uname; 6874329Seric 68864819Seric if (tTd(29, 5)) 68965064Seric printf("writable(%s, %x)\n", filename, flags); 69064944Seric 69165225Seric #ifdef SUID_ROOT_FILES_OK 69265225Seric /* really ought to be passed down -- and not a good idea */ 69365225Seric flags |= SFF_ROOTOK; 69465225Seric #endif 69565225Seric 69664944Seric /* 69764944Seric ** File does exist -- check that it is writable. 69864944Seric */ 69964944Seric 70065112Seric if (ctladdr != NULL && geteuid() == 0) 70164944Seric { 70265112Seric euid = ctladdr->q_uid; 70365112Seric egid = ctladdr->q_gid; 70465112Seric uname = ctladdr->q_user; 70564944Seric } 70668481Seric #ifdef RUN_AS_REAL_UID 70765112Seric else 70865112Seric { 70968494Seric extern char RealUserName[]; 71068494Seric 71165112Seric euid = RealUid; 71265112Seric egid = RealGid; 71365112Seric uname = RealUserName; 71465112Seric } 71568481Seric #else 71668481Seric else if (FileMailer != NULL) 71768481Seric { 71868481Seric euid = FileMailer->m_uid; 71968481Seric egid = FileMailer->m_gid; 72068481Seric } 72168481Seric else 72268481Seric { 72368481Seric euid = egid = 0; 72468481Seric } 72568481Seric #endif 72665138Seric if (euid == 0) 72765138Seric { 72865138Seric euid = DefUid; 72965138Seric uname = DefUser; 73065138Seric } 73165138Seric if (egid == 0) 73265138Seric egid = DefGid; 7334329Seric if (geteuid() == 0) 73468494Seric flags |= SFF_SETUIDOK; 7354329Seric 73668494Seric errno = safefile(filename, euid, egid, uname, flags, S_IWRITE, NULL); 73765067Seric return errno == 0; 7384329Seric } 7394329Seric /* 7404174Seric ** INCLUDE -- handle :include: specification. 7414174Seric ** 7424174Seric ** Parameters: 7434174Seric ** fname -- filename to include. 74453037Seric ** forwarding -- if TRUE, we are reading a .forward file. 74553037Seric ** if FALSE, it's a :include: file. 7464399Seric ** ctladdr -- address template to use to fill in these 7474399Seric ** addresses -- effective user/group id are 7484399Seric ** the important things. 7495006Seric ** sendq -- a pointer to the head of the send queue 7505006Seric ** to put these addresses in. 75168481Seric ** aliaslevel -- the alias nesting depth. 75268481Seric ** e -- the current envelope. 7534174Seric ** 7544174Seric ** Returns: 75557136Seric ** open error status 7564174Seric ** 7574174Seric ** Side Effects: 7584174Seric ** reads the :include: file and sends to everyone 7594174Seric ** listed in that file. 76065909Seric ** 76165909Seric ** Security Note: 76265909Seric ** If you have restricted chown (that is, you can't 76365909Seric ** give a file away), it is reasonable to allow programs 76465909Seric ** and files called from this :include: file to be to be 76565909Seric ** run as the owner of the :include: file. This is bogus 76665909Seric ** if there is any chance of someone giving away a file. 76765909Seric ** We assume that pre-POSIX systems can give away files. 76865909Seric ** 76965909Seric ** There is an additional restriction that if you 77065909Seric ** forward to a :include: file, it will not take on 77165909Seric ** the ownership of the :include: file. This may not 77265909Seric ** be necessary, but shouldn't hurt. 7734174Seric */ 7744174Seric 77553037Seric static jmp_buf CtxIncludeTimeout; 77668481Seric static void includetimeout(); 77753037Seric 77857136Seric int 77968481Seric include(fname, forwarding, ctladdr, sendq, aliaslevel, e) 7804174Seric char *fname; 78153037Seric bool forwarding; 7824399Seric ADDRESS *ctladdr; 7835006Seric ADDRESS **sendq; 78468481Seric int aliaslevel; 78555012Seric ENVELOPE *e; 7864174Seric { 78768481Seric FILE *fp = NULL; 78855012Seric char *oldto = e->e_to; 7899379Seric char *oldfilename = FileName; 7909379Seric int oldlinenumber = LineNumber; 79153037Seric register EVENT *ev = NULL; 79258082Seric int nincludes; 79364325Seric register ADDRESS *ca; 79464325Seric uid_t saveduid, uid; 79564325Seric gid_t savedgid, gid; 79664083Seric char *uname; 79764325Seric int rval = 0; 79868513Seric int sfflags = SFF_REGONLY; 79965496Seric struct stat st; 80065948Seric char buf[MAXLINE]; 80165909Seric #ifdef _POSIX_CHOWN_RESTRICTED 80265948Seric # if _POSIX_CHOWN_RESTRICTED == -1 80365948Seric # define safechown FALSE 80465948Seric # else 80565948Seric # define safechown TRUE 80665948Seric # endif 80765948Seric #else 80865948Seric # ifdef _PC_CHOWN_RESTRICTED 80965909Seric bool safechown; 81065948Seric # else 81165948Seric # ifdef BSD 81265948Seric # define safechown TRUE 81365948Seric # else 81465948Seric # define safechown FALSE 81565948Seric # endif 81665948Seric # endif 81765909Seric #endif 81865948Seric extern bool chownsafe(); 8194174Seric 82057186Seric if (tTd(27, 2)) 82157186Seric printf("include(%s)\n", fname); 82263902Seric if (tTd(27, 4)) 82363902Seric printf(" ruid=%d euid=%d\n", getuid(), geteuid()); 82463581Seric if (tTd(27, 14)) 82563581Seric { 82663581Seric printf("ctladdr "); 82763581Seric printaddr(ctladdr, FALSE); 82863581Seric } 82957186Seric 83064325Seric if (tTd(27, 9)) 83164325Seric printf("include: old uid = %d/%d\n", getuid(), geteuid()); 83253037Seric 83368513Seric if (forwarding) 83468513Seric sfflags |= SFF_MUSTOWN; 83568513Seric 83663581Seric ca = getctladdr(ctladdr); 83763581Seric if (ca == NULL) 83864083Seric { 83964846Seric uid = DefUid; 84064846Seric gid = DefGid; 84164846Seric uname = DefUser; 84264083Seric } 84363581Seric else 84464083Seric { 84563581Seric uid = ca->q_uid; 84664083Seric gid = ca->q_gid; 84764083Seric uname = ca->q_user; 84868481Seric } 84964325Seric #ifdef HASSETREUID 85068481Seric saveduid = geteuid(); 85168481Seric savedgid = getegid(); 85268481Seric if (saveduid == 0) 85368481Seric { 85468481Seric initgroups(uname, gid); 85568481Seric if (uid != 0) 85664325Seric { 85768481Seric if (setreuid(0, uid) < 0) 85868481Seric syserr("setreuid(0, %d) failure (real=%d, eff=%d)", 85968481Seric uid, getuid(), geteuid()); 86068481Seric else 86168481Seric sfflags |= SFF_NOPATHCHECK; 86264325Seric } 86368481Seric } 86468478Seric #endif 86563581Seric 86664325Seric if (tTd(27, 9)) 86764325Seric printf("include: new uid = %d/%d\n", getuid(), geteuid()); 86864325Seric 86964325Seric /* 87064325Seric ** If home directory is remote mounted but server is down, 87164325Seric ** this can hang or give errors; use a timeout to avoid this 87264325Seric */ 87364325Seric 87453037Seric if (setjmp(CtxIncludeTimeout) != 0) 87553037Seric { 87663853Seric ctladdr->q_flags |= QQUEUEUP; 87753037Seric errno = 0; 87863993Seric 87963993Seric /* return pseudo-error code */ 88064325Seric rval = EOPENTIMEOUT; 88164325Seric goto resetuid; 88253037Seric } 88368481Seric if (TimeOuts.to_fileopen > 0) 88468481Seric ev = setevent(TimeOuts.to_fileopen, includetimeout, 0); 88568481Seric else 88668481Seric ev = NULL; 88753037Seric 88863581Seric /* the input file must be marked safe */ 88968494Seric rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD, NULL); 89064329Seric if (rval != 0) 89153037Seric { 89264325Seric /* don't use this :include: file */ 89357186Seric if (tTd(27, 4)) 89458247Seric printf("include: not safe (uid=%d): %s\n", 89564329Seric uid, errstring(rval)); 89653037Seric } 89765496Seric else 8984174Seric { 89965496Seric fp = fopen(fname, "r"); 90065496Seric if (fp == NULL) 90158061Seric { 90264329Seric rval = errno; 90365496Seric if (tTd(27, 4)) 90465496Seric printf("include: open: %s\n", errstring(rval)); 90558061Seric } 9064406Seric } 90768481Seric if (ev != NULL) 90868481Seric clrevent(ev); 90953037Seric 91064570Seric resetuid: 91164570Seric 91264570Seric #ifdef HASSETREUID 91364570Seric if (saveduid == 0) 91464570Seric { 91564570Seric if (uid != 0) 91668481Seric { 91768481Seric if (setreuid(-1, 0) < 0) 91868481Seric syserr("setreuid(-1, 0) failure (real=%d, eff=%d)", 91968481Seric getuid(), geteuid()); 92068481Seric if (setreuid(RealUid, 0) < 0) 92164570Seric syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", 92264570Seric RealUid, getuid(), geteuid()); 92368481Seric } 92464570Seric setgid(savedgid); 92564570Seric } 92664570Seric #endif 92764570Seric 92864570Seric if (tTd(27, 9)) 92964570Seric printf("include: reset uid = %d/%d\n", getuid(), geteuid()); 93064570Seric 93165593Seric if (rval == EOPENTIMEOUT) 93265593Seric usrerr("451 open timeout on %s", fname); 93365593Seric 93464570Seric if (fp == NULL) 93564570Seric return rval; 93664570Seric 93765496Seric if (fstat(fileno(fp), &st) < 0) 93865496Seric { 93965496Seric rval = errno; 94065496Seric syserr("Cannot fstat %s!", fname); 94165496Seric return rval; 94265496Seric } 94365496Seric 94465948Seric #ifndef safechown 94565948Seric safechown = chownsafe(fileno(fp)); 94665948Seric #endif 94765909Seric if (ca == NULL && safechown) 94865496Seric { 94965496Seric ctladdr->q_uid = st.st_uid; 95065496Seric ctladdr->q_gid = st.st_gid; 95165496Seric ctladdr->q_flags |= QGOODUID; 95265496Seric } 95365496Seric if (ca != NULL && ca->q_uid == st.st_uid) 95465496Seric { 95565496Seric /* optimization -- avoid getpwuid if we already have info */ 95665496Seric ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; 95765496Seric ctladdr->q_ruser = ca->q_ruser; 95865496Seric } 95965496Seric else 96065496Seric { 96165496Seric register struct passwd *pw; 96265496Seric 96365496Seric pw = getpwuid(st.st_uid); 96468481Seric if (pw == NULL) 96568481Seric ctladdr->q_flags |= QBOGUSSHELL; 96668481Seric else 96768478Seric { 96868481Seric char *sh; 96968481Seric 97068478Seric ctladdr->q_ruser = newstr(pw->pw_name); 97168478Seric if (safechown) 97268478Seric sh = pw->pw_shell; 97365909Seric else 97468481Seric sh = "/SENDMAIL/ANY/SHELL/"; 97568481Seric if (!usershellok(sh)) 97668481Seric { 97768481Seric if (safechown) 97868481Seric ctladdr->q_flags |= QBOGUSSHELL; 97968481Seric else 98068481Seric ctladdr->q_flags |= QUNSAFEADDR; 98168481Seric } 98265496Seric } 98365496Seric } 98465496Seric 98558092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 98658092Seric { 98758092Seric /* don't do any more now */ 98858868Seric ctladdr->q_flags |= QVERIFIED; 98958884Seric e->e_nrcpts++; 99058680Seric xfclose(fp, "include", fname); 99164570Seric return rval; 99258092Seric } 99358092Seric 99465496Seric /* 99565496Seric ** Check to see if some bad guy can write this file 99665496Seric ** 99765496Seric ** This should really do something clever with group 99865496Seric ** permissions; currently we just view world writable 99965496Seric ** as unsafe. Also, we don't check for writable 100065496Seric ** directories in the path. We've got to leave 100165496Seric ** something for the local sysad to do. 100265496Seric */ 100365496Seric 100465496Seric if (bitset(S_IWOTH, st.st_mode)) 100565496Seric ctladdr->q_flags |= QUNSAFEADDR; 100665496Seric 10074174Seric /* read the file -- each line is a comma-separated list. */ 10089379Seric FileName = fname; 10099379Seric LineNumber = 0; 101058082Seric ctladdr->q_flags &= ~QSELFREF; 101158082Seric nincludes = 0; 10124174Seric while (fgets(buf, sizeof buf, fp) != NULL) 10134174Seric { 101456795Seric register char *p = strchr(buf, '\n'); 10154174Seric 101640963Sbostic LineNumber++; 10174174Seric if (p != NULL) 10184174Seric *p = '\0'; 101957186Seric if (buf[0] == '#' || buf[0] == '\0') 102057139Seric continue; 102158008Seric e->e_to = NULL; 102258151Seric message("%s to %s", 102353037Seric forwarding ? "forwarding" : "sending", buf); 102457977Seric #ifdef LOG 102558020Seric if (forwarding && LogLevel > 9) 102657977Seric syslog(LOG_INFO, "%s: forward %s => %s", 102766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 102866284Seric oldto, buf); 102957977Seric #endif 103057977Seric 103168481Seric nincludes += sendtolist(buf, ctladdr, sendq, aliaslevel + 1, e); 10324174Seric } 103363902Seric 103463902Seric if (ferror(fp) && tTd(27, 3)) 103563902Seric printf("include: read error: %s\n", errstring(errno)); 103658082Seric if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) 103758065Seric { 103858065Seric if (tTd(27, 5)) 103958065Seric { 104058065Seric printf("include: QDONTSEND "); 104158065Seric printaddr(ctladdr, FALSE); 104258065Seric } 104358065Seric ctladdr->q_flags |= QDONTSEND; 104458065Seric } 10454174Seric 104658680Seric (void) xfclose(fp, "include", fname); 10479379Seric FileName = oldfilename; 10489379Seric LineNumber = oldlinenumber; 104963847Seric e->e_to = oldto; 105064325Seric return rval; 10514174Seric } 105253037Seric 105368481Seric static void 105453037Seric includetimeout() 105553037Seric { 105653037Seric longjmp(CtxIncludeTimeout, 1); 105753037Seric } 10584324Seric /* 10594324Seric ** SENDTOARGV -- send to an argument vector. 10604324Seric ** 10614324Seric ** Parameters: 10624324Seric ** argv -- argument vector to send to. 106358247Seric ** e -- the current envelope. 10644324Seric ** 10654324Seric ** Returns: 10664324Seric ** none. 10674324Seric ** 10684324Seric ** Side Effects: 10694324Seric ** puts all addresses on the argument vector onto the 10704324Seric ** send queue. 10714324Seric */ 10724324Seric 107355012Seric sendtoargv(argv, e) 10744324Seric register char **argv; 107555012Seric register ENVELOPE *e; 10764324Seric { 10774324Seric register char *p; 10784324Seric 10794324Seric while ((p = *argv++) != NULL) 10804324Seric { 108168481Seric (void) sendtolist(p, NULLADDR, &e->e_sendqueue, 0, e); 10824324Seric } 10834324Seric } 10844399Seric /* 10854399Seric ** GETCTLADDR -- get controlling address from an address header. 10864399Seric ** 10874399Seric ** If none, get one corresponding to the effective userid. 10884399Seric ** 10894399Seric ** Parameters: 10904399Seric ** a -- the address to find the controller of. 10914399Seric ** 10924399Seric ** Returns: 10934399Seric ** the controlling address. 10944399Seric ** 10954399Seric ** Side Effects: 10964399Seric ** none. 10974399Seric */ 10984399Seric 10994399Seric ADDRESS * 11004399Seric getctladdr(a) 11014399Seric register ADDRESS *a; 11024399Seric { 11034404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 11044399Seric a = a->q_alias; 11054399Seric return (a); 11064399Seric } 1107