122710Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822710Sdist 922710Sdist #ifndef lint 10*57731Seric static char sccsid[] = "@(#)recipient.c 6.4 (Berkeley) 01/26/93"; 1133731Sbostic #endif /* not lint */ 1222710Sdist 1336928Sbostic # include <sys/types.h> 1436928Sbostic # include <sys/stat.h> 1552046Seric # include <sys/file.h> 164174Seric # include <pwd.h> 174627Seric # include "sendmail.h" 184174Seric 194174Seric /* 209622Seric ** SENDTOLIST -- Designate a send list. 214174Seric ** 224174Seric ** The parameter is a comma-separated list of people to send to. 234174Seric ** This routine arranges to send to all of them. 244174Seric ** 254174Seric ** Parameters: 264174Seric ** list -- the send list. 274399Seric ** ctladdr -- the address template for the person to 284399Seric ** send to -- effective uid/gid are important. 295006Seric ** This is typically the alias that caused this 305006Seric ** expansion. 315006Seric ** sendq -- a pointer to the head of a queue to put 325006Seric ** these people into. 334174Seric ** 344174Seric ** Returns: 354998Seric ** none 364174Seric ** 374174Seric ** Side Effects: 384174Seric ** none. 394174Seric */ 404174Seric 414174Seric # define MAXRCRSN 10 424174Seric 4355012Seric sendtolist(list, ctladdr, sendq, e) 444174Seric char *list; 454399Seric ADDRESS *ctladdr; 465198Seric ADDRESS **sendq; 4755012Seric register ENVELOPE *e; 484174Seric { 494174Seric register char *p; 508223Seric register ADDRESS *al; /* list of addresses to send to */ 514423Seric bool firstone; /* set on first address sent */ 524444Seric bool selfref; /* set if this list includes ctladdr */ 5311446Seric char delimiter; /* the address delimiter */ 544174Seric 557676Seric if (tTd(25, 1)) 564444Seric { 574444Seric printf("sendto: %s\n ctladdr=", list); 584444Seric printaddr(ctladdr, FALSE); 594444Seric } 604324Seric 618223Seric /* heuristic to determine old versus new style addresses */ 628230Seric if (ctladdr == NULL && 6356795Seric (strchr(list, ',') != NULL || strchr(list, ';') != NULL || 6456795Seric strchr(list, '<') != NULL || strchr(list, '(') != NULL)) 6555012Seric e->e_flags &= ~EF_OLDSTYLE; 6611446Seric delimiter = ' '; 6755012Seric if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) 6811446Seric delimiter = ','; 698223Seric 704423Seric firstone = TRUE; 714444Seric selfref = FALSE; 724324Seric al = NULL; 738223Seric 748081Seric for (p = list; *p != '\0'; ) 754174Seric { 768081Seric register ADDRESS *a; 778081Seric extern char *DelimChar; /* defined in prescan */ 784319Seric 798081Seric /* parse the address */ 808081Seric while (isspace(*p) || *p == ',') 814174Seric p++; 8255012Seric a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter, e); 839297Seric p = DelimChar; 849297Seric if (a == NULL) 854174Seric continue; 864324Seric a->q_next = al; 874399Seric a->q_alias = ctladdr; 884444Seric 894444Seric /* see if this should be marked as a primary address */ 904423Seric if (ctladdr == NULL || 918081Seric (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 924423Seric a->q_flags |= QPRIMARY; 934444Seric 949379Seric if (ctladdr != NULL && sameaddr(ctladdr, a)) 954444Seric selfref = TRUE; 96*57731Seric al = a; 974423Seric firstone = FALSE; 984324Seric } 994324Seric 1004444Seric /* if this alias doesn't include itself, delete ctladdr */ 1014444Seric if (!selfref && ctladdr != NULL) 102*57731Seric { 103*57731Seric if (tTd(25, 5)) 104*57731Seric { 105*57731Seric printf("sendtolist: QDONTSEND "); 106*57731Seric printaddr(ctladdr, FALSE); 107*57731Seric } 1084444Seric ctladdr->q_flags |= QDONTSEND; 109*57731Seric } 1104444Seric 1114324Seric /* arrange to send to everyone on the local send list */ 1124324Seric while (al != NULL) 1134324Seric { 1144324Seric register ADDRESS *a = al; 11512613Seric extern ADDRESS *recipient(); 1164324Seric 1174324Seric al = a->q_next; 11855012Seric a = recipient(a, sendq, e); 1194993Seric 1204998Seric /* arrange to inherit full name */ 1214998Seric if (a->q_fullname == NULL && ctladdr != NULL) 1224998Seric a->q_fullname = ctladdr->q_fullname; 1234174Seric } 1244324Seric 12555012Seric e->e_to = NULL; 1264174Seric } 1274174Seric /* 1284174Seric ** RECIPIENT -- Designate a message recipient 1294174Seric ** 1304174Seric ** Saves the named person for future mailing. 1314174Seric ** 1324174Seric ** Parameters: 1334174Seric ** a -- the (preparsed) address header for the recipient. 1345006Seric ** sendq -- a pointer to the head of a queue to put the 1355006Seric ** recipient in. Duplicate supression is done 1365006Seric ** in this queue. 137*57731Seric ** e -- the current envelope. 1384174Seric ** 1394174Seric ** Returns: 14012613Seric ** The actual address in the queue. This will be "a" if 14112613Seric ** the address is not a duplicate, else the original address. 1424174Seric ** 1434174Seric ** Side Effects: 1444174Seric ** none. 1454174Seric */ 1464174Seric 14746928Sbostic extern ADDRESS *getctladdr(); 14852046Seric extern char *RcptLogFile; 14946928Sbostic 15012613Seric ADDRESS * 15155012Seric recipient(a, sendq, e) 1524174Seric register ADDRESS *a; 1535006Seric register ADDRESS **sendq; 15455012Seric register ENVELOPE *e; 1554174Seric { 1564174Seric register ADDRESS *q; 1574319Seric ADDRESS **pq; 1584174Seric register struct mailer *m; 1599210Seric register char *p; 1609210Seric bool quoted = FALSE; /* set if the addr has a quote bit */ 16153735Seric int findusercount = 0; 1629210Seric char buf[MAXNAME]; /* unquoted image of the user name */ 1634627Seric extern bool safefile(); 1644174Seric 16555012Seric e->e_to = a->q_paddr; 1664600Seric m = a->q_mailer; 1674174Seric errno = 0; 1687676Seric if (tTd(26, 1)) 1694444Seric { 1704444Seric printf("\nrecipient: "); 1714444Seric printaddr(a, FALSE); 1724444Seric } 1734174Seric 1744174Seric /* break aliasing loops */ 1754174Seric if (AliasLevel > MAXRCRSN) 1764174Seric { 1774174Seric usrerr("aliasing/forwarding loop broken"); 17812613Seric return (a); 1794174Seric } 1804174Seric 1814174Seric /* 1824627Seric ** Finish setting up address structure. 1834174Seric */ 1844174Seric 18516160Seric /* set the queue timeout */ 1864627Seric a->q_timeout = TimeOut; 1874627Seric 18816160Seric /* map user & host to lower case if requested on non-aliases */ 18916160Seric if (a->q_alias == NULL) 19016160Seric loweraddr(a); 19116160Seric 19216160Seric /* get unquoted user for file, program or user.name check */ 1939210Seric (void) strcpy(buf, a->q_user); 1949210Seric for (p = buf; *p != '\0' && !quoted; p++) 1959210Seric { 19654993Seric if (*p == '\\') 1979210Seric quoted = TRUE; 1989210Seric } 19954983Seric stripquotes(buf); 2009210Seric 20157402Seric /* check for direct mailing to restricted mailers */ 202*57731Seric if (a->q_alias == NULL && m == ProgMailer) 2034174Seric { 20457402Seric a->q_flags |= QDONTSEND|QBADADDR; 20557402Seric usrerr("Cannot mail directly to programs", m->m_name); 2064174Seric } 2074174Seric 2084174Seric /* 2094419Seric ** Look up this person in the recipient list. 2104419Seric ** If they are there already, return, otherwise continue. 2114419Seric ** If the list is empty, just add it. Notice the cute 2124419Seric ** hack to make from addresses suppress things correctly: 2134419Seric ** the QDONTSEND bit will be set in the send list. 2144419Seric ** [Please note: the emphasis is on "hack."] 2154174Seric */ 2164174Seric 2175006Seric for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 2184174Seric { 2199379Seric if (!ForceMail && sameaddr(q, a)) 2204174Seric { 2217676Seric if (tTd(26, 1)) 2224444Seric { 2234444Seric printf("%s in sendq: ", a->q_paddr); 2244444Seric printaddr(q, FALSE); 2254444Seric } 2267054Seric if (!bitset(QDONTSEND, a->q_flags)) 2274324Seric message(Arpa_Info, "duplicate suppressed"); 2284423Seric if (!bitset(QPRIMARY, q->q_flags)) 2294423Seric q->q_flags |= a->q_flags; 23012613Seric return (q); 2314174Seric } 2324319Seric } 2334174Seric 2344319Seric /* add address on list */ 2354319Seric *pq = a; 2364174Seric a->q_next = NULL; 2374174Seric 23852046Seric if (a->q_alias == NULL && RcptLogFile != NULL && 23952046Seric !bitset(QDONTSEND, a->q_flags)) 24052046Seric { 24152046Seric static int RcptLogFd = -1; 24252046Seric 24352046Seric /* 24452046Seric ** Log the incoming recipient name before aliasing, 24552046Seric ** expanding, forwarding, rewriting, and all that jazz. 24652046Seric ** We'll use this to track down out-of-date aliases, 24752046Seric ** host names, and so forth. 24852046Seric */ 24952046Seric 25052046Seric if (RcptLogFd < 0) 25152046Seric { 25252046Seric /* try to open the log file */ 25352046Seric RcptLogFd = open(RcptLogFile, O_WRONLY|O_APPEND|O_CREAT, 0666); 25452047Seric if (RcptLogFd >= 0) 25552047Seric (void) fcntl(RcptLogFd, F_SETFD, 1); 25652046Seric } 25752046Seric if (RcptLogFd >= 0) 25852046Seric { 25952046Seric int l = strlen(a->q_paddr); 26052046Seric 26152046Seric a->q_paddr[l] = '\n'; 26252046Seric if (write(RcptLogFd, a->q_paddr, l + 1) < 0) 26352046Seric { 26452046Seric (void) close(RcptLogFd); 26552046Seric RcptLogFd = -1; 26652046Seric } 26752046Seric a->q_paddr[l] = '\0'; 26852046Seric } 26952046Seric } 27052046Seric 2714174Seric /* 27257402Seric ** Alias the name and handle special mailer types. 2734174Seric */ 2744174Seric 27553735Seric trylocaluser: 27655354Seric if (tTd(29, 7)) 27755354Seric printf("at trylocaluser %s\n", a->q_user); 27855354Seric 27957402Seric if (bitset(QDONTSEND, a->q_flags)) 28057402Seric return (a); 28157402Seric 28257402Seric if (m == InclMailer) 2834174Seric { 28457402Seric a->q_flags |= QDONTSEND; 285*57731Seric if (a->q_alias == NULL) 2864174Seric { 28757402Seric a->q_flags |= QBADADDR; 28857402Seric usrerr("Cannot mail directly to :include:s"); 2894174Seric } 2904174Seric else 29150556Seric { 29257402Seric message(Arpa_Info, "including file %s", &a->q_user[9]); 29357402Seric (void) include(&a->q_user[9], FALSE, a, sendq, e); 29450556Seric } 2954174Seric } 29657642Seric else if (m == FileMailer) 2974174Seric { 2984329Seric struct stat stb; 2994329Seric extern bool writable(); 3004174Seric 30156795Seric p = strrchr(buf, '/'); 30251317Seric /* check if writable or creatable */ 303*57731Seric if (a->q_alias == NULL && !QueueRun) 3044174Seric { 30551317Seric a->q_flags |= QDONTSEND|QBADADDR; 30651317Seric usrerr("Cannot mail directly to files"); 3074174Seric } 30851317Seric else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 30951317Seric (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 31051317Seric { 31151317Seric a->q_flags |= QBADADDR; 31255012Seric giveresponse(EX_CANTCREAT, m, e); 31351317Seric } 31451317Seric } 31551317Seric 31657402Seric if (m != LocalMailer) 31757642Seric { 31857642Seric if (!bitset(QDONTSEND, a->q_flags)) 31957642Seric e->e_nrcpts++; 32057402Seric return (a); 32157642Seric } 32257402Seric 32357402Seric /* try aliasing */ 32457402Seric alias(a, sendq, e); 32557402Seric 32657402Seric # ifdef USERDB 32757402Seric /* if not aliased, look it up in the user database */ 32857402Seric if (!bitset(QDONTSEND|QNOTREMOTE, a->q_flags)) 32957402Seric { 33057402Seric extern int udbexpand(); 33157402Seric 33257402Seric if (udbexpand(a, sendq, e) == EX_TEMPFAIL) 33357402Seric { 33457402Seric a->q_flags |= QQUEUEUP; 33557402Seric if (e->e_message == NULL) 33657402Seric e->e_message = newstr("Deferred: user database error"); 33757402Seric # ifdef LOG 33857402Seric if (LogLevel > 3) 33957402Seric syslog(LOG_INFO, "%s: deferred: udbexpand", 34057402Seric e->e_id); 34157402Seric # endif 34257402Seric message(Arpa_Info, "queued (user database error)"); 34357642Seric e->e_nrcpts++; 34457402Seric return (a); 34557402Seric } 34657402Seric } 34757402Seric # endif 34857402Seric 34957402Seric /* if it was an alias or a UDB expansion, just return now */ 35057402Seric if (bitset(QDONTSEND, a->q_flags)) 35157402Seric return (a); 35257402Seric 35351317Seric /* 35451317Seric ** If we have a level two config file, then pass the name through 35551317Seric ** Ruleset 5 before sending it off. Ruleset 5 has the right 35651317Seric ** to send rewrite it to another mailer. This gives us a hook 35751317Seric ** after local aliasing has been done. 35851317Seric */ 35951317Seric 36051317Seric if (tTd(29, 5)) 36151317Seric { 36251317Seric printf("recipient: testing local? cl=%d, rr5=%x\n\t", 36351317Seric ConfigLevel, RewriteRules[5]); 36451317Seric printaddr(a, FALSE); 36551317Seric } 36651317Seric if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 && 36751317Seric RewriteRules[5] != NULL) 36851317Seric { 36955012Seric maplocaluser(a, sendq, e); 37051317Seric } 37151317Seric 37251317Seric /* 37351317Seric ** If it didn't get rewritten to another mailer, go ahead 37451317Seric ** and deliver it. 37551317Seric */ 37651317Seric 37751317Seric if (!bitset(QDONTSEND, a->q_flags)) 37851317Seric { 37955354Seric auto bool fuzzy; 38051317Seric register struct passwd *pw; 38151317Seric extern struct passwd *finduser(); 38251317Seric 38351317Seric /* warning -- finduser may trash buf */ 38455354Seric pw = finduser(buf, &fuzzy); 38551317Seric if (pw == NULL) 38651317Seric { 38751317Seric a->q_flags |= QBADADDR; 38855012Seric giveresponse(EX_NOUSER, m, e); 38951317Seric } 3904174Seric else 3914174Seric { 39251317Seric char nbuf[MAXNAME]; 3934373Seric 39455354Seric if (fuzzy) 3954174Seric { 39653735Seric /* name was a fuzzy match */ 39751317Seric a->q_user = newstr(pw->pw_name); 39853735Seric if (findusercount++ > 3) 39953735Seric { 40053735Seric usrerr("aliasing/forwarding loop for %s broken", 40153735Seric pw->pw_name); 40253735Seric return (a); 40353735Seric } 40453735Seric 40553735Seric /* see if it aliases */ 40651317Seric (void) strcpy(buf, pw->pw_name); 40753735Seric goto trylocaluser; 4084174Seric } 40951317Seric a->q_home = newstr(pw->pw_dir); 41051317Seric a->q_uid = pw->pw_uid; 41151317Seric a->q_gid = pw->pw_gid; 41251317Seric a->q_flags |= QGOODUID; 41351317Seric buildfname(pw->pw_gecos, pw->pw_name, nbuf); 41451317Seric if (nbuf[0] != '\0') 41551317Seric a->q_fullname = newstr(nbuf); 41651317Seric if (!quoted) 41755012Seric forward(a, sendq, e); 4184174Seric } 4194174Seric } 42057642Seric if (!bitset(QDONTSEND, a->q_flags)) 42157642Seric e->e_nrcpts++; 42212613Seric return (a); 4234174Seric } 4244174Seric /* 4254373Seric ** FINDUSER -- find the password entry for a user. 4264373Seric ** 4274373Seric ** This looks a lot like getpwnam, except that it may want to 4284373Seric ** do some fancier pattern matching in /etc/passwd. 4294373Seric ** 4309379Seric ** This routine contains most of the time of many sendmail runs. 4319379Seric ** It deserves to be optimized. 4329379Seric ** 4334373Seric ** Parameters: 4344373Seric ** name -- the name to match against. 43555354Seric ** fuzzyp -- an outarg that is set to TRUE if this entry 43655354Seric ** was found using the fuzzy matching algorithm; 43755354Seric ** set to FALSE otherwise. 4384373Seric ** 4394373Seric ** Returns: 4404373Seric ** A pointer to a pw struct. 4414373Seric ** NULL if name is unknown or ambiguous. 4424373Seric ** 4434373Seric ** Side Effects: 4444407Seric ** may modify name. 4454373Seric */ 4464373Seric 4474373Seric struct passwd * 44855354Seric finduser(name, fuzzyp) 4494373Seric char *name; 45055354Seric bool *fuzzyp; 4514373Seric { 4524376Seric register struct passwd *pw; 4534407Seric register char *p; 45415325Seric extern struct passwd *getpwent(); 45515325Seric extern struct passwd *getpwnam(); 4564373Seric 45755354Seric if (tTd(29, 4)) 45855354Seric printf("finduser(%s): ", name); 45955354Seric 46025777Seric /* map upper => lower case */ 4614407Seric for (p = name; *p != '\0'; p++) 4624407Seric { 46325777Seric if (isascii(*p) && isupper(*p)) 46425568Seric *p = tolower(*p); 4654407Seric } 46655354Seric *fuzzyp = FALSE; 4674407Seric 46825777Seric /* look up this login name using fast path */ 46912634Seric if ((pw = getpwnam(name)) != NULL) 47055354Seric { 47155354Seric if (tTd(29, 4)) 47255354Seric printf("found (non-fuzzy)\n"); 47312634Seric return (pw); 47455354Seric } 47512634Seric 47653735Seric #ifdef MATCHGECOS 47753735Seric /* see if fuzzy matching allowed */ 47853735Seric if (!MatchGecos) 47955354Seric { 48055354Seric if (tTd(29, 4)) 48155354Seric printf("not found (fuzzy disabled)\n"); 48253735Seric return NULL; 48355354Seric } 48453735Seric 48512634Seric /* search for a matching full name instead */ 48625777Seric for (p = name; *p != '\0'; p++) 48725777Seric { 48825777Seric if (*p == (SpaceSub & 0177) || *p == '_') 48925777Seric *p = ' '; 49025777Seric } 49123107Seric (void) setpwent(); 4924376Seric while ((pw = getpwent()) != NULL) 4934376Seric { 4944998Seric char buf[MAXNAME]; 4954376Seric 4964998Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 49756795Seric if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) 4984381Seric { 49955354Seric if (tTd(29, 4)) 50055354Seric printf("fuzzy matches %s\n", pw->pw_name); 5017054Seric message(Arpa_Info, "sending to login name %s", pw->pw_name); 50255354Seric *fuzzyp = TRUE; 5034376Seric return (pw); 5044377Seric } 5054376Seric } 50653735Seric #endif 50755354Seric if (tTd(29, 4)) 50855354Seric printf("no fuzzy match found\n"); 5094376Seric return (NULL); 5104373Seric } 5114373Seric /* 5124329Seric ** WRITABLE -- predicate returning if the file is writable. 5134329Seric ** 5144329Seric ** This routine must duplicate the algorithm in sys/fio.c. 5154329Seric ** Unfortunately, we cannot use the access call since we 5164329Seric ** won't necessarily be the real uid when we try to 5174329Seric ** actually open the file. 5184329Seric ** 5194329Seric ** Notice that ANY file with ANY execute bit is automatically 5204329Seric ** not writable. This is also enforced by mailfile. 5214329Seric ** 5224329Seric ** Parameters: 5234329Seric ** s -- pointer to a stat struct for the file. 5244329Seric ** 5254329Seric ** Returns: 5264329Seric ** TRUE -- if we will be able to write this file. 5274329Seric ** FALSE -- if we cannot write this file. 5284329Seric ** 5294329Seric ** Side Effects: 5304329Seric ** none. 5314329Seric */ 5324329Seric 5334329Seric bool 5344329Seric writable(s) 5354329Seric register struct stat *s; 5364329Seric { 53755372Seric uid_t euid; 53855372Seric gid_t egid; 5394329Seric int bits; 5404329Seric 5414329Seric if (bitset(0111, s->st_mode)) 5424329Seric return (FALSE); 5434329Seric euid = getruid(); 5444329Seric egid = getrgid(); 5454329Seric if (geteuid() == 0) 5464329Seric { 5474329Seric if (bitset(S_ISUID, s->st_mode)) 5484329Seric euid = s->st_uid; 5494329Seric if (bitset(S_ISGID, s->st_mode)) 5504329Seric egid = s->st_gid; 5514329Seric } 5524329Seric 5534329Seric if (euid == 0) 5544329Seric return (TRUE); 5554329Seric bits = S_IWRITE; 5564329Seric if (euid != s->st_uid) 5574329Seric { 5584329Seric bits >>= 3; 5594329Seric if (egid != s->st_gid) 5604329Seric bits >>= 3; 5614329Seric } 5624329Seric return ((s->st_mode & bits) != 0); 5634329Seric } 5644329Seric /* 5654174Seric ** INCLUDE -- handle :include: specification. 5664174Seric ** 5674174Seric ** Parameters: 5684174Seric ** fname -- filename to include. 56953037Seric ** forwarding -- if TRUE, we are reading a .forward file. 57053037Seric ** if FALSE, it's a :include: file. 5714399Seric ** ctladdr -- address template to use to fill in these 5724399Seric ** addresses -- effective user/group id are 5734399Seric ** the important things. 5745006Seric ** sendq -- a pointer to the head of the send queue 5755006Seric ** to put these addresses in. 5764174Seric ** 5774174Seric ** Returns: 57857136Seric ** open error status 5794174Seric ** 5804174Seric ** Side Effects: 5814174Seric ** reads the :include: file and sends to everyone 5824174Seric ** listed in that file. 5834174Seric */ 5844174Seric 58553037Seric static jmp_buf CtxIncludeTimeout; 58653037Seric 58757136Seric int 58855012Seric include(fname, forwarding, ctladdr, sendq, e) 5894174Seric char *fname; 59053037Seric bool forwarding; 5914399Seric ADDRESS *ctladdr; 5925006Seric ADDRESS **sendq; 59355012Seric ENVELOPE *e; 5944174Seric { 5954174Seric register FILE *fp; 59655012Seric char *oldto = e->e_to; 5979379Seric char *oldfilename = FileName; 5989379Seric int oldlinenumber = LineNumber; 59953037Seric register EVENT *ev = NULL; 60053037Seric char buf[MAXLINE]; 60153037Seric static int includetimeout(); 6024174Seric 60357186Seric if (tTd(27, 2)) 60457186Seric printf("include(%s)\n", fname); 60557186Seric 60653037Seric /* 60753037Seric ** If home directory is remote mounted but server is down, 60853037Seric ** this can hang or give errors; use a timeout to avoid this 60953037Seric */ 61053037Seric 61153037Seric if (setjmp(CtxIncludeTimeout) != 0) 61253037Seric { 61353037Seric ctladdr->q_flags |= QQUEUEUP|QDONTSEND; 61453037Seric errno = 0; 61553037Seric usrerr("451 open timeout on %s", fname); 61657136Seric return ETIMEDOUT; 61753037Seric } 61853037Seric ev = setevent((time_t) 60, includetimeout, 0); 61953037Seric 62053037Seric /* if forwarding, the input file must be marked safe */ 62153037Seric if (forwarding && !safefile(fname, ctladdr->q_uid, S_IREAD)) 62253037Seric { 62353037Seric /* don't use this .forward file */ 62453037Seric clrevent(ev); 62557186Seric if (tTd(27, 4)) 62657186Seric printf("include: not safe (uid=%d)\n", ctladdr->q_uid); 62757136Seric return EPERM; 62853037Seric } 62953037Seric 6304174Seric fp = fopen(fname, "r"); 6314174Seric if (fp == NULL) 6324174Seric { 63357136Seric int ret = errno; 63457136Seric 6354174Seric usrerr("Cannot open %s", fname); 63657136Seric return ret; 6374174Seric } 63853037Seric 6394406Seric if (getctladdr(ctladdr) == NULL) 6404406Seric { 6414406Seric struct stat st; 6424174Seric 6434406Seric if (fstat(fileno(fp), &st) < 0) 6444406Seric syserr("Cannot fstat %s!", fname); 6454406Seric ctladdr->q_uid = st.st_uid; 6464406Seric ctladdr->q_gid = st.st_gid; 6474406Seric ctladdr->q_flags |= QGOODUID; 6484406Seric } 6494406Seric 65053037Seric clrevent(ev); 65153037Seric 6524174Seric /* read the file -- each line is a comma-separated list. */ 6539379Seric FileName = fname; 6549379Seric LineNumber = 0; 6554174Seric while (fgets(buf, sizeof buf, fp) != NULL) 6564174Seric { 65756795Seric register char *p = strchr(buf, '\n'); 6584174Seric 65940963Sbostic LineNumber++; 6604174Seric if (p != NULL) 6614174Seric *p = '\0'; 66257186Seric if (buf[0] == '#' || buf[0] == '\0') 66357139Seric continue; 66455012Seric e->e_to = oldto; 66553037Seric message(Arpa_Info, "%s to %s", 66653037Seric forwarding ? "forwarding" : "sending", buf); 6674176Seric AliasLevel++; 66855012Seric sendtolist(buf, ctladdr, sendq, e); 6694176Seric AliasLevel--; 6704174Seric } 6714174Seric 6724319Seric (void) fclose(fp); 6739379Seric FileName = oldfilename; 6749379Seric LineNumber = oldlinenumber; 67557136Seric return 0; 6764174Seric } 67753037Seric 67853037Seric static 67953037Seric includetimeout() 68053037Seric { 68153037Seric longjmp(CtxIncludeTimeout, 1); 68253037Seric } 6834324Seric /* 6844324Seric ** SENDTOARGV -- send to an argument vector. 6854324Seric ** 6864324Seric ** Parameters: 6874324Seric ** argv -- argument vector to send to. 6884324Seric ** 6894324Seric ** Returns: 6904324Seric ** none. 6914324Seric ** 6924324Seric ** Side Effects: 6934324Seric ** puts all addresses on the argument vector onto the 6944324Seric ** send queue. 6954324Seric */ 6964324Seric 69755012Seric sendtoargv(argv, e) 6984324Seric register char **argv; 69955012Seric register ENVELOPE *e; 7004324Seric { 7014324Seric register char *p; 7024324Seric 7034324Seric while ((p = *argv++) != NULL) 7044324Seric { 70533725Sbostic if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at")) 7064324Seric { 7074324Seric char nbuf[MAXNAME]; 7084324Seric 7094324Seric if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 7104324Seric usrerr("address overflow"); 7114324Seric else 7124324Seric { 7134324Seric (void) strcpy(nbuf, p); 7144324Seric (void) strcat(nbuf, "@"); 7154324Seric (void) strcat(nbuf, argv[1]); 7164324Seric p = newstr(nbuf); 7174324Seric argv += 2; 7184324Seric } 7194324Seric } 72055012Seric sendtolist(p, (ADDRESS *) NULL, &e->e_sendqueue, e); 7214324Seric } 7224324Seric } 7234399Seric /* 7244399Seric ** GETCTLADDR -- get controlling address from an address header. 7254399Seric ** 7264399Seric ** If none, get one corresponding to the effective userid. 7274399Seric ** 7284399Seric ** Parameters: 7294399Seric ** a -- the address to find the controller of. 7304399Seric ** 7314399Seric ** Returns: 7324399Seric ** the controlling address. 7334399Seric ** 7344399Seric ** Side Effects: 7354399Seric ** none. 7364399Seric */ 7374399Seric 7384399Seric ADDRESS * 7394399Seric getctladdr(a) 7404399Seric register ADDRESS *a; 7414399Seric { 7424404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 7434399Seric a = a->q_alias; 7444399Seric return (a); 7454399Seric } 746