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*68001Seric static char sccsid[] = "@(#)alias.c 8.33 (Berkeley) 11/28/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. 3067982Seric ** 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 4467982Seric alias(a, sendq, aliaslevel, e) 454097Seric register ADDRESS *a; 464999Seric ADDRESS **sendq; 4767982Seric 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; 9867982Seric if (tTd(27, 5)) 9958065Seric { 10067982Seric printf("alias: QDONTSEND "); 10167982Seric printaddr(a, FALSE); 10258065Seric } 10367982Seric a->q_flags |= QDONTSEND; 10467982Seric naliases = sendtolist(p, a, sendq, aliaslevel + 1, e); 10567982Seric if (bitset(QSELFREF, a->q_flags)) 10667982Seric 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) 13066784Seric fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 13166784Seric a->q_paddr); 132*68001Seric e->e_flags |= EF_SENDRECEIPT; 133*68001Seric a->q_flags |= QREPORT; 1344098Seric } 1354098Seric /* 1365701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1375701Seric ** 1385701Seric ** Parameters: 1395701Seric ** name -- the name to look up. 1405701Seric ** 1415701Seric ** Returns: 1425701Seric ** the value of name. 1435701Seric ** NULL if unknown. 1445701Seric ** 1455701Seric ** Side Effects: 1465701Seric ** none. 1475701Seric ** 1485701Seric ** Warnings: 1495701Seric ** The return value will be trashed across calls. 1505701Seric */ 1515701Seric 1525701Seric char * 15359673Seric aliaslookup(name, e) 1545701Seric char *name; 15559673Seric ENVELOPE *e; 1565701Seric { 15759673Seric register int dbno; 15860089Seric register MAP *map; 15959673Seric register char *p; 1605701Seric 16159673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 16259673Seric { 16360089Seric auto int stat; 16460089Seric 16560537Seric map = AliasDB[dbno]; 16660207Seric if (!bitset(MF_OPEN, map->map_mflags)) 16759673Seric continue; 16860207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 16959673Seric if (p != NULL) 17059673Seric return p; 17159673Seric } 17259673Seric return NULL; 17359673Seric } 17459673Seric /* 17559673Seric ** SETALIAS -- set up an alias map 17659673Seric ** 17759673Seric ** Called when reading configuration file. 17859673Seric ** 17959673Seric ** Parameters: 18059673Seric ** spec -- the alias specification 18159673Seric ** 18259673Seric ** Returns: 18359673Seric ** none. 18459673Seric */ 18557381Seric 18659673Seric setalias(spec) 18759673Seric char *spec; 18859673Seric { 18959673Seric register char *p; 19060089Seric register MAP *map; 19159673Seric char *class; 19259673Seric STAB *s; 19359673Seric 19459697Seric if (tTd(27, 8)) 19559697Seric printf("setalias(%s)\n", spec); 19659697Seric 19759758Seric for (p = spec; p != NULL; ) 19851756Seric { 19959758Seric while (isspace(*p)) 20059758Seric p++; 20160502Seric if (*p == '\0') 20259673Seric break; 20359673Seric spec = p; 20459673Seric 20567848Seric /* 20667848Seric ** Treat simple filename specially -- this is the file name 20767848Seric ** for the files implementation, not necessarily in order. 20867848Seric */ 20967848Seric 21067848Seric if (spec[0] == '/') 21159758Seric { 21267848Seric s = stab("aliases.files", ST_MAP, ST_ENTER); 21367848Seric map = &s->s_map; 21459758Seric } 21567848Seric else 21667848Seric { 21767848Seric char aname[50]; 21867848Seric 21967848Seric if (NAliasDBs >= MAXALIASDB) 22067848Seric { 22167848Seric syserr("Too many alias databases defined, %d max", 22267848Seric MAXALIASDB); 22367848Seric return; 22467848Seric } 22567848Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 22667848Seric s = stab(aname, ST_MAP, ST_ENTER); 22767848Seric map = &s->s_map; 22867848Seric AliasDB[NAliasDBs] = map; 22967848Seric } 23060089Seric bzero(map, sizeof *map); 23167973Seric map->map_mname = s->s_name; 23259758Seric 23359758Seric p = strpbrk(p, " ,/:"); 23459758Seric if (p != NULL && *p == ':') 23559758Seric { 23660089Seric /* map name */ 23759758Seric *p++ = '\0'; 23859758Seric class = spec; 23959758Seric spec = p; 24059758Seric } 24159758Seric else 24259758Seric { 24359758Seric class = "implicit"; 24460228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 24559758Seric } 24659758Seric 24759758Seric /* find end of spec */ 24859758Seric if (p != NULL) 24959758Seric p = strchr(p, ','); 25059758Seric if (p != NULL) 25159758Seric *p++ = '\0'; 25259758Seric 25367848Seric if (tTd(27, 20)) 25467848Seric printf(" map %s:%s %s\n", class, s->s_name, spec); 25567848Seric 25659758Seric /* look up class */ 25760089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 25859758Seric if (s == NULL) 25959758Seric { 26059758Seric if (tTd(27, 1)) 26159758Seric printf("Unknown alias class %s\n", class); 26259758Seric } 26360207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 26460207Seric { 26560207Seric syserr("setalias: map class %s can't handle aliases", 26660207Seric class); 26760207Seric } 26859758Seric else 26959758Seric { 27060207Seric map->map_class = &s->s_mapclass; 27160089Seric if (map->map_class->map_parse(map, spec)) 27260089Seric { 27360207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 27467848Seric if (AliasDB[NAliasDBs] == map) 27567848Seric NAliasDBs++; 27660089Seric } 27759758Seric } 27859756Seric } 2795701Seric } 2805701Seric /* 28159673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 28259673Seric ** 28359673Seric ** This can decide to reopen or rebuild the alias file 28464718Seric ** 28564718Seric ** Parameters: 28664718Seric ** map -- a pointer to the map descriptor for this alias file. 28764718Seric ** ext -- the filename extension (e.g., ".db") for the 28864718Seric ** database file. 28964718Seric ** isopen -- if set, the database is already open, and we 29064718Seric ** should check for validity; otherwise, we are 29164718Seric ** just checking to see if it should be created. 29264718Seric ** 29364718Seric ** Returns: 29464718Seric ** TRUE -- if the database is open when we return. 29564718Seric ** FALSE -- if the database is closed when we return. 29659673Seric */ 29759673Seric 29864718Seric bool 29964718Seric aliaswait(map, ext, isopen) 30060089Seric MAP *map; 30160207Seric char *ext; 30264718Seric int isopen; 30359673Seric { 30464795Seric bool attimeout = FALSE; 30559673Seric time_t mtime; 30659673Seric struct stat stb; 30759673Seric char buf[MAXNAME]; 30859673Seric 30959697Seric if (tTd(27, 3)) 31060207Seric printf("aliaswait(%s:%s)\n", 31160207Seric map->map_class->map_cname, map->map_file); 31264648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 31364795Seric return isopen; 31464648Seric map->map_mflags |= MF_ALIASWAIT; 31559697Seric 31664795Seric if (SafeAlias > 0) 31717471Seric { 31860089Seric auto int st; 31964795Seric time_t toolong = curtime() + SafeAlias; 32064795Seric unsigned int sleeptime = 2; 32160089Seric 32264795Seric while (isopen && 32360089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 32425689Seric { 32564795Seric if (curtime() > toolong) 32664795Seric { 32764795Seric /* we timed out */ 32864795Seric attimeout = TRUE; 32964795Seric break; 33064795Seric } 33164795Seric 33225689Seric /* 33359673Seric ** Close and re-open the alias database in case 33459673Seric ** the one is mv'ed instead of cp'ed in. 33525689Seric */ 33625689Seric 33759697Seric if (tTd(27, 2)) 33864795Seric printf("aliaswait: sleeping for %d seconds\n", 33964795Seric sleeptime); 34059697Seric 34160089Seric map->map_class->map_close(map); 34264795Seric sleep(sleeptime); 34364795Seric sleeptime *= 2; 34464795Seric if (sleeptime > 60) 34564795Seric sleeptime = 60; 34664718Seric isopen = map->map_class->map_open(map, O_RDONLY); 34725689Seric } 34817471Seric } 3498437Seric 35059673Seric /* see if we need to go into auto-rebuild mode */ 35160207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35260207Seric { 35360207Seric if (tTd(27, 3)) 35460207Seric printf("aliaswait: not rebuildable\n"); 35564648Seric map->map_mflags &= ~MF_ALIASWAIT; 35664718Seric return isopen; 35760207Seric } 35860207Seric if (stat(map->map_file, &stb) < 0) 35960207Seric { 36060207Seric if (tTd(27, 3)) 36160207Seric printf("aliaswait: no source file\n"); 36264648Seric map->map_mflags &= ~MF_ALIASWAIT; 36364718Seric return isopen; 36460207Seric } 36559673Seric mtime = stb.st_mtime; 36660089Seric (void) strcpy(buf, map->map_file); 36760207Seric if (ext != NULL) 36860207Seric (void) strcat(buf, ext); 36964795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3704322Seric { 37159673Seric /* database is out of date */ 37240559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3734322Seric { 37460089Seric message("auto-rebuilding alias database %s", buf); 37564718Seric if (isopen) 37664718Seric map->map_class->map_close(map); 37760207Seric rebuildaliases(map, TRUE); 37864718Seric isopen = map->map_class->map_open(map, O_RDONLY); 3794322Seric } 3804322Seric else 3814322Seric { 38219039Seric #ifdef LOG 38358020Seric if (LogLevel > 3) 38459673Seric syslog(LOG_INFO, "alias database %s out of date", 38560089Seric buf); 38656795Seric #endif /* LOG */ 38760089Seric message("Warning: alias database %s out of date", buf); 3884322Seric } 3894322Seric } 39064648Seric map->map_mflags &= ~MF_ALIASWAIT; 39164718Seric return isopen; 39259673Seric } 39359673Seric /* 39459673Seric ** REBUILDALIASES -- rebuild the alias database. 39559673Seric ** 39659673Seric ** Parameters: 39760089Seric ** map -- the database to rebuild. 39859673Seric ** automatic -- set if this was automatically generated. 39959673Seric ** 40059673Seric ** Returns: 40159673Seric ** none. 40259673Seric ** 40359673Seric ** Side Effects: 40459673Seric ** Reads the text version of the database, builds the 40559673Seric ** DBM or DB version. 40659673Seric */ 4074322Seric 40860207Seric rebuildaliases(map, automatic) 40960089Seric register MAP *map; 41059673Seric bool automatic; 41159673Seric { 41259673Seric FILE *af; 41364388Seric bool nolock = FALSE; 41467430Seric sigfunc_t oldsigint, oldsigquit; 41567430Seric #ifdef SIGTSTP 41667430Seric sigfunc_t oldsigtstp; 41767430Seric #endif 4184322Seric 41960207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 42059673Seric return; 4214322Seric 42259673Seric /* try to lock the source file */ 42360089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 42459673Seric { 42565953Seric if ((errno != EACCES && errno != EROFS) || automatic || 42664388Seric (af = fopen(map->map_file, "r")) == NULL) 42764388Seric { 42864388Seric int saveerr = errno; 42964382Seric 43064388Seric if (tTd(27, 1)) 43164388Seric printf("Can't open %s: %s\n", 43264388Seric map->map_file, errstring(saveerr)); 43364388Seric if (!automatic) 43464388Seric message("newaliases: cannot open %s: %s", 43564388Seric map->map_file, errstring(saveerr)); 43664388Seric errno = 0; 43764388Seric return; 43864388Seric } 43964388Seric nolock = TRUE; 44064388Seric message("warning: cannot lock %s: %s", 44164388Seric map->map_file, errstring(errno)); 4428437Seric } 44359673Seric 44459673Seric /* see if someone else is rebuilding the alias file */ 44564388Seric if (!nolock && 44664388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 44759673Seric { 44859673Seric /* yes, they are -- wait until done */ 44959673Seric message("Alias file %s is already being rebuilt", 45060089Seric map->map_file); 45159673Seric if (OpMode != MD_INITALIAS) 45259673Seric { 45359673Seric /* wait for other rebuild to complete */ 45464335Seric (void) lockfile(fileno(af), map->map_file, NULL, 45559673Seric LOCK_EX); 45659673Seric } 45764772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 45859673Seric errno = 0; 45959673Seric return; 46059673Seric } 46159673Seric 46267430Seric /* avoid denial-of-service attacks */ 46367430Seric resetlimits(); 46464035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 46567430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 46667430Seric #ifdef SIGTSTP 46767430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 46867430Seric #endif 46959673Seric 47060207Seric if (map->map_class->map_open(map, O_RDWR)) 47160089Seric { 47264382Seric #ifdef LOG 47364382Seric if (LogLevel > 7) 47464382Seric { 47564382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 47664382Seric map->map_file, automatic ? "auto" : "", 47764382Seric username()); 47864382Seric } 47964382Seric #endif /* LOG */ 48060207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 48167263Seric readaliases(map, af, !automatic, TRUE); 48260089Seric } 48360207Seric else 48460207Seric { 48560207Seric if (tTd(27, 1)) 48660207Seric printf("Can't create database for %s: %s\n", 48760207Seric map->map_file, errstring(errno)); 48860207Seric if (!automatic) 48960207Seric syserr("Cannot create database for alias file %s", 49060207Seric map->map_file); 49160207Seric } 49259673Seric 49359673Seric /* close the file, thus releasing locks */ 49464772Seric xfclose(af, "rebuildaliases2", map->map_file); 49559673Seric 49659673Seric /* add distinguished entries and close the database */ 49760207Seric if (bitset(MF_OPEN, map->map_mflags)) 49860089Seric map->map_class->map_close(map); 49959673Seric 50067430Seric /* restore the old signals */ 50164035Seric (void) setsignal(SIGINT, oldsigint); 50267430Seric (void) setsignal(SIGQUIT, oldsigquit); 50367430Seric #ifdef SIGTSTP 50467430Seric (void) setsignal(SIGTSTP, oldsigtstp); 50567430Seric #endif 5064157Seric } 5074157Seric /* 5084157Seric ** READALIASES -- read and process the alias file. 5094157Seric ** 5104157Seric ** This routine implements the part of initaliases that occurs 5114157Seric ** when we are not going to use the DBM stuff. 5124157Seric ** 5134157Seric ** Parameters: 51460089Seric ** map -- the alias database descriptor. 51559673Seric ** af -- file to read the aliases from. 51667263Seric ** announcestats -- anounce statistics regarding number of 51767263Seric ** aliases, longest alias, etc. 51867263Seric ** logstats -- lot the same info. 5194157Seric ** 5204157Seric ** Returns: 5214157Seric ** none. 5224157Seric ** 5234157Seric ** Side Effects: 5244157Seric ** Reads aliasfile into the symbol table. 5254157Seric ** Optionally, builds the .dir & .pag files. 5264157Seric */ 5274157Seric 52867263Seric readaliases(map, af, announcestats, logstats) 52960089Seric register MAP *map; 53059673Seric FILE *af; 53167263Seric bool announcestats; 53267263Seric bool logstats; 5334157Seric { 5344098Seric register char *p; 5354098Seric char *rhs; 5364098Seric bool skipping; 53759673Seric long naliases, bytes, longest; 5384098Seric ADDRESS al, bl; 5399368Seric char line[BUFSIZ]; 5404098Seric 5414314Seric /* 5424314Seric ** Read and interpret lines 5434314Seric */ 5444314Seric 54560089Seric FileName = map->map_file; 5469368Seric LineNumber = 0; 5474322Seric naliases = bytes = longest = 0; 5484098Seric skipping = FALSE; 5494098Seric while (fgets(line, sizeof (line), af) != NULL) 5504098Seric { 5514322Seric int lhssize, rhssize; 5524322Seric 5539368Seric LineNumber++; 55456795Seric p = strchr(line, '\n'); 55525278Seric if (p != NULL) 55625278Seric *p = '\0'; 5574098Seric switch (line[0]) 5584098Seric { 5594098Seric case '#': 5604098Seric case '\0': 5614098Seric skipping = FALSE; 5624098Seric continue; 5634065Seric 5644098Seric case ' ': 5654098Seric case '\t': 5664098Seric if (!skipping) 56758151Seric syserr("554 Non-continuation line starts with space"); 5684098Seric skipping = TRUE; 5694097Seric continue; 5704098Seric } 5714098Seric skipping = FALSE; 5721874Seric 5734314Seric /* 5744314Seric ** Process the LHS 57557736Seric ** Find the colon separator, and parse the address. 57616898Seric ** It should resolve to a local name -- this will 57716898Seric ** be checked later (we want to optionally do 57816898Seric ** parsing of the RHS first to maximize error 57916898Seric ** detection). 5804314Seric */ 5814314Seric 5824098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5834097Seric continue; 58416898Seric if (*p++ != ':') 5854098Seric { 58658151Seric syserr("554 missing colon"); 5874097Seric continue; 5884098Seric } 58964284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 5904098Seric { 59164838Seric syserr("554 %.40s... illegal alias name", line); 59216898Seric continue; 5934098Seric } 5944314Seric 5954314Seric /* 5964314Seric ** Process the RHS. 5974314Seric ** 'al' is the internal form of the LHS address. 5984314Seric ** 'p' points to the text of the RHS. 5994314Seric */ 6004314Seric 60158914Seric while (isascii(*p) && isspace(*p)) 60258914Seric p++; 6034098Seric rhs = p; 6044098Seric for (;;) 6054098Seric { 6064098Seric register char c; 60758662Seric register char *nlp; 6081515Seric 60958662Seric nlp = &p[strlen(p)]; 61058662Seric if (nlp[-1] == '\n') 61158662Seric *--nlp = '\0'; 61258662Seric 61359673Seric if (CheckAliases) 6144098Seric { 6154157Seric /* do parsing & compression of addresses */ 61625278Seric while (*p != '\0') 6174098Seric { 61858333Seric auto char *delimptr; 61925278Seric 62058050Seric while ((isascii(*p) && isspace(*p)) || 62158050Seric *p == ',') 6224157Seric p++; 62325278Seric if (*p == '\0') 62425278Seric break; 62564284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 62664284Seric &delimptr, CurEnv) == NULL) 62758151Seric usrerr("553 %s... bad address", p); 62858333Seric p = delimptr; 6294098Seric } 6304098Seric } 6314157Seric else 63215769Seric { 63358662Seric p = nlp; 63415769Seric } 6351515Seric 6364098Seric /* see if there should be a continuation line */ 6374106Seric c = fgetc(af); 6384106Seric if (!feof(af)) 6394314Seric (void) ungetc(c, af); 6404106Seric if (c != ' ' && c != '\t') 6414098Seric break; 6424098Seric 6434098Seric /* read continuation line */ 6444098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6454098Seric break; 6469368Seric LineNumber++; 64757135Seric 64857135Seric /* check for line overflow */ 64957135Seric if (strchr(p, '\n') == NULL) 65057135Seric { 65158151Seric usrerr("554 alias too long"); 65257135Seric break; 65357135Seric } 6544098Seric } 65567473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 65616898Seric { 65764278Seric syserr("554 %s... cannot alias non-local names", 65864278Seric al.q_paddr); 65916898Seric continue; 66016898Seric } 6614314Seric 6624314Seric /* 6634314Seric ** Insert alias into symbol table or DBM file 6644314Seric */ 6654314Seric 66657381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 66757381Seric makelower(al.q_user); 6684322Seric 66959673Seric lhssize = strlen(al.q_user); 67059673Seric rhssize = strlen(rhs); 67160089Seric map->map_class->map_store(map, al.q_user, rhs); 6724157Seric 67359673Seric if (al.q_paddr != NULL) 67459673Seric free(al.q_paddr); 67559673Seric if (al.q_host != NULL) 67659673Seric free(al.q_host); 67759673Seric if (al.q_user != NULL) 67859673Seric free(al.q_user); 6794322Seric 6804322Seric /* statistics */ 6814322Seric naliases++; 6824322Seric bytes += lhssize + rhssize; 6834322Seric if (rhssize > longest) 6844322Seric longest = rhssize; 6851515Seric } 68619784Seric 68760207Seric CurEnv->e_to = NULL; 68859673Seric FileName = NULL; 68967263Seric if (Verbose || announcestats) 69059733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 69160089Seric map->map_file, naliases, longest, bytes); 69259673Seric # ifdef LOG 69367263Seric if (LogLevel > 7 && logstats) 69459673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 69560089Seric map->map_file, naliases, longest, bytes); 69659673Seric # endif /* LOG */ 69759673Seric } 69859673Seric /* 699292Seric ** FORWARD -- Try to forward mail 700292Seric ** 701292Seric ** This is similar but not identical to aliasing. 702292Seric ** 703292Seric ** Parameters: 7044314Seric ** user -- the name of the user who's mail we would like 7054314Seric ** to forward to. It must have been verified -- 7064314Seric ** i.e., the q_home field must have been filled 7074314Seric ** in. 7084999Seric ** sendq -- a pointer to the head of the send queue to 7094999Seric ** put this user's aliases in. 71067982Seric ** aliaslevel -- the current alias nesting depth. 71167982Seric ** e -- the current envelope. 712292Seric ** 713292Seric ** Returns: 7144098Seric ** none. 715292Seric ** 716292Seric ** Side Effects: 7173185Seric ** New names are added to send queues. 718292Seric */ 719292Seric 72067982Seric forward(user, sendq, aliaslevel, e) 7212966Seric ADDRESS *user; 7224999Seric ADDRESS **sendq; 72367982Seric int aliaslevel; 72455012Seric register ENVELOPE *e; 725292Seric { 72657136Seric char *pp; 72757136Seric char *ep; 7284069Seric 7297671Seric if (tTd(27, 1)) 7304098Seric printf("forward(%s)\n", user->q_paddr); 7314098Seric 73267473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 73367473Seric bitset(QBADADDR, user->q_flags)) 7344098Seric return; 7354314Seric if (user->q_home == NULL) 73658059Seric { 73758151Seric syserr("554 forward: no home"); 73858059Seric user->q_home = "/nosuchdirectory"; 73958059Seric } 7404069Seric 7414069Seric /* good address -- look for .forward file in home */ 74255012Seric define('z', user->q_home, e); 74357136Seric define('u', user->q_user, e); 74457136Seric define('h', user->q_host, e); 74557136Seric if (ForwardPath == NULL) 74658050Seric ForwardPath = newstr("\201z/.forward"); 74757136Seric 74857136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 74957136Seric { 75058247Seric int err; 75157232Seric char buf[MAXPATHLEN+1]; 75257136Seric 75357136Seric ep = strchr(pp, ':'); 75457136Seric if (ep != NULL) 75557136Seric *ep = '\0'; 75657136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 75757136Seric if (ep != NULL) 75857136Seric *ep++ = ':'; 75957136Seric if (tTd(27, 3)) 76057136Seric printf("forward: trying %s\n", buf); 76163753Seric 76267982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 76358247Seric if (err == 0) 76457136Seric break; 76564325Seric else if (transienterror(err)) 76658247Seric { 76758247Seric /* we have to suspend this message */ 76859563Seric if (tTd(27, 2)) 76959563Seric printf("forward: transient error on %s\n", buf); 77059563Seric #ifdef LOG 77159563Seric if (LogLevel > 2) 77259624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 77366284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 77466284Seric buf, errstring(err)); 77559563Seric #endif 77659611Seric message("%s: %s: message queued", buf, errstring(err)); 77763853Seric user->q_flags |= QQUEUEUP; 77858247Seric return; 77958247Seric } 78057136Seric } 781292Seric } 782