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*68096Seric static char sccsid[] = "@(#)alias.c 8.34 (Berkeley) 12/27/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); 13268001Seric e->e_flags |= EF_SENDRECEIPT; 13368001Seric 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; 193*68096Seric static bool first_unqual = TRUE; 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 211*68096Seric if (spec[0] == '/' && first_unqual) 21259758Seric { 21367848Seric s = stab("aliases.files", ST_MAP, ST_ENTER); 21467848Seric map = &s->s_map; 215*68096Seric first_unqual = FALSE; 21659758Seric } 21767848Seric else 21867848Seric { 21967848Seric char aname[50]; 22067848Seric 22167848Seric if (NAliasDBs >= MAXALIASDB) 22267848Seric { 22367848Seric syserr("Too many alias databases defined, %d max", 22467848Seric MAXALIASDB); 22567848Seric return; 22667848Seric } 22767848Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 22867848Seric s = stab(aname, ST_MAP, ST_ENTER); 22967848Seric map = &s->s_map; 23067848Seric AliasDB[NAliasDBs] = map; 23167848Seric } 23260089Seric bzero(map, sizeof *map); 23367973Seric map->map_mname = s->s_name; 23459758Seric 23559758Seric p = strpbrk(p, " ,/:"); 23659758Seric if (p != NULL && *p == ':') 23759758Seric { 23860089Seric /* map name */ 23959758Seric *p++ = '\0'; 24059758Seric class = spec; 24159758Seric spec = p; 24259758Seric } 24359758Seric else 24459758Seric { 24559758Seric class = "implicit"; 24660228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 24759758Seric } 24859758Seric 24959758Seric /* find end of spec */ 25059758Seric if (p != NULL) 25159758Seric p = strchr(p, ','); 25259758Seric if (p != NULL) 25359758Seric *p++ = '\0'; 25459758Seric 25567848Seric if (tTd(27, 20)) 25667848Seric printf(" map %s:%s %s\n", class, s->s_name, spec); 25767848Seric 25859758Seric /* look up class */ 25960089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 26059758Seric if (s == NULL) 26159758Seric { 26259758Seric if (tTd(27, 1)) 26359758Seric printf("Unknown alias class %s\n", class); 26459758Seric } 26560207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 26660207Seric { 26760207Seric syserr("setalias: map class %s can't handle aliases", 26860207Seric class); 26960207Seric } 27059758Seric else 27159758Seric { 27260207Seric map->map_class = &s->s_mapclass; 27360089Seric if (map->map_class->map_parse(map, spec)) 27460089Seric { 27560207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 27667848Seric if (AliasDB[NAliasDBs] == map) 27767848Seric NAliasDBs++; 27860089Seric } 27959758Seric } 28059756Seric } 2815701Seric } 2825701Seric /* 28359673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 28459673Seric ** 28559673Seric ** This can decide to reopen or rebuild the alias file 28664718Seric ** 28764718Seric ** Parameters: 28864718Seric ** map -- a pointer to the map descriptor for this alias file. 28964718Seric ** ext -- the filename extension (e.g., ".db") for the 29064718Seric ** database file. 29164718Seric ** isopen -- if set, the database is already open, and we 29264718Seric ** should check for validity; otherwise, we are 29364718Seric ** just checking to see if it should be created. 29464718Seric ** 29564718Seric ** Returns: 29664718Seric ** TRUE -- if the database is open when we return. 29764718Seric ** FALSE -- if the database is closed when we return. 29859673Seric */ 29959673Seric 30064718Seric bool 30164718Seric aliaswait(map, ext, isopen) 30260089Seric MAP *map; 30360207Seric char *ext; 30464718Seric int isopen; 30559673Seric { 30664795Seric bool attimeout = FALSE; 30759673Seric time_t mtime; 30859673Seric struct stat stb; 30959673Seric char buf[MAXNAME]; 31059673Seric 31159697Seric if (tTd(27, 3)) 31260207Seric printf("aliaswait(%s:%s)\n", 31360207Seric map->map_class->map_cname, map->map_file); 31464648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 31564795Seric return isopen; 31664648Seric map->map_mflags |= MF_ALIASWAIT; 31759697Seric 31864795Seric if (SafeAlias > 0) 31917471Seric { 32060089Seric auto int st; 32164795Seric time_t toolong = curtime() + SafeAlias; 32264795Seric unsigned int sleeptime = 2; 32360089Seric 32464795Seric while (isopen && 32560089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 32625689Seric { 32764795Seric if (curtime() > toolong) 32864795Seric { 32964795Seric /* we timed out */ 33064795Seric attimeout = TRUE; 33164795Seric break; 33264795Seric } 33364795Seric 33425689Seric /* 33559673Seric ** Close and re-open the alias database in case 33659673Seric ** the one is mv'ed instead of cp'ed in. 33725689Seric */ 33825689Seric 33959697Seric if (tTd(27, 2)) 34064795Seric printf("aliaswait: sleeping for %d seconds\n", 34164795Seric sleeptime); 34259697Seric 34360089Seric map->map_class->map_close(map); 34464795Seric sleep(sleeptime); 34564795Seric sleeptime *= 2; 34664795Seric if (sleeptime > 60) 34764795Seric sleeptime = 60; 34864718Seric isopen = map->map_class->map_open(map, O_RDONLY); 34925689Seric } 35017471Seric } 3518437Seric 35259673Seric /* see if we need to go into auto-rebuild mode */ 35360207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35460207Seric { 35560207Seric if (tTd(27, 3)) 35660207Seric printf("aliaswait: not rebuildable\n"); 35764648Seric map->map_mflags &= ~MF_ALIASWAIT; 35864718Seric return isopen; 35960207Seric } 36060207Seric if (stat(map->map_file, &stb) < 0) 36160207Seric { 36260207Seric if (tTd(27, 3)) 36360207Seric printf("aliaswait: no source file\n"); 36464648Seric map->map_mflags &= ~MF_ALIASWAIT; 36564718Seric return isopen; 36660207Seric } 36759673Seric mtime = stb.st_mtime; 36860089Seric (void) strcpy(buf, map->map_file); 36960207Seric if (ext != NULL) 37060207Seric (void) strcat(buf, ext); 37164795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3724322Seric { 37359673Seric /* database is out of date */ 37440559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3754322Seric { 37660089Seric message("auto-rebuilding alias database %s", buf); 37764718Seric if (isopen) 37864718Seric map->map_class->map_close(map); 37960207Seric rebuildaliases(map, TRUE); 38064718Seric isopen = map->map_class->map_open(map, O_RDONLY); 3814322Seric } 3824322Seric else 3834322Seric { 38419039Seric #ifdef LOG 38558020Seric if (LogLevel > 3) 38659673Seric syslog(LOG_INFO, "alias database %s out of date", 38760089Seric buf); 38856795Seric #endif /* LOG */ 38960089Seric message("Warning: alias database %s out of date", buf); 3904322Seric } 3914322Seric } 39264648Seric map->map_mflags &= ~MF_ALIASWAIT; 39364718Seric return isopen; 39459673Seric } 39559673Seric /* 39659673Seric ** REBUILDALIASES -- rebuild the alias database. 39759673Seric ** 39859673Seric ** Parameters: 39960089Seric ** map -- the database to rebuild. 40059673Seric ** automatic -- set if this was automatically generated. 40159673Seric ** 40259673Seric ** Returns: 40359673Seric ** none. 40459673Seric ** 40559673Seric ** Side Effects: 40659673Seric ** Reads the text version of the database, builds the 40759673Seric ** DBM or DB version. 40859673Seric */ 4094322Seric 41060207Seric rebuildaliases(map, automatic) 41160089Seric register MAP *map; 41259673Seric bool automatic; 41359673Seric { 41459673Seric FILE *af; 41564388Seric bool nolock = FALSE; 41667430Seric sigfunc_t oldsigint, oldsigquit; 41767430Seric #ifdef SIGTSTP 41867430Seric sigfunc_t oldsigtstp; 41967430Seric #endif 4204322Seric 42160207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 42259673Seric return; 4234322Seric 42459673Seric /* try to lock the source file */ 42560089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 42659673Seric { 42765953Seric if ((errno != EACCES && errno != EROFS) || automatic || 42864388Seric (af = fopen(map->map_file, "r")) == NULL) 42964388Seric { 43064388Seric int saveerr = errno; 43164382Seric 43264388Seric if (tTd(27, 1)) 43364388Seric printf("Can't open %s: %s\n", 43464388Seric map->map_file, errstring(saveerr)); 43564388Seric if (!automatic) 43664388Seric message("newaliases: cannot open %s: %s", 43764388Seric map->map_file, errstring(saveerr)); 43864388Seric errno = 0; 43964388Seric return; 44064388Seric } 44164388Seric nolock = TRUE; 44264388Seric message("warning: cannot lock %s: %s", 44364388Seric map->map_file, errstring(errno)); 4448437Seric } 44559673Seric 44659673Seric /* see if someone else is rebuilding the alias file */ 44764388Seric if (!nolock && 44864388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 44959673Seric { 45059673Seric /* yes, they are -- wait until done */ 45159673Seric message("Alias file %s is already being rebuilt", 45260089Seric map->map_file); 45359673Seric if (OpMode != MD_INITALIAS) 45459673Seric { 45559673Seric /* wait for other rebuild to complete */ 45664335Seric (void) lockfile(fileno(af), map->map_file, NULL, 45759673Seric LOCK_EX); 45859673Seric } 45964772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 46059673Seric errno = 0; 46159673Seric return; 46259673Seric } 46359673Seric 46467430Seric /* avoid denial-of-service attacks */ 46567430Seric resetlimits(); 46664035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 46767430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 46867430Seric #ifdef SIGTSTP 46967430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 47067430Seric #endif 47159673Seric 47260207Seric if (map->map_class->map_open(map, O_RDWR)) 47360089Seric { 47464382Seric #ifdef LOG 47564382Seric if (LogLevel > 7) 47664382Seric { 47764382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 47864382Seric map->map_file, automatic ? "auto" : "", 47964382Seric username()); 48064382Seric } 48164382Seric #endif /* LOG */ 48260207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 48367263Seric readaliases(map, af, !automatic, TRUE); 48460089Seric } 48560207Seric else 48660207Seric { 48760207Seric if (tTd(27, 1)) 48860207Seric printf("Can't create database for %s: %s\n", 48960207Seric map->map_file, errstring(errno)); 49060207Seric if (!automatic) 49160207Seric syserr("Cannot create database for alias file %s", 49260207Seric map->map_file); 49360207Seric } 49459673Seric 49559673Seric /* close the file, thus releasing locks */ 49664772Seric xfclose(af, "rebuildaliases2", map->map_file); 49759673Seric 49859673Seric /* add distinguished entries and close the database */ 49960207Seric if (bitset(MF_OPEN, map->map_mflags)) 50060089Seric map->map_class->map_close(map); 50159673Seric 50267430Seric /* restore the old signals */ 50364035Seric (void) setsignal(SIGINT, oldsigint); 50467430Seric (void) setsignal(SIGQUIT, oldsigquit); 50567430Seric #ifdef SIGTSTP 50667430Seric (void) setsignal(SIGTSTP, oldsigtstp); 50767430Seric #endif 5084157Seric } 5094157Seric /* 5104157Seric ** READALIASES -- read and process the alias file. 5114157Seric ** 5124157Seric ** This routine implements the part of initaliases that occurs 5134157Seric ** when we are not going to use the DBM stuff. 5144157Seric ** 5154157Seric ** Parameters: 51660089Seric ** map -- the alias database descriptor. 51759673Seric ** af -- file to read the aliases from. 51867263Seric ** announcestats -- anounce statistics regarding number of 51967263Seric ** aliases, longest alias, etc. 52067263Seric ** logstats -- lot the same info. 5214157Seric ** 5224157Seric ** Returns: 5234157Seric ** none. 5244157Seric ** 5254157Seric ** Side Effects: 5264157Seric ** Reads aliasfile into the symbol table. 5274157Seric ** Optionally, builds the .dir & .pag files. 5284157Seric */ 5294157Seric 53067263Seric readaliases(map, af, announcestats, logstats) 53160089Seric register MAP *map; 53259673Seric FILE *af; 53367263Seric bool announcestats; 53467263Seric bool logstats; 5354157Seric { 5364098Seric register char *p; 5374098Seric char *rhs; 5384098Seric bool skipping; 53959673Seric long naliases, bytes, longest; 5404098Seric ADDRESS al, bl; 5419368Seric char line[BUFSIZ]; 5424098Seric 5434314Seric /* 5444314Seric ** Read and interpret lines 5454314Seric */ 5464314Seric 54760089Seric FileName = map->map_file; 5489368Seric LineNumber = 0; 5494322Seric naliases = bytes = longest = 0; 5504098Seric skipping = FALSE; 5514098Seric while (fgets(line, sizeof (line), af) != NULL) 5524098Seric { 5534322Seric int lhssize, rhssize; 5544322Seric 5559368Seric LineNumber++; 55656795Seric p = strchr(line, '\n'); 55725278Seric if (p != NULL) 55825278Seric *p = '\0'; 5594098Seric switch (line[0]) 5604098Seric { 5614098Seric case '#': 5624098Seric case '\0': 5634098Seric skipping = FALSE; 5644098Seric continue; 5654065Seric 5664098Seric case ' ': 5674098Seric case '\t': 5684098Seric if (!skipping) 56958151Seric syserr("554 Non-continuation line starts with space"); 5704098Seric skipping = TRUE; 5714097Seric continue; 5724098Seric } 5734098Seric skipping = FALSE; 5741874Seric 5754314Seric /* 5764314Seric ** Process the LHS 57757736Seric ** Find the colon separator, and parse the address. 57816898Seric ** It should resolve to a local name -- this will 57916898Seric ** be checked later (we want to optionally do 58016898Seric ** parsing of the RHS first to maximize error 58116898Seric ** detection). 5824314Seric */ 5834314Seric 5844098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5854097Seric continue; 58616898Seric if (*p++ != ':') 5874098Seric { 58858151Seric syserr("554 missing colon"); 5894097Seric continue; 5904098Seric } 59164284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 5924098Seric { 59364838Seric syserr("554 %.40s... illegal alias name", line); 59416898Seric continue; 5954098Seric } 5964314Seric 5974314Seric /* 5984314Seric ** Process the RHS. 5994314Seric ** 'al' is the internal form of the LHS address. 6004314Seric ** 'p' points to the text of the RHS. 6014314Seric */ 6024314Seric 60358914Seric while (isascii(*p) && isspace(*p)) 60458914Seric p++; 6054098Seric rhs = p; 6064098Seric for (;;) 6074098Seric { 6084098Seric register char c; 60958662Seric register char *nlp; 6101515Seric 61158662Seric nlp = &p[strlen(p)]; 61258662Seric if (nlp[-1] == '\n') 61358662Seric *--nlp = '\0'; 61458662Seric 61559673Seric if (CheckAliases) 6164098Seric { 6174157Seric /* do parsing & compression of addresses */ 61825278Seric while (*p != '\0') 6194098Seric { 62058333Seric auto char *delimptr; 62125278Seric 62258050Seric while ((isascii(*p) && isspace(*p)) || 62358050Seric *p == ',') 6244157Seric p++; 62525278Seric if (*p == '\0') 62625278Seric break; 62764284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 62864284Seric &delimptr, CurEnv) == NULL) 62958151Seric usrerr("553 %s... bad address", p); 63058333Seric p = delimptr; 6314098Seric } 6324098Seric } 6334157Seric else 63415769Seric { 63558662Seric p = nlp; 63615769Seric } 6371515Seric 6384098Seric /* see if there should be a continuation line */ 6394106Seric c = fgetc(af); 6404106Seric if (!feof(af)) 6414314Seric (void) ungetc(c, af); 6424106Seric if (c != ' ' && c != '\t') 6434098Seric break; 6444098Seric 6454098Seric /* read continuation line */ 6464098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6474098Seric break; 6489368Seric LineNumber++; 64957135Seric 65057135Seric /* check for line overflow */ 65157135Seric if (strchr(p, '\n') == NULL) 65257135Seric { 65358151Seric usrerr("554 alias too long"); 65457135Seric break; 65557135Seric } 6564098Seric } 65767473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 65816898Seric { 65964278Seric syserr("554 %s... cannot alias non-local names", 66064278Seric al.q_paddr); 66116898Seric continue; 66216898Seric } 6634314Seric 6644314Seric /* 6654314Seric ** Insert alias into symbol table or DBM file 6664314Seric */ 6674314Seric 66857381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 66957381Seric makelower(al.q_user); 6704322Seric 67159673Seric lhssize = strlen(al.q_user); 67259673Seric rhssize = strlen(rhs); 67360089Seric map->map_class->map_store(map, al.q_user, rhs); 6744157Seric 67559673Seric if (al.q_paddr != NULL) 67659673Seric free(al.q_paddr); 67759673Seric if (al.q_host != NULL) 67859673Seric free(al.q_host); 67959673Seric if (al.q_user != NULL) 68059673Seric free(al.q_user); 6814322Seric 6824322Seric /* statistics */ 6834322Seric naliases++; 6844322Seric bytes += lhssize + rhssize; 6854322Seric if (rhssize > longest) 6864322Seric longest = rhssize; 6871515Seric } 68819784Seric 68960207Seric CurEnv->e_to = NULL; 69059673Seric FileName = NULL; 69167263Seric if (Verbose || announcestats) 69259733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 69360089Seric map->map_file, naliases, longest, bytes); 69459673Seric # ifdef LOG 69567263Seric if (LogLevel > 7 && logstats) 69659673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 69760089Seric map->map_file, naliases, longest, bytes); 69859673Seric # endif /* LOG */ 69959673Seric } 70059673Seric /* 701292Seric ** FORWARD -- Try to forward mail 702292Seric ** 703292Seric ** This is similar but not identical to aliasing. 704292Seric ** 705292Seric ** Parameters: 7064314Seric ** user -- the name of the user who's mail we would like 7074314Seric ** to forward to. It must have been verified -- 7084314Seric ** i.e., the q_home field must have been filled 7094314Seric ** in. 7104999Seric ** sendq -- a pointer to the head of the send queue to 7114999Seric ** put this user's aliases in. 71267982Seric ** aliaslevel -- the current alias nesting depth. 71367982Seric ** e -- the current envelope. 714292Seric ** 715292Seric ** Returns: 7164098Seric ** none. 717292Seric ** 718292Seric ** Side Effects: 7193185Seric ** New names are added to send queues. 720292Seric */ 721292Seric 72267982Seric forward(user, sendq, aliaslevel, e) 7232966Seric ADDRESS *user; 7244999Seric ADDRESS **sendq; 72567982Seric int aliaslevel; 72655012Seric register ENVELOPE *e; 727292Seric { 72857136Seric char *pp; 72957136Seric char *ep; 7304069Seric 7317671Seric if (tTd(27, 1)) 7324098Seric printf("forward(%s)\n", user->q_paddr); 7334098Seric 73467473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 73567473Seric bitset(QBADADDR, user->q_flags)) 7364098Seric return; 7374314Seric if (user->q_home == NULL) 73858059Seric { 73958151Seric syserr("554 forward: no home"); 74058059Seric user->q_home = "/nosuchdirectory"; 74158059Seric } 7424069Seric 7434069Seric /* good address -- look for .forward file in home */ 74455012Seric define('z', user->q_home, e); 74557136Seric define('u', user->q_user, e); 74657136Seric define('h', user->q_host, e); 74757136Seric if (ForwardPath == NULL) 74858050Seric ForwardPath = newstr("\201z/.forward"); 74957136Seric 75057136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 75157136Seric { 75258247Seric int err; 75357232Seric char buf[MAXPATHLEN+1]; 75457136Seric 75557136Seric ep = strchr(pp, ':'); 75657136Seric if (ep != NULL) 75757136Seric *ep = '\0'; 75857136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 75957136Seric if (ep != NULL) 76057136Seric *ep++ = ':'; 76157136Seric if (tTd(27, 3)) 76257136Seric printf("forward: trying %s\n", buf); 76363753Seric 76467982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 76558247Seric if (err == 0) 76657136Seric break; 76764325Seric else if (transienterror(err)) 76858247Seric { 76958247Seric /* we have to suspend this message */ 77059563Seric if (tTd(27, 2)) 77159563Seric printf("forward: transient error on %s\n", buf); 77259563Seric #ifdef LOG 77359563Seric if (LogLevel > 2) 77459624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 77566284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 77666284Seric buf, errstring(err)); 77759563Seric #endif 77859611Seric message("%s: %s: message queued", buf, errstring(err)); 77963853Seric user->q_flags |= QQUEUEUP; 78058247Seric return; 78158247Seric } 78257136Seric } 783292Seric } 784