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*68433Seric static char sccsid[] = "@(#)alias.c 8.36 (Berkeley) 02/23/95"; 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 44*68433Seric void 4567982Seric alias(a, sendq, aliaslevel, e) 464097Seric register ADDRESS *a; 474999Seric ADDRESS **sendq; 4867982Seric int aliaslevel; 4955012Seric register ENVELOPE *e; 50292Seric { 514081Seric register char *p; 5258082Seric int naliases; 5358170Seric char *owner; 5458170Seric char obuf[MAXNAME + 6]; 555701Seric extern char *aliaslookup(); 56292Seric 577671Seric if (tTd(27, 1)) 5867426Seric printf("alias(%s)\n", a->q_user); 59292Seric 604098Seric /* don't realias already aliased names */ 6158680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 624098Seric return; 634098Seric 6459673Seric if (NoAlias) 6559673Seric return; 6659673Seric 6755012Seric e->e_to = a->q_paddr; 684098Seric 694314Seric /* 704314Seric ** Look up this name 714314Seric */ 724314Seric 7359673Seric p = aliaslookup(a->q_user, e); 744098Seric if (p == NULL) 754098Seric return; 76292Seric 77292Seric /* 784098Seric ** Match on Alias. 794098Seric ** Deliver to the target list. 801515Seric */ 811515Seric 827671Seric if (tTd(27, 1)) 834098Seric printf("%s (%s, %s) aliased to %s\n", 844098Seric a->q_paddr, a->q_host, a->q_user, p); 8558092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8658154Seric { 8758154Seric a->q_flags |= QVERIFIED; 8858884Seric e->e_nrcpts++; 8958092Seric return; 9058154Seric } 9158154Seric message("aliased to %s", p); 9257977Seric #ifdef LOG 9358020Seric if (LogLevel > 9) 9466280Seric syslog(LOG_INFO, "%s: alias %s => %s", 9566280Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 9666280Seric a->q_paddr, p); 9757977Seric #endif 9858082Seric a->q_flags &= ~QSELFREF; 9967982Seric if (tTd(27, 5)) 10058065Seric { 10167982Seric printf("alias: QDONTSEND "); 10267982Seric printaddr(a, FALSE); 10358065Seric } 10467982Seric a->q_flags |= QDONTSEND; 10567982Seric naliases = sendtolist(p, a, sendq, aliaslevel + 1, e); 10667982Seric if (bitset(QSELFREF, a->q_flags)) 10767982Seric a->q_flags &= ~QDONTSEND; 10858170Seric 10958170Seric /* 11058170Seric ** Look for owner of alias 11158170Seric */ 11258170Seric 11358170Seric (void) strcpy(obuf, "owner-"); 11458170Seric if (strncmp(a->q_user, "owner-", 6) == 0) 11558170Seric (void) strcat(obuf, "owner"); 11658170Seric else 11758170Seric (void) strcat(obuf, a->q_user); 11858170Seric if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 11958170Seric makelower(obuf); 12059673Seric owner = aliaslookup(obuf, e); 12166784Seric if (owner == NULL) 12266784Seric return; 12366784Seric 12466784Seric /* reflect owner into envelope sender */ 12566784Seric if (strpbrk(owner, ",:/|\"") != NULL) 12666784Seric owner = obuf; 12766784Seric a->q_owner = newstr(owner); 12866784Seric 12966784Seric /* announce delivery to this alias; NORECEIPT bit set later */ 13066784Seric if (e->e_xfp != NULL) 13166784Seric fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 13266784Seric a->q_paddr); 13368001Seric e->e_flags |= EF_SENDRECEIPT; 13468001Seric a->q_flags |= QREPORT; 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 187*68433Seric void 18859673Seric setalias(spec) 18959673Seric char *spec; 19059673Seric { 19159673Seric register char *p; 19260089Seric register MAP *map; 19359673Seric char *class; 19459673Seric STAB *s; 19568096Seric static bool first_unqual = TRUE; 19659673Seric 19759697Seric if (tTd(27, 8)) 19859697Seric printf("setalias(%s)\n", spec); 19959697Seric 20059758Seric for (p = spec; p != NULL; ) 20151756Seric { 20259758Seric while (isspace(*p)) 20359758Seric p++; 20460502Seric if (*p == '\0') 20559673Seric break; 20659673Seric spec = p; 20759673Seric 20867848Seric /* 20967848Seric ** Treat simple filename specially -- this is the file name 21067848Seric ** for the files implementation, not necessarily in order. 21167848Seric */ 21267848Seric 21368096Seric if (spec[0] == '/' && first_unqual) 21459758Seric { 21567848Seric s = stab("aliases.files", ST_MAP, ST_ENTER); 21667848Seric map = &s->s_map; 21768096Seric first_unqual = FALSE; 21859758Seric } 21967848Seric else 22067848Seric { 22167848Seric char aname[50]; 22267848Seric 22367848Seric if (NAliasDBs >= MAXALIASDB) 22467848Seric { 22567848Seric syserr("Too many alias databases defined, %d max", 22667848Seric MAXALIASDB); 22767848Seric return; 22867848Seric } 22967848Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 23067848Seric s = stab(aname, ST_MAP, ST_ENTER); 23167848Seric map = &s->s_map; 23267848Seric AliasDB[NAliasDBs] = map; 23367848Seric } 23460089Seric bzero(map, sizeof *map); 23567973Seric map->map_mname = s->s_name; 23659758Seric 23759758Seric p = strpbrk(p, " ,/:"); 23859758Seric if (p != NULL && *p == ':') 23959758Seric { 24060089Seric /* map name */ 24159758Seric *p++ = '\0'; 24259758Seric class = spec; 24359758Seric spec = p; 24459758Seric } 24559758Seric else 24659758Seric { 24759758Seric class = "implicit"; 24860228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 24959758Seric } 25059758Seric 25159758Seric /* find end of spec */ 25259758Seric if (p != NULL) 25359758Seric p = strchr(p, ','); 25459758Seric if (p != NULL) 25559758Seric *p++ = '\0'; 25659758Seric 25767848Seric if (tTd(27, 20)) 25867848Seric printf(" map %s:%s %s\n", class, s->s_name, spec); 25967848Seric 26059758Seric /* look up class */ 26160089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 26259758Seric if (s == NULL) 26359758Seric { 26459758Seric if (tTd(27, 1)) 26559758Seric printf("Unknown alias class %s\n", class); 26659758Seric } 26760207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 26860207Seric { 26960207Seric syserr("setalias: map class %s can't handle aliases", 27060207Seric class); 27160207Seric } 27259758Seric else 27359758Seric { 27460207Seric map->map_class = &s->s_mapclass; 27560089Seric if (map->map_class->map_parse(map, spec)) 27660089Seric { 27760207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 27867848Seric if (AliasDB[NAliasDBs] == map) 27967848Seric NAliasDBs++; 28060089Seric } 28159758Seric } 28259756Seric } 2835701Seric } 2845701Seric /* 28559673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 28659673Seric ** 28759673Seric ** This can decide to reopen or rebuild the alias file 28864718Seric ** 28964718Seric ** Parameters: 29064718Seric ** map -- a pointer to the map descriptor for this alias file. 29164718Seric ** ext -- the filename extension (e.g., ".db") for the 29264718Seric ** database file. 29364718Seric ** isopen -- if set, the database is already open, and we 29464718Seric ** should check for validity; otherwise, we are 29564718Seric ** just checking to see if it should be created. 29664718Seric ** 29764718Seric ** Returns: 29864718Seric ** TRUE -- if the database is open when we return. 29964718Seric ** FALSE -- if the database is closed when we return. 30059673Seric */ 30159673Seric 30264718Seric bool 30364718Seric aliaswait(map, ext, isopen) 30460089Seric MAP *map; 30560207Seric char *ext; 30664718Seric int isopen; 30759673Seric { 30864795Seric bool attimeout = FALSE; 30959673Seric time_t mtime; 31059673Seric struct stat stb; 31159673Seric char buf[MAXNAME]; 31259673Seric 31359697Seric if (tTd(27, 3)) 31460207Seric printf("aliaswait(%s:%s)\n", 31560207Seric map->map_class->map_cname, map->map_file); 31664648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 31764795Seric return isopen; 31864648Seric map->map_mflags |= MF_ALIASWAIT; 31959697Seric 32064795Seric if (SafeAlias > 0) 32117471Seric { 32260089Seric auto int st; 32364795Seric time_t toolong = curtime() + SafeAlias; 32464795Seric unsigned int sleeptime = 2; 32560089Seric 32664795Seric while (isopen && 32760089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 32825689Seric { 32964795Seric if (curtime() > toolong) 33064795Seric { 33164795Seric /* we timed out */ 33264795Seric attimeout = TRUE; 33364795Seric break; 33464795Seric } 33564795Seric 33625689Seric /* 33759673Seric ** Close and re-open the alias database in case 33859673Seric ** the one is mv'ed instead of cp'ed in. 33925689Seric */ 34025689Seric 34159697Seric if (tTd(27, 2)) 34264795Seric printf("aliaswait: sleeping for %d seconds\n", 34364795Seric sleeptime); 34459697Seric 34560089Seric map->map_class->map_close(map); 34664795Seric sleep(sleeptime); 34764795Seric sleeptime *= 2; 34864795Seric if (sleeptime > 60) 34964795Seric sleeptime = 60; 35064718Seric isopen = map->map_class->map_open(map, O_RDONLY); 35125689Seric } 35217471Seric } 3538437Seric 35459673Seric /* see if we need to go into auto-rebuild mode */ 35560207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35660207Seric { 35760207Seric if (tTd(27, 3)) 35860207Seric printf("aliaswait: not rebuildable\n"); 35964648Seric map->map_mflags &= ~MF_ALIASWAIT; 36064718Seric return isopen; 36160207Seric } 36260207Seric if (stat(map->map_file, &stb) < 0) 36360207Seric { 36460207Seric if (tTd(27, 3)) 36560207Seric printf("aliaswait: no source file\n"); 36664648Seric map->map_mflags &= ~MF_ALIASWAIT; 36764718Seric return isopen; 36860207Seric } 36959673Seric mtime = stb.st_mtime; 37060089Seric (void) strcpy(buf, map->map_file); 37160207Seric if (ext != NULL) 37260207Seric (void) strcat(buf, ext); 37364795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3744322Seric { 37559673Seric /* database is out of date */ 37640559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3774322Seric { 37868101Seric bool oldSuprErrs; 37968101Seric 38060089Seric message("auto-rebuilding alias database %s", buf); 38168101Seric oldSuprErrs = SuprErrs; 38268101Seric SuprErrs = TRUE; 38364718Seric if (isopen) 38464718Seric map->map_class->map_close(map); 38560207Seric rebuildaliases(map, TRUE); 38664718Seric isopen = map->map_class->map_open(map, O_RDONLY); 38768101Seric SuprErrs = oldSuprErrs; 3884322Seric } 3894322Seric else 3904322Seric { 39119039Seric #ifdef LOG 39258020Seric if (LogLevel > 3) 39359673Seric syslog(LOG_INFO, "alias database %s out of date", 39460089Seric buf); 39556795Seric #endif /* LOG */ 39660089Seric message("Warning: alias database %s out of date", buf); 3974322Seric } 3984322Seric } 39964648Seric map->map_mflags &= ~MF_ALIASWAIT; 40064718Seric return isopen; 40159673Seric } 40259673Seric /* 40359673Seric ** REBUILDALIASES -- rebuild the alias database. 40459673Seric ** 40559673Seric ** Parameters: 40660089Seric ** map -- the database to rebuild. 40759673Seric ** automatic -- set if this was automatically generated. 40859673Seric ** 40959673Seric ** Returns: 41059673Seric ** none. 41159673Seric ** 41259673Seric ** Side Effects: 41359673Seric ** Reads the text version of the database, builds the 41459673Seric ** DBM or DB version. 41559673Seric */ 4164322Seric 417*68433Seric void 41860207Seric rebuildaliases(map, automatic) 41960089Seric register MAP *map; 42059673Seric bool automatic; 42159673Seric { 42259673Seric FILE *af; 42364388Seric bool nolock = FALSE; 42467430Seric sigfunc_t oldsigint, oldsigquit; 42567430Seric #ifdef SIGTSTP 42667430Seric sigfunc_t oldsigtstp; 42767430Seric #endif 4284322Seric 42960207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 43059673Seric return; 4314322Seric 43259673Seric /* try to lock the source file */ 43360089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 43459673Seric { 43565953Seric if ((errno != EACCES && errno != EROFS) || automatic || 43664388Seric (af = fopen(map->map_file, "r")) == NULL) 43764388Seric { 43864388Seric int saveerr = errno; 43964382Seric 44064388Seric if (tTd(27, 1)) 44164388Seric printf("Can't open %s: %s\n", 44264388Seric map->map_file, errstring(saveerr)); 44364388Seric if (!automatic) 44464388Seric message("newaliases: cannot open %s: %s", 44564388Seric map->map_file, errstring(saveerr)); 44664388Seric errno = 0; 44764388Seric return; 44864388Seric } 44964388Seric nolock = TRUE; 45064388Seric message("warning: cannot lock %s: %s", 45164388Seric map->map_file, errstring(errno)); 4528437Seric } 45359673Seric 45459673Seric /* see if someone else is rebuilding the alias file */ 45564388Seric if (!nolock && 45664388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 45759673Seric { 45859673Seric /* yes, they are -- wait until done */ 45959673Seric message("Alias file %s is already being rebuilt", 46060089Seric map->map_file); 46159673Seric if (OpMode != MD_INITALIAS) 46259673Seric { 46359673Seric /* wait for other rebuild to complete */ 46464335Seric (void) lockfile(fileno(af), map->map_file, NULL, 46559673Seric LOCK_EX); 46659673Seric } 46764772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 46859673Seric errno = 0; 46959673Seric return; 47059673Seric } 47159673Seric 47267430Seric /* avoid denial-of-service attacks */ 47367430Seric resetlimits(); 47464035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 47567430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 47667430Seric #ifdef SIGTSTP 47767430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 47867430Seric #endif 47959673Seric 48060207Seric if (map->map_class->map_open(map, O_RDWR)) 48160089Seric { 48264382Seric #ifdef LOG 48364382Seric if (LogLevel > 7) 48464382Seric { 48564382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 48664382Seric map->map_file, automatic ? "auto" : "", 48764382Seric username()); 48864382Seric } 48964382Seric #endif /* LOG */ 49060207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 49167263Seric readaliases(map, af, !automatic, TRUE); 49260089Seric } 49360207Seric else 49460207Seric { 49560207Seric if (tTd(27, 1)) 49660207Seric printf("Can't create database for %s: %s\n", 49760207Seric map->map_file, errstring(errno)); 49860207Seric if (!automatic) 49960207Seric syserr("Cannot create database for alias file %s", 50060207Seric map->map_file); 50160207Seric } 50259673Seric 50359673Seric /* close the file, thus releasing locks */ 50464772Seric xfclose(af, "rebuildaliases2", map->map_file); 50559673Seric 50659673Seric /* add distinguished entries and close the database */ 50760207Seric if (bitset(MF_OPEN, map->map_mflags)) 50860089Seric map->map_class->map_close(map); 50959673Seric 51067430Seric /* restore the old signals */ 51164035Seric (void) setsignal(SIGINT, oldsigint); 51267430Seric (void) setsignal(SIGQUIT, oldsigquit); 51367430Seric #ifdef SIGTSTP 51467430Seric (void) setsignal(SIGTSTP, oldsigtstp); 51567430Seric #endif 5164157Seric } 5174157Seric /* 5184157Seric ** READALIASES -- read and process the alias file. 5194157Seric ** 5204157Seric ** This routine implements the part of initaliases that occurs 5214157Seric ** when we are not going to use the DBM stuff. 5224157Seric ** 5234157Seric ** Parameters: 52460089Seric ** map -- the alias database descriptor. 52559673Seric ** af -- file to read the aliases from. 52667263Seric ** announcestats -- anounce statistics regarding number of 52767263Seric ** aliases, longest alias, etc. 52867263Seric ** logstats -- lot the same info. 5294157Seric ** 5304157Seric ** Returns: 5314157Seric ** none. 5324157Seric ** 5334157Seric ** Side Effects: 5344157Seric ** Reads aliasfile into the symbol table. 5354157Seric ** Optionally, builds the .dir & .pag files. 5364157Seric */ 5374157Seric 538*68433Seric void 53967263Seric readaliases(map, af, announcestats, logstats) 54060089Seric register MAP *map; 54159673Seric FILE *af; 54267263Seric bool announcestats; 54367263Seric bool logstats; 5444157Seric { 5454098Seric register char *p; 5464098Seric char *rhs; 5474098Seric bool skipping; 54859673Seric long naliases, bytes, longest; 5494098Seric ADDRESS al, bl; 5509368Seric char line[BUFSIZ]; 5514098Seric 5524314Seric /* 5534314Seric ** Read and interpret lines 5544314Seric */ 5554314Seric 55660089Seric FileName = map->map_file; 5579368Seric LineNumber = 0; 5584322Seric naliases = bytes = longest = 0; 5594098Seric skipping = FALSE; 5604098Seric while (fgets(line, sizeof (line), af) != NULL) 5614098Seric { 5624322Seric int lhssize, rhssize; 5634322Seric 5649368Seric LineNumber++; 56556795Seric p = strchr(line, '\n'); 56625278Seric if (p != NULL) 56725278Seric *p = '\0'; 5684098Seric switch (line[0]) 5694098Seric { 5704098Seric case '#': 5714098Seric case '\0': 5724098Seric skipping = FALSE; 5734098Seric continue; 5744065Seric 5754098Seric case ' ': 5764098Seric case '\t': 5774098Seric if (!skipping) 57858151Seric syserr("554 Non-continuation line starts with space"); 5794098Seric skipping = TRUE; 5804097Seric continue; 5814098Seric } 5824098Seric skipping = FALSE; 5831874Seric 5844314Seric /* 5854314Seric ** Process the LHS 58657736Seric ** Find the colon separator, and parse the address. 58716898Seric ** It should resolve to a local name -- this will 58816898Seric ** be checked later (we want to optionally do 58916898Seric ** parsing of the RHS first to maximize error 59016898Seric ** detection). 5914314Seric */ 5924314Seric 5934098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5944097Seric continue; 59516898Seric if (*p++ != ':') 5964098Seric { 59758151Seric syserr("554 missing colon"); 5984097Seric continue; 5994098Seric } 60064284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 6014098Seric { 60264838Seric syserr("554 %.40s... illegal alias name", line); 60316898Seric continue; 6044098Seric } 6054314Seric 6064314Seric /* 6074314Seric ** Process the RHS. 6084314Seric ** 'al' is the internal form of the LHS address. 6094314Seric ** 'p' points to the text of the RHS. 6104314Seric */ 6114314Seric 61258914Seric while (isascii(*p) && isspace(*p)) 61358914Seric p++; 6144098Seric rhs = p; 6154098Seric for (;;) 6164098Seric { 6174098Seric register char c; 61858662Seric register char *nlp; 6191515Seric 62058662Seric nlp = &p[strlen(p)]; 62158662Seric if (nlp[-1] == '\n') 62258662Seric *--nlp = '\0'; 62358662Seric 62459673Seric if (CheckAliases) 6254098Seric { 6264157Seric /* do parsing & compression of addresses */ 62725278Seric while (*p != '\0') 6284098Seric { 62958333Seric auto char *delimptr; 63025278Seric 63158050Seric while ((isascii(*p) && isspace(*p)) || 63258050Seric *p == ',') 6334157Seric p++; 63425278Seric if (*p == '\0') 63525278Seric break; 63664284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 63764284Seric &delimptr, CurEnv) == NULL) 63858151Seric usrerr("553 %s... bad address", p); 63958333Seric p = delimptr; 6404098Seric } 6414098Seric } 6424157Seric else 64315769Seric { 64458662Seric p = nlp; 64515769Seric } 6461515Seric 6474098Seric /* see if there should be a continuation line */ 6484106Seric c = fgetc(af); 6494106Seric if (!feof(af)) 6504314Seric (void) ungetc(c, af); 6514106Seric if (c != ' ' && c != '\t') 6524098Seric break; 6534098Seric 6544098Seric /* read continuation line */ 6554098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6564098Seric break; 6579368Seric LineNumber++; 65857135Seric 65957135Seric /* check for line overflow */ 66057135Seric if (strchr(p, '\n') == NULL) 66157135Seric { 66258151Seric usrerr("554 alias too long"); 66357135Seric break; 66457135Seric } 6654098Seric } 66667473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 66716898Seric { 66864278Seric syserr("554 %s... cannot alias non-local names", 66964278Seric al.q_paddr); 67016898Seric continue; 67116898Seric } 6724314Seric 6734314Seric /* 6744314Seric ** Insert alias into symbol table or DBM file 6754314Seric */ 6764314Seric 67757381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 67857381Seric makelower(al.q_user); 6794322Seric 68059673Seric lhssize = strlen(al.q_user); 68159673Seric rhssize = strlen(rhs); 68260089Seric map->map_class->map_store(map, al.q_user, rhs); 6834157Seric 68459673Seric if (al.q_paddr != NULL) 68559673Seric free(al.q_paddr); 68659673Seric if (al.q_host != NULL) 68759673Seric free(al.q_host); 68859673Seric if (al.q_user != NULL) 68959673Seric free(al.q_user); 6904322Seric 6914322Seric /* statistics */ 6924322Seric naliases++; 6934322Seric bytes += lhssize + rhssize; 6944322Seric if (rhssize > longest) 6954322Seric longest = rhssize; 6961515Seric } 69719784Seric 69860207Seric CurEnv->e_to = NULL; 69959673Seric FileName = NULL; 70067263Seric if (Verbose || announcestats) 70159733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 70260089Seric map->map_file, naliases, longest, bytes); 70359673Seric # ifdef LOG 70467263Seric if (LogLevel > 7 && logstats) 70559673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 70660089Seric map->map_file, naliases, longest, bytes); 70759673Seric # endif /* LOG */ 70859673Seric } 70959673Seric /* 710292Seric ** FORWARD -- Try to forward mail 711292Seric ** 712292Seric ** This is similar but not identical to aliasing. 713292Seric ** 714292Seric ** Parameters: 7154314Seric ** user -- the name of the user who's mail we would like 7164314Seric ** to forward to. It must have been verified -- 7174314Seric ** i.e., the q_home field must have been filled 7184314Seric ** in. 7194999Seric ** sendq -- a pointer to the head of the send queue to 7204999Seric ** put this user's aliases in. 72167982Seric ** aliaslevel -- the current alias nesting depth. 72267982Seric ** e -- the current envelope. 723292Seric ** 724292Seric ** Returns: 7254098Seric ** none. 726292Seric ** 727292Seric ** Side Effects: 7283185Seric ** New names are added to send queues. 729292Seric */ 730292Seric 731*68433Seric void 73267982Seric forward(user, sendq, aliaslevel, e) 7332966Seric ADDRESS *user; 7344999Seric ADDRESS **sendq; 73567982Seric int aliaslevel; 73655012Seric register ENVELOPE *e; 737292Seric { 73857136Seric char *pp; 73957136Seric char *ep; 7404069Seric 7417671Seric if (tTd(27, 1)) 7424098Seric printf("forward(%s)\n", user->q_paddr); 7434098Seric 74467473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 74567473Seric bitset(QBADADDR, user->q_flags)) 7464098Seric return; 7474314Seric if (user->q_home == NULL) 74858059Seric { 74958151Seric syserr("554 forward: no home"); 75058059Seric user->q_home = "/nosuchdirectory"; 75158059Seric } 7524069Seric 7534069Seric /* good address -- look for .forward file in home */ 75455012Seric define('z', user->q_home, e); 75557136Seric define('u', user->q_user, e); 75657136Seric define('h', user->q_host, e); 75757136Seric if (ForwardPath == NULL) 75858050Seric ForwardPath = newstr("\201z/.forward"); 75957136Seric 76057136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 76157136Seric { 76258247Seric int err; 76357232Seric char buf[MAXPATHLEN+1]; 764*68433Seric extern int include(); 76557136Seric 76657136Seric ep = strchr(pp, ':'); 76757136Seric if (ep != NULL) 76857136Seric *ep = '\0'; 76957136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 77057136Seric if (ep != NULL) 77157136Seric *ep++ = ':'; 77257136Seric if (tTd(27, 3)) 77357136Seric printf("forward: trying %s\n", buf); 77463753Seric 77567982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 77658247Seric if (err == 0) 77757136Seric break; 77864325Seric else if (transienterror(err)) 77958247Seric { 78058247Seric /* we have to suspend this message */ 78159563Seric if (tTd(27, 2)) 78259563Seric printf("forward: transient error on %s\n", buf); 78359563Seric #ifdef LOG 78459563Seric if (LogLevel > 2) 78559624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 78666284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 78766284Seric buf, errstring(err)); 78859563Seric #endif 78959611Seric message("%s: %s: message queued", buf, errstring(err)); 79063853Seric user->q_flags |= QQUEUEUP; 79158247Seric return; 79258247Seric } 79357136Seric } 794292Seric } 795