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> 1157948Seric # include <sys/file.h> 1250577Seric # include <signal.h> 1350577Seric # include "sendmail.h" 1457737Seric # include <fcntl.h> 1550577Seric # include <pwd.h> 1650577Seric 1756845Seric # ifdef DBM 1856848Seric ERROR: DBM is no longer supported -- use NDBM instead. 1956845Seric # endif 2056845Seric 2150577Seric # ifdef NEWDB 2250577Seric # include <db.h> 2350577Seric # endif 2450577Seric 2556766Seric # ifdef NDBM 2656845Seric # include <ndbm.h> 2756766Seric # endif 2856766Seric 2933728Sbostic #ifndef lint 3051756Seric #ifdef NEWDB 3157736Seric #ifdef NDBM 32*58065Seric static char sccsid[] = "@(#)alias.c 6.13 (Berkeley) 02/19/93 (with NEWDB and NDBM)"; 3351756Seric #else 34*58065Seric static char sccsid[] = "@(#)alias.c 6.13 (Berkeley) 02/19/93 (with NEWDB)"; 3557736Seric #endif 3657736Seric #else 3756845Seric #ifdef NDBM 38*58065Seric static char sccsid[] = "@(#)alias.c 6.13 (Berkeley) 02/19/93 (with NDBM)"; 3933728Sbostic #else 40*58065Seric static char sccsid[] = "@(#)alias.c 6.13 (Berkeley) 02/19/93 (without NEWDB or NDBM)"; 4133728Sbostic #endif 4250575Seric #endif 4333728Sbostic #endif /* not lint */ 4451756Seric /* 45292Seric ** ALIAS -- Compute aliases. 46292Seric ** 479368Seric ** Scans the alias file for an alias for the given address. 489368Seric ** If found, it arranges to deliver to the alias list instead. 499368Seric ** Uses libdbm database if -DDBM. 50292Seric ** 51292Seric ** Parameters: 524097Seric ** a -- address to alias. 534999Seric ** sendq -- a pointer to the head of the send queue 544999Seric ** to put the aliases in. 55292Seric ** 56292Seric ** Returns: 57292Seric ** none 58292Seric ** 59292Seric ** Side Effects: 603185Seric ** Aliases found are expanded. 61292Seric ** 62292Seric ** Notes: 63292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 64292Seric ** done. 65292Seric ** 66292Seric ** Deficiencies: 67292Seric ** It should complain about names that are aliased to 68292Seric ** nothing. 69292Seric */ 70292Seric 71292Seric 7253742Seric /* 7353742Seric ** Sun YP servers read the dbm files directly, so we have to build them 7453742Seric ** even if NEWDB 7553742Seric */ 7653742Seric 7756845Seric #ifdef NDBM 7853742Seric # ifndef NEWDB 7953742Seric # define IF_MAKEDBMFILES 8053742Seric # else 8153742Seric # ifdef YPCOMPAT 8253742Seric # define IF_MAKEDBMFILES if (makedbmfiles) 8353742Seric # endif 8453742Seric # endif 8553742Seric #endif 8653742Seric 8756845Seric typedef union 882966Seric { 8956845Seric #ifdef NDBM 9056845Seric datum dbm; 9151756Seric #endif 9256845Seric #ifdef NEWDB 9356845Seric DBT dbt; 9456845Seric #endif 9556845Seric struct 9656845Seric { 9756845Seric char *data; 9856845Seric int size; 9956845Seric } xx; 10056845Seric } DBdatum; 101292Seric 10250575Seric #ifdef NEWDB 10350575Seric static DB *AliasDBptr; 10450575Seric #endif 10556845Seric #ifdef NDBM 10656845Seric static DBM *AliasDBMptr; 10756845Seric #endif 10850575Seric 10955012Seric alias(a, sendq, e) 1104097Seric register ADDRESS *a; 1114999Seric ADDRESS **sendq; 11255012Seric register ENVELOPE *e; 113292Seric { 1144081Seric register char *p; 1155701Seric extern char *aliaslookup(); 116292Seric 1177671Seric if (tTd(27, 1)) 1184098Seric printf("alias(%s)\n", a->q_paddr); 119292Seric 1204098Seric /* don't realias already aliased names */ 1214098Seric if (bitset(QDONTSEND, a->q_flags)) 1224098Seric return; 1234098Seric 12455012Seric e->e_to = a->q_paddr; 1254098Seric 1264314Seric /* 1274314Seric ** Look up this name 1284314Seric */ 1294314Seric 13024944Seric if (NoAlias) 13124944Seric p = NULL; 13224944Seric else 13324944Seric p = aliaslookup(a->q_user); 1344098Seric if (p == NULL) 1354098Seric return; 136292Seric 137292Seric /* 1384098Seric ** Match on Alias. 1394098Seric ** Deliver to the target list. 1401515Seric */ 1411515Seric 1427671Seric if (tTd(27, 1)) 1434098Seric printf("%s (%s, %s) aliased to %s\n", 1444098Seric a->q_paddr, a->q_host, a->q_user, p); 1457051Seric message(Arpa_Info, "aliased to %s", p); 14657977Seric #ifdef LOG 14758020Seric if (LogLevel > 9) 14857977Seric syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 14957977Seric #endif 1504098Seric AliasLevel++; 15155012Seric sendtolist(p, a, sendq, e); 1524098Seric AliasLevel--; 153*58065Seric if (!bitset(QSELFREF, a->q_flags)) 154*58065Seric { 155*58065Seric if (tTd(27, 5)) 156*58065Seric { 157*58065Seric printf("alias: QDONTSEND "); 158*58065Seric printaddr(a, FALSE); 159*58065Seric } 160*58065Seric a->q_flags |= QDONTSEND; 161*58065Seric } 1624098Seric } 1634098Seric /* 1645701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1655701Seric ** 1665701Seric ** Parameters: 1675701Seric ** name -- the name to look up. 1685701Seric ** 1695701Seric ** Returns: 1705701Seric ** the value of name. 1715701Seric ** NULL if unknown. 1725701Seric ** 1735701Seric ** Side Effects: 1745701Seric ** none. 1755701Seric ** 1765701Seric ** Warnings: 1775701Seric ** The return value will be trashed across calls. 1785701Seric */ 1795701Seric 1805701Seric char * 1815701Seric aliaslookup(name) 1825701Seric char *name; 1835701Seric { 18457381Seric int i; 18557381Seric char keybuf[MAXNAME + 1]; 18656845Seric # if defined(NEWDB) || defined(NDBM) 18756845Seric DBdatum rhs, lhs; 18850575Seric int s; 18957381Seric # else /* neither NEWDB nor NDBM */ 19057381Seric register STAB *s; 19157381Seric # endif 1925701Seric 1935701Seric /* create a key for fetch */ 19457381Seric i = strlen(name) + 1; 19557381Seric if (i > sizeof keybuf) 19657381Seric i = sizeof keybuf; 19757381Seric bcopy(name, keybuf, i); 19857381Seric if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 19957381Seric makelower(keybuf); 20057381Seric 20157381Seric # if defined(NEWDB) || defined(NDBM) 20257381Seric lhs.xx.size = i; 20357381Seric lhs.xx.data = keybuf; 20450575Seric # ifdef NEWDB 20551756Seric if (AliasDBptr != NULL) 20651756Seric { 20757381Seric i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0); 20857381Seric if (i == 0) 20956845Seric return (rhs.dbt.data); 21051756Seric } 21156845Seric # ifdef NDBM 21257249Seric else if (AliasDBMptr != NULL) 21351756Seric { 21456845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 21556845Seric return (rhs.dbm.dptr); 21651756Seric } 21756845Seric # endif /* NDBM */ 21857530Seric return (NULL); 21956845Seric # else /* not NEWDB */ 22056845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 22156845Seric return (rhs.dbm.dptr); 22256845Seric # endif /* NEWDB */ 22356845Seric # else /* neither NEWDB nor NDBM */ 22457381Seric s = stab(keybuf, ST_ALIAS, ST_FIND); 22551756Seric if (s != NULL) 22651756Seric return (s->s_alias); 22757530Seric return (NULL); 22851756Seric # endif 2295701Seric } 2305701Seric /* 2314098Seric ** INITALIASES -- initialize for aliasing 2324098Seric ** 23356845Seric ** Very different depending on whether we are running NDBM or not. 2344098Seric ** 2354098Seric ** Parameters: 2364098Seric ** aliasfile -- location of aliases. 23756845Seric ** init -- if set and if NDBM, initialize the NDBM files. 2384098Seric ** 2394098Seric ** Returns: 2404098Seric ** none. 2414098Seric ** 2424098Seric ** Side Effects: 2434098Seric ** initializes aliases: 24456845Seric ** if NDBM: opens the database. 24556845Seric ** if ~NDBM: reads the aliases into the symbol table. 2464098Seric */ 2474098Seric 24840559Sbostic # define DBMMODE 0644 2494157Seric 25055012Seric initaliases(aliasfile, init, e) 2514098Seric char *aliasfile; 2524157Seric bool init; 25355012Seric register ENVELOPE *e; 2544098Seric { 25556845Seric #if defined(NDBM) || defined(NEWDB) 2568437Seric int atcnt; 25725522Seric time_t modtime; 25825522Seric bool automatic = FALSE; 2594322Seric char buf[MAXNAME]; 26050575Seric #endif 2619368Seric struct stat stb; 26227176Seric static bool initialized = FALSE; 26346928Sbostic static int readaliases(); 2644322Seric 26527176Seric if (initialized) 26627176Seric return; 26727176Seric initialized = TRUE; 26827176Seric 26917984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 2708437Seric { 27125522Seric if (aliasfile != NULL && init) 27225522Seric syserr("Cannot open %s", aliasfile); 2738437Seric NoAlias = TRUE; 27411937Seric errno = 0; 2758437Seric return; 2768437Seric } 2778437Seric 27856845Seric # if defined(NDBM) || defined(NEWDB) 2794322Seric /* 2808437Seric ** Check to see that the alias file is complete. 2818437Seric ** If not, we will assume that someone died, and it is up 2828437Seric ** to us to rebuild it. 2838437Seric */ 2848437Seric 28525689Seric if (!init) 28650575Seric { 28750575Seric # ifdef NEWDB 28850575Seric (void) strcpy(buf, aliasfile); 28950575Seric (void) strcat(buf, ".db"); 29051171Sbostic AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 29150576Seric if (AliasDBptr == NULL) 29250576Seric { 29356845Seric # ifdef NDBM 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 } 30151756Seric # else 30250576Seric syserr("initaliases: cannot open %s", buf); 30350576Seric NoAlias = TRUE; 30450576Seric return; 30551756Seric # endif 30650576Seric } 30750575Seric # else 30856845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 30957249Seric if (AliasDBMptr == NULL) 31057249Seric { 31157977Seric syserr("initaliases: cannot open DBM database %s.{pag,dir}", 31257977Seric aliasfile); 31357249Seric NoAlias = TRUE; 31457249Seric return; 31557249Seric } 31650575Seric # endif 31750575Seric } 31817471Seric atcnt = SafeAlias * 2; 31917471Seric if (atcnt > 0) 32017471Seric { 32117471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 32225689Seric { 32325689Seric /* 32425689Seric ** Reinitialize alias file in case the new 32525689Seric ** one is mv'ed in instead of cp'ed in. 32625689Seric ** 32725689Seric ** Only works with new DBM -- old one will 32825689Seric ** just consume file descriptors forever. 32925689Seric ** If you have a dbmclose() it can be 33025689Seric ** added before the sleep(30). 33125689Seric */ 33225689Seric 33350575Seric # ifdef NEWDB 33451756Seric if (AliasDBptr != NULL) 33551756Seric AliasDBptr->close(AliasDBptr); 33650575Seric # endif 33756845Seric # ifdef NDBM 33856845Seric if (AliasDBMptr != NULL) 33956845Seric dbm_close(AliasDBMptr); 34056845Seric # endif 34150575Seric 34217471Seric sleep(30); 34350575Seric # ifdef NEWDB 34450575Seric (void) strcpy(buf, aliasfile); 34550575Seric (void) strcat(buf, ".db"); 34651171Sbostic AliasDBptr = 34751171Sbostic dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 34850576Seric if (AliasDBptr == NULL) 34950576Seric { 35051756Seric # ifdef NDBM 35156845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 35251756Seric # else 35350576Seric syserr("initaliases: cannot open %s", buf); 35450576Seric NoAlias = TRUE; 35550576Seric return; 35651756Seric # endif 35750576Seric } 35850575Seric # else 35925689Seric # ifdef NDBM 36056845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 36157249Seric if (AliasDBMptr == NULL) 36257249Seric { 36358008Seric syserr("initaliases: cannot open DBM database %s.{pag,dir}", 36458008Seric aliasfile); 36557249Seric NoAlias = TRUE; 36657249Seric return; 36757249Seric } 36850575Seric # endif 36950575Seric # endif 37025689Seric } 37117471Seric } 37217471Seric else 37317471Seric atcnt = 1; 3748437Seric 3758437Seric /* 37656845Seric ** See if the NDBM version of the file is out of date with 3774322Seric ** the text version. If so, go into 'init' mode automatically. 37840559Sbostic ** This only happens if our effective userid owns the DBM. 37940559Sbostic ** Note the unpalatable hack to see if the stat succeeded. 3804322Seric */ 3814322Seric 3824322Seric modtime = stb.st_mtime; 3834322Seric (void) strcpy(buf, aliasfile); 38450575Seric # ifdef NEWDB 38550575Seric (void) strcat(buf, ".db"); 38650575Seric # else 3874322Seric (void) strcat(buf, ".pag"); 38850575Seric # endif 3894322Seric stb.st_ino = 0; 39019039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 3914322Seric { 39211937Seric errno = 0; 39340559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3944322Seric { 3954322Seric init = TRUE; 39625522Seric automatic = TRUE; 3977051Seric message(Arpa_Info, "rebuilding alias database"); 39824944Seric #ifdef LOG 39958020Seric if (LogLevel > 14) 40024944Seric syslog(LOG_INFO, "rebuilding alias database"); 40156795Seric #endif /* LOG */ 4024322Seric } 4034322Seric else 4044322Seric { 40519039Seric #ifdef LOG 40658020Seric if (LogLevel > 3) 40724944Seric syslog(LOG_INFO, "alias database out of date"); 40856795Seric #endif /* LOG */ 4094322Seric message(Arpa_Info, "Warning: alias database out of date"); 4104322Seric } 4114322Seric } 4124322Seric 4134322Seric 4144322Seric /* 41556845Seric ** If necessary, load the NDBM file. 41656845Seric ** If running without NDBM, load the symbol table. 4174322Seric */ 4184322Seric 4194157Seric if (init) 4208437Seric { 42125522Seric #ifdef LOG 42258020Seric if (LogLevel > 7) 42325522Seric { 42425522Seric extern char *username(); 42525522Seric 42625522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 42725522Seric automatic ? "auto" : "", username()); 42825522Seric } 42956795Seric #endif /* LOG */ 43055012Seric readaliases(aliasfile, TRUE, e); 4318437Seric } 43256845Seric # else /* NDBM */ 43355012Seric readaliases(aliasfile, init, e); 43456845Seric # endif /* NDBM */ 4354157Seric } 4364157Seric /* 4374157Seric ** READALIASES -- read and process the alias file. 4384157Seric ** 4394157Seric ** This routine implements the part of initaliases that occurs 4404157Seric ** when we are not going to use the DBM stuff. 4414157Seric ** 4424157Seric ** Parameters: 4434157Seric ** aliasfile -- the pathname of the alias file master. 44456845Seric ** init -- if set, initialize the NDBM stuff. 4454157Seric ** 4464157Seric ** Returns: 4474157Seric ** none. 4484157Seric ** 4494157Seric ** Side Effects: 4504157Seric ** Reads aliasfile into the symbol table. 4514157Seric ** Optionally, builds the .dir & .pag files. 4524157Seric */ 4534157Seric 4544157Seric static 45555012Seric readaliases(aliasfile, init, e) 4564157Seric char *aliasfile; 4574157Seric bool init; 45855012Seric register ENVELOPE *e; 4594157Seric { 4604098Seric register char *p; 4614098Seric char *rhs; 4624098Seric bool skipping; 4639368Seric int naliases, bytes, longest; 4649368Seric FILE *af; 46553742Seric bool makedbmfiles; 46640970Sbostic void (*oldsigint)(); 4674098Seric ADDRESS al, bl; 4684106Seric register STAB *s; 46950575Seric # ifdef NEWDB 47050575Seric DB *dbp; 47150575Seric # endif 47256845Seric # ifdef NDBM 47356845Seric DBM *dbmp; 47456845Seric # endif 47551937Seric # ifdef LOCKF 47651937Seric struct flock fld; 47751937Seric # endif 4789368Seric char line[BUFSIZ]; 4794098Seric 48051937Seric if ((af = fopen(aliasfile, "r+")) == NULL) 4811515Seric { 48257249Seric if (init) 48357249Seric syserr("Can't open %s", aliasfile); 48457249Seric else if (tTd(27, 1)) 4854106Seric printf("Can't open %s\n", aliasfile); 4864098Seric errno = 0; 4874098Seric NoAlias++; 4884098Seric return; 4894098Seric } 4904314Seric 49156845Seric # if defined(NDBM) || defined(NEWDB) 49219784Seric /* see if someone else is rebuilding the alias file already */ 49351835Seric # ifdef LOCKF 49451937Seric fld.l_type = F_WRLCK; 49551937Seric fld.l_whence = fld.l_start = fld.l_len = 0; 49651937Seric if (fcntl(fileno(af), F_SETLK, &fld) < 0) 49751835Seric # else 49819784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 49951835Seric # endif 50019784Seric { 50119784Seric /* yes, they are -- wait until done and then return */ 50219784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 50319784Seric if (OpMode != MD_INITALIAS) 50419784Seric { 50519784Seric /* wait for other rebuild to complete */ 50651835Seric # ifdef LOCKF 50751937Seric (void) fcntl(fileno(af), F_SETLKW, &fld); 50851835Seric # else 50919784Seric (void) flock(fileno(af), LOCK_EX); 51051835Seric # endif 51119784Seric } 51223108Seric (void) fclose(af); 51319784Seric errno = 0; 51419784Seric return; 51519784Seric } 51656845Seric # endif /* NDBM */ 51719784Seric 5184314Seric /* 51919784Seric ** If initializing, create the new DBM files. 52019784Seric */ 52119784Seric 52219784Seric if (init) 52319784Seric { 52419784Seric oldsigint = signal(SIGINT, SIG_IGN); 52551756Seric # ifdef NEWDB 52651756Seric (void) strcpy(line, aliasfile); 52751756Seric (void) strcat(line, ".db"); 52851756Seric dbp = dbopen(line, 52951756Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 53051756Seric if (dbp == NULL) 53151756Seric { 53251756Seric syserr("readaliases: cannot create %s", line); 53351756Seric (void) signal(SIGINT, oldsigint); 53451756Seric return; 53551756Seric } 53653742Seric # endif 53753742Seric # ifdef IF_MAKEDBMFILES 53853742Seric # ifdef NEWDB 53953742Seric makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 54053742Seric # endif 54153742Seric IF_MAKEDBMFILES 54219784Seric { 54356845Seric dbmp = dbm_open(aliasfile, 54456845Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 54556845Seric if (dbmp == NULL) 54653742Seric { 54756845Seric syserr("readaliases: cannot create %s.{dir,pag}", 54856845Seric aliasfile); 54953742Seric (void) signal(SIGINT, oldsigint); 55053742Seric return; 55153742Seric } 55219784Seric } 55350575Seric # endif 55419784Seric } 55519784Seric 55619784Seric /* 5574314Seric ** Read and interpret lines 5584314Seric */ 5594314Seric 5609368Seric FileName = aliasfile; 5619368Seric LineNumber = 0; 5624322Seric naliases = bytes = longest = 0; 5634098Seric skipping = FALSE; 5644098Seric while (fgets(line, sizeof (line), af) != NULL) 5654098Seric { 5664322Seric int lhssize, rhssize; 5674322Seric 5689368Seric LineNumber++; 56956795Seric p = strchr(line, '\n'); 57025278Seric if (p != NULL) 57125278Seric *p = '\0'; 5724098Seric switch (line[0]) 5734098Seric { 5744098Seric case '#': 5754098Seric case '\0': 5764098Seric skipping = FALSE; 5774098Seric continue; 5784065Seric 5794098Seric case ' ': 5804098Seric case '\t': 5814098Seric if (!skipping) 5829368Seric syserr("Non-continuation line starts with space"); 5834098Seric skipping = TRUE; 5844097Seric continue; 5854098Seric } 5864098Seric skipping = FALSE; 5871874Seric 5884314Seric /* 5894314Seric ** Process the LHS 59057736Seric ** Find the colon separator, and parse the address. 59116898Seric ** It should resolve to a local name -- this will 59216898Seric ** be checked later (we want to optionally do 59316898Seric ** parsing of the RHS first to maximize error 59416898Seric ** detection). 5954314Seric */ 5964314Seric 5974098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5984097Seric continue; 59916898Seric if (*p++ != ':') 6004098Seric { 6019368Seric syserr("missing colon"); 6024097Seric continue; 6034098Seric } 60455012Seric if (parseaddr(line, &al, 1, ':', e) == NULL) 6054098Seric { 60616898Seric syserr("illegal alias name"); 60716898Seric continue; 6084098Seric } 60916898Seric loweraddr(&al); 6104314Seric 6114314Seric /* 6124314Seric ** Process the RHS. 6134314Seric ** 'al' is the internal form of the LHS address. 6144314Seric ** 'p' points to the text of the RHS. 6154314Seric */ 6164314Seric 6174098Seric rhs = p; 6184098Seric for (;;) 6194098Seric { 6204098Seric register char c; 6211515Seric 62225821Seric if (init && CheckAliases) 6234098Seric { 6244157Seric /* do parsing & compression of addresses */ 62525278Seric while (*p != '\0') 6264098Seric { 62725278Seric extern char *DelimChar; 62825278Seric 62958050Seric while ((isascii(*p) && isspace(*p)) || 63058050Seric *p == ',') 6314157Seric p++; 63225278Seric if (*p == '\0') 63325278Seric break; 63455012Seric if (parseaddr(p, &bl, -1, ',', e) == NULL) 63525278Seric usrerr("%s... bad address", p); 63625278Seric p = DelimChar; 6374098Seric } 6384098Seric } 6394157Seric else 64015769Seric { 64116898Seric p = &p[strlen(p)]; 64216898Seric if (p[-1] == '\n') 64316898Seric *--p = '\0'; 64415769Seric } 6451515Seric 6464098Seric /* see if there should be a continuation line */ 6474106Seric c = fgetc(af); 6484106Seric if (!feof(af)) 6494314Seric (void) ungetc(c, af); 6504106Seric if (c != ' ' && c != '\t') 6514098Seric break; 6524098Seric 6534098Seric /* read continuation line */ 6544098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6554098Seric break; 6569368Seric LineNumber++; 65757135Seric 65857135Seric /* check for line overflow */ 65957135Seric if (strchr(p, '\n') == NULL) 66057135Seric { 66157135Seric usrerr("alias too long"); 66257135Seric break; 66357135Seric } 6644098Seric } 66516898Seric if (al.q_mailer != LocalMailer) 66616898Seric { 66716898Seric syserr("cannot alias non-local names"); 66816898Seric continue; 66916898Seric } 6704314Seric 6714314Seric /* 6724314Seric ** Insert alias into symbol table or DBM file 6734314Seric */ 6744314Seric 67516898Seric lhssize = strlen(al.q_user) + 1; 67657381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 67757381Seric makelower(al.q_user); 6784322Seric rhssize = strlen(rhs) + 1; 6794322Seric 68056845Seric # if defined(NDBM) || defined(NEWDB) 6814157Seric if (init) 6824157Seric { 68356845Seric DBdatum key, content; 68457381Seric int putstat; 6854157Seric 68656845Seric key.xx.size = lhssize; 68756845Seric key.xx.data = al.q_user; 68856845Seric content.xx.size = rhssize; 68956845Seric content.xx.data = rhs; 69051756Seric # ifdef NEWDB 69157381Seric putstat = dbp->put(dbp, &key.dbt, &content.dbt, 69257381Seric R_NOOVERWRITE); 69357381Seric if (putstat > 0) 69457381Seric { 69557977Seric usrerr("050 Warning: duplicate alias name %s", 69657381Seric al.q_user); 69757381Seric putstat = dbp->put(dbp, &key.dbt, 69857381Seric &content.dbt, 0); 69957381Seric } 70057381Seric if (putstat != 0) 70150576Seric syserr("readaliases: db put (%s)", al.q_user); 70250575Seric # endif 70353742Seric # ifdef IF_MAKEDBMFILES 70453742Seric IF_MAKEDBMFILES 70557381Seric { 70657381Seric putstat = dbm_store(dbmp, key.dbm, content.dbm, 70757381Seric DBM_INSERT); 70857381Seric if (putstat > 0) 70957381Seric { 71057977Seric usrerr("050 Warning: duplicate alias name %s", 71157381Seric al.q_user); 71257381Seric putstat = dbm_store(dbmp, key.dbm, 71357381Seric content.dbm, DBM_REPLACE); 71457381Seric } 71557381Seric if (putstat != 0) 71656845Seric syserr("readaliases: dbm store (%s)", 71756845Seric al.q_user); 71857381Seric } 71953742Seric # endif 72057381Seric if (al.q_paddr != NULL) 72157381Seric free(al.q_paddr); 72257381Seric if (al.q_host != NULL) 72357381Seric free(al.q_host); 72457381Seric if (al.q_user != NULL) 72557381Seric free(al.q_user); 7264157Seric } 7274157Seric else 72856845Seric # endif /* NDBM */ 7294157Seric { 7304157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 7314157Seric s->s_alias = newstr(rhs); 7324157Seric } 7334322Seric 7344322Seric /* statistics */ 7354322Seric naliases++; 7364322Seric bytes += lhssize + rhssize; 7374322Seric if (rhssize > longest) 7384322Seric longest = rhssize; 7391515Seric } 74019784Seric 74156845Seric # if defined(NDBM) || defined(NEWDB) 74219784Seric if (init) 74319784Seric { 74419784Seric /* add the distinquished alias "@" */ 74556845Seric DBdatum key; 74619784Seric 74756845Seric key.xx.size = 2; 74856845Seric key.xx.data = "@"; 74950575Seric # ifdef NEWDB 75050576Seric if (dbp->sync(dbp) != 0 || 75156845Seric dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 75250576Seric dbp->close(dbp) != 0) 75350576Seric syserr("readaliases: db close failure"); 75453742Seric # endif 75556789Seric # ifdef IF_MAKEDBMFILES 75656793Seric IF_MAKEDBMFILES 75756845Seric { 75858059Seric #ifdef YPCOMPAT 75958059Seric nis_magic(dbmp); 76058059Seric #endif 76156845Seric if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 76256845Seric dbm_error(dbmp)) 76356845Seric syserr("readaliases: dbm close failure"); 76456845Seric dbm_close(dbmp); 76556845Seric } 76650575Seric # endif 76719784Seric 76819784Seric /* restore the old signal */ 76919784Seric (void) signal(SIGINT, oldsigint); 77019784Seric } 77156845Seric # endif /* NDBM */ 77219784Seric 77319784Seric /* closing the alias file drops the lock */ 7744098Seric (void) fclose(af); 77555012Seric e->e_to = NULL; 7769368Seric FileName = NULL; 7777051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 7784322Seric naliases, longest, bytes); 77924944Seric # ifdef LOG 78058020Seric if (LogLevel > 7) 78124944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 78224944Seric naliases, longest, bytes); 78356795Seric # endif /* LOG */ 784292Seric } 785292Seric /* 78658059Seric ** NIS_MAGIC -- Add NIS magic dbm data 78758059Seric ** 78858059Seric ** This adds the magic entries needed by SunOS to make this a valid 78958059Seric ** NIS map. 79058059Seric ** 79158059Seric ** Parameters: 79258059Seric ** dbmp -- a pointer to the DBM structure. 79358059Seric ** 79458059Seric ** Returns: 79558059Seric ** none. 79658059Seric */ 79758059Seric 79858059Seric # ifdef YPCOMPAT 79958059Seric 80058059Seric static void 80158059Seric nis_magic(dbmp) 80258059Seric DBM *dbmp; 80358059Seric { 80458059Seric int i; 80558059Seric static datum key[2] = 80658059Seric { 80758059Seric { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 }, 80858059Seric { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 }, 80958059Seric }; 81058059Seric datum contents[2]; 81158059Seric char tbuf[12]; 81258059Seric char hbuf[MAXHOSTNAMELEN]; 81358059Seric 81458059Seric (void) sprintf(tbuf, "%010ld", curtime()); 81558059Seric contents[0].dptr = tbuf; 81658059Seric contents[0].dsize = strlen(tbuf); 81758059Seric 81858059Seric (void) myhostname(hbuf, sizeof hbuf); 81958059Seric contents[1].dptr = hbuf; 82058059Seric contents[1].dptr = strlen(hbuf); 82158059Seric 82258059Seric for (i = 0; i < sizeof key / sizeof *key; i++) 82358059Seric { 82458059Seric if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 || 82558059Seric dbm_error(dbmp)) 82658059Seric syserr("nis_magic: dbm_store failure"); 82758059Seric } 82858059Seric } 82958059Seric 83058059Seric # endif 83158059Seric /* 832292Seric ** FORWARD -- Try to forward mail 833292Seric ** 834292Seric ** This is similar but not identical to aliasing. 835292Seric ** 836292Seric ** Parameters: 8374314Seric ** user -- the name of the user who's mail we would like 8384314Seric ** to forward to. It must have been verified -- 8394314Seric ** i.e., the q_home field must have been filled 8404314Seric ** in. 8414999Seric ** sendq -- a pointer to the head of the send queue to 8424999Seric ** put this user's aliases in. 843292Seric ** 844292Seric ** Returns: 8454098Seric ** none. 846292Seric ** 847292Seric ** Side Effects: 8483185Seric ** New names are added to send queues. 849292Seric */ 850292Seric 85155012Seric forward(user, sendq, e) 8522966Seric ADDRESS *user; 8534999Seric ADDRESS **sendq; 85455012Seric register ENVELOPE *e; 855292Seric { 85657136Seric char *pp; 85757136Seric char *ep; 8584536Seric extern bool safefile(); 8594069Seric 8607671Seric if (tTd(27, 1)) 8614098Seric printf("forward(%s)\n", user->q_paddr); 8624098Seric 8634594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 8644098Seric return; 8654314Seric if (user->q_home == NULL) 86658059Seric { 8674314Seric syserr("forward: no home"); 86858059Seric user->q_home = "/nosuchdirectory"; 86958059Seric } 8704069Seric 8714069Seric /* good address -- look for .forward file in home */ 87255012Seric define('z', user->q_home, e); 87357136Seric define('u', user->q_user, e); 87457136Seric define('h', user->q_host, e); 87557136Seric if (ForwardPath == NULL) 87658050Seric ForwardPath = newstr("\201z/.forward"); 87757136Seric 87857136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 87957136Seric { 88057232Seric char buf[MAXPATHLEN+1]; 88157136Seric 88257136Seric ep = strchr(pp, ':'); 88357136Seric if (ep != NULL) 88457136Seric *ep = '\0'; 88557136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 88657136Seric if (ep != NULL) 88757136Seric *ep++ = ':'; 88857136Seric if (tTd(27, 3)) 88957136Seric printf("forward: trying %s\n", buf); 89057136Seric if (include(buf, TRUE, user, sendq, e) == 0) 89157136Seric break; 89257136Seric } 893292Seric } 894