122694Sdist /* 235073Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 642824Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822694Sdist 958332Seric # include "sendmail.h" 1050577Seric # include <signal.h> 1150577Seric # include <pwd.h> 1256766Seric 1333728Sbostic #ifndef lint 14*60228Seric static char sccsid[] = "@(#)alias.c 6.48 (Berkeley) 05/22/93"; 1533728Sbostic #endif /* not lint */ 1659673Seric 1759673Seric 1860089Seric MAP AliasDB[MAXALIASDB + 1]; /* actual database list */ 1959673Seric int NAliasDBs; /* number of alias databases */ 2059673Seric /* 21292Seric ** ALIAS -- Compute aliases. 22292Seric ** 239368Seric ** Scans the alias file for an alias for the given address. 249368Seric ** If found, it arranges to deliver to the alias list instead. 259368Seric ** Uses libdbm database if -DDBM. 26292Seric ** 27292Seric ** Parameters: 284097Seric ** a -- address to alias. 294999Seric ** sendq -- a pointer to the head of the send queue 304999Seric ** to put the aliases in. 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 4455012Seric alias(a, sendq, e) 454097Seric register ADDRESS *a; 464999Seric ADDRESS **sendq; 4755012Seric register ENVELOPE *e; 48292Seric { 494081Seric register char *p; 5058082Seric int naliases; 5158170Seric char *owner; 5258170Seric char obuf[MAXNAME + 6]; 535701Seric extern char *aliaslookup(); 54292Seric 557671Seric if (tTd(27, 1)) 564098Seric printf("alias(%s)\n", a->q_paddr); 57292Seric 584098Seric /* don't realias already aliased names */ 5958680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 604098Seric return; 614098Seric 6259673Seric if (NoAlias) 6359673Seric return; 6459673Seric 6555012Seric e->e_to = a->q_paddr; 664098Seric 674314Seric /* 684314Seric ** Look up this name 694314Seric */ 704314Seric 7159673Seric p = aliaslookup(a->q_user, e); 724098Seric if (p == NULL) 734098Seric return; 74292Seric 75292Seric /* 764098Seric ** Match on Alias. 774098Seric ** Deliver to the target list. 781515Seric */ 791515Seric 807671Seric if (tTd(27, 1)) 814098Seric printf("%s (%s, %s) aliased to %s\n", 824098Seric a->q_paddr, a->q_host, a->q_user, p); 8358092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8458154Seric { 8558154Seric a->q_flags |= QVERIFIED; 8658884Seric e->e_nrcpts++; 8758092Seric return; 8858154Seric } 8958154Seric message("aliased to %s", p); 9057977Seric #ifdef LOG 9158020Seric if (LogLevel > 9) 9257977Seric syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 9357977Seric #endif 9458082Seric a->q_flags &= ~QSELFREF; 954098Seric AliasLevel++; 9658082Seric naliases = sendtolist(p, a, sendq, e); 974098Seric AliasLevel--; 9858082Seric if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 9958065Seric { 10058065Seric if (tTd(27, 5)) 10158065Seric { 10258065Seric printf("alias: QDONTSEND "); 10358065Seric printaddr(a, FALSE); 10458065Seric } 10558065Seric a->q_flags |= QDONTSEND; 10658065Seric } 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); 12058170Seric if (owner != NULL) 12158170Seric { 12258170Seric if (strchr(owner, ',') != NULL) 12358170Seric owner = obuf; 12458170Seric a->q_owner = newstr(owner); 12558170Seric } 1264098Seric } 1274098Seric /* 1285701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1295701Seric ** 1305701Seric ** Parameters: 1315701Seric ** name -- the name to look up. 1325701Seric ** 1335701Seric ** Returns: 1345701Seric ** the value of name. 1355701Seric ** NULL if unknown. 1365701Seric ** 1375701Seric ** Side Effects: 1385701Seric ** none. 1395701Seric ** 1405701Seric ** Warnings: 1415701Seric ** The return value will be trashed across calls. 1425701Seric */ 1435701Seric 1445701Seric char * 14559673Seric aliaslookup(name, e) 1465701Seric char *name; 14759673Seric ENVELOPE *e; 1485701Seric { 14959673Seric register int dbno; 15060089Seric register MAP *map; 15159673Seric register char *p; 1525701Seric 15359673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 15459673Seric { 15560089Seric auto int stat; 15660089Seric 15760089Seric map = &AliasDB[dbno]; 15860207Seric if (!bitset(MF_OPEN, map->map_mflags)) 15959673Seric continue; 16060207Seric p = (*map->map_class->map_lookup)(map, name, NULL, &stat); 16159673Seric if (p != NULL) 16259673Seric return p; 16359673Seric } 16459673Seric return NULL; 16559673Seric } 16659673Seric /* 16759673Seric ** SETALIAS -- set up an alias map 16859673Seric ** 16959673Seric ** Called when reading configuration file. 17059673Seric ** 17159673Seric ** Parameters: 17259673Seric ** spec -- the alias specification 17359673Seric ** 17459673Seric ** Returns: 17559673Seric ** none. 17659673Seric */ 17757381Seric 17859673Seric setalias(spec) 17959673Seric char *spec; 18059673Seric { 18159673Seric register char *p; 18260089Seric register MAP *map; 18359673Seric char *class; 18459673Seric STAB *s; 18559673Seric 18659697Seric if (tTd(27, 8)) 18759697Seric printf("setalias(%s)\n", spec); 18859697Seric 18959758Seric for (p = spec; p != NULL; ) 19051756Seric { 19159758Seric while (isspace(*p)) 19259758Seric p++; 19359758Seric if (*p == NULL) 19459673Seric break; 19559673Seric spec = p; 19659673Seric 19759758Seric if (NAliasDBs >= MAXALIASDB) 19859758Seric { 19959758Seric syserr("Too many alias databases defined, %d max", MAXALIASDB); 20059758Seric return; 20159758Seric } 20260089Seric map = &AliasDB[NAliasDBs]; 20360089Seric bzero(map, sizeof *map); 20459758Seric 20559758Seric p = strpbrk(p, " ,/:"); 20659758Seric if (p != NULL && *p == ':') 20759758Seric { 20860089Seric /* map name */ 20959758Seric *p++ = '\0'; 21059758Seric class = spec; 21159758Seric spec = p; 21259758Seric } 21359758Seric else 21459758Seric { 21559758Seric class = "implicit"; 216*60228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 21759758Seric } 21859758Seric 21959758Seric /* find end of spec */ 22059758Seric if (p != NULL) 22159758Seric p = strchr(p, ','); 22259758Seric if (p != NULL) 22359758Seric *p++ = '\0'; 22459758Seric 22559758Seric /* look up class */ 22660089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 22759758Seric if (s == NULL) 22859758Seric { 22959758Seric if (tTd(27, 1)) 23059758Seric printf("Unknown alias class %s\n", class); 23159758Seric } 23260207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 23360207Seric { 23460207Seric syserr("setalias: map class %s can't handle aliases", 23560207Seric class); 23660207Seric } 23759758Seric else 23859758Seric { 23960207Seric map->map_class = &s->s_mapclass; 24060089Seric if (map->map_class->map_parse(map, spec)) 24160089Seric { 24260207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 24360089Seric NAliasDBs++; 24460089Seric } 24559758Seric } 24659756Seric } 2475701Seric } 2485701Seric /* 2494098Seric ** INITALIASES -- initialize for aliasing 2504098Seric ** 25156845Seric ** Very different depending on whether we are running NDBM or not. 2524098Seric ** 2534098Seric ** Parameters: 25459673Seric ** rebuild -- if TRUE, this rebuilds the cached versions. 25559673Seric ** e -- current envelope. 2564098Seric ** 2574098Seric ** Returns: 2584098Seric ** none. 2594098Seric ** 2604098Seric ** Side Effects: 2614098Seric ** initializes aliases: 26256845Seric ** if NDBM: opens the database. 26356845Seric ** if ~NDBM: reads the aliases into the symbol table. 2644098Seric */ 2654098Seric 26659673Seric initaliases(rebuild, e) 26759673Seric bool rebuild; 26855012Seric register ENVELOPE *e; 2694098Seric { 27059673Seric int dbno; 27160089Seric register MAP *map; 2724322Seric 27360207Seric CurEnv = e; 27459673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 2758437Seric { 27660089Seric map = &AliasDB[dbno]; 27760207Seric if (!bitset(MF_VALID, map->map_mflags)) 27860207Seric continue; 27959697Seric 28059697Seric if (tTd(27, 2)) 28159697Seric printf("initaliases(%s:%s)\n", 28260089Seric map->map_class->map_cname, map->map_file); 28359697Seric 28460207Seric /* if already open, close it (for nested open) */ 28560207Seric if (bitset(MF_OPEN, map->map_mflags)) 28660207Seric { 28760207Seric map->map_class->map_close(map); 28860207Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 28960207Seric } 29060207Seric 29159673Seric if (rebuild) 29250576Seric { 29360207Seric if (bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 29460207Seric rebuildaliases(map, FALSE); 29550576Seric } 29659673Seric else 29757249Seric { 29860089Seric if (map->map_class->map_open(map, O_RDONLY)) 29959756Seric { 30059756Seric if (tTd(27, 4)) 30159756Seric printf("%s:%s: valid\n", 30260089Seric map->map_class->map_cname, 30360089Seric map->map_file); 30460207Seric map->map_mflags |= MF_OPEN; 30559756Seric } 30659756Seric else if (tTd(27, 4)) 30759756Seric printf("%s:%s: invalid: %s\n", 30860207Seric map->map_class->map_cname, 30960207Seric map->map_file, 31059756Seric errstring(errno)); 31157249Seric } 31250575Seric } 31359673Seric } 31459673Seric /* 31559673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 31659673Seric ** 31759673Seric ** This can decide to reopen or rebuild the alias file 31859673Seric */ 31959673Seric 32060207Seric aliaswait(map, ext) 32160089Seric MAP *map; 32260207Seric char *ext; 32359673Seric { 32459673Seric int atcnt; 32559673Seric time_t mtime; 32659673Seric struct stat stb; 32759673Seric char buf[MAXNAME]; 32859673Seric 32959697Seric if (tTd(27, 3)) 33060207Seric printf("aliaswait(%s:%s)\n", 33160207Seric map->map_class->map_cname, map->map_file); 33259697Seric 33317471Seric atcnt = SafeAlias * 2; 33417471Seric if (atcnt > 0) 33517471Seric { 33660089Seric auto int st; 33760089Seric 33859673Seric while (atcnt-- >= 0 && 33960089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 34025689Seric { 34125689Seric /* 34259673Seric ** Close and re-open the alias database in case 34359673Seric ** the one is mv'ed instead of cp'ed in. 34425689Seric */ 34525689Seric 34659697Seric if (tTd(27, 2)) 34759697Seric printf("aliaswait: sleeping\n"); 34859697Seric 34960089Seric map->map_class->map_close(map); 35017471Seric sleep(30); 35160089Seric map->map_class->map_open(map, O_RDONLY); 35225689Seric } 35317471Seric } 3548437Seric 35559673Seric /* see if we need to go into auto-rebuild mode */ 35660207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 35760207Seric { 35860207Seric if (tTd(27, 3)) 35960207Seric printf("aliaswait: not rebuildable\n"); 36059673Seric return; 36160207Seric } 36260207Seric if (stat(map->map_file, &stb) < 0) 36360207Seric { 36460207Seric if (tTd(27, 3)) 36560207Seric printf("aliaswait: no source file\n"); 36660207Seric return; 36760207Seric } 36859673Seric mtime = stb.st_mtime; 36960089Seric (void) strcpy(buf, map->map_file); 37060207Seric if (ext != NULL) 37160207Seric (void) strcat(buf, ext); 37259673Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0) 3734322Seric { 37459673Seric /* database is out of date */ 37540559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3764322Seric { 37760089Seric message("auto-rebuilding alias database %s", buf); 37860207Seric rebuildaliases(map, TRUE); 3794322Seric } 3804322Seric else 3814322Seric { 38219039Seric #ifdef LOG 38358020Seric if (LogLevel > 3) 38459673Seric syslog(LOG_INFO, "alias database %s out of date", 38560089Seric buf); 38656795Seric #endif /* LOG */ 38760089Seric message("Warning: alias database %s out of date", buf); 3884322Seric } 3894322Seric } 39059673Seric } 39159673Seric /* 39259673Seric ** REBUILDALIASES -- rebuild the alias database. 39359673Seric ** 39459673Seric ** Parameters: 39560089Seric ** map -- the database to rebuild. 39659673Seric ** automatic -- set if this was automatically generated. 39759673Seric ** 39859673Seric ** Returns: 39959673Seric ** none. 40059673Seric ** 40159673Seric ** Side Effects: 40259673Seric ** Reads the text version of the database, builds the 40359673Seric ** DBM or DB version. 40459673Seric */ 4054322Seric 40660207Seric rebuildaliases(map, automatic) 40760089Seric register MAP *map; 40859673Seric bool automatic; 40959673Seric { 41059673Seric FILE *af; 41159673Seric void (*oldsigint)(); 4124322Seric 41360207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 41459673Seric return; 4154322Seric 41659673Seric #ifdef LOG 41759673Seric if (LogLevel > 7) 4188437Seric { 41959673Seric extern char *username(); 42025522Seric 42159673Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 42260089Seric map->map_file, automatic ? "auto" : "", username()); 42359673Seric } 42456795Seric #endif /* LOG */ 42559673Seric 42659673Seric /* try to lock the source file */ 42760089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 42859673Seric { 42959756Seric if (tTd(27, 1)) 43059756Seric printf("Can't open %s: %s\n", 43160089Seric map->map_file, errstring(errno)); 43259673Seric errno = 0; 43359673Seric return; 4348437Seric } 43559673Seric 43659673Seric /* see if someone else is rebuilding the alias file */ 43760089Seric if (!lockfile(fileno(af), map->map_file, LOCK_EX|LOCK_NB)) 43859673Seric { 43959673Seric /* yes, they are -- wait until done */ 44059673Seric message("Alias file %s is already being rebuilt", 44160089Seric map->map_file); 44259673Seric if (OpMode != MD_INITALIAS) 44359673Seric { 44459673Seric /* wait for other rebuild to complete */ 44560089Seric (void) lockfile(fileno(af), map->map_file, 44659673Seric LOCK_EX); 44759673Seric } 44859673Seric (void) fclose(af); 44959673Seric errno = 0; 45059673Seric return; 45159673Seric } 45259673Seric 45359673Seric oldsigint = signal(SIGINT, SIG_IGN); 45459673Seric 45560207Seric if (map->map_class->map_open(map, O_RDWR)) 45660089Seric { 45760207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 45860207Seric readaliases(map, af, automatic); 45960089Seric } 46060207Seric else 46160207Seric { 46260207Seric if (tTd(27, 1)) 46360207Seric printf("Can't create database for %s: %s\n", 46460207Seric map->map_file, errstring(errno)); 46560207Seric if (!automatic) 46660207Seric syserr("Cannot create database for alias file %s", 46760207Seric map->map_file); 46860207Seric } 46959673Seric 47059673Seric /* close the file, thus releasing locks */ 47159673Seric fclose(af); 47259673Seric 47359673Seric /* add distinguished entries and close the database */ 47460207Seric if (bitset(MF_OPEN, map->map_mflags)) 47560089Seric map->map_class->map_close(map); 47659673Seric 47759673Seric /* restore the old signal */ 47859673Seric (void) signal(SIGINT, oldsigint); 4794157Seric } 4804157Seric /* 4814157Seric ** READALIASES -- read and process the alias file. 4824157Seric ** 4834157Seric ** This routine implements the part of initaliases that occurs 4844157Seric ** when we are not going to use the DBM stuff. 4854157Seric ** 4864157Seric ** Parameters: 48760089Seric ** map -- the alias database descriptor. 48859673Seric ** af -- file to read the aliases from. 48959733Seric ** automatic -- set if this was an automatic rebuild. 4904157Seric ** 4914157Seric ** Returns: 4924157Seric ** none. 4934157Seric ** 4944157Seric ** Side Effects: 4954157Seric ** Reads aliasfile into the symbol table. 4964157Seric ** Optionally, builds the .dir & .pag files. 4974157Seric */ 4984157Seric 49960207Seric readaliases(map, af, automatic) 50060089Seric register MAP *map; 50159673Seric FILE *af; 50259733Seric int automatic; 5034157Seric { 5044098Seric register char *p; 5054098Seric char *rhs; 5064098Seric bool skipping; 50759673Seric long naliases, bytes, longest; 5084098Seric ADDRESS al, bl; 5094106Seric register STAB *s; 5109368Seric char line[BUFSIZ]; 5114098Seric 5124314Seric /* 5134314Seric ** Read and interpret lines 5144314Seric */ 5154314Seric 51660089Seric FileName = map->map_file; 5179368Seric LineNumber = 0; 5184322Seric naliases = bytes = longest = 0; 5194098Seric skipping = FALSE; 5204098Seric while (fgets(line, sizeof (line), af) != NULL) 5214098Seric { 5224322Seric int lhssize, rhssize; 5234322Seric 5249368Seric LineNumber++; 52556795Seric p = strchr(line, '\n'); 52625278Seric if (p != NULL) 52725278Seric *p = '\0'; 5284098Seric switch (line[0]) 5294098Seric { 5304098Seric case '#': 5314098Seric case '\0': 5324098Seric skipping = FALSE; 5334098Seric continue; 5344065Seric 5354098Seric case ' ': 5364098Seric case '\t': 5374098Seric if (!skipping) 53858151Seric syserr("554 Non-continuation line starts with space"); 5394098Seric skipping = TRUE; 5404097Seric continue; 5414098Seric } 5424098Seric skipping = FALSE; 5431874Seric 5444314Seric /* 5454314Seric ** Process the LHS 54657736Seric ** Find the colon separator, and parse the address. 54716898Seric ** It should resolve to a local name -- this will 54816898Seric ** be checked later (we want to optionally do 54916898Seric ** parsing of the RHS first to maximize error 55016898Seric ** detection). 5514314Seric */ 5524314Seric 5534098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5544097Seric continue; 55516898Seric if (*p++ != ':') 5564098Seric { 55758151Seric syserr("554 missing colon"); 5584097Seric continue; 5594098Seric } 56060207Seric if (parseaddr(line, &al, 1, ':', NULL, CurEnv) == NULL) 5614098Seric { 56258151Seric syserr("554 illegal alias name"); 56316898Seric continue; 5644098Seric } 5654314Seric 5664314Seric /* 5674314Seric ** Process the RHS. 5684314Seric ** 'al' is the internal form of the LHS address. 5694314Seric ** 'p' points to the text of the RHS. 5704314Seric */ 5714314Seric 57258914Seric while (isascii(*p) && isspace(*p)) 57358914Seric p++; 5744098Seric rhs = p; 5754098Seric for (;;) 5764098Seric { 5774098Seric register char c; 57858662Seric register char *nlp; 5791515Seric 58058662Seric nlp = &p[strlen(p)]; 58158662Seric if (nlp[-1] == '\n') 58258662Seric *--nlp = '\0'; 58358662Seric 58459673Seric if (CheckAliases) 5854098Seric { 5864157Seric /* do parsing & compression of addresses */ 58725278Seric while (*p != '\0') 5884098Seric { 58958333Seric auto char *delimptr; 59025278Seric 59158050Seric while ((isascii(*p) && isspace(*p)) || 59258050Seric *p == ',') 5934157Seric p++; 59425278Seric if (*p == '\0') 59525278Seric break; 59660207Seric if (parseaddr(p, &bl, -1, ',', &delimptr, CurEnv) == NULL) 59758151Seric usrerr("553 %s... bad address", p); 59858333Seric p = delimptr; 5994098Seric } 6004098Seric } 6014157Seric else 60215769Seric { 60358662Seric p = nlp; 60415769Seric } 6051515Seric 6064098Seric /* see if there should be a continuation line */ 6074106Seric c = fgetc(af); 6084106Seric if (!feof(af)) 6094314Seric (void) ungetc(c, af); 6104106Seric if (c != ' ' && c != '\t') 6114098Seric break; 6124098Seric 6134098Seric /* read continuation line */ 6144098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6154098Seric break; 6169368Seric LineNumber++; 61757135Seric 61857135Seric /* check for line overflow */ 61957135Seric if (strchr(p, '\n') == NULL) 62057135Seric { 62158151Seric usrerr("554 alias too long"); 62257135Seric break; 62357135Seric } 6244098Seric } 62516898Seric if (al.q_mailer != LocalMailer) 62616898Seric { 62758151Seric syserr("554 cannot alias non-local names"); 62816898Seric continue; 62916898Seric } 6304314Seric 6314314Seric /* 6324314Seric ** Insert alias into symbol table or DBM file 6334314Seric */ 6344314Seric 63557381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 63657381Seric makelower(al.q_user); 6374322Seric 63859673Seric lhssize = strlen(al.q_user); 63959673Seric rhssize = strlen(rhs); 64060089Seric map->map_class->map_store(map, al.q_user, rhs); 6414157Seric 64259673Seric if (al.q_paddr != NULL) 64359673Seric free(al.q_paddr); 64459673Seric if (al.q_host != NULL) 64559673Seric free(al.q_host); 64659673Seric if (al.q_user != NULL) 64759673Seric free(al.q_user); 6484322Seric 6494322Seric /* statistics */ 6504322Seric naliases++; 6514322Seric bytes += lhssize + rhssize; 6524322Seric if (rhssize > longest) 6534322Seric longest = rhssize; 6541515Seric } 65519784Seric 65660207Seric CurEnv->e_to = NULL; 65759673Seric FileName = NULL; 65859733Seric if (Verbose || !automatic) 65959733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 66060089Seric map->map_file, naliases, longest, bytes); 66159673Seric # ifdef LOG 66259673Seric if (LogLevel > 7) 66359673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 66460089Seric map->map_file, naliases, longest, bytes); 66559673Seric # endif /* LOG */ 66659673Seric } 66759673Seric /* 668292Seric ** FORWARD -- Try to forward mail 669292Seric ** 670292Seric ** This is similar but not identical to aliasing. 671292Seric ** 672292Seric ** Parameters: 6734314Seric ** user -- the name of the user who's mail we would like 6744314Seric ** to forward to. It must have been verified -- 6754314Seric ** i.e., the q_home field must have been filled 6764314Seric ** in. 6774999Seric ** sendq -- a pointer to the head of the send queue to 6784999Seric ** put this user's aliases in. 679292Seric ** 680292Seric ** Returns: 6814098Seric ** none. 682292Seric ** 683292Seric ** Side Effects: 6843185Seric ** New names are added to send queues. 685292Seric */ 686292Seric 68755012Seric forward(user, sendq, e) 6882966Seric ADDRESS *user; 6894999Seric ADDRESS **sendq; 69055012Seric register ENVELOPE *e; 691292Seric { 69257136Seric char *pp; 69357136Seric char *ep; 6944069Seric 6957671Seric if (tTd(27, 1)) 6964098Seric printf("forward(%s)\n", user->q_paddr); 6974098Seric 6984594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 6994098Seric return; 7004314Seric if (user->q_home == NULL) 70158059Seric { 70258151Seric syserr("554 forward: no home"); 70358059Seric user->q_home = "/nosuchdirectory"; 70458059Seric } 7054069Seric 7064069Seric /* good address -- look for .forward file in home */ 70755012Seric define('z', user->q_home, e); 70857136Seric define('u', user->q_user, e); 70957136Seric define('h', user->q_host, e); 71057136Seric if (ForwardPath == NULL) 71158050Seric ForwardPath = newstr("\201z/.forward"); 71257136Seric 71357136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 71457136Seric { 71558247Seric int err; 71657232Seric char buf[MAXPATHLEN+1]; 71757136Seric 71857136Seric ep = strchr(pp, ':'); 71957136Seric if (ep != NULL) 72057136Seric *ep = '\0'; 72157136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 72257136Seric if (ep != NULL) 72357136Seric *ep++ = ':'; 72457136Seric if (tTd(27, 3)) 72557136Seric printf("forward: trying %s\n", buf); 72658247Seric err = include(buf, TRUE, user, sendq, e); 72758247Seric if (err == 0) 72857136Seric break; 72958247Seric if (transienterror(err)) 73058247Seric { 73158247Seric /* we have to suspend this message */ 73259563Seric if (tTd(27, 2)) 73359563Seric printf("forward: transient error on %s\n", buf); 73459563Seric #ifdef LOG 73559563Seric if (LogLevel > 2) 73659624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 73759624Seric e->e_id, buf, errstring(err)); 73859563Seric #endif 73959611Seric message("%s: %s: message queued", buf, errstring(err)); 74058247Seric user->q_flags |= QQUEUEUP|QDONTSEND; 74158247Seric return; 74258247Seric } 74357136Seric } 744292Seric } 745