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 <sys/stat.h> 1157948Seric # include <sys/file.h> 1250577Seric # include <signal.h> 1357737Seric # include <fcntl.h> 1450577Seric # include <pwd.h> 1550577Seric 1656845Seric # ifdef DBM 1756848Seric ERROR: DBM is no longer supported -- use NDBM instead. 1856845Seric # endif 1956845Seric 2050577Seric # ifdef NEWDB 2150577Seric # include <db.h> 2250577Seric # endif 2350577Seric 2456766Seric # ifdef NDBM 2556845Seric # include <ndbm.h> 2656766Seric # endif 2756766Seric 2833728Sbostic #ifndef lint 2951756Seric #ifdef NEWDB 3057736Seric #ifdef NDBM 31*58333Seric static char sccsid[] = "@(#)alias.c 6.21 (Berkeley) 03/01/93 (with NEWDB and NDBM)"; 3251756Seric #else 33*58333Seric static char sccsid[] = "@(#)alias.c 6.21 (Berkeley) 03/01/93 (with NEWDB)"; 3457736Seric #endif 3557736Seric #else 3656845Seric #ifdef NDBM 37*58333Seric static char sccsid[] = "@(#)alias.c 6.21 (Berkeley) 03/01/93 (with NDBM)"; 3833728Sbostic #else 39*58333Seric static char sccsid[] = "@(#)alias.c 6.21 (Berkeley) 03/01/93 (without NEWDB or NDBM)"; 4033728Sbostic #endif 4150575Seric #endif 4233728Sbostic #endif /* not lint */ 4351756Seric /* 44292Seric ** ALIAS -- Compute aliases. 45292Seric ** 469368Seric ** Scans the alias file for an alias for the given address. 479368Seric ** If found, it arranges to deliver to the alias list instead. 489368Seric ** Uses libdbm database if -DDBM. 49292Seric ** 50292Seric ** Parameters: 514097Seric ** a -- address to alias. 524999Seric ** sendq -- a pointer to the head of the send queue 534999Seric ** to put the aliases in. 5458092Seric ** e -- the current envelope. 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; 11558082Seric int naliases; 11658170Seric char *owner; 11758170Seric char obuf[MAXNAME + 6]; 1185701Seric extern char *aliaslookup(); 119292Seric 1207671Seric if (tTd(27, 1)) 1214098Seric printf("alias(%s)\n", a->q_paddr); 122292Seric 1234098Seric /* don't realias already aliased names */ 12458154Seric if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 1254098Seric return; 1264098Seric 12755012Seric e->e_to = a->q_paddr; 1284098Seric 1294314Seric /* 1304314Seric ** Look up this name 1314314Seric */ 1324314Seric 13324944Seric if (NoAlias) 13424944Seric p = NULL; 13524944Seric else 13624944Seric p = aliaslookup(a->q_user); 1374098Seric if (p == NULL) 1384098Seric return; 139292Seric 140292Seric /* 1414098Seric ** Match on Alias. 1424098Seric ** Deliver to the target list. 1431515Seric */ 1441515Seric 1457671Seric if (tTd(27, 1)) 1464098Seric printf("%s (%s, %s) aliased to %s\n", 1474098Seric a->q_paddr, a->q_host, a->q_user, p); 14858092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 14958154Seric { 15058154Seric a->q_flags |= QVERIFIED; 15158092Seric return; 15258154Seric } 15358154Seric message("aliased to %s", p); 15457977Seric #ifdef LOG 15558020Seric if (LogLevel > 9) 15657977Seric syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 15757977Seric #endif 15858082Seric a->q_flags &= ~QSELFREF; 1594098Seric AliasLevel++; 16058082Seric naliases = sendtolist(p, a, sendq, e); 1614098Seric AliasLevel--; 16258082Seric if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 16358065Seric { 16458065Seric if (tTd(27, 5)) 16558065Seric { 16658065Seric printf("alias: QDONTSEND "); 16758065Seric printaddr(a, FALSE); 16858065Seric } 16958065Seric a->q_flags |= QDONTSEND; 17058065Seric } 17158170Seric 17258170Seric /* 17358170Seric ** Look for owner of alias 17458170Seric */ 17558170Seric 17658170Seric (void) strcpy(obuf, "owner-"); 17758170Seric if (strncmp(a->q_user, "owner-", 6) == 0) 17858170Seric (void) strcat(obuf, "owner"); 17958170Seric else 18058170Seric (void) strcat(obuf, a->q_user); 18158170Seric if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 18258170Seric makelower(obuf); 18358170Seric owner = aliaslookup(obuf); 18458170Seric if (owner != NULL) 18558170Seric { 18658170Seric if (strchr(owner, ',') != NULL) 18758170Seric owner = obuf; 18858170Seric a->q_owner = newstr(owner); 18958170Seric } 1904098Seric } 1914098Seric /* 1925701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1935701Seric ** 1945701Seric ** Parameters: 1955701Seric ** name -- the name to look up. 1965701Seric ** 1975701Seric ** Returns: 1985701Seric ** the value of name. 1995701Seric ** NULL if unknown. 2005701Seric ** 2015701Seric ** Side Effects: 2025701Seric ** none. 2035701Seric ** 2045701Seric ** Warnings: 2055701Seric ** The return value will be trashed across calls. 2065701Seric */ 2075701Seric 2085701Seric char * 2095701Seric aliaslookup(name) 2105701Seric char *name; 2115701Seric { 21257381Seric int i; 21357381Seric char keybuf[MAXNAME + 1]; 21456845Seric # if defined(NEWDB) || defined(NDBM) 21556845Seric DBdatum rhs, lhs; 21650575Seric int s; 21757381Seric # else /* neither NEWDB nor NDBM */ 21857381Seric register STAB *s; 21957381Seric # endif 2205701Seric 2215701Seric /* create a key for fetch */ 22257381Seric i = strlen(name) + 1; 22357381Seric if (i > sizeof keybuf) 22457381Seric i = sizeof keybuf; 22557381Seric bcopy(name, keybuf, i); 22657381Seric if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 22757381Seric makelower(keybuf); 22857381Seric 22957381Seric # if defined(NEWDB) || defined(NDBM) 23057381Seric lhs.xx.size = i; 23157381Seric lhs.xx.data = keybuf; 23250575Seric # ifdef NEWDB 23351756Seric if (AliasDBptr != NULL) 23451756Seric { 23557381Seric i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0); 23657381Seric if (i == 0) 23756845Seric return (rhs.dbt.data); 23851756Seric } 23956845Seric # ifdef NDBM 24057249Seric else if (AliasDBMptr != NULL) 24151756Seric { 24256845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 24356845Seric return (rhs.dbm.dptr); 24451756Seric } 24556845Seric # endif /* NDBM */ 24657530Seric return (NULL); 24756845Seric # else /* not NEWDB */ 24856845Seric rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 24956845Seric return (rhs.dbm.dptr); 25056845Seric # endif /* NEWDB */ 25156845Seric # else /* neither NEWDB nor NDBM */ 25257381Seric s = stab(keybuf, ST_ALIAS, ST_FIND); 25351756Seric if (s != NULL) 25451756Seric return (s->s_alias); 25557530Seric return (NULL); 25651756Seric # endif 2575701Seric } 2585701Seric /* 2594098Seric ** INITALIASES -- initialize for aliasing 2604098Seric ** 26156845Seric ** Very different depending on whether we are running NDBM or not. 2624098Seric ** 2634098Seric ** Parameters: 2644098Seric ** aliasfile -- location of aliases. 26556845Seric ** init -- if set and if NDBM, initialize the NDBM files. 2664098Seric ** 2674098Seric ** Returns: 2684098Seric ** none. 2694098Seric ** 2704098Seric ** Side Effects: 2714098Seric ** initializes aliases: 27256845Seric ** if NDBM: opens the database. 27356845Seric ** if ~NDBM: reads the aliases into the symbol table. 2744098Seric */ 2754098Seric 27640559Sbostic # define DBMMODE 0644 2774157Seric 27855012Seric initaliases(aliasfile, init, e) 2794098Seric char *aliasfile; 2804157Seric bool init; 28155012Seric register ENVELOPE *e; 2824098Seric { 28356845Seric #if defined(NDBM) || defined(NEWDB) 2848437Seric int atcnt; 28525522Seric time_t modtime; 28625522Seric bool automatic = FALSE; 2874322Seric char buf[MAXNAME]; 28850575Seric #endif 2899368Seric struct stat stb; 29027176Seric static bool initialized = FALSE; 29146928Sbostic static int readaliases(); 2924322Seric 29327176Seric if (initialized) 29427176Seric return; 29527176Seric initialized = TRUE; 29627176Seric 29717984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 2988437Seric { 29925522Seric if (aliasfile != NULL && init) 30058151Seric syserr("554 Cannot open %s", aliasfile); 3018437Seric NoAlias = TRUE; 30211937Seric errno = 0; 3038437Seric return; 3048437Seric } 3058437Seric 30656845Seric # if defined(NDBM) || defined(NEWDB) 3074322Seric /* 3088437Seric ** Check to see that the alias file is complete. 3098437Seric ** If not, we will assume that someone died, and it is up 3108437Seric ** to us to rebuild it. 3118437Seric */ 3128437Seric 31325689Seric if (!init) 31450575Seric { 31550575Seric # ifdef NEWDB 31650575Seric (void) strcpy(buf, aliasfile); 31750575Seric (void) strcat(buf, ".db"); 31851171Sbostic AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 31950576Seric if (AliasDBptr == NULL) 32050576Seric { 32156845Seric # ifdef NDBM 32256845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 32357249Seric if (AliasDBMptr == NULL) 32457249Seric { 32557249Seric syserr("initaliases: cannot open %s", buf); 32657249Seric NoAlias = TRUE; 32757249Seric return; 32857249Seric } 32951756Seric # else 33050576Seric syserr("initaliases: cannot open %s", buf); 33150576Seric NoAlias = TRUE; 33250576Seric return; 33351756Seric # endif 33450576Seric } 33550575Seric # else 33656845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 33757249Seric if (AliasDBMptr == NULL) 33857249Seric { 33957977Seric syserr("initaliases: cannot open DBM database %s.{pag,dir}", 34057977Seric aliasfile); 34157249Seric NoAlias = TRUE; 34257249Seric return; 34357249Seric } 34450575Seric # endif 34550575Seric } 34617471Seric atcnt = SafeAlias * 2; 34717471Seric if (atcnt > 0) 34817471Seric { 34917471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 35025689Seric { 35125689Seric /* 35225689Seric ** Reinitialize alias file in case the new 35325689Seric ** one is mv'ed in instead of cp'ed in. 35425689Seric ** 35525689Seric ** Only works with new DBM -- old one will 35625689Seric ** just consume file descriptors forever. 35725689Seric ** If you have a dbmclose() it can be 35825689Seric ** added before the sleep(30). 35925689Seric */ 36025689Seric 36150575Seric # ifdef NEWDB 36251756Seric if (AliasDBptr != NULL) 36351756Seric AliasDBptr->close(AliasDBptr); 36450575Seric # endif 36556845Seric # ifdef NDBM 36656845Seric if (AliasDBMptr != NULL) 36756845Seric dbm_close(AliasDBMptr); 36856845Seric # endif 36950575Seric 37017471Seric sleep(30); 37150575Seric # ifdef NEWDB 37250575Seric (void) strcpy(buf, aliasfile); 37350575Seric (void) strcat(buf, ".db"); 37451171Sbostic AliasDBptr = 37551171Sbostic dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 37650576Seric if (AliasDBptr == NULL) 37750576Seric { 37851756Seric # ifdef NDBM 37956845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 38051756Seric # else 38150576Seric syserr("initaliases: cannot open %s", buf); 38250576Seric NoAlias = TRUE; 38350576Seric return; 38451756Seric # endif 38550576Seric } 38650575Seric # else 38725689Seric # ifdef NDBM 38856845Seric AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 38957249Seric if (AliasDBMptr == NULL) 39057249Seric { 39158008Seric syserr("initaliases: cannot open DBM database %s.{pag,dir}", 39258008Seric aliasfile); 39357249Seric NoAlias = TRUE; 39457249Seric return; 39557249Seric } 39650575Seric # endif 39750575Seric # endif 39825689Seric } 39917471Seric } 40017471Seric else 40117471Seric atcnt = 1; 4028437Seric 4038437Seric /* 40456845Seric ** See if the NDBM version of the file is out of date with 4054322Seric ** the text version. If so, go into 'init' mode automatically. 40640559Sbostic ** This only happens if our effective userid owns the DBM. 40740559Sbostic ** Note the unpalatable hack to see if the stat succeeded. 4084322Seric */ 4094322Seric 4104322Seric modtime = stb.st_mtime; 4114322Seric (void) strcpy(buf, aliasfile); 41250575Seric # ifdef NEWDB 41350575Seric (void) strcat(buf, ".db"); 41450575Seric # else 4154322Seric (void) strcat(buf, ".pag"); 41650575Seric # endif 4174322Seric stb.st_ino = 0; 41819039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 4194322Seric { 42011937Seric errno = 0; 42140559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 4224322Seric { 4234322Seric init = TRUE; 42425522Seric automatic = TRUE; 42558151Seric message("rebuilding alias database"); 42624944Seric #ifdef LOG 42758020Seric if (LogLevel > 14) 42824944Seric syslog(LOG_INFO, "rebuilding alias database"); 42956795Seric #endif /* LOG */ 4304322Seric } 4314322Seric else 4324322Seric { 43319039Seric #ifdef LOG 43458020Seric if (LogLevel > 3) 43524944Seric syslog(LOG_INFO, "alias database out of date"); 43656795Seric #endif /* LOG */ 43758151Seric message("Warning: alias database out of date"); 4384322Seric } 4394322Seric } 4404322Seric 4414322Seric 4424322Seric /* 44356845Seric ** If necessary, load the NDBM file. 44456845Seric ** If running without NDBM, load the symbol table. 4454322Seric */ 4464322Seric 4474157Seric if (init) 4488437Seric { 44925522Seric #ifdef LOG 45058020Seric if (LogLevel > 7) 45125522Seric { 45225522Seric extern char *username(); 45325522Seric 45425522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 45525522Seric automatic ? "auto" : "", username()); 45625522Seric } 45756795Seric #endif /* LOG */ 45855012Seric readaliases(aliasfile, TRUE, e); 4598437Seric } 46056845Seric # else /* NDBM */ 46155012Seric readaliases(aliasfile, init, e); 46256845Seric # endif /* NDBM */ 4634157Seric } 4644157Seric /* 4654157Seric ** READALIASES -- read and process the alias file. 4664157Seric ** 4674157Seric ** This routine implements the part of initaliases that occurs 4684157Seric ** when we are not going to use the DBM stuff. 4694157Seric ** 4704157Seric ** Parameters: 4714157Seric ** aliasfile -- the pathname of the alias file master. 47256845Seric ** init -- if set, initialize the NDBM stuff. 4734157Seric ** 4744157Seric ** Returns: 4754157Seric ** none. 4764157Seric ** 4774157Seric ** Side Effects: 4784157Seric ** Reads aliasfile into the symbol table. 4794157Seric ** Optionally, builds the .dir & .pag files. 4804157Seric */ 4814157Seric 4824157Seric static 48355012Seric readaliases(aliasfile, init, e) 4844157Seric char *aliasfile; 4854157Seric bool init; 48655012Seric register ENVELOPE *e; 4874157Seric { 4884098Seric register char *p; 4894098Seric char *rhs; 4904098Seric bool skipping; 4919368Seric int naliases, bytes, longest; 4929368Seric FILE *af; 49353742Seric bool makedbmfiles; 49440970Sbostic void (*oldsigint)(); 4954098Seric ADDRESS al, bl; 4964106Seric register STAB *s; 49750575Seric # ifdef NEWDB 49850575Seric DB *dbp; 49950575Seric # endif 50056845Seric # ifdef NDBM 50156845Seric DBM *dbmp; 50256845Seric # endif 50351937Seric # ifdef LOCKF 50451937Seric struct flock fld; 50551937Seric # endif 5069368Seric char line[BUFSIZ]; 5074098Seric 50851937Seric if ((af = fopen(aliasfile, "r+")) == NULL) 5091515Seric { 51057249Seric if (init) 51158151Seric syserr("554 Can't open %s", aliasfile); 51257249Seric else if (tTd(27, 1)) 5134106Seric printf("Can't open %s\n", aliasfile); 5144098Seric errno = 0; 5154098Seric NoAlias++; 5164098Seric return; 5174098Seric } 5184314Seric 51956845Seric # if defined(NDBM) || defined(NEWDB) 52019784Seric /* see if someone else is rebuilding the alias file already */ 52151835Seric # ifdef LOCKF 52251937Seric fld.l_type = F_WRLCK; 52351937Seric fld.l_whence = fld.l_start = fld.l_len = 0; 52451937Seric if (fcntl(fileno(af), F_SETLK, &fld) < 0) 52551835Seric # else 52619784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 52751835Seric # endif 52819784Seric { 52919784Seric /* yes, they are -- wait until done and then return */ 53058151Seric message("Alias file is already being rebuilt"); 53119784Seric if (OpMode != MD_INITALIAS) 53219784Seric { 53319784Seric /* wait for other rebuild to complete */ 53451835Seric # ifdef LOCKF 53551937Seric (void) fcntl(fileno(af), F_SETLKW, &fld); 53651835Seric # else 53719784Seric (void) flock(fileno(af), LOCK_EX); 53851835Seric # endif 53919784Seric } 54023108Seric (void) fclose(af); 54119784Seric errno = 0; 54219784Seric return; 54319784Seric } 54456845Seric # endif /* NDBM */ 54519784Seric 5464314Seric /* 54719784Seric ** If initializing, create the new DBM files. 54819784Seric */ 54919784Seric 55019784Seric if (init) 55119784Seric { 55219784Seric oldsigint = signal(SIGINT, SIG_IGN); 55351756Seric # ifdef NEWDB 55451756Seric (void) strcpy(line, aliasfile); 55551756Seric (void) strcat(line, ".db"); 55651756Seric dbp = dbopen(line, 55751756Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 55851756Seric if (dbp == NULL) 55951756Seric { 56051756Seric syserr("readaliases: cannot create %s", line); 56151756Seric (void) signal(SIGINT, oldsigint); 56251756Seric return; 56351756Seric } 56453742Seric # endif 56553742Seric # ifdef IF_MAKEDBMFILES 56653742Seric # ifdef NEWDB 56753742Seric makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 56853742Seric # endif 56953742Seric IF_MAKEDBMFILES 57019784Seric { 57156845Seric dbmp = dbm_open(aliasfile, 57256845Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 57356845Seric if (dbmp == NULL) 57453742Seric { 57556845Seric syserr("readaliases: cannot create %s.{dir,pag}", 57656845Seric aliasfile); 57753742Seric (void) signal(SIGINT, oldsigint); 57853742Seric return; 57953742Seric } 58019784Seric } 58150575Seric # endif 58219784Seric } 58319784Seric 58419784Seric /* 5854314Seric ** Read and interpret lines 5864314Seric */ 5874314Seric 5889368Seric FileName = aliasfile; 5899368Seric LineNumber = 0; 5904322Seric naliases = bytes = longest = 0; 5914098Seric skipping = FALSE; 5924098Seric while (fgets(line, sizeof (line), af) != NULL) 5934098Seric { 5944322Seric int lhssize, rhssize; 5954322Seric 5969368Seric LineNumber++; 59756795Seric p = strchr(line, '\n'); 59825278Seric if (p != NULL) 59925278Seric *p = '\0'; 6004098Seric switch (line[0]) 6014098Seric { 6024098Seric case '#': 6034098Seric case '\0': 6044098Seric skipping = FALSE; 6054098Seric continue; 6064065Seric 6074098Seric case ' ': 6084098Seric case '\t': 6094098Seric if (!skipping) 61058151Seric syserr("554 Non-continuation line starts with space"); 6114098Seric skipping = TRUE; 6124097Seric continue; 6134098Seric } 6144098Seric skipping = FALSE; 6151874Seric 6164314Seric /* 6174314Seric ** Process the LHS 61857736Seric ** Find the colon separator, and parse the address. 61916898Seric ** It should resolve to a local name -- this will 62016898Seric ** be checked later (we want to optionally do 62116898Seric ** parsing of the RHS first to maximize error 62216898Seric ** detection). 6234314Seric */ 6244314Seric 6254098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 6264097Seric continue; 62716898Seric if (*p++ != ':') 6284098Seric { 62958151Seric syserr("554 missing colon"); 6304097Seric continue; 6314098Seric } 632*58333Seric if (parseaddr(line, &al, 1, ':', NULL, e) == NULL) 6334098Seric { 63458151Seric syserr("554 illegal alias name"); 63516898Seric continue; 6364098Seric } 63716898Seric loweraddr(&al); 6384314Seric 6394314Seric /* 6404314Seric ** Process the RHS. 6414314Seric ** 'al' is the internal form of the LHS address. 6424314Seric ** 'p' points to the text of the RHS. 6434314Seric */ 6444314Seric 6454098Seric rhs = p; 6464098Seric for (;;) 6474098Seric { 6484098Seric register char c; 6491515Seric 65025821Seric if (init && CheckAliases) 6514098Seric { 6524157Seric /* do parsing & compression of addresses */ 65325278Seric while (*p != '\0') 6544098Seric { 655*58333Seric auto char *delimptr; 65625278Seric 65758050Seric while ((isascii(*p) && isspace(*p)) || 65858050Seric *p == ',') 6594157Seric p++; 66025278Seric if (*p == '\0') 66125278Seric break; 662*58333Seric if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 66358151Seric usrerr("553 %s... bad address", p); 664*58333Seric p = delimptr; 6654098Seric } 6664098Seric } 6674157Seric else 66815769Seric { 66916898Seric p = &p[strlen(p)]; 67016898Seric if (p[-1] == '\n') 67116898Seric *--p = '\0'; 67215769Seric } 6731515Seric 6744098Seric /* see if there should be a continuation line */ 6754106Seric c = fgetc(af); 6764106Seric if (!feof(af)) 6774314Seric (void) ungetc(c, af); 6784106Seric if (c != ' ' && c != '\t') 6794098Seric break; 6804098Seric 6814098Seric /* read continuation line */ 6824098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6834098Seric break; 6849368Seric LineNumber++; 68557135Seric 68657135Seric /* check for line overflow */ 68757135Seric if (strchr(p, '\n') == NULL) 68857135Seric { 68958151Seric usrerr("554 alias too long"); 69057135Seric break; 69157135Seric } 6924098Seric } 69316898Seric if (al.q_mailer != LocalMailer) 69416898Seric { 69558151Seric syserr("554 cannot alias non-local names"); 69616898Seric continue; 69716898Seric } 6984314Seric 6994314Seric /* 7004314Seric ** Insert alias into symbol table or DBM file 7014314Seric */ 7024314Seric 70316898Seric lhssize = strlen(al.q_user) + 1; 70457381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 70557381Seric makelower(al.q_user); 7064322Seric rhssize = strlen(rhs) + 1; 7074322Seric 70856845Seric # if defined(NDBM) || defined(NEWDB) 7094157Seric if (init) 7104157Seric { 71156845Seric DBdatum key, content; 71257381Seric int putstat; 7134157Seric 71456845Seric key.xx.size = lhssize; 71556845Seric key.xx.data = al.q_user; 71656845Seric content.xx.size = rhssize; 71756845Seric content.xx.data = rhs; 71851756Seric # ifdef NEWDB 71957381Seric putstat = dbp->put(dbp, &key.dbt, &content.dbt, 72057381Seric R_NOOVERWRITE); 72157381Seric if (putstat > 0) 72257381Seric { 72357977Seric usrerr("050 Warning: duplicate alias name %s", 72457381Seric al.q_user); 72557381Seric putstat = dbp->put(dbp, &key.dbt, 72657381Seric &content.dbt, 0); 72757381Seric } 72857381Seric if (putstat != 0) 72950576Seric syserr("readaliases: db put (%s)", al.q_user); 73050575Seric # endif 73153742Seric # ifdef IF_MAKEDBMFILES 73253742Seric IF_MAKEDBMFILES 73357381Seric { 73457381Seric putstat = dbm_store(dbmp, key.dbm, content.dbm, 73557381Seric DBM_INSERT); 73657381Seric if (putstat > 0) 73757381Seric { 73857977Seric usrerr("050 Warning: duplicate alias name %s", 73957381Seric al.q_user); 74057381Seric putstat = dbm_store(dbmp, key.dbm, 74157381Seric content.dbm, DBM_REPLACE); 74257381Seric } 74357381Seric if (putstat != 0) 74456845Seric syserr("readaliases: dbm store (%s)", 74556845Seric al.q_user); 74657381Seric } 74753742Seric # endif 74857381Seric if (al.q_paddr != NULL) 74957381Seric free(al.q_paddr); 75057381Seric if (al.q_host != NULL) 75157381Seric free(al.q_host); 75257381Seric if (al.q_user != NULL) 75357381Seric free(al.q_user); 7544157Seric } 7554157Seric else 75656845Seric # endif /* NDBM */ 7574157Seric { 7584157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 7594157Seric s->s_alias = newstr(rhs); 7604157Seric } 7614322Seric 7624322Seric /* statistics */ 7634322Seric naliases++; 7644322Seric bytes += lhssize + rhssize; 7654322Seric if (rhssize > longest) 7664322Seric longest = rhssize; 7671515Seric } 76819784Seric 76956845Seric # if defined(NDBM) || defined(NEWDB) 77019784Seric if (init) 77119784Seric { 77219784Seric /* add the distinquished alias "@" */ 77356845Seric DBdatum key; 77419784Seric 77556845Seric key.xx.size = 2; 77656845Seric key.xx.data = "@"; 77750575Seric # ifdef NEWDB 77850576Seric if (dbp->sync(dbp) != 0 || 77956845Seric dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 78050576Seric dbp->close(dbp) != 0) 78150576Seric syserr("readaliases: db close failure"); 78253742Seric # endif 78356789Seric # ifdef IF_MAKEDBMFILES 78456793Seric IF_MAKEDBMFILES 78556845Seric { 78658059Seric #ifdef YPCOMPAT 78758059Seric nis_magic(dbmp); 78858059Seric #endif 78956845Seric if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 79056845Seric dbm_error(dbmp)) 79156845Seric syserr("readaliases: dbm close failure"); 79256845Seric dbm_close(dbmp); 79356845Seric } 79450575Seric # endif 79519784Seric 79619784Seric /* restore the old signal */ 79719784Seric (void) signal(SIGINT, oldsigint); 79819784Seric } 79956845Seric # endif /* NDBM */ 80019784Seric 80119784Seric /* closing the alias file drops the lock */ 8024098Seric (void) fclose(af); 80355012Seric e->e_to = NULL; 8049368Seric FileName = NULL; 80558151Seric message("%d aliases, longest %d bytes, %d bytes total", 8064322Seric naliases, longest, bytes); 80724944Seric # ifdef LOG 80858020Seric if (LogLevel > 7) 80924944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 81024944Seric naliases, longest, bytes); 81156795Seric # endif /* LOG */ 812292Seric } 813292Seric /* 81458059Seric ** NIS_MAGIC -- Add NIS magic dbm data 81558059Seric ** 81658059Seric ** This adds the magic entries needed by SunOS to make this a valid 81758059Seric ** NIS map. 81858059Seric ** 81958059Seric ** Parameters: 82058059Seric ** dbmp -- a pointer to the DBM structure. 82158059Seric ** 82258059Seric ** Returns: 82358059Seric ** none. 82458059Seric */ 82558059Seric 82658059Seric # ifdef YPCOMPAT 82758059Seric 82858059Seric static void 82958059Seric nis_magic(dbmp) 83058059Seric DBM *dbmp; 83158059Seric { 83258059Seric int i; 83358059Seric static datum key[2] = 83458059Seric { 83558059Seric { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 }, 83658059Seric { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 }, 83758059Seric }; 83858059Seric datum contents[2]; 83958059Seric char tbuf[12]; 84058059Seric char hbuf[MAXHOSTNAMELEN]; 84158059Seric 84258059Seric (void) sprintf(tbuf, "%010ld", curtime()); 84358059Seric contents[0].dptr = tbuf; 84458059Seric contents[0].dsize = strlen(tbuf); 84558059Seric 84658059Seric (void) myhostname(hbuf, sizeof hbuf); 84758059Seric contents[1].dptr = hbuf; 84858059Seric contents[1].dptr = strlen(hbuf); 84958059Seric 85058059Seric for (i = 0; i < sizeof key / sizeof *key; i++) 85158059Seric { 85258059Seric if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 || 85358059Seric dbm_error(dbmp)) 85458059Seric syserr("nis_magic: dbm_store failure"); 85558059Seric } 85658059Seric } 85758059Seric 85858059Seric # endif 85958059Seric /* 860292Seric ** FORWARD -- Try to forward mail 861292Seric ** 862292Seric ** This is similar but not identical to aliasing. 863292Seric ** 864292Seric ** Parameters: 8654314Seric ** user -- the name of the user who's mail we would like 8664314Seric ** to forward to. It must have been verified -- 8674314Seric ** i.e., the q_home field must have been filled 8684314Seric ** in. 8694999Seric ** sendq -- a pointer to the head of the send queue to 8704999Seric ** put this user's aliases in. 871292Seric ** 872292Seric ** Returns: 8734098Seric ** none. 874292Seric ** 875292Seric ** Side Effects: 8763185Seric ** New names are added to send queues. 877292Seric */ 878292Seric 87955012Seric forward(user, sendq, e) 8802966Seric ADDRESS *user; 8814999Seric ADDRESS **sendq; 88255012Seric register ENVELOPE *e; 883292Seric { 88457136Seric char *pp; 88557136Seric char *ep; 8864069Seric 8877671Seric if (tTd(27, 1)) 8884098Seric printf("forward(%s)\n", user->q_paddr); 8894098Seric 8904594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 8914098Seric return; 8924314Seric if (user->q_home == NULL) 89358059Seric { 89458151Seric syserr("554 forward: no home"); 89558059Seric user->q_home = "/nosuchdirectory"; 89658059Seric } 8974069Seric 8984069Seric /* good address -- look for .forward file in home */ 89955012Seric define('z', user->q_home, e); 90057136Seric define('u', user->q_user, e); 90157136Seric define('h', user->q_host, e); 90257136Seric if (ForwardPath == NULL) 90358050Seric ForwardPath = newstr("\201z/.forward"); 90457136Seric 90557136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 90657136Seric { 90758247Seric int err; 90857232Seric char buf[MAXPATHLEN+1]; 90958247Seric extern bool transienterror(); 91057136Seric 91157136Seric ep = strchr(pp, ':'); 91257136Seric if (ep != NULL) 91357136Seric *ep = '\0'; 91457136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 91557136Seric if (ep != NULL) 91657136Seric *ep++ = ':'; 91757136Seric if (tTd(27, 3)) 91857136Seric printf("forward: trying %s\n", buf); 91958247Seric err = include(buf, TRUE, user, sendq, e); 92058247Seric if (err == 0) 92157136Seric break; 92258247Seric if (transienterror(err)) 92358247Seric { 92458247Seric /* we have to suspend this message */ 92558247Seric user->q_flags |= QQUEUEUP|QDONTSEND; 92658247Seric return; 92758247Seric } 92857136Seric } 929292Seric } 930