122694Sdist /* 235073Sbostic * Copyright (c) 1983 Eric P. Allman 362522Sbostic * Copyright (c) 1988, 1993 462522Sbostic * The Regents of the University of California. All rights reserved. 533728Sbostic * 642824Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822694Sdist 958332Seric # include "sendmail.h" 1050577Seric # include <signal.h> 1150577Seric # include <pwd.h> 1256766Seric 1333728Sbostic #ifndef lint 14*63787Seric static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 07/13/93"; 1533728Sbostic #endif /* not lint */ 1659673Seric 1759673Seric 1860537Seric MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ 1959673Seric int NAliasDBs; /* number of alias databases */ 2059673Seric /* 21292Seric ** ALIAS -- Compute aliases. 22292Seric ** 239368Seric ** Scans the alias file for an alias for the given address. 249368Seric ** If found, it arranges to deliver to the alias list instead. 259368Seric ** Uses libdbm database if -DDBM. 26292Seric ** 27292Seric ** Parameters: 284097Seric ** a -- address to alias. 294999Seric ** sendq -- a pointer to the head of the send queue 304999Seric ** to put the aliases in. 3158092Seric ** e -- the current envelope. 32292Seric ** 33292Seric ** Returns: 34292Seric ** none 35292Seric ** 36292Seric ** Side Effects: 373185Seric ** Aliases found are expanded. 38292Seric ** 39292Seric ** Deficiencies: 40292Seric ** It should complain about names that are aliased to 41292Seric ** nothing. 42292Seric */ 43292Seric 4455012Seric alias(a, sendq, e) 454097Seric register ADDRESS *a; 464999Seric ADDRESS **sendq; 4755012Seric register ENVELOPE *e; 48292Seric { 494081Seric register char *p; 5058082Seric int naliases; 5158170Seric char *owner; 5258170Seric char obuf[MAXNAME + 6]; 535701Seric extern char *aliaslookup(); 54292Seric 557671Seric if (tTd(27, 1)) 564098Seric printf("alias(%s)\n", a->q_paddr); 57292Seric 584098Seric /* don't realias already aliased names */ 5958680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 604098Seric return; 614098Seric 6259673Seric if (NoAlias) 6359673Seric return; 6459673Seric 6555012Seric e->e_to = a->q_paddr; 664098Seric 674314Seric /* 684314Seric ** Look up this name 694314Seric */ 704314Seric 7159673Seric p = aliaslookup(a->q_user, e); 724098Seric if (p == NULL) 734098Seric return; 74292Seric 75292Seric /* 764098Seric ** Match on Alias. 774098Seric ** Deliver to the target list. 781515Seric */ 791515Seric 807671Seric if (tTd(27, 1)) 814098Seric printf("%s (%s, %s) aliased to %s\n", 824098Seric a->q_paddr, a->q_host, a->q_user, p); 8358092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8458154Seric { 8558154Seric a->q_flags |= QVERIFIED; 8658884Seric e->e_nrcpts++; 8758092Seric return; 8858154Seric } 8958154Seric message("aliased to %s", p); 9057977Seric #ifdef LOG 9158020Seric if (LogLevel > 9) 9257977Seric syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 9357977Seric #endif 9458082Seric a->q_flags &= ~QSELFREF; 954098Seric AliasLevel++; 9658082Seric naliases = sendtolist(p, a, sendq, e); 974098Seric AliasLevel--; 9858082Seric if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 9958065Seric { 10058065Seric if (tTd(27, 5)) 10158065Seric { 10258065Seric printf("alias: QDONTSEND "); 10358065Seric printaddr(a, FALSE); 10458065Seric } 10558065Seric a->q_flags |= QDONTSEND; 10658065Seric } 10758170Seric 10858170Seric /* 10958170Seric ** Look for owner of alias 11058170Seric */ 11158170Seric 11258170Seric (void) strcpy(obuf, "owner-"); 11358170Seric if (strncmp(a->q_user, "owner-", 6) == 0) 11458170Seric (void) strcat(obuf, "owner"); 11558170Seric else 11658170Seric (void) strcat(obuf, a->q_user); 11758170Seric if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 11858170Seric makelower(obuf); 11959673Seric owner = aliaslookup(obuf, e); 12058170Seric if (owner != NULL) 12158170Seric { 12258170Seric if (strchr(owner, ',') != NULL) 12358170Seric owner = obuf; 12458170Seric a->q_owner = newstr(owner); 12558170Seric } 1264098Seric } 1274098Seric /* 1285701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1295701Seric ** 1305701Seric ** Parameters: 1315701Seric ** name -- the name to look up. 1325701Seric ** 1335701Seric ** Returns: 1345701Seric ** the value of name. 1355701Seric ** NULL if unknown. 1365701Seric ** 1375701Seric ** Side Effects: 1385701Seric ** none. 1395701Seric ** 1405701Seric ** Warnings: 1415701Seric ** The return value will be trashed across calls. 1425701Seric */ 1435701Seric 1445701Seric char * 14559673Seric aliaslookup(name, e) 1465701Seric char *name; 14759673Seric ENVELOPE *e; 1485701Seric { 14959673Seric register int dbno; 15060089Seric register MAP *map; 15159673Seric register char *p; 1525701Seric 15359673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 15459673Seric { 15560089Seric auto int stat; 15660089Seric 15760537Seric map = AliasDB[dbno]; 15860207Seric if (!bitset(MF_OPEN, map->map_mflags)) 15959673Seric continue; 16060207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 16159673Seric if (p != NULL) 16259673Seric return p; 16359673Seric } 16459673Seric return NULL; 16559673Seric } 16659673Seric /* 16759673Seric ** SETALIAS -- set up an alias map 16859673Seric ** 16959673Seric ** Called when reading configuration file. 17059673Seric ** 17159673Seric ** Parameters: 17259673Seric ** spec -- the alias specification 17359673Seric ** 17459673Seric ** Returns: 17559673Seric ** none. 17659673Seric */ 17757381Seric 17859673Seric setalias(spec) 17959673Seric char *spec; 18059673Seric { 18159673Seric register char *p; 18260089Seric register MAP *map; 18359673Seric char *class; 18459673Seric STAB *s; 18559673Seric 18659697Seric if (tTd(27, 8)) 18759697Seric printf("setalias(%s)\n", spec); 18859697Seric 18959758Seric for (p = spec; p != NULL; ) 19051756Seric { 19160537Seric char aname[50]; 19260537Seric 19359758Seric while (isspace(*p)) 19459758Seric p++; 19560502Seric if (*p == '\0') 19659673Seric break; 19759673Seric spec = p; 19859673Seric 19959758Seric if (NAliasDBs >= MAXALIASDB) 20059758Seric { 20159758Seric syserr("Too many alias databases defined, %d max", MAXALIASDB); 20259758Seric return; 20359758Seric } 20460537Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 20560537Seric s = stab(aname, ST_MAP, ST_ENTER); 20660537Seric map = &s->s_map; 20760537Seric AliasDB[NAliasDBs] = map; 20860089Seric bzero(map, sizeof *map); 20959758Seric 21059758Seric p = strpbrk(p, " ,/:"); 21159758Seric if (p != NULL && *p == ':') 21259758Seric { 21360089Seric /* map name */ 21459758Seric *p++ = '\0'; 21559758Seric class = spec; 21659758Seric spec = p; 21759758Seric } 21859758Seric else 21959758Seric { 22059758Seric class = "implicit"; 22160228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 22259758Seric } 22359758Seric 22459758Seric /* find end of spec */ 22559758Seric if (p != NULL) 22659758Seric p = strchr(p, ','); 22759758Seric if (p != NULL) 22859758Seric *p++ = '\0'; 22959758Seric 23059758Seric /* look up class */ 23160089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 23259758Seric if (s == NULL) 23359758Seric { 23459758Seric if (tTd(27, 1)) 23559758Seric printf("Unknown alias class %s\n", class); 23659758Seric } 23760207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 23860207Seric { 23960207Seric syserr("setalias: map class %s can't handle aliases", 24060207Seric class); 24160207Seric } 24259758Seric else 24359758Seric { 24460207Seric map->map_class = &s->s_mapclass; 24560089Seric if (map->map_class->map_parse(map, spec)) 24660089Seric { 24760207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 24860089Seric NAliasDBs++; 24960089Seric } 25059758Seric } 25159756Seric } 2525701Seric } 2535701Seric /* 25459673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 25559673Seric ** 25659673Seric ** This can decide to reopen or rebuild the alias file 25759673Seric */ 25859673Seric 25960207Seric aliaswait(map, ext) 26060089Seric MAP *map; 26160207Seric char *ext; 26259673Seric { 26359673Seric int atcnt; 26459673Seric time_t mtime; 26559673Seric struct stat stb; 26659673Seric char buf[MAXNAME]; 26759673Seric 26859697Seric if (tTd(27, 3)) 26960207Seric printf("aliaswait(%s:%s)\n", 27060207Seric map->map_class->map_cname, map->map_file); 27159697Seric 27217471Seric atcnt = SafeAlias * 2; 27317471Seric if (atcnt > 0) 27417471Seric { 27560089Seric auto int st; 27660089Seric 27759673Seric while (atcnt-- >= 0 && 27860089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 27925689Seric { 28025689Seric /* 28159673Seric ** Close and re-open the alias database in case 28259673Seric ** the one is mv'ed instead of cp'ed in. 28325689Seric */ 28425689Seric 28559697Seric if (tTd(27, 2)) 28659697Seric printf("aliaswait: sleeping\n"); 28759697Seric 28860089Seric map->map_class->map_close(map); 28917471Seric sleep(30); 29060089Seric map->map_class->map_open(map, O_RDONLY); 29125689Seric } 29217471Seric } 2938437Seric 29459673Seric /* see if we need to go into auto-rebuild mode */ 29560207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 29660207Seric { 29760207Seric if (tTd(27, 3)) 29860207Seric printf("aliaswait: not rebuildable\n"); 29959673Seric return; 30060207Seric } 30160207Seric if (stat(map->map_file, &stb) < 0) 30260207Seric { 30360207Seric if (tTd(27, 3)) 30460207Seric printf("aliaswait: no source file\n"); 30560207Seric return; 30660207Seric } 30759673Seric mtime = stb.st_mtime; 30860089Seric (void) strcpy(buf, map->map_file); 30960207Seric if (ext != NULL) 31060207Seric (void) strcat(buf, ext); 31159673Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0) 3124322Seric { 31359673Seric /* database is out of date */ 31440559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3154322Seric { 31660089Seric message("auto-rebuilding alias database %s", buf); 31760207Seric rebuildaliases(map, TRUE); 3184322Seric } 3194322Seric else 3204322Seric { 32119039Seric #ifdef LOG 32258020Seric if (LogLevel > 3) 32359673Seric syslog(LOG_INFO, "alias database %s out of date", 32460089Seric buf); 32556795Seric #endif /* LOG */ 32660089Seric message("Warning: alias database %s out of date", buf); 3274322Seric } 3284322Seric } 32959673Seric } 33059673Seric /* 33159673Seric ** REBUILDALIASES -- rebuild the alias database. 33259673Seric ** 33359673Seric ** Parameters: 33460089Seric ** map -- the database to rebuild. 33559673Seric ** automatic -- set if this was automatically generated. 33659673Seric ** 33759673Seric ** Returns: 33859673Seric ** none. 33959673Seric ** 34059673Seric ** Side Effects: 34159673Seric ** Reads the text version of the database, builds the 34259673Seric ** DBM or DB version. 34359673Seric */ 3444322Seric 34560207Seric rebuildaliases(map, automatic) 34660089Seric register MAP *map; 34759673Seric bool automatic; 34859673Seric { 34959673Seric FILE *af; 35059673Seric void (*oldsigint)(); 3514322Seric 35260207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35359673Seric return; 3544322Seric 35559673Seric #ifdef LOG 35659673Seric if (LogLevel > 7) 3578437Seric { 35859673Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 35960089Seric map->map_file, automatic ? "auto" : "", username()); 36059673Seric } 36156795Seric #endif /* LOG */ 36259673Seric 36359673Seric /* try to lock the source file */ 36460089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 36559673Seric { 36659756Seric if (tTd(27, 1)) 36759756Seric printf("Can't open %s: %s\n", 36860089Seric map->map_file, errstring(errno)); 36959673Seric errno = 0; 37059673Seric return; 3718437Seric } 37259673Seric 37359673Seric /* see if someone else is rebuilding the alias file */ 37460089Seric if (!lockfile(fileno(af), map->map_file, LOCK_EX|LOCK_NB)) 37559673Seric { 37659673Seric /* yes, they are -- wait until done */ 37759673Seric message("Alias file %s is already being rebuilt", 37860089Seric map->map_file); 37959673Seric if (OpMode != MD_INITALIAS) 38059673Seric { 38159673Seric /* wait for other rebuild to complete */ 38260089Seric (void) lockfile(fileno(af), map->map_file, 38359673Seric LOCK_EX); 38459673Seric } 38559673Seric (void) fclose(af); 38659673Seric errno = 0; 38759673Seric return; 38859673Seric } 38959673Seric 39059673Seric oldsigint = signal(SIGINT, SIG_IGN); 39159673Seric 39260207Seric if (map->map_class->map_open(map, O_RDWR)) 39360089Seric { 39460207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 39560207Seric readaliases(map, af, automatic); 39660089Seric } 39760207Seric else 39860207Seric { 39960207Seric if (tTd(27, 1)) 40060207Seric printf("Can't create database for %s: %s\n", 40160207Seric map->map_file, errstring(errno)); 40260207Seric if (!automatic) 40360207Seric syserr("Cannot create database for alias file %s", 40460207Seric map->map_file); 40560207Seric } 40659673Seric 40759673Seric /* close the file, thus releasing locks */ 40859673Seric fclose(af); 40959673Seric 41059673Seric /* add distinguished entries and close the database */ 41160207Seric if (bitset(MF_OPEN, map->map_mflags)) 41260089Seric map->map_class->map_close(map); 41359673Seric 41459673Seric /* restore the old signal */ 41559673Seric (void) signal(SIGINT, oldsigint); 4164157Seric } 4174157Seric /* 4184157Seric ** READALIASES -- read and process the alias file. 4194157Seric ** 4204157Seric ** This routine implements the part of initaliases that occurs 4214157Seric ** when we are not going to use the DBM stuff. 4224157Seric ** 4234157Seric ** Parameters: 42460089Seric ** map -- the alias database descriptor. 42559673Seric ** af -- file to read the aliases from. 42659733Seric ** automatic -- set if this was an automatic rebuild. 4274157Seric ** 4284157Seric ** Returns: 4294157Seric ** none. 4304157Seric ** 4314157Seric ** Side Effects: 4324157Seric ** Reads aliasfile into the symbol table. 4334157Seric ** Optionally, builds the .dir & .pag files. 4344157Seric */ 4354157Seric 43660207Seric readaliases(map, af, automatic) 43760089Seric register MAP *map; 43859673Seric FILE *af; 43959733Seric int automatic; 4404157Seric { 4414098Seric register char *p; 4424098Seric char *rhs; 4434098Seric bool skipping; 44459673Seric long naliases, bytes, longest; 4454098Seric ADDRESS al, bl; 4469368Seric char line[BUFSIZ]; 4474098Seric 4484314Seric /* 4494314Seric ** Read and interpret lines 4504314Seric */ 4514314Seric 45260089Seric FileName = map->map_file; 4539368Seric LineNumber = 0; 4544322Seric naliases = bytes = longest = 0; 4554098Seric skipping = FALSE; 4564098Seric while (fgets(line, sizeof (line), af) != NULL) 4574098Seric { 4584322Seric int lhssize, rhssize; 4594322Seric 4609368Seric LineNumber++; 46156795Seric p = strchr(line, '\n'); 46225278Seric if (p != NULL) 46325278Seric *p = '\0'; 4644098Seric switch (line[0]) 4654098Seric { 4664098Seric case '#': 4674098Seric case '\0': 4684098Seric skipping = FALSE; 4694098Seric continue; 4704065Seric 4714098Seric case ' ': 4724098Seric case '\t': 4734098Seric if (!skipping) 47458151Seric syserr("554 Non-continuation line starts with space"); 4754098Seric skipping = TRUE; 4764097Seric continue; 4774098Seric } 4784098Seric skipping = FALSE; 4791874Seric 4804314Seric /* 4814314Seric ** Process the LHS 48257736Seric ** Find the colon separator, and parse the address. 48316898Seric ** It should resolve to a local name -- this will 48416898Seric ** be checked later (we want to optionally do 48516898Seric ** parsing of the RHS first to maximize error 48616898Seric ** detection). 4874314Seric */ 4884314Seric 4894098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 4904097Seric continue; 49116898Seric if (*p++ != ':') 4924098Seric { 49358151Seric syserr("554 missing colon"); 4944097Seric continue; 4954098Seric } 49660207Seric if (parseaddr(line, &al, 1, ':', NULL, CurEnv) == NULL) 4974098Seric { 49858151Seric syserr("554 illegal alias name"); 49916898Seric continue; 5004098Seric } 5014314Seric 5024314Seric /* 5034314Seric ** Process the RHS. 5044314Seric ** 'al' is the internal form of the LHS address. 5054314Seric ** 'p' points to the text of the RHS. 5064314Seric */ 5074314Seric 50858914Seric while (isascii(*p) && isspace(*p)) 50958914Seric p++; 5104098Seric rhs = p; 5114098Seric for (;;) 5124098Seric { 5134098Seric register char c; 51458662Seric register char *nlp; 5151515Seric 51658662Seric nlp = &p[strlen(p)]; 51758662Seric if (nlp[-1] == '\n') 51858662Seric *--nlp = '\0'; 51958662Seric 52059673Seric if (CheckAliases) 5214098Seric { 5224157Seric /* do parsing & compression of addresses */ 52325278Seric while (*p != '\0') 5244098Seric { 52558333Seric auto char *delimptr; 52625278Seric 52758050Seric while ((isascii(*p) && isspace(*p)) || 52858050Seric *p == ',') 5294157Seric p++; 53025278Seric if (*p == '\0') 53125278Seric break; 53260207Seric if (parseaddr(p, &bl, -1, ',', &delimptr, CurEnv) == NULL) 53358151Seric usrerr("553 %s... bad address", p); 53458333Seric p = delimptr; 5354098Seric } 5364098Seric } 5374157Seric else 53815769Seric { 53958662Seric p = nlp; 54015769Seric } 5411515Seric 5424098Seric /* see if there should be a continuation line */ 5434106Seric c = fgetc(af); 5444106Seric if (!feof(af)) 5454314Seric (void) ungetc(c, af); 5464106Seric if (c != ' ' && c != '\t') 5474098Seric break; 5484098Seric 5494098Seric /* read continuation line */ 5504098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 5514098Seric break; 5529368Seric LineNumber++; 55357135Seric 55457135Seric /* check for line overflow */ 55557135Seric if (strchr(p, '\n') == NULL) 55657135Seric { 55758151Seric usrerr("554 alias too long"); 55857135Seric break; 55957135Seric } 5604098Seric } 56116898Seric if (al.q_mailer != LocalMailer) 56216898Seric { 56358151Seric syserr("554 cannot alias non-local names"); 56416898Seric continue; 56516898Seric } 5664314Seric 5674314Seric /* 5684314Seric ** Insert alias into symbol table or DBM file 5694314Seric */ 5704314Seric 57157381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 57257381Seric makelower(al.q_user); 5734322Seric 57459673Seric lhssize = strlen(al.q_user); 57559673Seric rhssize = strlen(rhs); 57660089Seric map->map_class->map_store(map, al.q_user, rhs); 5774157Seric 57859673Seric if (al.q_paddr != NULL) 57959673Seric free(al.q_paddr); 58059673Seric if (al.q_host != NULL) 58159673Seric free(al.q_host); 58259673Seric if (al.q_user != NULL) 58359673Seric free(al.q_user); 5844322Seric 5854322Seric /* statistics */ 5864322Seric naliases++; 5874322Seric bytes += lhssize + rhssize; 5884322Seric if (rhssize > longest) 5894322Seric longest = rhssize; 5901515Seric } 59119784Seric 59260207Seric CurEnv->e_to = NULL; 59359673Seric FileName = NULL; 59459733Seric if (Verbose || !automatic) 59559733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 59660089Seric map->map_file, naliases, longest, bytes); 59759673Seric # ifdef LOG 59859673Seric if (LogLevel > 7) 59959673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 60060089Seric map->map_file, naliases, longest, bytes); 60159673Seric # endif /* LOG */ 60259673Seric } 60359673Seric /* 604292Seric ** FORWARD -- Try to forward mail 605292Seric ** 606292Seric ** This is similar but not identical to aliasing. 607292Seric ** 608292Seric ** Parameters: 6094314Seric ** user -- the name of the user who's mail we would like 6104314Seric ** to forward to. It must have been verified -- 6114314Seric ** i.e., the q_home field must have been filled 6124314Seric ** in. 6134999Seric ** sendq -- a pointer to the head of the send queue to 6144999Seric ** put this user's aliases in. 615292Seric ** 616292Seric ** Returns: 6174098Seric ** none. 618292Seric ** 619292Seric ** Side Effects: 6203185Seric ** New names are added to send queues. 621292Seric */ 622292Seric 62355012Seric forward(user, sendq, e) 6242966Seric ADDRESS *user; 6254999Seric ADDRESS **sendq; 62655012Seric register ENVELOPE *e; 627292Seric { 62857136Seric char *pp; 62957136Seric char *ep; 630*63787Seric #ifdef HASSETEUID 63163753Seric register ADDRESS *ca; 63263753Seric uid_t saveduid, uid; 63363753Seric #endif 6344069Seric 6357671Seric if (tTd(27, 1)) 6364098Seric printf("forward(%s)\n", user->q_paddr); 6374098Seric 6384594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 6394098Seric return; 6404314Seric if (user->q_home == NULL) 64158059Seric { 64258151Seric syserr("554 forward: no home"); 64358059Seric user->q_home = "/nosuchdirectory"; 64458059Seric } 6454069Seric 6464069Seric /* good address -- look for .forward file in home */ 64755012Seric define('z', user->q_home, e); 64857136Seric define('u', user->q_user, e); 64957136Seric define('h', user->q_host, e); 65057136Seric if (ForwardPath == NULL) 65158050Seric ForwardPath = newstr("\201z/.forward"); 65257136Seric 653*63787Seric #ifdef HASSETEUID 65463753Seric ca = getctladdr(user); 65563753Seric if (ca != NULL) 65663753Seric uid = ca->q_uid; 65763753Seric else 65863753Seric uid = DefUid; 65963753Seric #endif 66063753Seric 66157136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 66257136Seric { 66358247Seric int err; 66457232Seric char buf[MAXPATHLEN+1]; 66557136Seric 66657136Seric ep = strchr(pp, ':'); 66757136Seric if (ep != NULL) 66857136Seric *ep = '\0'; 66957136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 67057136Seric if (ep != NULL) 67157136Seric *ep++ = ':'; 67257136Seric if (tTd(27, 3)) 67357136Seric printf("forward: trying %s\n", buf); 67463753Seric 675*63787Seric if (tTd(27, 9)) 676*63787Seric printf("forward: old uid = %d/%d\n", getuid(), geteuid()); 677*63787Seric 678*63787Seric #ifdef HASSETEUID 67963753Seric saveduid = geteuid(); 68063753Seric if (saveduid == 0 && uid != 0) 68163753Seric (void) seteuid(uid); 68263753Seric #endif 68363753Seric 684*63787Seric if (tTd(27, 9)) 685*63787Seric printf("forward: new uid = %d/%d\n", getuid(), geteuid()); 686*63787Seric 68758247Seric err = include(buf, TRUE, user, sendq, e); 68863753Seric 689*63787Seric #ifdef HASSETEUID 69063753Seric if (saveduid == 0 && uid != 0) 691*63787Seric if (seteuid(saveduid) < 0) 692*63787Seric syserr("seteuid(%d) failure (real=%d, eff=%d)", 693*63787Seric saveduid, getuid(), geteuid()); 69463753Seric #endif 69563753Seric 696*63787Seric if (tTd(27, 9)) 697*63787Seric printf("forward: reset uid = %d/%d\n", getuid(), geteuid()); 698*63787Seric 69958247Seric if (err == 0) 70057136Seric break; 70158247Seric if (transienterror(err)) 70258247Seric { 70358247Seric /* we have to suspend this message */ 70459563Seric if (tTd(27, 2)) 70559563Seric printf("forward: transient error on %s\n", buf); 70659563Seric #ifdef LOG 70759563Seric if (LogLevel > 2) 70859624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 70959624Seric e->e_id, buf, errstring(err)); 71059563Seric #endif 71159611Seric message("%s: %s: message queued", buf, errstring(err)); 71258247Seric user->q_flags |= QQUEUEUP|QDONTSEND; 71358247Seric return; 71458247Seric } 71557136Seric } 716292Seric } 717