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*66280Seric static char sccsid[] = "@(#)alias.c 8.23 (Berkeley) 02/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. 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)) 554098Seric printf("alias(%s)\n", a->q_paddr); 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) 91*66280Seric syslog(LOG_INFO, "%s: alias %s => %s", 92*66280Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 93*66280Seric 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); 12158170Seric if (owner != NULL) 12258170Seric { 12365091Seric if (strpbrk(owner, ",:/|\"") != NULL) 12458170Seric owner = obuf; 12558170Seric a->q_owner = newstr(owner); 12658170Seric } 1274098Seric } 1284098Seric /* 1295701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1305701Seric ** 1315701Seric ** Parameters: 1325701Seric ** name -- the name to look up. 1335701Seric ** 1345701Seric ** Returns: 1355701Seric ** the value of name. 1365701Seric ** NULL if unknown. 1375701Seric ** 1385701Seric ** Side Effects: 1395701Seric ** none. 1405701Seric ** 1415701Seric ** Warnings: 1425701Seric ** The return value will be trashed across calls. 1435701Seric */ 1445701Seric 1455701Seric char * 14659673Seric aliaslookup(name, e) 1475701Seric char *name; 14859673Seric ENVELOPE *e; 1495701Seric { 15059673Seric register int dbno; 15160089Seric register MAP *map; 15259673Seric register char *p; 1535701Seric 15459673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 15559673Seric { 15660089Seric auto int stat; 15760089Seric 15860537Seric map = AliasDB[dbno]; 15960207Seric if (!bitset(MF_OPEN, map->map_mflags)) 16059673Seric continue; 16160207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 16259673Seric if (p != NULL) 16359673Seric return p; 16459673Seric } 16559673Seric return NULL; 16659673Seric } 16759673Seric /* 16859673Seric ** SETALIAS -- set up an alias map 16959673Seric ** 17059673Seric ** Called when reading configuration file. 17159673Seric ** 17259673Seric ** Parameters: 17359673Seric ** spec -- the alias specification 17459673Seric ** 17559673Seric ** Returns: 17659673Seric ** none. 17759673Seric */ 17857381Seric 17959673Seric setalias(spec) 18059673Seric char *spec; 18159673Seric { 18259673Seric register char *p; 18360089Seric register MAP *map; 18459673Seric char *class; 18559673Seric STAB *s; 18659673Seric 18759697Seric if (tTd(27, 8)) 18859697Seric printf("setalias(%s)\n", spec); 18959697Seric 19059758Seric for (p = spec; p != NULL; ) 19151756Seric { 19260537Seric char aname[50]; 19360537Seric 19459758Seric while (isspace(*p)) 19559758Seric p++; 19660502Seric if (*p == '\0') 19759673Seric break; 19859673Seric spec = p; 19959673Seric 20059758Seric if (NAliasDBs >= MAXALIASDB) 20159758Seric { 20259758Seric syserr("Too many alias databases defined, %d max", MAXALIASDB); 20359758Seric return; 20459758Seric } 20560537Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 20660537Seric s = stab(aname, ST_MAP, ST_ENTER); 20760537Seric map = &s->s_map; 20860537Seric AliasDB[NAliasDBs] = map; 20960089Seric bzero(map, sizeof *map); 21059758Seric 21159758Seric p = strpbrk(p, " ,/:"); 21259758Seric if (p != NULL && *p == ':') 21359758Seric { 21460089Seric /* map name */ 21559758Seric *p++ = '\0'; 21659758Seric class = spec; 21759758Seric spec = p; 21859758Seric } 21959758Seric else 22059758Seric { 22159758Seric class = "implicit"; 22260228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 22359758Seric } 22459758Seric 22559758Seric /* find end of spec */ 22659758Seric if (p != NULL) 22759758Seric p = strchr(p, ','); 22859758Seric if (p != NULL) 22959758Seric *p++ = '\0'; 23059758Seric 23159758Seric /* look up class */ 23260089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 23359758Seric if (s == NULL) 23459758Seric { 23559758Seric if (tTd(27, 1)) 23659758Seric printf("Unknown alias class %s\n", class); 23759758Seric } 23860207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 23960207Seric { 24060207Seric syserr("setalias: map class %s can't handle aliases", 24160207Seric class); 24260207Seric } 24359758Seric else 24459758Seric { 24560207Seric map->map_class = &s->s_mapclass; 24660089Seric if (map->map_class->map_parse(map, spec)) 24760089Seric { 24860207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 24960089Seric NAliasDBs++; 25060089Seric } 25159758Seric } 25259756Seric } 2535701Seric } 2545701Seric /* 25559673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 25659673Seric ** 25759673Seric ** This can decide to reopen or rebuild the alias file 25864718Seric ** 25964718Seric ** Parameters: 26064718Seric ** map -- a pointer to the map descriptor for this alias file. 26164718Seric ** ext -- the filename extension (e.g., ".db") for the 26264718Seric ** database file. 26364718Seric ** isopen -- if set, the database is already open, and we 26464718Seric ** should check for validity; otherwise, we are 26564718Seric ** just checking to see if it should be created. 26664718Seric ** 26764718Seric ** Returns: 26864718Seric ** TRUE -- if the database is open when we return. 26964718Seric ** FALSE -- if the database is closed when we return. 27059673Seric */ 27159673Seric 27264718Seric bool 27364718Seric aliaswait(map, ext, isopen) 27460089Seric MAP *map; 27560207Seric char *ext; 27664718Seric int isopen; 27759673Seric { 27864795Seric bool attimeout = FALSE; 27959673Seric time_t mtime; 28059673Seric struct stat stb; 28159673Seric char buf[MAXNAME]; 28259673Seric 28359697Seric if (tTd(27, 3)) 28460207Seric printf("aliaswait(%s:%s)\n", 28560207Seric map->map_class->map_cname, map->map_file); 28664648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 28764795Seric return isopen; 28864648Seric map->map_mflags |= MF_ALIASWAIT; 28959697Seric 29064795Seric if (SafeAlias > 0) 29117471Seric { 29260089Seric auto int st; 29364795Seric time_t toolong = curtime() + SafeAlias; 29464795Seric unsigned int sleeptime = 2; 29560089Seric 29664795Seric while (isopen && 29760089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 29825689Seric { 29964795Seric if (curtime() > toolong) 30064795Seric { 30164795Seric /* we timed out */ 30264795Seric attimeout = TRUE; 30364795Seric break; 30464795Seric } 30564795Seric 30625689Seric /* 30759673Seric ** Close and re-open the alias database in case 30859673Seric ** the one is mv'ed instead of cp'ed in. 30925689Seric */ 31025689Seric 31159697Seric if (tTd(27, 2)) 31264795Seric printf("aliaswait: sleeping for %d seconds\n", 31364795Seric sleeptime); 31459697Seric 31560089Seric map->map_class->map_close(map); 31664795Seric sleep(sleeptime); 31764795Seric sleeptime *= 2; 31864795Seric if (sleeptime > 60) 31964795Seric sleeptime = 60; 32064718Seric isopen = map->map_class->map_open(map, O_RDONLY); 32125689Seric } 32217471Seric } 3238437Seric 32459673Seric /* see if we need to go into auto-rebuild mode */ 32560207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 32660207Seric { 32760207Seric if (tTd(27, 3)) 32860207Seric printf("aliaswait: not rebuildable\n"); 32964648Seric map->map_mflags &= ~MF_ALIASWAIT; 33064718Seric return isopen; 33160207Seric } 33260207Seric if (stat(map->map_file, &stb) < 0) 33360207Seric { 33460207Seric if (tTd(27, 3)) 33560207Seric printf("aliaswait: no source file\n"); 33664648Seric map->map_mflags &= ~MF_ALIASWAIT; 33764718Seric return isopen; 33860207Seric } 33959673Seric mtime = stb.st_mtime; 34060089Seric (void) strcpy(buf, map->map_file); 34160207Seric if (ext != NULL) 34260207Seric (void) strcat(buf, ext); 34364795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3444322Seric { 34559673Seric /* database is out of date */ 34640559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3474322Seric { 34860089Seric message("auto-rebuilding alias database %s", buf); 34964718Seric if (isopen) 35064718Seric map->map_class->map_close(map); 35160207Seric rebuildaliases(map, TRUE); 35264718Seric isopen = map->map_class->map_open(map, O_RDONLY); 3534322Seric } 3544322Seric else 3554322Seric { 35619039Seric #ifdef LOG 35758020Seric if (LogLevel > 3) 35859673Seric syslog(LOG_INFO, "alias database %s out of date", 35960089Seric buf); 36056795Seric #endif /* LOG */ 36160089Seric message("Warning: alias database %s out of date", buf); 3624322Seric } 3634322Seric } 36464648Seric map->map_mflags &= ~MF_ALIASWAIT; 36564718Seric return isopen; 36659673Seric } 36759673Seric /* 36859673Seric ** REBUILDALIASES -- rebuild the alias database. 36959673Seric ** 37059673Seric ** Parameters: 37160089Seric ** map -- the database to rebuild. 37259673Seric ** automatic -- set if this was automatically generated. 37359673Seric ** 37459673Seric ** Returns: 37559673Seric ** none. 37659673Seric ** 37759673Seric ** Side Effects: 37859673Seric ** Reads the text version of the database, builds the 37959673Seric ** DBM or DB version. 38059673Seric */ 3814322Seric 38260207Seric rebuildaliases(map, automatic) 38360089Seric register MAP *map; 38459673Seric bool automatic; 38559673Seric { 38659673Seric FILE *af; 38764388Seric bool nolock = FALSE; 38864564Seric sigfunc_t oldsigint; 3894322Seric 39060207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 39159673Seric return; 3924322Seric 39359673Seric /* try to lock the source file */ 39460089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 39559673Seric { 39665953Seric if ((errno != EACCES && errno != EROFS) || automatic || 39764388Seric (af = fopen(map->map_file, "r")) == NULL) 39864388Seric { 39964388Seric int saveerr = errno; 40064382Seric 40164388Seric if (tTd(27, 1)) 40264388Seric printf("Can't open %s: %s\n", 40364388Seric map->map_file, errstring(saveerr)); 40464388Seric if (!automatic) 40564388Seric message("newaliases: cannot open %s: %s", 40664388Seric map->map_file, errstring(saveerr)); 40764388Seric errno = 0; 40864388Seric return; 40964388Seric } 41064388Seric nolock = TRUE; 41164388Seric message("warning: cannot lock %s: %s", 41264388Seric map->map_file, errstring(errno)); 4138437Seric } 41459673Seric 41559673Seric /* see if someone else is rebuilding the alias file */ 41664388Seric if (!nolock && 41764388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 41859673Seric { 41959673Seric /* yes, they are -- wait until done */ 42059673Seric message("Alias file %s is already being rebuilt", 42160089Seric map->map_file); 42259673Seric if (OpMode != MD_INITALIAS) 42359673Seric { 42459673Seric /* wait for other rebuild to complete */ 42564335Seric (void) lockfile(fileno(af), map->map_file, NULL, 42659673Seric LOCK_EX); 42759673Seric } 42864772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 42959673Seric errno = 0; 43059673Seric return; 43159673Seric } 43259673Seric 43364035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 43459673Seric 43560207Seric if (map->map_class->map_open(map, O_RDWR)) 43660089Seric { 43764382Seric #ifdef LOG 43864382Seric if (LogLevel > 7) 43964382Seric { 44064382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 44164382Seric map->map_file, automatic ? "auto" : "", 44264382Seric username()); 44364382Seric } 44464382Seric #endif /* LOG */ 44560207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 44660207Seric readaliases(map, af, automatic); 44760089Seric } 44860207Seric else 44960207Seric { 45060207Seric if (tTd(27, 1)) 45160207Seric printf("Can't create database for %s: %s\n", 45260207Seric map->map_file, errstring(errno)); 45360207Seric if (!automatic) 45460207Seric syserr("Cannot create database for alias file %s", 45560207Seric map->map_file); 45660207Seric } 45759673Seric 45859673Seric /* close the file, thus releasing locks */ 45964772Seric xfclose(af, "rebuildaliases2", map->map_file); 46059673Seric 46159673Seric /* add distinguished entries and close the database */ 46260207Seric if (bitset(MF_OPEN, map->map_mflags)) 46360089Seric map->map_class->map_close(map); 46459673Seric 46559673Seric /* restore the old signal */ 46664035Seric (void) setsignal(SIGINT, oldsigint); 4674157Seric } 4684157Seric /* 4694157Seric ** READALIASES -- read and process the alias file. 4704157Seric ** 4714157Seric ** This routine implements the part of initaliases that occurs 4724157Seric ** when we are not going to use the DBM stuff. 4734157Seric ** 4744157Seric ** Parameters: 47560089Seric ** map -- the alias database descriptor. 47659673Seric ** af -- file to read the aliases from. 47759733Seric ** automatic -- set if this was an automatic rebuild. 4784157Seric ** 4794157Seric ** Returns: 4804157Seric ** none. 4814157Seric ** 4824157Seric ** Side Effects: 4834157Seric ** Reads aliasfile into the symbol table. 4844157Seric ** Optionally, builds the .dir & .pag files. 4854157Seric */ 4864157Seric 48760207Seric readaliases(map, af, automatic) 48860089Seric register MAP *map; 48959673Seric FILE *af; 49059733Seric int automatic; 4914157Seric { 4924098Seric register char *p; 4934098Seric char *rhs; 4944098Seric bool skipping; 49559673Seric long naliases, bytes, longest; 4964098Seric ADDRESS al, bl; 4979368Seric char line[BUFSIZ]; 4984098Seric 4994314Seric /* 5004314Seric ** Read and interpret lines 5014314Seric */ 5024314Seric 50360089Seric FileName = map->map_file; 5049368Seric LineNumber = 0; 5054322Seric naliases = bytes = longest = 0; 5064098Seric skipping = FALSE; 5074098Seric while (fgets(line, sizeof (line), af) != NULL) 5084098Seric { 5094322Seric int lhssize, rhssize; 5104322Seric 5119368Seric LineNumber++; 51256795Seric p = strchr(line, '\n'); 51325278Seric if (p != NULL) 51425278Seric *p = '\0'; 5154098Seric switch (line[0]) 5164098Seric { 5174098Seric case '#': 5184098Seric case '\0': 5194098Seric skipping = FALSE; 5204098Seric continue; 5214065Seric 5224098Seric case ' ': 5234098Seric case '\t': 5244098Seric if (!skipping) 52558151Seric syserr("554 Non-continuation line starts with space"); 5264098Seric skipping = TRUE; 5274097Seric continue; 5284098Seric } 5294098Seric skipping = FALSE; 5301874Seric 5314314Seric /* 5324314Seric ** Process the LHS 53357736Seric ** Find the colon separator, and parse the address. 53416898Seric ** It should resolve to a local name -- this will 53516898Seric ** be checked later (we want to optionally do 53616898Seric ** parsing of the RHS first to maximize error 53716898Seric ** detection). 5384314Seric */ 5394314Seric 5404098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5414097Seric continue; 54216898Seric if (*p++ != ':') 5434098Seric { 54458151Seric syserr("554 missing colon"); 5454097Seric continue; 5464098Seric } 54764284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 5484098Seric { 54964838Seric syserr("554 %.40s... illegal alias name", line); 55016898Seric continue; 5514098Seric } 5524314Seric 5534314Seric /* 5544314Seric ** Process the RHS. 5554314Seric ** 'al' is the internal form of the LHS address. 5564314Seric ** 'p' points to the text of the RHS. 5574314Seric */ 5584314Seric 55958914Seric while (isascii(*p) && isspace(*p)) 56058914Seric p++; 5614098Seric rhs = p; 5624098Seric for (;;) 5634098Seric { 5644098Seric register char c; 56558662Seric register char *nlp; 5661515Seric 56758662Seric nlp = &p[strlen(p)]; 56858662Seric if (nlp[-1] == '\n') 56958662Seric *--nlp = '\0'; 57058662Seric 57159673Seric if (CheckAliases) 5724098Seric { 5734157Seric /* do parsing & compression of addresses */ 57425278Seric while (*p != '\0') 5754098Seric { 57658333Seric auto char *delimptr; 57725278Seric 57858050Seric while ((isascii(*p) && isspace(*p)) || 57958050Seric *p == ',') 5804157Seric p++; 58125278Seric if (*p == '\0') 58225278Seric break; 58364284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 58464284Seric &delimptr, CurEnv) == NULL) 58558151Seric usrerr("553 %s... bad address", p); 58658333Seric p = delimptr; 5874098Seric } 5884098Seric } 5894157Seric else 59015769Seric { 59158662Seric p = nlp; 59215769Seric } 5931515Seric 5944098Seric /* see if there should be a continuation line */ 5954106Seric c = fgetc(af); 5964106Seric if (!feof(af)) 5974314Seric (void) ungetc(c, af); 5984106Seric if (c != ' ' && c != '\t') 5994098Seric break; 6004098Seric 6014098Seric /* read continuation line */ 6024098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6034098Seric break; 6049368Seric LineNumber++; 60557135Seric 60657135Seric /* check for line overflow */ 60757135Seric if (strchr(p, '\n') == NULL) 60857135Seric { 60958151Seric usrerr("554 alias too long"); 61057135Seric break; 61157135Seric } 6124098Seric } 61316898Seric if (al.q_mailer != LocalMailer) 61416898Seric { 61564278Seric syserr("554 %s... cannot alias non-local names", 61664278Seric al.q_paddr); 61716898Seric continue; 61816898Seric } 6194314Seric 6204314Seric /* 6214314Seric ** Insert alias into symbol table or DBM file 6224314Seric */ 6234314Seric 62457381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 62557381Seric makelower(al.q_user); 6264322Seric 62759673Seric lhssize = strlen(al.q_user); 62859673Seric rhssize = strlen(rhs); 62960089Seric map->map_class->map_store(map, al.q_user, rhs); 6304157Seric 63159673Seric if (al.q_paddr != NULL) 63259673Seric free(al.q_paddr); 63359673Seric if (al.q_host != NULL) 63459673Seric free(al.q_host); 63559673Seric if (al.q_user != NULL) 63659673Seric free(al.q_user); 6374322Seric 6384322Seric /* statistics */ 6394322Seric naliases++; 6404322Seric bytes += lhssize + rhssize; 6414322Seric if (rhssize > longest) 6424322Seric longest = rhssize; 6431515Seric } 64419784Seric 64560207Seric CurEnv->e_to = NULL; 64659673Seric FileName = NULL; 64759733Seric if (Verbose || !automatic) 64859733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 64960089Seric map->map_file, naliases, longest, bytes); 65059673Seric # ifdef LOG 65159673Seric if (LogLevel > 7) 65259673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 65360089Seric map->map_file, naliases, longest, bytes); 65459673Seric # endif /* LOG */ 65559673Seric } 65659673Seric /* 657292Seric ** FORWARD -- Try to forward mail 658292Seric ** 659292Seric ** This is similar but not identical to aliasing. 660292Seric ** 661292Seric ** Parameters: 6624314Seric ** user -- the name of the user who's mail we would like 6634314Seric ** to forward to. It must have been verified -- 6644314Seric ** i.e., the q_home field must have been filled 6654314Seric ** in. 6664999Seric ** sendq -- a pointer to the head of the send queue to 6674999Seric ** put this user's aliases in. 668292Seric ** 669292Seric ** Returns: 6704098Seric ** none. 671292Seric ** 672292Seric ** Side Effects: 6733185Seric ** New names are added to send queues. 674292Seric */ 675292Seric 67655012Seric forward(user, sendq, e) 6772966Seric ADDRESS *user; 6784999Seric ADDRESS **sendq; 67955012Seric register ENVELOPE *e; 680292Seric { 68157136Seric char *pp; 68257136Seric char *ep; 6834069Seric 6847671Seric if (tTd(27, 1)) 6854098Seric printf("forward(%s)\n", user->q_paddr); 6864098Seric 6874594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 6884098Seric return; 6894314Seric if (user->q_home == NULL) 69058059Seric { 69158151Seric syserr("554 forward: no home"); 69258059Seric user->q_home = "/nosuchdirectory"; 69358059Seric } 6944069Seric 6954069Seric /* good address -- look for .forward file in home */ 69655012Seric define('z', user->q_home, e); 69757136Seric define('u', user->q_user, e); 69857136Seric define('h', user->q_host, e); 69957136Seric if (ForwardPath == NULL) 70058050Seric ForwardPath = newstr("\201z/.forward"); 70157136Seric 70257136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 70357136Seric { 70458247Seric int err; 70557232Seric char buf[MAXPATHLEN+1]; 70657136Seric 70757136Seric ep = strchr(pp, ':'); 70857136Seric if (ep != NULL) 70957136Seric *ep = '\0'; 71057136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 71157136Seric if (ep != NULL) 71257136Seric *ep++ = ':'; 71357136Seric if (tTd(27, 3)) 71457136Seric printf("forward: trying %s\n", buf); 71563753Seric 71658247Seric err = include(buf, TRUE, user, sendq, e); 71758247Seric if (err == 0) 71857136Seric break; 71964325Seric else if (transienterror(err)) 72058247Seric { 72158247Seric /* we have to suspend this message */ 72259563Seric if (tTd(27, 2)) 72359563Seric printf("forward: transient error on %s\n", buf); 72459563Seric #ifdef LOG 72559563Seric if (LogLevel > 2) 72659624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 72759624Seric e->e_id, buf, errstring(err)); 72859563Seric #endif 72959611Seric message("%s: %s: message queued", buf, errstring(err)); 73063853Seric user->q_flags |= QQUEUEUP; 73158247Seric return; 73258247Seric } 73357136Seric } 734292Seric } 735