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 <errno.h> 1350577Seric # include "sendmail.h" 1450577Seric # include <sys/file.h> 1550577Seric # include <pwd.h> 1651937Seric # ifdef LOCKF 1751937Seric # include <fcntl.h> 1851937Seric # endif 1950577Seric 2050577Seric # ifdef NEWDB 2150577Seric # include <db.h> 2250577Seric # endif 2350577Seric 2433728Sbostic #ifndef lint 2551756Seric #ifdef NEWDB 26*55012Seric static char sccsid[] = "@(#)alias.c 5.34 (Berkeley) 07/12/92 (with NEWDB)"; 2751756Seric #else 2833728Sbostic #ifdef DBM 29*55012Seric static char sccsid[] = "@(#)alias.c 5.34 (Berkeley) 07/12/92 (with DBM)"; 3033728Sbostic #else 31*55012Seric static char sccsid[] = "@(#)alias.c 5.34 (Berkeley) 07/12/92 (without DBM)"; 3233728Sbostic #endif 3350575Seric #endif 3433728Sbostic #endif /* not lint */ 3551756Seric /* 36292Seric ** ALIAS -- Compute aliases. 37292Seric ** 389368Seric ** Scans the alias file for an alias for the given address. 399368Seric ** If found, it arranges to deliver to the alias list instead. 409368Seric ** Uses libdbm database if -DDBM. 41292Seric ** 42292Seric ** Parameters: 434097Seric ** a -- address to alias. 444999Seric ** sendq -- a pointer to the head of the send queue 454999Seric ** to put the aliases in. 46292Seric ** 47292Seric ** Returns: 48292Seric ** none 49292Seric ** 50292Seric ** Side Effects: 513185Seric ** Aliases found are expanded. 52292Seric ** 53292Seric ** Notes: 54292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 55292Seric ** done. 56292Seric ** 57292Seric ** Deficiencies: 58292Seric ** It should complain about names that are aliased to 59292Seric ** nothing. 60292Seric */ 61292Seric 62292Seric 6353742Seric /* 6453742Seric ** Sun YP servers read the dbm files directly, so we have to build them 6553742Seric ** even if NEWDB 6653742Seric */ 6753742Seric 681503Smark #ifdef DBM 6953742Seric # ifndef NEWDB 7053742Seric # define IF_MAKEDBMFILES 7153742Seric # else 7253742Seric # ifdef YPCOMPAT 7353742Seric # define IF_MAKEDBMFILES if (makedbmfiles) 7453742Seric # endif 7553742Seric # endif 7653742Seric #endif 7753742Seric 7853742Seric #ifdef DBM 7951756Seric #ifndef NEWDB 802966Seric typedef struct 812966Seric { 8250575Seric char *data; 8350575Seric int size; 8450575Seric } DBT; 8551756Seric #endif 8650575Seric extern DBT fetch(); 8750575Seric #endif /* DBM */ 88292Seric 8950575Seric #ifdef NEWDB 9050575Seric static DB *AliasDBptr; 9150575Seric #endif 9250575Seric 93*55012Seric alias(a, sendq, e) 944097Seric register ADDRESS *a; 954999Seric ADDRESS **sendq; 96*55012Seric register ENVELOPE *e; 97292Seric { 984081Seric register char *p; 995701Seric extern char *aliaslookup(); 100292Seric 1017671Seric if (tTd(27, 1)) 1024098Seric printf("alias(%s)\n", a->q_paddr); 103292Seric 1044098Seric /* don't realias already aliased names */ 1054098Seric if (bitset(QDONTSEND, a->q_flags)) 1064098Seric return; 1074098Seric 108*55012Seric e->e_to = a->q_paddr; 1094098Seric 1104314Seric /* 1114314Seric ** Look up this name 1124314Seric */ 1134314Seric 11424944Seric if (NoAlias) 11524944Seric p = NULL; 11624944Seric else 11724944Seric p = aliaslookup(a->q_user); 1184098Seric if (p == NULL) 1194098Seric return; 120292Seric 121292Seric /* 1224098Seric ** Match on Alias. 1234098Seric ** Deliver to the target list. 1241515Seric */ 1251515Seric 1267671Seric if (tTd(27, 1)) 1274098Seric printf("%s (%s, %s) aliased to %s\n", 1284098Seric a->q_paddr, a->q_host, a->q_user, p); 1297051Seric message(Arpa_Info, "aliased to %s", p); 1304098Seric AliasLevel++; 131*55012Seric sendtolist(p, a, sendq, e); 1324098Seric AliasLevel--; 1334098Seric } 1344098Seric /* 1355701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1365701Seric ** 1375701Seric ** Parameters: 1385701Seric ** name -- the name to look up. 1395701Seric ** 1405701Seric ** Returns: 1415701Seric ** the value of name. 1425701Seric ** NULL if unknown. 1435701Seric ** 1445701Seric ** Side Effects: 1455701Seric ** none. 1465701Seric ** 1475701Seric ** Warnings: 1485701Seric ** The return value will be trashed across calls. 1495701Seric */ 1505701Seric 1515701Seric char * 1525701Seric aliaslookup(name) 1535701Seric char *name; 1545701Seric { 15550575Seric # if defined(NEWDB) || defined(DBM) 15650575Seric DBT rhs, lhs; 15750575Seric int s; 1585701Seric 1595701Seric /* create a key for fetch */ 16050575Seric lhs.data = name; 16150575Seric lhs.size = strlen(name) + 1; 16250575Seric # ifdef NEWDB 16351756Seric if (AliasDBptr != NULL) 16451756Seric { 16551756Seric s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0); 16651756Seric if (s == 0) 16751756Seric return (rhs.data); 16851756Seric } 16951756Seric # ifdef DBM 17051756Seric else 17151756Seric { 17251756Seric rhs = fetch(lhs); 17351756Seric return (rhs.data); 17451756Seric } 17551756Seric # endif 17650575Seric # else 1775701Seric rhs = fetch(lhs); 17851756Seric return (rhs.data); 17950575Seric # endif 18051756Seric # else /* neither NEWDB nor DBM */ 1815701Seric register STAB *s; 1825701Seric 1835701Seric s = stab(name, ST_ALIAS, ST_FIND); 18451756Seric if (s != NULL) 18551756Seric return (s->s_alias); 18651756Seric # endif 18751756Seric return (NULL); 1885701Seric } 1895701Seric /* 1904098Seric ** INITALIASES -- initialize for aliasing 1914098Seric ** 1924098Seric ** Very different depending on whether we are running DBM or not. 1934098Seric ** 1944098Seric ** Parameters: 1954098Seric ** aliasfile -- location of aliases. 1964157Seric ** init -- if set and if DBM, initialize the DBM files. 1974098Seric ** 1984098Seric ** Returns: 1994098Seric ** none. 2004098Seric ** 2014098Seric ** Side Effects: 2024098Seric ** initializes aliases: 2034098Seric ** if DBM: opens the database. 2044098Seric ** if ~DBM: reads the aliases into the symbol table. 2054098Seric */ 2064098Seric 20740559Sbostic # define DBMMODE 0644 2084157Seric 209*55012Seric initaliases(aliasfile, init, e) 2104098Seric char *aliasfile; 2114157Seric bool init; 212*55012Seric register ENVELOPE *e; 2134098Seric { 21450575Seric #if defined(DBM) || defined(NEWDB) 2158437Seric int atcnt; 21625522Seric time_t modtime; 21725522Seric bool automatic = FALSE; 2184322Seric char buf[MAXNAME]; 21950575Seric #endif 2209368Seric struct stat stb; 22127176Seric static bool initialized = FALSE; 22246928Sbostic static int readaliases(); 2234322Seric 22427176Seric if (initialized) 22527176Seric return; 22627176Seric initialized = TRUE; 22727176Seric 22817984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 2298437Seric { 23025522Seric if (aliasfile != NULL && init) 23125522Seric syserr("Cannot open %s", aliasfile); 2328437Seric NoAlias = TRUE; 23311937Seric errno = 0; 2348437Seric return; 2358437Seric } 2368437Seric 23750575Seric # if defined(DBM) || defined(NEWDB) 2384322Seric /* 2398437Seric ** Check to see that the alias file is complete. 2408437Seric ** If not, we will assume that someone died, and it is up 2418437Seric ** to us to rebuild it. 2428437Seric */ 2438437Seric 24425689Seric if (!init) 24550575Seric { 24650575Seric # ifdef NEWDB 24750575Seric (void) strcpy(buf, aliasfile); 24850575Seric (void) strcat(buf, ".db"); 24951171Sbostic AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 25050576Seric if (AliasDBptr == NULL) 25150576Seric { 25251756Seric # ifdef DBM 25351756Seric dbminit(aliasfile); 25451756Seric # else 25550576Seric syserr("initaliases: cannot open %s", buf); 25650576Seric NoAlias = TRUE; 25750576Seric return; 25851756Seric # endif 25950576Seric } 26050575Seric # else 26125689Seric dbminit(aliasfile); 26250575Seric # endif 26350575Seric } 26417471Seric atcnt = SafeAlias * 2; 26517471Seric if (atcnt > 0) 26617471Seric { 26717471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 26825689Seric { 26925689Seric /* 27025689Seric ** Reinitialize alias file in case the new 27125689Seric ** one is mv'ed in instead of cp'ed in. 27225689Seric ** 27325689Seric ** Only works with new DBM -- old one will 27425689Seric ** just consume file descriptors forever. 27525689Seric ** If you have a dbmclose() it can be 27625689Seric ** added before the sleep(30). 27725689Seric */ 27825689Seric 27950575Seric # ifdef NEWDB 28051756Seric if (AliasDBptr != NULL) 28151756Seric AliasDBptr->close(AliasDBptr); 28250575Seric # endif 28350575Seric 28417471Seric sleep(30); 28550575Seric # ifdef NEWDB 28650575Seric (void) strcpy(buf, aliasfile); 28750575Seric (void) strcat(buf, ".db"); 28851171Sbostic AliasDBptr = 28951171Sbostic dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 29050576Seric if (AliasDBptr == NULL) 29150576Seric { 29251756Seric # ifdef NDBM 29351756Seric dbminit(aliasfile); 29451756Seric # else 29550576Seric syserr("initaliases: cannot open %s", buf); 29650576Seric NoAlias = TRUE; 29750576Seric return; 29851756Seric # endif 29950576Seric } 30050575Seric # else 30125689Seric # ifdef NDBM 30225689Seric dbminit(aliasfile); 30350575Seric # endif 30450575Seric # endif 30525689Seric } 30617471Seric } 30717471Seric else 30817471Seric atcnt = 1; 3098437Seric 3108437Seric /* 3114322Seric ** See if the DBM version of the file is out of date with 3124322Seric ** the text version. If so, go into 'init' mode automatically. 31340559Sbostic ** This only happens if our effective userid owns the DBM. 31440559Sbostic ** Note the unpalatable hack to see if the stat succeeded. 3154322Seric */ 3164322Seric 3174322Seric modtime = stb.st_mtime; 3184322Seric (void) strcpy(buf, aliasfile); 31950575Seric # ifdef NEWDB 32050575Seric (void) strcat(buf, ".db"); 32150575Seric # else 3224322Seric (void) strcat(buf, ".pag"); 32350575Seric # endif 3244322Seric stb.st_ino = 0; 32519039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 3264322Seric { 32711937Seric errno = 0; 32840559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3294322Seric { 3304322Seric init = TRUE; 33125522Seric automatic = TRUE; 3327051Seric message(Arpa_Info, "rebuilding alias database"); 33324944Seric #ifdef LOG 33424944Seric if (LogLevel >= 7) 33524944Seric syslog(LOG_INFO, "rebuilding alias database"); 33624944Seric #endif LOG 3374322Seric } 3384322Seric else 3394322Seric { 34019039Seric #ifdef LOG 34124944Seric if (LogLevel >= 7) 34224944Seric syslog(LOG_INFO, "alias database out of date"); 34319039Seric #endif LOG 3444322Seric message(Arpa_Info, "Warning: alias database out of date"); 3454322Seric } 3464322Seric } 3474322Seric 3484322Seric 3494322Seric /* 3508437Seric ** If necessary, load the DBM file. 3514322Seric ** If running without DBM, load the symbol table. 3524322Seric */ 3534322Seric 3544157Seric if (init) 3558437Seric { 35625522Seric #ifdef LOG 35725522Seric if (LogLevel >= 6) 35825522Seric { 35925522Seric extern char *username(); 36025522Seric 36125522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 36225522Seric automatic ? "auto" : "", username()); 36325522Seric } 36425522Seric #endif LOG 365*55012Seric readaliases(aliasfile, TRUE, e); 3668437Seric } 3674098Seric # else DBM 368*55012Seric readaliases(aliasfile, init, e); 3694157Seric # endif DBM 3704157Seric } 3714157Seric /* 3724157Seric ** READALIASES -- read and process the alias file. 3734157Seric ** 3744157Seric ** This routine implements the part of initaliases that occurs 3754157Seric ** when we are not going to use the DBM stuff. 3764157Seric ** 3774157Seric ** Parameters: 3784157Seric ** aliasfile -- the pathname of the alias file master. 3794157Seric ** init -- if set, initialize the DBM stuff. 3804157Seric ** 3814157Seric ** Returns: 3824157Seric ** none. 3834157Seric ** 3844157Seric ** Side Effects: 3854157Seric ** Reads aliasfile into the symbol table. 3864157Seric ** Optionally, builds the .dir & .pag files. 3874157Seric */ 3884157Seric 3894157Seric static 390*55012Seric readaliases(aliasfile, init, e) 3914157Seric char *aliasfile; 3924157Seric bool init; 393*55012Seric register ENVELOPE *e; 3944157Seric { 3954098Seric register char *p; 3964098Seric char *rhs; 3974098Seric bool skipping; 3989368Seric int naliases, bytes, longest; 3999368Seric FILE *af; 40053742Seric bool makedbmfiles; 40140970Sbostic void (*oldsigint)(); 4024098Seric ADDRESS al, bl; 4034106Seric register STAB *s; 40450575Seric # ifdef NEWDB 40550575Seric DB *dbp; 40650575Seric # endif 40751937Seric # ifdef LOCKF 40851937Seric struct flock fld; 40951937Seric # endif 4109368Seric char line[BUFSIZ]; 4114098Seric 41251937Seric if ((af = fopen(aliasfile, "r+")) == NULL) 4131515Seric { 4147671Seric if (tTd(27, 1)) 4154106Seric printf("Can't open %s\n", aliasfile); 4164098Seric errno = 0; 4174098Seric NoAlias++; 4184098Seric return; 4194098Seric } 4204314Seric 42150575Seric # if defined(DBM) || defined(NEWDB) 42219784Seric /* see if someone else is rebuilding the alias file already */ 42351835Seric # ifdef LOCKF 42451937Seric fld.l_type = F_WRLCK; 42551937Seric fld.l_whence = fld.l_start = fld.l_len = 0; 42651937Seric if (fcntl(fileno(af), F_SETLK, &fld) < 0) 42751835Seric # else 42819784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 42951835Seric # endif 43019784Seric { 43119784Seric /* yes, they are -- wait until done and then return */ 43219784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 43319784Seric if (OpMode != MD_INITALIAS) 43419784Seric { 43519784Seric /* wait for other rebuild to complete */ 43651835Seric # ifdef LOCKF 43751937Seric (void) fcntl(fileno(af), F_SETLKW, &fld); 43851835Seric # else 43919784Seric (void) flock(fileno(af), LOCK_EX); 44051835Seric # endif 44119784Seric } 44223108Seric (void) fclose(af); 44319784Seric errno = 0; 44419784Seric return; 44519784Seric } 44619784Seric # endif DBM 44719784Seric 4484314Seric /* 44919784Seric ** If initializing, create the new DBM files. 45019784Seric */ 45119784Seric 45219784Seric if (init) 45319784Seric { 45419784Seric oldsigint = signal(SIGINT, SIG_IGN); 45551756Seric # ifdef NEWDB 45651756Seric (void) strcpy(line, aliasfile); 45751756Seric (void) strcat(line, ".db"); 45851756Seric dbp = dbopen(line, 45951756Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 46051756Seric if (dbp == NULL) 46151756Seric { 46251756Seric syserr("readaliases: cannot create %s", line); 46351756Seric (void) signal(SIGINT, oldsigint); 46451756Seric return; 46551756Seric } 46653742Seric # endif 46753742Seric # ifdef IF_MAKEDBMFILES 46853742Seric # ifdef NEWDB 46953742Seric makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 47053742Seric # endif 47153742Seric IF_MAKEDBMFILES 47219784Seric { 47353742Seric (void) strcpy(line, aliasfile); 47453742Seric (void) strcat(line, ".dir"); 47553742Seric if (close(creat(line, DBMMODE)) < 0) 47653742Seric { 47753742Seric syserr("cannot make %s", line); 47853742Seric (void) signal(SIGINT, oldsigint); 47953742Seric return; 48053742Seric } 48153742Seric (void) strcpy(line, aliasfile); 48253742Seric (void) strcat(line, ".pag"); 48353742Seric if (close(creat(line, DBMMODE)) < 0) 48453742Seric { 48553742Seric syserr("cannot make %s", line); 48653742Seric (void) signal(SIGINT, oldsigint); 48753742Seric return; 48853742Seric } 48953742Seric dbminit(aliasfile); 49019784Seric } 49150575Seric # endif 49219784Seric } 49319784Seric 49419784Seric /* 4954314Seric ** Read and interpret lines 4964314Seric */ 4974314Seric 4989368Seric FileName = aliasfile; 4999368Seric LineNumber = 0; 5004322Seric naliases = bytes = longest = 0; 5014098Seric skipping = FALSE; 5024098Seric while (fgets(line, sizeof (line), af) != NULL) 5034098Seric { 5044322Seric int lhssize, rhssize; 5054322Seric 5069368Seric LineNumber++; 50725278Seric p = index(line, '\n'); 50825278Seric if (p != NULL) 50925278Seric *p = '\0'; 5104098Seric switch (line[0]) 5114098Seric { 5124098Seric case '#': 5134098Seric case '\0': 5144098Seric skipping = FALSE; 5154098Seric continue; 5164065Seric 5174098Seric case ' ': 5184098Seric case '\t': 5194098Seric if (!skipping) 5209368Seric syserr("Non-continuation line starts with space"); 5214098Seric skipping = TRUE; 5224097Seric continue; 5234098Seric } 5244098Seric skipping = FALSE; 5251874Seric 5264314Seric /* 5274314Seric ** Process the LHS 5284314Seric ** Find the final colon, and parse the address. 52916898Seric ** It should resolve to a local name -- this will 53016898Seric ** be checked later (we want to optionally do 53116898Seric ** parsing of the RHS first to maximize error 53216898Seric ** detection). 5334314Seric */ 5344314Seric 5354098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5364097Seric continue; 53716898Seric if (*p++ != ':') 5384098Seric { 5399368Seric syserr("missing colon"); 5404097Seric continue; 5414098Seric } 542*55012Seric if (parseaddr(line, &al, 1, ':', e) == NULL) 5434098Seric { 54416898Seric syserr("illegal alias name"); 54516898Seric continue; 5464098Seric } 54716898Seric loweraddr(&al); 5484314Seric 5494314Seric /* 5504314Seric ** Process the RHS. 5514314Seric ** 'al' is the internal form of the LHS address. 5524314Seric ** 'p' points to the text of the RHS. 5534314Seric */ 5544314Seric 5554098Seric rhs = p; 5564098Seric for (;;) 5574098Seric { 5584098Seric register char c; 5591515Seric 56025821Seric if (init && CheckAliases) 5614098Seric { 5624157Seric /* do parsing & compression of addresses */ 56325278Seric while (*p != '\0') 5644098Seric { 56525278Seric extern char *DelimChar; 56625278Seric 56725278Seric while (isspace(*p) || *p == ',') 5684157Seric p++; 56925278Seric if (*p == '\0') 57025278Seric break; 571*55012Seric if (parseaddr(p, &bl, -1, ',', e) == NULL) 57225278Seric usrerr("%s... bad address", p); 57325278Seric p = DelimChar; 5744098Seric } 5754098Seric } 5764157Seric else 57715769Seric { 57816898Seric p = &p[strlen(p)]; 57916898Seric if (p[-1] == '\n') 58016898Seric *--p = '\0'; 58115769Seric } 5821515Seric 5834098Seric /* see if there should be a continuation line */ 5844106Seric c = fgetc(af); 5854106Seric if (!feof(af)) 5864314Seric (void) ungetc(c, af); 5874106Seric if (c != ' ' && c != '\t') 5884098Seric break; 5894098Seric 5904098Seric /* read continuation line */ 5914098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 5924098Seric break; 5939368Seric LineNumber++; 5944098Seric } 59516898Seric if (al.q_mailer != LocalMailer) 59616898Seric { 59716898Seric syserr("cannot alias non-local names"); 59816898Seric continue; 59916898Seric } 6004314Seric 6014314Seric /* 6024314Seric ** Insert alias into symbol table or DBM file 6034314Seric */ 6044314Seric 60516898Seric lhssize = strlen(al.q_user) + 1; 6064322Seric rhssize = strlen(rhs) + 1; 6074322Seric 60850575Seric # if defined(DBM) || defined(NEWDB) 6094157Seric if (init) 6104157Seric { 61150575Seric DBT key, content; 6124157Seric 61350575Seric key.size = lhssize; 61450575Seric key.data = al.q_user; 61550575Seric content.size = rhssize; 61650575Seric content.data = rhs; 61751756Seric # ifdef NEWDB 61851171Sbostic if (dbp->put(dbp, &key, &content, 0) != 0) 61950576Seric syserr("readaliases: db put (%s)", al.q_user); 62050575Seric # endif 62153742Seric # ifdef IF_MAKEDBMFILES 62253742Seric IF_MAKEDBMFILES 62353742Seric store(key, content); 62453742Seric # endif 6254157Seric } 6264157Seric else 6274157Seric # endif DBM 6284157Seric { 6294157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 6304157Seric s->s_alias = newstr(rhs); 6314157Seric } 6324322Seric 6334322Seric /* statistics */ 6344322Seric naliases++; 6354322Seric bytes += lhssize + rhssize; 6364322Seric if (rhssize > longest) 6374322Seric longest = rhssize; 6381515Seric } 63919784Seric 64050575Seric # if defined(DBM) || defined(NEWDB) 64119784Seric if (init) 64219784Seric { 64319784Seric /* add the distinquished alias "@" */ 64450575Seric DBT key; 64519784Seric 64650575Seric key.size = 2; 64750575Seric key.data = "@"; 64850575Seric # ifdef NEWDB 64950576Seric if (dbp->sync(dbp) != 0 || 65051171Sbostic dbp->put(dbp, &key, &key, 0) != 0 || 65150576Seric dbp->close(dbp) != 0) 65250576Seric syserr("readaliases: db close failure"); 65353742Seric # endif 65453742Seric # ifdef MAKEDBMFILES 65519784Seric store(key, key); 65650575Seric # endif 65719784Seric 65819784Seric /* restore the old signal */ 65919784Seric (void) signal(SIGINT, oldsigint); 66019784Seric } 66119784Seric # endif DBM 66219784Seric 66319784Seric /* closing the alias file drops the lock */ 6644098Seric (void) fclose(af); 665*55012Seric e->e_to = NULL; 6669368Seric FileName = NULL; 6677051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 6684322Seric naliases, longest, bytes); 66924944Seric # ifdef LOG 67024944Seric if (LogLevel >= 8) 67124944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 67224944Seric naliases, longest, bytes); 67324944Seric # endif LOG 674292Seric } 675292Seric /* 676292Seric ** FORWARD -- Try to forward mail 677292Seric ** 678292Seric ** This is similar but not identical to aliasing. 679292Seric ** 680292Seric ** Parameters: 6814314Seric ** user -- the name of the user who's mail we would like 6824314Seric ** to forward to. It must have been verified -- 6834314Seric ** i.e., the q_home field must have been filled 6844314Seric ** in. 6854999Seric ** sendq -- a pointer to the head of the send queue to 6864999Seric ** put this user's aliases in. 687292Seric ** 688292Seric ** Returns: 6894098Seric ** none. 690292Seric ** 691292Seric ** Side Effects: 6923185Seric ** New names are added to send queues. 693292Seric */ 694292Seric 695*55012Seric forward(user, sendq, e) 6962966Seric ADDRESS *user; 6974999Seric ADDRESS **sendq; 698*55012Seric register ENVELOPE *e; 699292Seric { 7004078Seric char buf[60]; 7014536Seric extern bool safefile(); 7024069Seric 7037671Seric if (tTd(27, 1)) 7044098Seric printf("forward(%s)\n", user->q_paddr); 7054098Seric 7064594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 7074098Seric return; 7084314Seric if (user->q_home == NULL) 7094314Seric syserr("forward: no home"); 7104069Seric 7114069Seric /* good address -- look for .forward file in home */ 712*55012Seric define('z', user->q_home, e); 713*55012Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], e); 714*55012Seric include(buf, TRUE, user, sendq, e); 715292Seric } 716