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 <pwd.h> 1156766Seric 1233728Sbostic #ifndef lint 13*67982Seric static char sccsid[] = "@(#)alias.c 8.32 (Berkeley) 11/22/94"; 1433728Sbostic #endif /* not lint */ 1559673Seric 1659673Seric 1760537Seric MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ 1859673Seric int NAliasDBs; /* number of alias databases */ 1959673Seric /* 20292Seric ** ALIAS -- Compute aliases. 21292Seric ** 229368Seric ** Scans the alias file for an alias for the given address. 239368Seric ** If found, it arranges to deliver to the alias list instead. 249368Seric ** Uses libdbm database if -DDBM. 25292Seric ** 26292Seric ** Parameters: 274097Seric ** a -- address to alias. 284999Seric ** sendq -- a pointer to the head of the send queue 294999Seric ** to put the aliases in. 30*67982Seric ** aliaslevel -- the current alias nesting depth. 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 44*67982Seric alias(a, sendq, aliaslevel, e) 454097Seric register ADDRESS *a; 464999Seric ADDRESS **sendq; 47*67982Seric int aliaslevel; 4855012Seric register ENVELOPE *e; 49292Seric { 504081Seric register char *p; 5158082Seric int naliases; 5258170Seric char *owner; 5358170Seric char obuf[MAXNAME + 6]; 545701Seric extern char *aliaslookup(); 55292Seric 567671Seric if (tTd(27, 1)) 5767426Seric printf("alias(%s)\n", a->q_user); 58292Seric 594098Seric /* don't realias already aliased names */ 6058680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 614098Seric return; 624098Seric 6359673Seric if (NoAlias) 6459673Seric return; 6559673Seric 6655012Seric e->e_to = a->q_paddr; 674098Seric 684314Seric /* 694314Seric ** Look up this name 704314Seric */ 714314Seric 7259673Seric p = aliaslookup(a->q_user, e); 734098Seric if (p == NULL) 744098Seric return; 75292Seric 76292Seric /* 774098Seric ** Match on Alias. 784098Seric ** Deliver to the target list. 791515Seric */ 801515Seric 817671Seric if (tTd(27, 1)) 824098Seric printf("%s (%s, %s) aliased to %s\n", 834098Seric a->q_paddr, a->q_host, a->q_user, p); 8458092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8558154Seric { 8658154Seric a->q_flags |= QVERIFIED; 8758884Seric e->e_nrcpts++; 8858092Seric return; 8958154Seric } 9058154Seric message("aliased to %s", p); 9157977Seric #ifdef LOG 9258020Seric if (LogLevel > 9) 9366280Seric syslog(LOG_INFO, "%s: alias %s => %s", 9466280Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 9566280Seric a->q_paddr, p); 9657977Seric #endif 9758082Seric a->q_flags &= ~QSELFREF; 98*67982Seric if (tTd(27, 5)) 9958065Seric { 100*67982Seric printf("alias: QDONTSEND "); 101*67982Seric printaddr(a, FALSE); 10258065Seric } 103*67982Seric a->q_flags |= QDONTSEND; 104*67982Seric naliases = sendtolist(p, a, sendq, aliaslevel + 1, e); 105*67982Seric if (bitset(QSELFREF, a->q_flags)) 106*67982Seric a->q_flags &= ~QDONTSEND; 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); 12066784Seric if (owner == NULL) 12166784Seric return; 12266784Seric 12366784Seric /* reflect owner into envelope sender */ 12466784Seric if (strpbrk(owner, ",:/|\"") != NULL) 12566784Seric owner = obuf; 12666784Seric a->q_owner = newstr(owner); 12766784Seric 12866784Seric /* announce delivery to this alias; NORECEIPT bit set later */ 12966784Seric if (e->e_xfp != NULL) 13058170Seric { 13166784Seric fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 13266784Seric a->q_paddr); 13366784Seric e->e_flags |= EF_SENDRECEIPT; 13458170Seric } 1354098Seric } 1364098Seric /* 1375701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1385701Seric ** 1395701Seric ** Parameters: 1405701Seric ** name -- the name to look up. 1415701Seric ** 1425701Seric ** Returns: 1435701Seric ** the value of name. 1445701Seric ** NULL if unknown. 1455701Seric ** 1465701Seric ** Side Effects: 1475701Seric ** none. 1485701Seric ** 1495701Seric ** Warnings: 1505701Seric ** The return value will be trashed across calls. 1515701Seric */ 1525701Seric 1535701Seric char * 15459673Seric aliaslookup(name, e) 1555701Seric char *name; 15659673Seric ENVELOPE *e; 1575701Seric { 15859673Seric register int dbno; 15960089Seric register MAP *map; 16059673Seric register char *p; 1615701Seric 16259673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 16359673Seric { 16460089Seric auto int stat; 16560089Seric 16660537Seric map = AliasDB[dbno]; 16760207Seric if (!bitset(MF_OPEN, map->map_mflags)) 16859673Seric continue; 16960207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 17059673Seric if (p != NULL) 17159673Seric return p; 17259673Seric } 17359673Seric return NULL; 17459673Seric } 17559673Seric /* 17659673Seric ** SETALIAS -- set up an alias map 17759673Seric ** 17859673Seric ** Called when reading configuration file. 17959673Seric ** 18059673Seric ** Parameters: 18159673Seric ** spec -- the alias specification 18259673Seric ** 18359673Seric ** Returns: 18459673Seric ** none. 18559673Seric */ 18657381Seric 18759673Seric setalias(spec) 18859673Seric char *spec; 18959673Seric { 19059673Seric register char *p; 19160089Seric register MAP *map; 19259673Seric char *class; 19359673Seric STAB *s; 19459673Seric 19559697Seric if (tTd(27, 8)) 19659697Seric printf("setalias(%s)\n", spec); 19759697Seric 19859758Seric for (p = spec; p != NULL; ) 19951756Seric { 20059758Seric while (isspace(*p)) 20159758Seric p++; 20260502Seric if (*p == '\0') 20359673Seric break; 20459673Seric spec = p; 20559673Seric 20667848Seric /* 20767848Seric ** Treat simple filename specially -- this is the file name 20867848Seric ** for the files implementation, not necessarily in order. 20967848Seric */ 21067848Seric 21167848Seric if (spec[0] == '/') 21259758Seric { 21367848Seric s = stab("aliases.files", ST_MAP, ST_ENTER); 21467848Seric map = &s->s_map; 21559758Seric } 21667848Seric else 21767848Seric { 21867848Seric char aname[50]; 21967848Seric 22067848Seric if (NAliasDBs >= MAXALIASDB) 22167848Seric { 22267848Seric syserr("Too many alias databases defined, %d max", 22367848Seric MAXALIASDB); 22467848Seric return; 22567848Seric } 22667848Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 22767848Seric s = stab(aname, ST_MAP, ST_ENTER); 22867848Seric map = &s->s_map; 22967848Seric AliasDB[NAliasDBs] = map; 23067848Seric } 23160089Seric bzero(map, sizeof *map); 23267973Seric map->map_mname = s->s_name; 23359758Seric 23459758Seric p = strpbrk(p, " ,/:"); 23559758Seric if (p != NULL && *p == ':') 23659758Seric { 23760089Seric /* map name */ 23859758Seric *p++ = '\0'; 23959758Seric class = spec; 24059758Seric spec = p; 24159758Seric } 24259758Seric else 24359758Seric { 24459758Seric class = "implicit"; 24560228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 24659758Seric } 24759758Seric 24859758Seric /* find end of spec */ 24959758Seric if (p != NULL) 25059758Seric p = strchr(p, ','); 25159758Seric if (p != NULL) 25259758Seric *p++ = '\0'; 25359758Seric 25467848Seric if (tTd(27, 20)) 25567848Seric printf(" map %s:%s %s\n", class, s->s_name, spec); 25667848Seric 25759758Seric /* look up class */ 25860089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 25959758Seric if (s == NULL) 26059758Seric { 26159758Seric if (tTd(27, 1)) 26259758Seric printf("Unknown alias class %s\n", class); 26359758Seric } 26460207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 26560207Seric { 26660207Seric syserr("setalias: map class %s can't handle aliases", 26760207Seric class); 26860207Seric } 26959758Seric else 27059758Seric { 27160207Seric map->map_class = &s->s_mapclass; 27260089Seric if (map->map_class->map_parse(map, spec)) 27360089Seric { 27460207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 27567848Seric if (AliasDB[NAliasDBs] == map) 27667848Seric NAliasDBs++; 27760089Seric } 27859758Seric } 27959756Seric } 2805701Seric } 2815701Seric /* 28259673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 28359673Seric ** 28459673Seric ** This can decide to reopen or rebuild the alias file 28564718Seric ** 28664718Seric ** Parameters: 28764718Seric ** map -- a pointer to the map descriptor for this alias file. 28864718Seric ** ext -- the filename extension (e.g., ".db") for the 28964718Seric ** database file. 29064718Seric ** isopen -- if set, the database is already open, and we 29164718Seric ** should check for validity; otherwise, we are 29264718Seric ** just checking to see if it should be created. 29364718Seric ** 29464718Seric ** Returns: 29564718Seric ** TRUE -- if the database is open when we return. 29664718Seric ** FALSE -- if the database is closed when we return. 29759673Seric */ 29859673Seric 29964718Seric bool 30064718Seric aliaswait(map, ext, isopen) 30160089Seric MAP *map; 30260207Seric char *ext; 30364718Seric int isopen; 30459673Seric { 30564795Seric bool attimeout = FALSE; 30659673Seric time_t mtime; 30759673Seric struct stat stb; 30859673Seric char buf[MAXNAME]; 30959673Seric 31059697Seric if (tTd(27, 3)) 31160207Seric printf("aliaswait(%s:%s)\n", 31260207Seric map->map_class->map_cname, map->map_file); 31364648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 31464795Seric return isopen; 31564648Seric map->map_mflags |= MF_ALIASWAIT; 31659697Seric 31764795Seric if (SafeAlias > 0) 31817471Seric { 31960089Seric auto int st; 32064795Seric time_t toolong = curtime() + SafeAlias; 32164795Seric unsigned int sleeptime = 2; 32260089Seric 32364795Seric while (isopen && 32460089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 32525689Seric { 32664795Seric if (curtime() > toolong) 32764795Seric { 32864795Seric /* we timed out */ 32964795Seric attimeout = TRUE; 33064795Seric break; 33164795Seric } 33264795Seric 33325689Seric /* 33459673Seric ** Close and re-open the alias database in case 33559673Seric ** the one is mv'ed instead of cp'ed in. 33625689Seric */ 33725689Seric 33859697Seric if (tTd(27, 2)) 33964795Seric printf("aliaswait: sleeping for %d seconds\n", 34064795Seric sleeptime); 34159697Seric 34260089Seric map->map_class->map_close(map); 34364795Seric sleep(sleeptime); 34464795Seric sleeptime *= 2; 34564795Seric if (sleeptime > 60) 34664795Seric sleeptime = 60; 34764718Seric isopen = map->map_class->map_open(map, O_RDONLY); 34825689Seric } 34917471Seric } 3508437Seric 35159673Seric /* see if we need to go into auto-rebuild mode */ 35260207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35360207Seric { 35460207Seric if (tTd(27, 3)) 35560207Seric printf("aliaswait: not rebuildable\n"); 35664648Seric map->map_mflags &= ~MF_ALIASWAIT; 35764718Seric return isopen; 35860207Seric } 35960207Seric if (stat(map->map_file, &stb) < 0) 36060207Seric { 36160207Seric if (tTd(27, 3)) 36260207Seric printf("aliaswait: no source file\n"); 36364648Seric map->map_mflags &= ~MF_ALIASWAIT; 36464718Seric return isopen; 36560207Seric } 36659673Seric mtime = stb.st_mtime; 36760089Seric (void) strcpy(buf, map->map_file); 36860207Seric if (ext != NULL) 36960207Seric (void) strcat(buf, ext); 37064795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3714322Seric { 37259673Seric /* database is out of date */ 37340559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3744322Seric { 37560089Seric message("auto-rebuilding alias database %s", buf); 37664718Seric if (isopen) 37764718Seric map->map_class->map_close(map); 37860207Seric rebuildaliases(map, TRUE); 37964718Seric isopen = map->map_class->map_open(map, O_RDONLY); 3804322Seric } 3814322Seric else 3824322Seric { 38319039Seric #ifdef LOG 38458020Seric if (LogLevel > 3) 38559673Seric syslog(LOG_INFO, "alias database %s out of date", 38660089Seric buf); 38756795Seric #endif /* LOG */ 38860089Seric message("Warning: alias database %s out of date", buf); 3894322Seric } 3904322Seric } 39164648Seric map->map_mflags &= ~MF_ALIASWAIT; 39264718Seric return isopen; 39359673Seric } 39459673Seric /* 39559673Seric ** REBUILDALIASES -- rebuild the alias database. 39659673Seric ** 39759673Seric ** Parameters: 39860089Seric ** map -- the database to rebuild. 39959673Seric ** automatic -- set if this was automatically generated. 40059673Seric ** 40159673Seric ** Returns: 40259673Seric ** none. 40359673Seric ** 40459673Seric ** Side Effects: 40559673Seric ** Reads the text version of the database, builds the 40659673Seric ** DBM or DB version. 40759673Seric */ 4084322Seric 40960207Seric rebuildaliases(map, automatic) 41060089Seric register MAP *map; 41159673Seric bool automatic; 41259673Seric { 41359673Seric FILE *af; 41464388Seric bool nolock = FALSE; 41567430Seric sigfunc_t oldsigint, oldsigquit; 41667430Seric #ifdef SIGTSTP 41767430Seric sigfunc_t oldsigtstp; 41867430Seric #endif 4194322Seric 42060207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 42159673Seric return; 4224322Seric 42359673Seric /* try to lock the source file */ 42460089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 42559673Seric { 42665953Seric if ((errno != EACCES && errno != EROFS) || automatic || 42764388Seric (af = fopen(map->map_file, "r")) == NULL) 42864388Seric { 42964388Seric int saveerr = errno; 43064382Seric 43164388Seric if (tTd(27, 1)) 43264388Seric printf("Can't open %s: %s\n", 43364388Seric map->map_file, errstring(saveerr)); 43464388Seric if (!automatic) 43564388Seric message("newaliases: cannot open %s: %s", 43664388Seric map->map_file, errstring(saveerr)); 43764388Seric errno = 0; 43864388Seric return; 43964388Seric } 44064388Seric nolock = TRUE; 44164388Seric message("warning: cannot lock %s: %s", 44264388Seric map->map_file, errstring(errno)); 4438437Seric } 44459673Seric 44559673Seric /* see if someone else is rebuilding the alias file */ 44664388Seric if (!nolock && 44764388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 44859673Seric { 44959673Seric /* yes, they are -- wait until done */ 45059673Seric message("Alias file %s is already being rebuilt", 45160089Seric map->map_file); 45259673Seric if (OpMode != MD_INITALIAS) 45359673Seric { 45459673Seric /* wait for other rebuild to complete */ 45564335Seric (void) lockfile(fileno(af), map->map_file, NULL, 45659673Seric LOCK_EX); 45759673Seric } 45864772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 45959673Seric errno = 0; 46059673Seric return; 46159673Seric } 46259673Seric 46367430Seric /* avoid denial-of-service attacks */ 46467430Seric resetlimits(); 46564035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 46667430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 46767430Seric #ifdef SIGTSTP 46867430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 46967430Seric #endif 47059673Seric 47160207Seric if (map->map_class->map_open(map, O_RDWR)) 47260089Seric { 47364382Seric #ifdef LOG 47464382Seric if (LogLevel > 7) 47564382Seric { 47664382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 47764382Seric map->map_file, automatic ? "auto" : "", 47864382Seric username()); 47964382Seric } 48064382Seric #endif /* LOG */ 48160207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 48267263Seric readaliases(map, af, !automatic, TRUE); 48360089Seric } 48460207Seric else 48560207Seric { 48660207Seric if (tTd(27, 1)) 48760207Seric printf("Can't create database for %s: %s\n", 48860207Seric map->map_file, errstring(errno)); 48960207Seric if (!automatic) 49060207Seric syserr("Cannot create database for alias file %s", 49160207Seric map->map_file); 49260207Seric } 49359673Seric 49459673Seric /* close the file, thus releasing locks */ 49564772Seric xfclose(af, "rebuildaliases2", map->map_file); 49659673Seric 49759673Seric /* add distinguished entries and close the database */ 49860207Seric if (bitset(MF_OPEN, map->map_mflags)) 49960089Seric map->map_class->map_close(map); 50059673Seric 50167430Seric /* restore the old signals */ 50264035Seric (void) setsignal(SIGINT, oldsigint); 50367430Seric (void) setsignal(SIGQUIT, oldsigquit); 50467430Seric #ifdef SIGTSTP 50567430Seric (void) setsignal(SIGTSTP, oldsigtstp); 50667430Seric #endif 5074157Seric } 5084157Seric /* 5094157Seric ** READALIASES -- read and process the alias file. 5104157Seric ** 5114157Seric ** This routine implements the part of initaliases that occurs 5124157Seric ** when we are not going to use the DBM stuff. 5134157Seric ** 5144157Seric ** Parameters: 51560089Seric ** map -- the alias database descriptor. 51659673Seric ** af -- file to read the aliases from. 51767263Seric ** announcestats -- anounce statistics regarding number of 51867263Seric ** aliases, longest alias, etc. 51967263Seric ** logstats -- lot the same info. 5204157Seric ** 5214157Seric ** Returns: 5224157Seric ** none. 5234157Seric ** 5244157Seric ** Side Effects: 5254157Seric ** Reads aliasfile into the symbol table. 5264157Seric ** Optionally, builds the .dir & .pag files. 5274157Seric */ 5284157Seric 52967263Seric readaliases(map, af, announcestats, logstats) 53060089Seric register MAP *map; 53159673Seric FILE *af; 53267263Seric bool announcestats; 53367263Seric bool logstats; 5344157Seric { 5354098Seric register char *p; 5364098Seric char *rhs; 5374098Seric bool skipping; 53859673Seric long naliases, bytes, longest; 5394098Seric ADDRESS al, bl; 5409368Seric char line[BUFSIZ]; 5414098Seric 5424314Seric /* 5434314Seric ** Read and interpret lines 5444314Seric */ 5454314Seric 54660089Seric FileName = map->map_file; 5479368Seric LineNumber = 0; 5484322Seric naliases = bytes = longest = 0; 5494098Seric skipping = FALSE; 5504098Seric while (fgets(line, sizeof (line), af) != NULL) 5514098Seric { 5524322Seric int lhssize, rhssize; 5534322Seric 5549368Seric LineNumber++; 55556795Seric p = strchr(line, '\n'); 55625278Seric if (p != NULL) 55725278Seric *p = '\0'; 5584098Seric switch (line[0]) 5594098Seric { 5604098Seric case '#': 5614098Seric case '\0': 5624098Seric skipping = FALSE; 5634098Seric continue; 5644065Seric 5654098Seric case ' ': 5664098Seric case '\t': 5674098Seric if (!skipping) 56858151Seric syserr("554 Non-continuation line starts with space"); 5694098Seric skipping = TRUE; 5704097Seric continue; 5714098Seric } 5724098Seric skipping = FALSE; 5731874Seric 5744314Seric /* 5754314Seric ** Process the LHS 57657736Seric ** Find the colon separator, and parse the address. 57716898Seric ** It should resolve to a local name -- this will 57816898Seric ** be checked later (we want to optionally do 57916898Seric ** parsing of the RHS first to maximize error 58016898Seric ** detection). 5814314Seric */ 5824314Seric 5834098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5844097Seric continue; 58516898Seric if (*p++ != ':') 5864098Seric { 58758151Seric syserr("554 missing colon"); 5884097Seric continue; 5894098Seric } 59064284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 5914098Seric { 59264838Seric syserr("554 %.40s... illegal alias name", line); 59316898Seric continue; 5944098Seric } 5954314Seric 5964314Seric /* 5974314Seric ** Process the RHS. 5984314Seric ** 'al' is the internal form of the LHS address. 5994314Seric ** 'p' points to the text of the RHS. 6004314Seric */ 6014314Seric 60258914Seric while (isascii(*p) && isspace(*p)) 60358914Seric p++; 6044098Seric rhs = p; 6054098Seric for (;;) 6064098Seric { 6074098Seric register char c; 60858662Seric register char *nlp; 6091515Seric 61058662Seric nlp = &p[strlen(p)]; 61158662Seric if (nlp[-1] == '\n') 61258662Seric *--nlp = '\0'; 61358662Seric 61459673Seric if (CheckAliases) 6154098Seric { 6164157Seric /* do parsing & compression of addresses */ 61725278Seric while (*p != '\0') 6184098Seric { 61958333Seric auto char *delimptr; 62025278Seric 62158050Seric while ((isascii(*p) && isspace(*p)) || 62258050Seric *p == ',') 6234157Seric p++; 62425278Seric if (*p == '\0') 62525278Seric break; 62664284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 62764284Seric &delimptr, CurEnv) == NULL) 62858151Seric usrerr("553 %s... bad address", p); 62958333Seric p = delimptr; 6304098Seric } 6314098Seric } 6324157Seric else 63315769Seric { 63458662Seric p = nlp; 63515769Seric } 6361515Seric 6374098Seric /* see if there should be a continuation line */ 6384106Seric c = fgetc(af); 6394106Seric if (!feof(af)) 6404314Seric (void) ungetc(c, af); 6414106Seric if (c != ' ' && c != '\t') 6424098Seric break; 6434098Seric 6444098Seric /* read continuation line */ 6454098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6464098Seric break; 6479368Seric LineNumber++; 64857135Seric 64957135Seric /* check for line overflow */ 65057135Seric if (strchr(p, '\n') == NULL) 65157135Seric { 65258151Seric usrerr("554 alias too long"); 65357135Seric break; 65457135Seric } 6554098Seric } 65667473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 65716898Seric { 65864278Seric syserr("554 %s... cannot alias non-local names", 65964278Seric al.q_paddr); 66016898Seric continue; 66116898Seric } 6624314Seric 6634314Seric /* 6644314Seric ** Insert alias into symbol table or DBM file 6654314Seric */ 6664314Seric 66757381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 66857381Seric makelower(al.q_user); 6694322Seric 67059673Seric lhssize = strlen(al.q_user); 67159673Seric rhssize = strlen(rhs); 67260089Seric map->map_class->map_store(map, al.q_user, rhs); 6734157Seric 67459673Seric if (al.q_paddr != NULL) 67559673Seric free(al.q_paddr); 67659673Seric if (al.q_host != NULL) 67759673Seric free(al.q_host); 67859673Seric if (al.q_user != NULL) 67959673Seric free(al.q_user); 6804322Seric 6814322Seric /* statistics */ 6824322Seric naliases++; 6834322Seric bytes += lhssize + rhssize; 6844322Seric if (rhssize > longest) 6854322Seric longest = rhssize; 6861515Seric } 68719784Seric 68860207Seric CurEnv->e_to = NULL; 68959673Seric FileName = NULL; 69067263Seric if (Verbose || announcestats) 69159733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 69260089Seric map->map_file, naliases, longest, bytes); 69359673Seric # ifdef LOG 69467263Seric if (LogLevel > 7 && logstats) 69559673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 69660089Seric map->map_file, naliases, longest, bytes); 69759673Seric # endif /* LOG */ 69859673Seric } 69959673Seric /* 700292Seric ** FORWARD -- Try to forward mail 701292Seric ** 702292Seric ** This is similar but not identical to aliasing. 703292Seric ** 704292Seric ** Parameters: 7054314Seric ** user -- the name of the user who's mail we would like 7064314Seric ** to forward to. It must have been verified -- 7074314Seric ** i.e., the q_home field must have been filled 7084314Seric ** in. 7094999Seric ** sendq -- a pointer to the head of the send queue to 7104999Seric ** put this user's aliases in. 711*67982Seric ** aliaslevel -- the current alias nesting depth. 712*67982Seric ** e -- the current envelope. 713292Seric ** 714292Seric ** Returns: 7154098Seric ** none. 716292Seric ** 717292Seric ** Side Effects: 7183185Seric ** New names are added to send queues. 719292Seric */ 720292Seric 721*67982Seric forward(user, sendq, aliaslevel, e) 7222966Seric ADDRESS *user; 7234999Seric ADDRESS **sendq; 724*67982Seric int aliaslevel; 72555012Seric register ENVELOPE *e; 726292Seric { 72757136Seric char *pp; 72857136Seric char *ep; 7294069Seric 7307671Seric if (tTd(27, 1)) 7314098Seric printf("forward(%s)\n", user->q_paddr); 7324098Seric 73367473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 73467473Seric bitset(QBADADDR, user->q_flags)) 7354098Seric return; 7364314Seric if (user->q_home == NULL) 73758059Seric { 73858151Seric syserr("554 forward: no home"); 73958059Seric user->q_home = "/nosuchdirectory"; 74058059Seric } 7414069Seric 7424069Seric /* good address -- look for .forward file in home */ 74355012Seric define('z', user->q_home, e); 74457136Seric define('u', user->q_user, e); 74557136Seric define('h', user->q_host, e); 74657136Seric if (ForwardPath == NULL) 74758050Seric ForwardPath = newstr("\201z/.forward"); 74857136Seric 74957136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 75057136Seric { 75158247Seric int err; 75257232Seric char buf[MAXPATHLEN+1]; 75357136Seric 75457136Seric ep = strchr(pp, ':'); 75557136Seric if (ep != NULL) 75657136Seric *ep = '\0'; 75757136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 75857136Seric if (ep != NULL) 75957136Seric *ep++ = ':'; 76057136Seric if (tTd(27, 3)) 76157136Seric printf("forward: trying %s\n", buf); 76263753Seric 763*67982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 76458247Seric if (err == 0) 76557136Seric break; 76664325Seric else if (transienterror(err)) 76758247Seric { 76858247Seric /* we have to suspend this message */ 76959563Seric if (tTd(27, 2)) 77059563Seric printf("forward: transient error on %s\n", buf); 77159563Seric #ifdef LOG 77259563Seric if (LogLevel > 2) 77359624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 77466284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 77566284Seric buf, errstring(err)); 77659563Seric #endif 77759611Seric message("%s: %s: message queued", buf, errstring(err)); 77863853Seric user->q_flags |= QQUEUEUP; 77958247Seric return; 78058247Seric } 78157136Seric } 782292Seric } 783