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*67473Seric static char sccsid[] = "@(#)alias.c 8.29 (Berkeley) 07/03/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. 3058092Seric ** e -- the current envelope. 31292Seric ** 32292Seric ** Returns: 33292Seric ** none 34292Seric ** 35292Seric ** Side Effects: 363185Seric ** Aliases found are expanded. 37292Seric ** 38292Seric ** Deficiencies: 39292Seric ** It should complain about names that are aliased to 40292Seric ** nothing. 41292Seric */ 42292Seric 4355012Seric alias(a, sendq, e) 444097Seric register ADDRESS *a; 454999Seric ADDRESS **sendq; 4655012Seric register ENVELOPE *e; 47292Seric { 484081Seric register char *p; 4958082Seric int naliases; 5058170Seric char *owner; 5158170Seric char obuf[MAXNAME + 6]; 525701Seric extern char *aliaslookup(); 53292Seric 547671Seric if (tTd(27, 1)) 5567426Seric printf("alias(%s)\n", a->q_user); 56292Seric 574098Seric /* don't realias already aliased names */ 5858680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 594098Seric return; 604098Seric 6159673Seric if (NoAlias) 6259673Seric return; 6359673Seric 6455012Seric e->e_to = a->q_paddr; 654098Seric 664314Seric /* 674314Seric ** Look up this name 684314Seric */ 694314Seric 7059673Seric p = aliaslookup(a->q_user, e); 714098Seric if (p == NULL) 724098Seric return; 73292Seric 74292Seric /* 754098Seric ** Match on Alias. 764098Seric ** Deliver to the target list. 771515Seric */ 781515Seric 797671Seric if (tTd(27, 1)) 804098Seric printf("%s (%s, %s) aliased to %s\n", 814098Seric a->q_paddr, a->q_host, a->q_user, p); 8258092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8358154Seric { 8458154Seric a->q_flags |= QVERIFIED; 8558884Seric e->e_nrcpts++; 8658092Seric return; 8758154Seric } 8858154Seric message("aliased to %s", p); 8957977Seric #ifdef LOG 9058020Seric if (LogLevel > 9) 9166280Seric syslog(LOG_INFO, "%s: alias %s => %s", 9266280Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 9366280Seric a->q_paddr, p); 9457977Seric #endif 9558082Seric a->q_flags &= ~QSELFREF; 964098Seric AliasLevel++; 9758082Seric naliases = sendtolist(p, a, sendq, e); 984098Seric AliasLevel--; 9964301Seric if (!bitset(QSELFREF, a->q_flags)) 10058065Seric { 10158065Seric if (tTd(27, 5)) 10258065Seric { 10358065Seric printf("alias: QDONTSEND "); 10458065Seric printaddr(a, FALSE); 10558065Seric } 10658065Seric a->q_flags |= QDONTSEND; 10758065Seric } 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) 13158170Seric { 13266784Seric fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 13366784Seric a->q_paddr); 13466784Seric e->e_flags |= EF_SENDRECEIPT; 13558170Seric } 1364098Seric } 1374098Seric /* 1385701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1395701Seric ** 1405701Seric ** Parameters: 1415701Seric ** name -- the name to look up. 1425701Seric ** 1435701Seric ** Returns: 1445701Seric ** the value of name. 1455701Seric ** NULL if unknown. 1465701Seric ** 1475701Seric ** Side Effects: 1485701Seric ** none. 1495701Seric ** 1505701Seric ** Warnings: 1515701Seric ** The return value will be trashed across calls. 1525701Seric */ 1535701Seric 1545701Seric char * 15559673Seric aliaslookup(name, e) 1565701Seric char *name; 15759673Seric ENVELOPE *e; 1585701Seric { 15959673Seric register int dbno; 16060089Seric register MAP *map; 16159673Seric register char *p; 1625701Seric 16359673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 16459673Seric { 16560089Seric auto int stat; 16660089Seric 16760537Seric map = AliasDB[dbno]; 16860207Seric if (!bitset(MF_OPEN, map->map_mflags)) 16959673Seric continue; 17060207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 17159673Seric if (p != NULL) 17259673Seric return p; 17359673Seric } 17459673Seric return NULL; 17559673Seric } 17659673Seric /* 17759673Seric ** SETALIAS -- set up an alias map 17859673Seric ** 17959673Seric ** Called when reading configuration file. 18059673Seric ** 18159673Seric ** Parameters: 18259673Seric ** spec -- the alias specification 18359673Seric ** 18459673Seric ** Returns: 18559673Seric ** none. 18659673Seric */ 18757381Seric 18859673Seric setalias(spec) 18959673Seric char *spec; 19059673Seric { 19159673Seric register char *p; 19260089Seric register MAP *map; 19359673Seric char *class; 19459673Seric STAB *s; 19559673Seric 19659697Seric if (tTd(27, 8)) 19759697Seric printf("setalias(%s)\n", spec); 19859697Seric 19959758Seric for (p = spec; p != NULL; ) 20051756Seric { 20160537Seric char aname[50]; 20260537Seric 20359758Seric while (isspace(*p)) 20459758Seric p++; 20560502Seric if (*p == '\0') 20659673Seric break; 20759673Seric spec = p; 20859673Seric 20959758Seric if (NAliasDBs >= MAXALIASDB) 21059758Seric { 21159758Seric syserr("Too many alias databases defined, %d max", MAXALIASDB); 21259758Seric return; 21359758Seric } 21460537Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 21560537Seric s = stab(aname, ST_MAP, ST_ENTER); 21660537Seric map = &s->s_map; 21760537Seric AliasDB[NAliasDBs] = map; 21860089Seric bzero(map, sizeof *map); 21959758Seric 22059758Seric p = strpbrk(p, " ,/:"); 22159758Seric if (p != NULL && *p == ':') 22259758Seric { 22360089Seric /* map name */ 22459758Seric *p++ = '\0'; 22559758Seric class = spec; 22659758Seric spec = p; 22759758Seric } 22859758Seric else 22959758Seric { 23059758Seric class = "implicit"; 23160228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 23259758Seric } 23359758Seric 23459758Seric /* find end of spec */ 23559758Seric if (p != NULL) 23659758Seric p = strchr(p, ','); 23759758Seric if (p != NULL) 23859758Seric *p++ = '\0'; 23959758Seric 24059758Seric /* look up class */ 24160089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 24259758Seric if (s == NULL) 24359758Seric { 24459758Seric if (tTd(27, 1)) 24559758Seric printf("Unknown alias class %s\n", class); 24659758Seric } 24760207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 24860207Seric { 24960207Seric syserr("setalias: map class %s can't handle aliases", 25060207Seric class); 25160207Seric } 25259758Seric else 25359758Seric { 25460207Seric map->map_class = &s->s_mapclass; 25560089Seric if (map->map_class->map_parse(map, spec)) 25660089Seric { 25760207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 25860089Seric NAliasDBs++; 25960089Seric } 26059758Seric } 26159756Seric } 2625701Seric } 2635701Seric /* 26459673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 26559673Seric ** 26659673Seric ** This can decide to reopen or rebuild the alias file 26764718Seric ** 26864718Seric ** Parameters: 26964718Seric ** map -- a pointer to the map descriptor for this alias file. 27064718Seric ** ext -- the filename extension (e.g., ".db") for the 27164718Seric ** database file. 27264718Seric ** isopen -- if set, the database is already open, and we 27364718Seric ** should check for validity; otherwise, we are 27464718Seric ** just checking to see if it should be created. 27564718Seric ** 27664718Seric ** Returns: 27764718Seric ** TRUE -- if the database is open when we return. 27864718Seric ** FALSE -- if the database is closed when we return. 27959673Seric */ 28059673Seric 28164718Seric bool 28264718Seric aliaswait(map, ext, isopen) 28360089Seric MAP *map; 28460207Seric char *ext; 28564718Seric int isopen; 28659673Seric { 28764795Seric bool attimeout = FALSE; 28859673Seric time_t mtime; 28959673Seric struct stat stb; 29059673Seric char buf[MAXNAME]; 29159673Seric 29259697Seric if (tTd(27, 3)) 29360207Seric printf("aliaswait(%s:%s)\n", 29460207Seric map->map_class->map_cname, map->map_file); 29564648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 29664795Seric return isopen; 29764648Seric map->map_mflags |= MF_ALIASWAIT; 29859697Seric 29964795Seric if (SafeAlias > 0) 30017471Seric { 30160089Seric auto int st; 30264795Seric time_t toolong = curtime() + SafeAlias; 30364795Seric unsigned int sleeptime = 2; 30460089Seric 30564795Seric while (isopen && 30660089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 30725689Seric { 30864795Seric if (curtime() > toolong) 30964795Seric { 31064795Seric /* we timed out */ 31164795Seric attimeout = TRUE; 31264795Seric break; 31364795Seric } 31464795Seric 31525689Seric /* 31659673Seric ** Close and re-open the alias database in case 31759673Seric ** the one is mv'ed instead of cp'ed in. 31825689Seric */ 31925689Seric 32059697Seric if (tTd(27, 2)) 32164795Seric printf("aliaswait: sleeping for %d seconds\n", 32264795Seric sleeptime); 32359697Seric 32460089Seric map->map_class->map_close(map); 32564795Seric sleep(sleeptime); 32664795Seric sleeptime *= 2; 32764795Seric if (sleeptime > 60) 32864795Seric sleeptime = 60; 32964718Seric isopen = map->map_class->map_open(map, O_RDONLY); 33025689Seric } 33117471Seric } 3328437Seric 33359673Seric /* see if we need to go into auto-rebuild mode */ 33460207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 33560207Seric { 33660207Seric if (tTd(27, 3)) 33760207Seric printf("aliaswait: not rebuildable\n"); 33864648Seric map->map_mflags &= ~MF_ALIASWAIT; 33964718Seric return isopen; 34060207Seric } 34160207Seric if (stat(map->map_file, &stb) < 0) 34260207Seric { 34360207Seric if (tTd(27, 3)) 34460207Seric printf("aliaswait: no source file\n"); 34564648Seric map->map_mflags &= ~MF_ALIASWAIT; 34664718Seric return isopen; 34760207Seric } 34859673Seric mtime = stb.st_mtime; 34960089Seric (void) strcpy(buf, map->map_file); 35060207Seric if (ext != NULL) 35160207Seric (void) strcat(buf, ext); 35264795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3534322Seric { 35459673Seric /* database is out of date */ 35540559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3564322Seric { 35760089Seric message("auto-rebuilding alias database %s", buf); 35864718Seric if (isopen) 35964718Seric map->map_class->map_close(map); 36060207Seric rebuildaliases(map, TRUE); 36164718Seric isopen = map->map_class->map_open(map, O_RDONLY); 3624322Seric } 3634322Seric else 3644322Seric { 36519039Seric #ifdef LOG 36658020Seric if (LogLevel > 3) 36759673Seric syslog(LOG_INFO, "alias database %s out of date", 36860089Seric buf); 36956795Seric #endif /* LOG */ 37060089Seric message("Warning: alias database %s out of date", buf); 3714322Seric } 3724322Seric } 37364648Seric map->map_mflags &= ~MF_ALIASWAIT; 37464718Seric return isopen; 37559673Seric } 37659673Seric /* 37759673Seric ** REBUILDALIASES -- rebuild the alias database. 37859673Seric ** 37959673Seric ** Parameters: 38060089Seric ** map -- the database to rebuild. 38159673Seric ** automatic -- set if this was automatically generated. 38259673Seric ** 38359673Seric ** Returns: 38459673Seric ** none. 38559673Seric ** 38659673Seric ** Side Effects: 38759673Seric ** Reads the text version of the database, builds the 38859673Seric ** DBM or DB version. 38959673Seric */ 3904322Seric 39160207Seric rebuildaliases(map, automatic) 39260089Seric register MAP *map; 39359673Seric bool automatic; 39459673Seric { 39559673Seric FILE *af; 39664388Seric bool nolock = FALSE; 39767430Seric sigfunc_t oldsigint, oldsigquit; 39867430Seric #ifdef SIGTSTP 39967430Seric sigfunc_t oldsigtstp; 40067430Seric #endif 4014322Seric 40260207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 40359673Seric return; 4044322Seric 40559673Seric /* try to lock the source file */ 40660089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 40759673Seric { 40865953Seric if ((errno != EACCES && errno != EROFS) || automatic || 40964388Seric (af = fopen(map->map_file, "r")) == NULL) 41064388Seric { 41164388Seric int saveerr = errno; 41264382Seric 41364388Seric if (tTd(27, 1)) 41464388Seric printf("Can't open %s: %s\n", 41564388Seric map->map_file, errstring(saveerr)); 41664388Seric if (!automatic) 41764388Seric message("newaliases: cannot open %s: %s", 41864388Seric map->map_file, errstring(saveerr)); 41964388Seric errno = 0; 42064388Seric return; 42164388Seric } 42264388Seric nolock = TRUE; 42364388Seric message("warning: cannot lock %s: %s", 42464388Seric map->map_file, errstring(errno)); 4258437Seric } 42659673Seric 42759673Seric /* see if someone else is rebuilding the alias file */ 42864388Seric if (!nolock && 42964388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 43059673Seric { 43159673Seric /* yes, they are -- wait until done */ 43259673Seric message("Alias file %s is already being rebuilt", 43360089Seric map->map_file); 43459673Seric if (OpMode != MD_INITALIAS) 43559673Seric { 43659673Seric /* wait for other rebuild to complete */ 43764335Seric (void) lockfile(fileno(af), map->map_file, NULL, 43859673Seric LOCK_EX); 43959673Seric } 44064772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 44159673Seric errno = 0; 44259673Seric return; 44359673Seric } 44459673Seric 44567430Seric /* avoid denial-of-service attacks */ 44667430Seric resetlimits(); 44764035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 44867430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 44967430Seric #ifdef SIGTSTP 45067430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 45167430Seric #endif 45259673Seric 45360207Seric if (map->map_class->map_open(map, O_RDWR)) 45460089Seric { 45564382Seric #ifdef LOG 45664382Seric if (LogLevel > 7) 45764382Seric { 45864382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 45964382Seric map->map_file, automatic ? "auto" : "", 46064382Seric username()); 46164382Seric } 46264382Seric #endif /* LOG */ 46360207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 46467263Seric readaliases(map, af, !automatic, TRUE); 46560089Seric } 46660207Seric else 46760207Seric { 46860207Seric if (tTd(27, 1)) 46960207Seric printf("Can't create database for %s: %s\n", 47060207Seric map->map_file, errstring(errno)); 47160207Seric if (!automatic) 47260207Seric syserr("Cannot create database for alias file %s", 47360207Seric map->map_file); 47460207Seric } 47559673Seric 47659673Seric /* close the file, thus releasing locks */ 47764772Seric xfclose(af, "rebuildaliases2", map->map_file); 47859673Seric 47959673Seric /* add distinguished entries and close the database */ 48060207Seric if (bitset(MF_OPEN, map->map_mflags)) 48160089Seric map->map_class->map_close(map); 48259673Seric 48367430Seric /* restore the old signals */ 48464035Seric (void) setsignal(SIGINT, oldsigint); 48567430Seric (void) setsignal(SIGQUIT, oldsigquit); 48667430Seric #ifdef SIGTSTP 48767430Seric (void) setsignal(SIGTSTP, oldsigtstp); 48867430Seric #endif 4894157Seric } 4904157Seric /* 4914157Seric ** READALIASES -- read and process the alias file. 4924157Seric ** 4934157Seric ** This routine implements the part of initaliases that occurs 4944157Seric ** when we are not going to use the DBM stuff. 4954157Seric ** 4964157Seric ** Parameters: 49760089Seric ** map -- the alias database descriptor. 49859673Seric ** af -- file to read the aliases from. 49967263Seric ** announcestats -- anounce statistics regarding number of 50067263Seric ** aliases, longest alias, etc. 50167263Seric ** logstats -- lot the same info. 5024157Seric ** 5034157Seric ** Returns: 5044157Seric ** none. 5054157Seric ** 5064157Seric ** Side Effects: 5074157Seric ** Reads aliasfile into the symbol table. 5084157Seric ** Optionally, builds the .dir & .pag files. 5094157Seric */ 5104157Seric 51167263Seric readaliases(map, af, announcestats, logstats) 51260089Seric register MAP *map; 51359673Seric FILE *af; 51467263Seric bool announcestats; 51567263Seric bool logstats; 5164157Seric { 5174098Seric register char *p; 5184098Seric char *rhs; 5194098Seric bool skipping; 52059673Seric long naliases, bytes, longest; 5214098Seric ADDRESS al, bl; 5229368Seric char line[BUFSIZ]; 5234098Seric 5244314Seric /* 5254314Seric ** Read and interpret lines 5264314Seric */ 5274314Seric 52860089Seric FileName = map->map_file; 5299368Seric LineNumber = 0; 5304322Seric naliases = bytes = longest = 0; 5314098Seric skipping = FALSE; 5324098Seric while (fgets(line, sizeof (line), af) != NULL) 5334098Seric { 5344322Seric int lhssize, rhssize; 5354322Seric 5369368Seric LineNumber++; 53756795Seric p = strchr(line, '\n'); 53825278Seric if (p != NULL) 53925278Seric *p = '\0'; 5404098Seric switch (line[0]) 5414098Seric { 5424098Seric case '#': 5434098Seric case '\0': 5444098Seric skipping = FALSE; 5454098Seric continue; 5464065Seric 5474098Seric case ' ': 5484098Seric case '\t': 5494098Seric if (!skipping) 55058151Seric syserr("554 Non-continuation line starts with space"); 5514098Seric skipping = TRUE; 5524097Seric continue; 5534098Seric } 5544098Seric skipping = FALSE; 5551874Seric 5564314Seric /* 5574314Seric ** Process the LHS 55857736Seric ** Find the colon separator, and parse the address. 55916898Seric ** It should resolve to a local name -- this will 56016898Seric ** be checked later (we want to optionally do 56116898Seric ** parsing of the RHS first to maximize error 56216898Seric ** detection). 5634314Seric */ 5644314Seric 5654098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5664097Seric continue; 56716898Seric if (*p++ != ':') 5684098Seric { 56958151Seric syserr("554 missing colon"); 5704097Seric continue; 5714098Seric } 57264284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 5734098Seric { 57464838Seric syserr("554 %.40s... illegal alias name", line); 57516898Seric continue; 5764098Seric } 5774314Seric 5784314Seric /* 5794314Seric ** Process the RHS. 5804314Seric ** 'al' is the internal form of the LHS address. 5814314Seric ** 'p' points to the text of the RHS. 5824314Seric */ 5834314Seric 58458914Seric while (isascii(*p) && isspace(*p)) 58558914Seric p++; 5864098Seric rhs = p; 5874098Seric for (;;) 5884098Seric { 5894098Seric register char c; 59058662Seric register char *nlp; 5911515Seric 59258662Seric nlp = &p[strlen(p)]; 59358662Seric if (nlp[-1] == '\n') 59458662Seric *--nlp = '\0'; 59558662Seric 59659673Seric if (CheckAliases) 5974098Seric { 5984157Seric /* do parsing & compression of addresses */ 59925278Seric while (*p != '\0') 6004098Seric { 60158333Seric auto char *delimptr; 60225278Seric 60358050Seric while ((isascii(*p) && isspace(*p)) || 60458050Seric *p == ',') 6054157Seric p++; 60625278Seric if (*p == '\0') 60725278Seric break; 60864284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 60964284Seric &delimptr, CurEnv) == NULL) 61058151Seric usrerr("553 %s... bad address", p); 61158333Seric p = delimptr; 6124098Seric } 6134098Seric } 6144157Seric else 61515769Seric { 61658662Seric p = nlp; 61715769Seric } 6181515Seric 6194098Seric /* see if there should be a continuation line */ 6204106Seric c = fgetc(af); 6214106Seric if (!feof(af)) 6224314Seric (void) ungetc(c, af); 6234106Seric if (c != ' ' && c != '\t') 6244098Seric break; 6254098Seric 6264098Seric /* read continuation line */ 6274098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6284098Seric break; 6299368Seric LineNumber++; 63057135Seric 63157135Seric /* check for line overflow */ 63257135Seric if (strchr(p, '\n') == NULL) 63357135Seric { 63458151Seric usrerr("554 alias too long"); 63557135Seric break; 63657135Seric } 6374098Seric } 638*67473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 63916898Seric { 64064278Seric syserr("554 %s... cannot alias non-local names", 64164278Seric al.q_paddr); 64216898Seric continue; 64316898Seric } 6444314Seric 6454314Seric /* 6464314Seric ** Insert alias into symbol table or DBM file 6474314Seric */ 6484314Seric 64957381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 65057381Seric makelower(al.q_user); 6514322Seric 65259673Seric lhssize = strlen(al.q_user); 65359673Seric rhssize = strlen(rhs); 65460089Seric map->map_class->map_store(map, al.q_user, rhs); 6554157Seric 65659673Seric if (al.q_paddr != NULL) 65759673Seric free(al.q_paddr); 65859673Seric if (al.q_host != NULL) 65959673Seric free(al.q_host); 66059673Seric if (al.q_user != NULL) 66159673Seric free(al.q_user); 6624322Seric 6634322Seric /* statistics */ 6644322Seric naliases++; 6654322Seric bytes += lhssize + rhssize; 6664322Seric if (rhssize > longest) 6674322Seric longest = rhssize; 6681515Seric } 66919784Seric 67060207Seric CurEnv->e_to = NULL; 67159673Seric FileName = NULL; 67267263Seric if (Verbose || announcestats) 67359733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 67460089Seric map->map_file, naliases, longest, bytes); 67559673Seric # ifdef LOG 67667263Seric if (LogLevel > 7 && logstats) 67759673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 67860089Seric map->map_file, naliases, longest, bytes); 67959673Seric # endif /* LOG */ 68059673Seric } 68159673Seric /* 682292Seric ** FORWARD -- Try to forward mail 683292Seric ** 684292Seric ** This is similar but not identical to aliasing. 685292Seric ** 686292Seric ** Parameters: 6874314Seric ** user -- the name of the user who's mail we would like 6884314Seric ** to forward to. It must have been verified -- 6894314Seric ** i.e., the q_home field must have been filled 6904314Seric ** in. 6914999Seric ** sendq -- a pointer to the head of the send queue to 6924999Seric ** put this user's aliases in. 693292Seric ** 694292Seric ** Returns: 6954098Seric ** none. 696292Seric ** 697292Seric ** Side Effects: 6983185Seric ** New names are added to send queues. 699292Seric */ 700292Seric 70155012Seric forward(user, sendq, e) 7022966Seric ADDRESS *user; 7034999Seric ADDRESS **sendq; 70455012Seric register ENVELOPE *e; 705292Seric { 70657136Seric char *pp; 70757136Seric char *ep; 7084069Seric 7097671Seric if (tTd(27, 1)) 7104098Seric printf("forward(%s)\n", user->q_paddr); 7114098Seric 712*67473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 713*67473Seric bitset(QBADADDR, user->q_flags)) 7144098Seric return; 7154314Seric if (user->q_home == NULL) 71658059Seric { 71758151Seric syserr("554 forward: no home"); 71858059Seric user->q_home = "/nosuchdirectory"; 71958059Seric } 7204069Seric 7214069Seric /* good address -- look for .forward file in home */ 72255012Seric define('z', user->q_home, e); 72357136Seric define('u', user->q_user, e); 72457136Seric define('h', user->q_host, e); 72557136Seric if (ForwardPath == NULL) 72658050Seric ForwardPath = newstr("\201z/.forward"); 72757136Seric 72857136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 72957136Seric { 73058247Seric int err; 73157232Seric char buf[MAXPATHLEN+1]; 73257136Seric 73357136Seric ep = strchr(pp, ':'); 73457136Seric if (ep != NULL) 73557136Seric *ep = '\0'; 73657136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 73757136Seric if (ep != NULL) 73857136Seric *ep++ = ':'; 73957136Seric if (tTd(27, 3)) 74057136Seric printf("forward: trying %s\n", buf); 74163753Seric 74258247Seric err = include(buf, TRUE, user, sendq, e); 74358247Seric if (err == 0) 74457136Seric break; 74564325Seric else if (transienterror(err)) 74658247Seric { 74758247Seric /* we have to suspend this message */ 74859563Seric if (tTd(27, 2)) 74959563Seric printf("forward: transient error on %s\n", buf); 75059563Seric #ifdef LOG 75159563Seric if (LogLevel > 2) 75259624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 75366284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 75466284Seric buf, errstring(err)); 75559563Seric #endif 75659611Seric message("%s: %s: message queued", buf, errstring(err)); 75763853Seric user->q_flags |= QQUEUEUP; 75858247Seric return; 75958247Seric } 76057136Seric } 761292Seric } 762