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 950577Seric # include <sys/types.h> 1050577Seric # include <sys/stat.h> 1150577Seric # include <signal.h> 1250577Seric # include "sendmail.h" 1350577Seric # include <sys/file.h> 1450577Seric # include <pwd.h> 1551937Seric # ifdef LOCKF 1651937Seric # include <fcntl.h> 1751937Seric # endif 1850577Seric 1956845Seric # ifdef DBM 2056848Seric ERROR: DBM is no longer supported -- use NDBM instead. 2156845Seric # endif 2256845Seric 2350577Seric # ifdef NEWDB 2450577Seric # include <db.h> 2550577Seric # endif 2650577Seric 2756766Seric # ifdef NDBM 2856845Seric # include <ndbm.h> 2956766Seric # endif 3056766Seric 3133728Sbostic #ifndef lint 3251756Seric #ifdef NEWDB 33*57381Seric static char sccsid[] = "@(#)alias.c 6.2 (Berkeley) 01/01/93 (with NEWDB)"; 3451756Seric #else 3556845Seric #ifdef NDBM 36*57381Seric static char sccsid[] = "@(#)alias.c 6.2 (Berkeley) 01/01/93 (with NDBM)"; 3733728Sbostic #else 38*57381Seric static char sccsid[] = "@(#)alias.c 6.2 (Berkeley) 01/01/93 (without NDBM)"; 3933728Sbostic #endif 4050575Seric #endif 4133728Sbostic #endif /* not lint */ 4251756Seric /* 43292Seric ** ALIAS -- Compute aliases. 44292Seric ** 459368Seric ** Scans the alias file for an alias for the given address. 469368Seric ** If found, it arranges to deliver to the alias list instead. 479368Seric ** Uses libdbm database if -DDBM. 48292Seric ** 49292Seric ** Parameters: 504097Seric ** a -- address to alias. 514999Seric ** sendq -- a pointer to the head of the send queue 524999Seric ** to put the aliases in. 53292Seric ** 54292Seric ** Returns: 55292Seric ** none 56292Seric ** 57292Seric ** Side Effects: 583185Seric ** Aliases found are expanded. 59292Seric ** 60292Seric ** Notes: 61292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 62292Seric ** done. 63292Seric ** 64292Seric ** Deficiencies: 65292Seric ** It should complain about names that are aliased to 66292Seric ** nothing. 67292Seric */ 68292Seric 69292Seric 7053742Seric /* 7153742Seric ** Sun YP servers read the dbm files directly, so we have to build them 7253742Seric ** even if NEWDB 7353742Seric */ 7453742Seric 7556845Seric #ifdef NDBM 7653742Seric # ifndef NEWDB 7753742Seric # define IF_MAKEDBMFILES 7853742Seric # else 7953742Seric # ifdef YPCOMPAT 8053742Seric # define IF_MAKEDBMFILES if (makedbmfiles) 8153742Seric # endif 8253742Seric # endif 8353742Seric #endif 8453742Seric 8556845Seric typedef union 862966Seric { 8756845Seric #ifdef NDBM 8856845Seric datum dbm; 8951756Seric #endif 9056845Seric #ifdef NEWDB 9156845Seric DBT dbt; 9256845Seric #endif 9356845Seric struct 9456845Seric { 9556845Seric char *data; 9656845Seric int size; 9756845Seric } xx; 9856845Seric } DBdatum; 99292Seric 10050575Seric #ifdef NEWDB 10150575Seric static DB *AliasDBptr; 10250575Seric #endif 10356845Seric #ifdef NDBM 10456845Seric static DBM *AliasDBMptr; 10556845Seric #endif 10650575Seric 10755012Seric alias(a, sendq, e) 1084097Seric register ADDRESS *a; 1094999Seric ADDRESS **sendq; 11055012Seric register ENVELOPE *e; 111292Seric { 1124081Seric register char *p; 1135701Seric extern char *aliaslookup(); 114292Seric 1157671Seric if (tTd(27, 1)) 1164098Seric printf("alias(%s)\n", a->q_paddr); 117292Seric 1184098Seric /* don't realias already aliased names */ 1194098Seric if (bitset(QDONTSEND, a->q_flags)) 1204098Seric return; 1214098Seric 12255012Seric e->e_to = a->q_paddr; 1234098Seric 1244314Seric /* 1254314Seric ** Look up this name 1264314Seric */ 1274314Seric 12824944Seric if (NoAlias) 12924944Seric p = NULL; 13024944Seric else 13124944Seric p = aliaslookup(a->q_user); 1324098Seric if (p == NULL) 1334098Seric return; 134292Seric 135292Seric /* 1364098Seric ** Match on Alias. 1374098Seric ** Deliver to the target list. 1381515Seric */ 1391515Seric 1407671Seric if (tTd(27, 1)) 1414098Seric printf("%s (%s, %s) aliased to %s\n", 1424098Seric a->q_paddr, a->q_host, a->q_user, p); 1437051Seric message(Arpa_Info, "aliased to %s", p); 1444098Seric AliasLevel++; 14555012Seric sendtolist(p, a, sendq, e); 1464098Seric AliasLevel--; 1474098Seric } 1484098Seric /* 1495701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1505701Seric ** 1515701Seric ** Parameters: 1525701Seric ** name -- the name to look up. 1535701Seric ** 1545701Seric ** Returns: 1555701Seric ** the value of name. 1565701Seric ** NULL if unknown. 1575701Seric ** 1585701Seric ** Side Effects: 1595701Seric ** none. 1605701Seric ** 1615701Seric ** Warnings: 1625701Seric ** The return value will be trashed across calls. 1635701Seric */ 1645701Seric 1655701Seric char * 1665701Seric aliaslookup(name) 1675701Seric char *name; 1685701Seric { 169*57381Seric int i; 170*57381Seric char keybuf[MAXNAME + 1]; 17156845Seric # if defined(NEWDB) || defined(NDBM) 17256845Seric DBdatum rhs, lhs; 17350575Seric int s; 174*57381Seric # else /* neither NEWDB nor NDBM */ 175*57381Seric register STAB *s; 176*57381Seric # endif 1775701Seric 1785701Seric /* create a key for fetch */ 179*57381Seric i = strlen(name) + 1; 180*57381Seric if (i > sizeof keybuf) 181*57381Seric i = sizeof keybuf; 182*57381Seric bcopy(name, keybuf, i); 183*57381Seric if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 184*57381Seric makelower(keybuf); 185*57381Seric 186*57381Seric # if defined(NEWDB) || defined(NDBM) 187*57381Seric lhs.xx.size = i; 188*57381Seric lhs.xx.data = keybuf; 18950575Seric # ifdef NEWDB 19051756Seric if (AliasDBptr != NULL) 19151756Seric { 192*57381Seric i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0); 193*57381Seric if (i == 0) 19456845Seric return (rhs.dbt.data); 19551756Seric } 19656845Seric # ifdef NDBM 19757249Seric else if (AliasDBMptr != NULL) 19851756Seric { 19956845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 20056845Seric return (rhs.dbm.dptr); 20151756Seric } 20256845Seric # endif /* NDBM */ 20356845Seric # else /* not NEWDB */ 20456845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 20556845Seric return (rhs.dbm.dptr); 20656845Seric # endif /* NEWDB */ 20756845Seric # else /* neither NEWDB nor NDBM */ 2085701Seric register STAB *s; 2095701Seric 210*57381Seric s = stab(keybuf, ST_ALIAS, ST_FIND); 21151756Seric if (s != NULL) 21251756Seric return (s->s_alias); 21351756Seric # endif 21451756Seric return (NULL); 2155701Seric } 2165701Seric /* 2174098Seric ** INITALIASES -- initialize for aliasing 2184098Seric ** 21956845Seric ** Very different depending on whether we are running NDBM or not. 2204098Seric ** 2214098Seric ** Parameters: 2224098Seric ** aliasfile -- location of aliases. 22356845Seric ** init -- if set and if NDBM, initialize the NDBM files. 2244098Seric ** 2254098Seric ** Returns: 2264098Seric ** none. 2274098Seric ** 2284098Seric ** Side Effects: 2294098Seric ** initializes aliases: 23056845Seric ** if NDBM: opens the database. 23156845Seric ** if ~NDBM: reads the aliases into the symbol table. 2324098Seric */ 2334098Seric 23440559Sbostic # define DBMMODE 0644 2354157Seric 23655012Seric initaliases(aliasfile, init, e) 2374098Seric char *aliasfile; 2384157Seric bool init; 23955012Seric register ENVELOPE *e; 2404098Seric { 24156845Seric #if defined(NDBM) || defined(NEWDB) 2428437Seric int atcnt; 24325522Seric time_t modtime; 24425522Seric bool automatic = FALSE; 2454322Seric char buf[MAXNAME]; 24650575Seric #endif 2479368Seric struct stat stb; 24827176Seric static bool initialized = FALSE; 24946928Sbostic static int readaliases(); 2504322Seric 25127176Seric if (initialized) 25227176Seric return; 25327176Seric initialized = TRUE; 25427176Seric 25517984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 2568437Seric { 25725522Seric if (aliasfile != NULL && init) 25825522Seric syserr("Cannot open %s", aliasfile); 2598437Seric NoAlias = TRUE; 26011937Seric errno = 0; 2618437Seric return; 2628437Seric } 2638437Seric 26456845Seric # if defined(NDBM) || defined(NEWDB) 2654322Seric /* 2668437Seric ** Check to see that the alias file is complete. 2678437Seric ** If not, we will assume that someone died, and it is up 2688437Seric ** to us to rebuild it. 2698437Seric */ 2708437Seric 27125689Seric if (!init) 27250575Seric { 27350575Seric # ifdef NEWDB 27450575Seric (void) strcpy(buf, aliasfile); 27550575Seric (void) strcat(buf, ".db"); 27651171Sbostic AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 27750576Seric if (AliasDBptr == NULL) 27850576Seric { 27956845Seric # ifdef NDBM 28056845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 28157249Seric if (AliasDBMptr == NULL) 28257249Seric { 28357249Seric syserr("initaliases: cannot open %s", buf); 28457249Seric NoAlias = TRUE; 28557249Seric return; 28657249Seric } 28751756Seric # else 28850576Seric syserr("initaliases: cannot open %s", buf); 28950576Seric NoAlias = TRUE; 29050576Seric return; 29151756Seric # endif 29250576Seric } 29350575Seric # else 29456845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 29557249Seric if (AliasDBMptr == NULL) 29657249Seric { 29757249Seric syserr("initaliases: cannot open %s", buf); 29857249Seric NoAlias = TRUE; 29957249Seric return; 30057249Seric } 30150575Seric # endif 30250575Seric } 30317471Seric atcnt = SafeAlias * 2; 30417471Seric if (atcnt > 0) 30517471Seric { 30617471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 30725689Seric { 30825689Seric /* 30925689Seric ** Reinitialize alias file in case the new 31025689Seric ** one is mv'ed in instead of cp'ed in. 31125689Seric ** 31225689Seric ** Only works with new DBM -- old one will 31325689Seric ** just consume file descriptors forever. 31425689Seric ** If you have a dbmclose() it can be 31525689Seric ** added before the sleep(30). 31625689Seric */ 31725689Seric 31850575Seric # ifdef NEWDB 31951756Seric if (AliasDBptr != NULL) 32051756Seric AliasDBptr->close(AliasDBptr); 32150575Seric # endif 32256845Seric # ifdef NDBM 32356845Seric if (AliasDBMptr != NULL) 32456845Seric dbm_close(AliasDBMptr); 32556845Seric # endif 32650575Seric 32717471Seric sleep(30); 32850575Seric # ifdef NEWDB 32950575Seric (void) strcpy(buf, aliasfile); 33050575Seric (void) strcat(buf, ".db"); 33151171Sbostic AliasDBptr = 33251171Sbostic dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 33350576Seric if (AliasDBptr == NULL) 33450576Seric { 33551756Seric # ifdef NDBM 33656845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 33751756Seric # else 33850576Seric syserr("initaliases: cannot open %s", buf); 33950576Seric NoAlias = TRUE; 34050576Seric return; 34151756Seric # endif 34250576Seric } 34350575Seric # else 34425689Seric # ifdef NDBM 34556845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 34657249Seric if (AliasDBMptr == NULL) 34757249Seric { 34857249Seric syserr("initaliases: cannot open %s", buf); 34957249Seric NoAlias = TRUE; 35057249Seric return; 35157249Seric } 35250575Seric # endif 35350575Seric # endif 35425689Seric } 35517471Seric } 35617471Seric else 35717471Seric atcnt = 1; 3588437Seric 3598437Seric /* 36056845Seric ** See if the NDBM version of the file is out of date with 3614322Seric ** the text version. If so, go into 'init' mode automatically. 36240559Sbostic ** This only happens if our effective userid owns the DBM. 36340559Sbostic ** Note the unpalatable hack to see if the stat succeeded. 3644322Seric */ 3654322Seric 3664322Seric modtime = stb.st_mtime; 3674322Seric (void) strcpy(buf, aliasfile); 36850575Seric # ifdef NEWDB 36950575Seric (void) strcat(buf, ".db"); 37050575Seric # else 3714322Seric (void) strcat(buf, ".pag"); 37250575Seric # endif 3734322Seric stb.st_ino = 0; 37419039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 3754322Seric { 37611937Seric errno = 0; 37740559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3784322Seric { 3794322Seric init = TRUE; 38025522Seric automatic = TRUE; 3817051Seric message(Arpa_Info, "rebuilding alias database"); 38224944Seric #ifdef LOG 38324944Seric if (LogLevel >= 7) 38424944Seric syslog(LOG_INFO, "rebuilding alias database"); 38556795Seric #endif /* LOG */ 3864322Seric } 3874322Seric else 3884322Seric { 38919039Seric #ifdef LOG 39024944Seric if (LogLevel >= 7) 39124944Seric syslog(LOG_INFO, "alias database out of date"); 39256795Seric #endif /* LOG */ 3934322Seric message(Arpa_Info, "Warning: alias database out of date"); 3944322Seric } 3954322Seric } 3964322Seric 3974322Seric 3984322Seric /* 39956845Seric ** If necessary, load the NDBM file. 40056845Seric ** If running without NDBM, load the symbol table. 4014322Seric */ 4024322Seric 4034157Seric if (init) 4048437Seric { 40525522Seric #ifdef LOG 40625522Seric if (LogLevel >= 6) 40725522Seric { 40825522Seric extern char *username(); 40925522Seric 41025522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 41125522Seric automatic ? "auto" : "", username()); 41225522Seric } 41356795Seric #endif /* LOG */ 41455012Seric readaliases(aliasfile, TRUE, e); 4158437Seric } 41656845Seric # else /* NDBM */ 41755012Seric readaliases(aliasfile, init, e); 41856845Seric # endif /* NDBM */ 4194157Seric } 4204157Seric /* 4214157Seric ** READALIASES -- read and process the alias file. 4224157Seric ** 4234157Seric ** This routine implements the part of initaliases that occurs 4244157Seric ** when we are not going to use the DBM stuff. 4254157Seric ** 4264157Seric ** Parameters: 4274157Seric ** aliasfile -- the pathname of the alias file master. 42856845Seric ** init -- if set, initialize the NDBM stuff. 4294157Seric ** 4304157Seric ** Returns: 4314157Seric ** none. 4324157Seric ** 4334157Seric ** Side Effects: 4344157Seric ** Reads aliasfile into the symbol table. 4354157Seric ** Optionally, builds the .dir & .pag files. 4364157Seric */ 4374157Seric 4384157Seric static 43955012Seric readaliases(aliasfile, init, e) 4404157Seric char *aliasfile; 4414157Seric bool init; 44255012Seric register ENVELOPE *e; 4434157Seric { 4444098Seric register char *p; 4454098Seric char *rhs; 4464098Seric bool skipping; 4479368Seric int naliases, bytes, longest; 4489368Seric FILE *af; 44953742Seric bool makedbmfiles; 45040970Sbostic void (*oldsigint)(); 4514098Seric ADDRESS al, bl; 4524106Seric register STAB *s; 45350575Seric # ifdef NEWDB 45450575Seric DB *dbp; 45550575Seric # endif 45656845Seric # ifdef NDBM 45756845Seric DBM *dbmp; 45856845Seric # endif 45951937Seric # ifdef LOCKF 46051937Seric struct flock fld; 46151937Seric # endif 4629368Seric char line[BUFSIZ]; 4634098Seric 46451937Seric if ((af = fopen(aliasfile, "r+")) == NULL) 4651515Seric { 46657249Seric if (init) 46757249Seric syserr("Can't open %s", aliasfile); 46857249Seric else if (tTd(27, 1)) 4694106Seric printf("Can't open %s\n", aliasfile); 4704098Seric errno = 0; 4714098Seric NoAlias++; 4724098Seric return; 4734098Seric } 4744314Seric 47556845Seric # if defined(NDBM) || defined(NEWDB) 47619784Seric /* see if someone else is rebuilding the alias file already */ 47751835Seric # ifdef LOCKF 47851937Seric fld.l_type = F_WRLCK; 47951937Seric fld.l_whence = fld.l_start = fld.l_len = 0; 48051937Seric if (fcntl(fileno(af), F_SETLK, &fld) < 0) 48151835Seric # else 48219784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 48351835Seric # endif 48419784Seric { 48519784Seric /* yes, they are -- wait until done and then return */ 48619784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 48719784Seric if (OpMode != MD_INITALIAS) 48819784Seric { 48919784Seric /* wait for other rebuild to complete */ 49051835Seric # ifdef LOCKF 49151937Seric (void) fcntl(fileno(af), F_SETLKW, &fld); 49251835Seric # else 49319784Seric (void) flock(fileno(af), LOCK_EX); 49451835Seric # endif 49519784Seric } 49623108Seric (void) fclose(af); 49719784Seric errno = 0; 49819784Seric return; 49919784Seric } 50056845Seric # endif /* NDBM */ 50119784Seric 5024314Seric /* 50319784Seric ** If initializing, create the new DBM files. 50419784Seric */ 50519784Seric 50619784Seric if (init) 50719784Seric { 50819784Seric oldsigint = signal(SIGINT, SIG_IGN); 50951756Seric # ifdef NEWDB 51051756Seric (void) strcpy(line, aliasfile); 51151756Seric (void) strcat(line, ".db"); 51251756Seric dbp = dbopen(line, 51351756Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 51451756Seric if (dbp == NULL) 51551756Seric { 51651756Seric syserr("readaliases: cannot create %s", line); 51751756Seric (void) signal(SIGINT, oldsigint); 51851756Seric return; 51951756Seric } 52053742Seric # endif 52153742Seric # ifdef IF_MAKEDBMFILES 52253742Seric # ifdef NEWDB 52353742Seric makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 52453742Seric # endif 52553742Seric IF_MAKEDBMFILES 52619784Seric { 52756845Seric dbmp = dbm_open(aliasfile, 52856845Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 52956845Seric if (dbmp == NULL) 53053742Seric { 53156845Seric syserr("readaliases: cannot create %s.{dir,pag}", 53256845Seric aliasfile); 53353742Seric (void) signal(SIGINT, oldsigint); 53453742Seric return; 53553742Seric } 53619784Seric } 53750575Seric # endif 53819784Seric } 53919784Seric 54019784Seric /* 5414314Seric ** Read and interpret lines 5424314Seric */ 5434314Seric 5449368Seric FileName = aliasfile; 5459368Seric LineNumber = 0; 5464322Seric naliases = bytes = longest = 0; 5474098Seric skipping = FALSE; 5484098Seric while (fgets(line, sizeof (line), af) != NULL) 5494098Seric { 5504322Seric int lhssize, rhssize; 5514322Seric 5529368Seric LineNumber++; 55356795Seric p = strchr(line, '\n'); 55425278Seric if (p != NULL) 55525278Seric *p = '\0'; 5564098Seric switch (line[0]) 5574098Seric { 5584098Seric case '#': 5594098Seric case '\0': 5604098Seric skipping = FALSE; 5614098Seric continue; 5624065Seric 5634098Seric case ' ': 5644098Seric case '\t': 5654098Seric if (!skipping) 5669368Seric syserr("Non-continuation line starts with space"); 5674098Seric skipping = TRUE; 5684097Seric continue; 5694098Seric } 5704098Seric skipping = FALSE; 5711874Seric 5724314Seric /* 5734314Seric ** Process the LHS 5744314Seric ** Find the final colon, and parse the address. 57516898Seric ** It should resolve to a local name -- this will 57616898Seric ** be checked later (we want to optionally do 57716898Seric ** parsing of the RHS first to maximize error 57816898Seric ** detection). 5794314Seric */ 5804314Seric 5814098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5824097Seric continue; 58316898Seric if (*p++ != ':') 5844098Seric { 5859368Seric syserr("missing colon"); 5864097Seric continue; 5874098Seric } 58855012Seric if (parseaddr(line, &al, 1, ':', e) == NULL) 5894098Seric { 59016898Seric syserr("illegal alias name"); 59116898Seric continue; 5924098Seric } 59316898Seric loweraddr(&al); 5944314Seric 5954314Seric /* 5964314Seric ** Process the RHS. 5974314Seric ** 'al' is the internal form of the LHS address. 5984314Seric ** 'p' points to the text of the RHS. 5994314Seric */ 6004314Seric 6014098Seric rhs = p; 6024098Seric for (;;) 6034098Seric { 6044098Seric register char c; 6051515Seric 60625821Seric if (init && CheckAliases) 6074098Seric { 6084157Seric /* do parsing & compression of addresses */ 60925278Seric while (*p != '\0') 6104098Seric { 61125278Seric extern char *DelimChar; 61225278Seric 61325278Seric while (isspace(*p) || *p == ',') 6144157Seric p++; 61525278Seric if (*p == '\0') 61625278Seric break; 61755012Seric if (parseaddr(p, &bl, -1, ',', e) == NULL) 61825278Seric usrerr("%s... bad address", p); 61925278Seric p = DelimChar; 6204098Seric } 6214098Seric } 6224157Seric else 62315769Seric { 62416898Seric p = &p[strlen(p)]; 62516898Seric if (p[-1] == '\n') 62616898Seric *--p = '\0'; 62715769Seric } 6281515Seric 6294098Seric /* see if there should be a continuation line */ 6304106Seric c = fgetc(af); 6314106Seric if (!feof(af)) 6324314Seric (void) ungetc(c, af); 6334106Seric if (c != ' ' && c != '\t') 6344098Seric break; 6354098Seric 6364098Seric /* read continuation line */ 6374098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6384098Seric break; 6399368Seric LineNumber++; 64057135Seric 64157135Seric /* check for line overflow */ 64257135Seric if (strchr(p, '\n') == NULL) 64357135Seric { 64457135Seric usrerr("alias too long"); 64557135Seric break; 64657135Seric } 6474098Seric } 64816898Seric if (al.q_mailer != LocalMailer) 64916898Seric { 65016898Seric syserr("cannot alias non-local names"); 65116898Seric continue; 65216898Seric } 6534314Seric 6544314Seric /* 6554314Seric ** Insert alias into symbol table or DBM file 6564314Seric */ 6574314Seric 65816898Seric lhssize = strlen(al.q_user) + 1; 659*57381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 660*57381Seric makelower(al.q_user); 6614322Seric rhssize = strlen(rhs) + 1; 6624322Seric 66356845Seric # if defined(NDBM) || defined(NEWDB) 6644157Seric if (init) 6654157Seric { 66656845Seric DBdatum key, content; 667*57381Seric int putstat; 6684157Seric 66956845Seric key.xx.size = lhssize; 67056845Seric key.xx.data = al.q_user; 67156845Seric content.xx.size = rhssize; 67256845Seric content.xx.data = rhs; 67351756Seric # ifdef NEWDB 674*57381Seric putstat = dbp->put(dbp, &key.dbt, &content.dbt, 675*57381Seric R_NOOVERWRITE); 676*57381Seric if (putstat > 0) 677*57381Seric { 678*57381Seric usrerr("Warning: duplicate alias name %s", 679*57381Seric al.q_user); 680*57381Seric putstat = dbp->put(dbp, &key.dbt, 681*57381Seric &content.dbt, 0); 682*57381Seric } 683*57381Seric if (putstat != 0) 68450576Seric syserr("readaliases: db put (%s)", al.q_user); 68550575Seric # endif 68653742Seric # ifdef IF_MAKEDBMFILES 68753742Seric IF_MAKEDBMFILES 688*57381Seric { 689*57381Seric putstat = dbm_store(dbmp, key.dbm, content.dbm, 690*57381Seric DBM_INSERT); 691*57381Seric if (putstat > 0) 692*57381Seric { 693*57381Seric usrerr("Warning: duplicate alias name %s", 694*57381Seric al.q_user); 695*57381Seric putstat = dbm_store(dbmp, key.dbm, 696*57381Seric content.dbm, DBM_REPLACE); 697*57381Seric } 698*57381Seric if (putstat != 0) 69956845Seric syserr("readaliases: dbm store (%s)", 70056845Seric al.q_user); 701*57381Seric } 70253742Seric # endif 703*57381Seric if (al.q_paddr != NULL) 704*57381Seric free(al.q_paddr); 705*57381Seric if (al.q_host != NULL) 706*57381Seric free(al.q_host); 707*57381Seric if (al.q_user != NULL) 708*57381Seric free(al.q_user); 7094157Seric } 7104157Seric else 71156845Seric # endif /* NDBM */ 7124157Seric { 7134157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 7144157Seric s->s_alias = newstr(rhs); 7154157Seric } 7164322Seric 7174322Seric /* statistics */ 7184322Seric naliases++; 7194322Seric bytes += lhssize + rhssize; 7204322Seric if (rhssize > longest) 7214322Seric longest = rhssize; 7221515Seric } 72319784Seric 72456845Seric # if defined(NDBM) || defined(NEWDB) 72519784Seric if (init) 72619784Seric { 72719784Seric /* add the distinquished alias "@" */ 72856845Seric DBdatum key; 72919784Seric 73056845Seric key.xx.size = 2; 73156845Seric key.xx.data = "@"; 73250575Seric # ifdef NEWDB 73350576Seric if (dbp->sync(dbp) != 0 || 73456845Seric dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 73550576Seric dbp->close(dbp) != 0) 73650576Seric syserr("readaliases: db close failure"); 73753742Seric # endif 73856789Seric # ifdef IF_MAKEDBMFILES 73956793Seric IF_MAKEDBMFILES 74056845Seric { 74156845Seric if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 74256845Seric dbm_error(dbmp)) 74356845Seric syserr("readaliases: dbm close failure"); 74456845Seric dbm_close(dbmp); 74556845Seric } 74650575Seric # endif 74719784Seric 74819784Seric /* restore the old signal */ 74919784Seric (void) signal(SIGINT, oldsigint); 75019784Seric } 75156845Seric # endif /* NDBM */ 75219784Seric 75319784Seric /* closing the alias file drops the lock */ 7544098Seric (void) fclose(af); 75555012Seric e->e_to = NULL; 7569368Seric FileName = NULL; 7577051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 7584322Seric naliases, longest, bytes); 75924944Seric # ifdef LOG 76024944Seric if (LogLevel >= 8) 76124944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 76224944Seric naliases, longest, bytes); 76356795Seric # endif /* LOG */ 764292Seric } 765292Seric /* 766292Seric ** FORWARD -- Try to forward mail 767292Seric ** 768292Seric ** This is similar but not identical to aliasing. 769292Seric ** 770292Seric ** Parameters: 7714314Seric ** user -- the name of the user who's mail we would like 7724314Seric ** to forward to. It must have been verified -- 7734314Seric ** i.e., the q_home field must have been filled 7744314Seric ** in. 7754999Seric ** sendq -- a pointer to the head of the send queue to 7764999Seric ** put this user's aliases in. 777292Seric ** 778292Seric ** Returns: 7794098Seric ** none. 780292Seric ** 781292Seric ** Side Effects: 7823185Seric ** New names are added to send queues. 783292Seric */ 784292Seric 78555012Seric forward(user, sendq, e) 7862966Seric ADDRESS *user; 7874999Seric ADDRESS **sendq; 78855012Seric register ENVELOPE *e; 789292Seric { 79057136Seric char *pp; 79157136Seric char *ep; 7924536Seric extern bool safefile(); 7934069Seric 7947671Seric if (tTd(27, 1)) 7954098Seric printf("forward(%s)\n", user->q_paddr); 7964098Seric 7974594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 7984098Seric return; 7994314Seric if (user->q_home == NULL) 8004314Seric syserr("forward: no home"); 8014069Seric 8024069Seric /* good address -- look for .forward file in home */ 80355012Seric define('z', user->q_home, e); 80457136Seric define('u', user->q_user, e); 80557136Seric define('h', user->q_host, e); 80657136Seric if (ForwardPath == NULL) 80757136Seric ForwardPath = newstr("\001z/.forward"); 80857136Seric 80957136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 81057136Seric { 81157232Seric char buf[MAXPATHLEN+1]; 81257136Seric 81357136Seric ep = strchr(pp, ':'); 81457136Seric if (ep != NULL) 81557136Seric *ep = '\0'; 81657136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 81757136Seric if (ep != NULL) 81857136Seric *ep++ = ':'; 81957136Seric if (tTd(27, 3)) 82057136Seric printf("forward: trying %s\n", buf); 82157136Seric if (include(buf, TRUE, user, sendq, e) == 0) 82257136Seric break; 82357136Seric } 824292Seric } 825