122694Sdist /* 2*33728Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33728Sbostic * All rights reserved. 4*33728Sbostic * 5*33728Sbostic * Redistribution and use in source and binary forms are permitted 6*33728Sbostic * provided that this notice is preserved and that due credit is given 7*33728Sbostic * to the University of California at Berkeley. The name of the University 8*33728Sbostic * may not be used to endorse or promote products derived from this 9*33728Sbostic * software without specific prior written permission. This software 10*33728Sbostic * is provided ``as is'' without express or implied warranty. 11*33728Sbostic * 12*33728Sbostic * Sendmail 13*33728Sbostic * Copyright (c) 1983 Eric P. Allman 14*33728Sbostic * Berkeley, California 15*33728Sbostic */ 1622694Sdist 17*33728Sbostic #ifndef lint 18*33728Sbostic #ifdef DBM 19*33728Sbostic static char sccsid[] = "@(#)alias.c 5.14 (Berkeley) 03/13/88 (with DBM)"; 20*33728Sbostic #else 21*33728Sbostic static char sccsid[] = "@(#)alias.c 5.14 (Berkeley) 03/13/88 (without DBM)"; 22*33728Sbostic #endif 23*33728Sbostic #endif /* not lint */ 24*33728Sbostic 25292Seric # include <pwd.h> 264212Seric # include <sys/types.h> 274212Seric # include <sys/stat.h> 288437Seric # include <signal.h> 2919784Seric # include <errno.h> 303309Seric # include "sendmail.h" 3119784Seric # ifdef FLOCK 3219784Seric # include <sys/file.h> 3319784Seric # endif FLOCK 34292Seric 35292Seric /* 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 631503Smark #ifdef DBM 642966Seric typedef struct 652966Seric { 662966Seric char *dptr; 674157Seric int dsize; 684157Seric } DATUM; 694157Seric extern DATUM fetch(); 701503Smark #endif DBM 71292Seric 724999Seric alias(a, sendq) 734097Seric register ADDRESS *a; 744999Seric ADDRESS **sendq; 75292Seric { 764081Seric register char *p; 775701Seric extern char *aliaslookup(); 78292Seric 79292Seric # ifdef DEBUG 807671Seric if (tTd(27, 1)) 814098Seric printf("alias(%s)\n", a->q_paddr); 82292Seric # endif 83292Seric 844098Seric /* don't realias already aliased names */ 854098Seric if (bitset(QDONTSEND, a->q_flags)) 864098Seric return; 874098Seric 886898Seric CurEnv->e_to = a->q_paddr; 894098Seric 904314Seric /* 914314Seric ** Look up this name 924314Seric */ 934314Seric 9424944Seric if (NoAlias) 9524944Seric p = NULL; 9624944Seric else 9724944Seric p = aliaslookup(a->q_user); 984098Seric if (p == NULL) 994098Seric return; 100292Seric 101292Seric /* 1024098Seric ** Match on Alias. 1034098Seric ** Deliver to the target list. 1041515Seric */ 1051515Seric 1064098Seric # ifdef DEBUG 1077671Seric if (tTd(27, 1)) 1084098Seric printf("%s (%s, %s) aliased to %s\n", 1094098Seric a->q_paddr, a->q_host, a->q_user, p); 1104098Seric # endif 1117051Seric message(Arpa_Info, "aliased to %s", p); 1124098Seric AliasLevel++; 1139614Seric sendtolist(p, a, sendq); 1144098Seric AliasLevel--; 1154098Seric } 1164098Seric /* 1175701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1185701Seric ** 1195701Seric ** Parameters: 1205701Seric ** name -- the name to look up. 1215701Seric ** 1225701Seric ** Returns: 1235701Seric ** the value of name. 1245701Seric ** NULL if unknown. 1255701Seric ** 1265701Seric ** Side Effects: 1275701Seric ** none. 1285701Seric ** 1295701Seric ** Warnings: 1305701Seric ** The return value will be trashed across calls. 1315701Seric */ 1325701Seric 1335701Seric char * 1345701Seric aliaslookup(name) 1355701Seric char *name; 1365701Seric { 1375701Seric # ifdef DBM 1385701Seric DATUM rhs, lhs; 1395701Seric 1405701Seric /* create a key for fetch */ 1415701Seric lhs.dptr = name; 1425701Seric lhs.dsize = strlen(name) + 1; 1435701Seric rhs = fetch(lhs); 1445701Seric return (rhs.dptr); 1455701Seric # else DBM 1465701Seric register STAB *s; 1475701Seric 1485701Seric s = stab(name, ST_ALIAS, ST_FIND); 1495701Seric if (s == NULL) 1505701Seric return (NULL); 1515701Seric return (s->s_alias); 1525701Seric # endif DBM 1535701Seric } 1545701Seric /* 1554098Seric ** INITALIASES -- initialize for aliasing 1564098Seric ** 1574098Seric ** Very different depending on whether we are running DBM or not. 1584098Seric ** 1594098Seric ** Parameters: 1604098Seric ** aliasfile -- location of aliases. 1614157Seric ** init -- if set and if DBM, initialize the DBM files. 1624098Seric ** 1634098Seric ** Returns: 1644098Seric ** none. 1654098Seric ** 1664098Seric ** Side Effects: 1674098Seric ** initializes aliases: 1684098Seric ** if DBM: opens the database. 1694098Seric ** if ~DBM: reads the aliases into the symbol table. 1704098Seric */ 1714098Seric 1724157Seric # define DBMMODE 0666 1734157Seric 1744157Seric initaliases(aliasfile, init) 1754098Seric char *aliasfile; 1764157Seric bool init; 1774098Seric { 1789368Seric #ifdef DBM 1798437Seric int atcnt; 18025522Seric time_t modtime; 18125522Seric bool automatic = FALSE; 1824322Seric char buf[MAXNAME]; 1839368Seric #endif DBM 1849368Seric struct stat stb; 18527176Seric static bool initialized = FALSE; 1864322Seric 18727176Seric if (initialized) 18827176Seric return; 18927176Seric initialized = TRUE; 19027176Seric 19117984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 1928437Seric { 19325522Seric if (aliasfile != NULL && init) 19425522Seric syserr("Cannot open %s", aliasfile); 1958437Seric NoAlias = TRUE; 19611937Seric errno = 0; 1978437Seric return; 1988437Seric } 1998437Seric 2008928Seric # ifdef DBM 2014322Seric /* 2028437Seric ** Check to see that the alias file is complete. 2038437Seric ** If not, we will assume that someone died, and it is up 2048437Seric ** to us to rebuild it. 2058437Seric */ 2068437Seric 20725689Seric if (!init) 20825689Seric dbminit(aliasfile); 20917471Seric atcnt = SafeAlias * 2; 21017471Seric if (atcnt > 0) 21117471Seric { 21217471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 21325689Seric { 21425689Seric /* 21525689Seric ** Reinitialize alias file in case the new 21625689Seric ** one is mv'ed in instead of cp'ed in. 21725689Seric ** 21825689Seric ** Only works with new DBM -- old one will 21925689Seric ** just consume file descriptors forever. 22025689Seric ** If you have a dbmclose() it can be 22125689Seric ** added before the sleep(30). 22225689Seric */ 22325689Seric 22417471Seric sleep(30); 22525689Seric # ifdef NDBM 22625689Seric dbminit(aliasfile); 22725689Seric # endif NDBM 22825689Seric } 22917471Seric } 23017471Seric else 23117471Seric atcnt = 1; 2328437Seric 2338437Seric /* 2344322Seric ** See if the DBM version of the file is out of date with 2354322Seric ** the text version. If so, go into 'init' mode automatically. 2364322Seric ** This only happens if our effective userid owns the DBM 2374325Seric ** version or if the mode of the database is 666 -- this 2384322Seric ** is an attempt to avoid protection problems. Note the 2394322Seric ** unpalatable hack to see if the stat succeeded. 2404322Seric */ 2414322Seric 2424322Seric modtime = stb.st_mtime; 2434322Seric (void) strcpy(buf, aliasfile); 2444322Seric (void) strcat(buf, ".pag"); 2454322Seric stb.st_ino = 0; 24619039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 2474322Seric { 24811937Seric errno = 0; 2499150Seric if (AutoRebuild && stb.st_ino != 0 && 2509368Seric ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) 2514322Seric { 2524322Seric init = TRUE; 25325522Seric automatic = TRUE; 2547051Seric message(Arpa_Info, "rebuilding alias database"); 25524944Seric #ifdef LOG 25624944Seric if (LogLevel >= 7) 25724944Seric syslog(LOG_INFO, "rebuilding alias database"); 25824944Seric #endif LOG 2594322Seric } 2604322Seric else 2614322Seric { 26219039Seric #ifdef LOG 26324944Seric if (LogLevel >= 7) 26424944Seric syslog(LOG_INFO, "alias database out of date"); 26519039Seric #endif LOG 2664322Seric message(Arpa_Info, "Warning: alias database out of date"); 2674322Seric } 2684322Seric } 2694322Seric 2704322Seric 2714322Seric /* 2728437Seric ** If necessary, load the DBM file. 2734322Seric ** If running without DBM, load the symbol table. 2744322Seric */ 2754322Seric 2764157Seric if (init) 2778437Seric { 27825522Seric #ifdef LOG 27925522Seric if (LogLevel >= 6) 28025522Seric { 28125522Seric extern char *username(); 28225522Seric 28325522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 28425522Seric automatic ? "auto" : "", username()); 28525522Seric } 28625522Seric #endif LOG 2874157Seric readaliases(aliasfile, TRUE); 2888437Seric } 2894098Seric # else DBM 2904157Seric readaliases(aliasfile, init); 2914157Seric # endif DBM 2924157Seric } 2934157Seric /* 2944157Seric ** READALIASES -- read and process the alias file. 2954157Seric ** 2964157Seric ** This routine implements the part of initaliases that occurs 2974157Seric ** when we are not going to use the DBM stuff. 2984157Seric ** 2994157Seric ** Parameters: 3004157Seric ** aliasfile -- the pathname of the alias file master. 3014157Seric ** init -- if set, initialize the DBM stuff. 3024157Seric ** 3034157Seric ** Returns: 3044157Seric ** none. 3054157Seric ** 3064157Seric ** Side Effects: 3074157Seric ** Reads aliasfile into the symbol table. 3084157Seric ** Optionally, builds the .dir & .pag files. 3094157Seric */ 3104157Seric 3114157Seric static 3124157Seric readaliases(aliasfile, init) 3134157Seric char *aliasfile; 3144157Seric bool init; 3154157Seric { 3164098Seric register char *p; 3174098Seric char *rhs; 3184098Seric bool skipping; 3199368Seric int naliases, bytes, longest; 3209368Seric FILE *af; 32119784Seric int (*oldsigint)(); 3224098Seric ADDRESS al, bl; 3234106Seric register STAB *s; 3249368Seric char line[BUFSIZ]; 3254098Seric 3264098Seric if ((af = fopen(aliasfile, "r")) == NULL) 3271515Seric { 3284098Seric # ifdef DEBUG 3297671Seric if (tTd(27, 1)) 3304106Seric printf("Can't open %s\n", aliasfile); 3314098Seric # endif 3324098Seric errno = 0; 3334098Seric NoAlias++; 3344098Seric return; 3354098Seric } 3364314Seric 33719784Seric # ifdef DBM 33819784Seric # ifdef FLOCK 33919784Seric /* see if someone else is rebuilding the alias file already */ 34019784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 34119784Seric { 34219784Seric /* yes, they are -- wait until done and then return */ 34319784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 34419784Seric if (OpMode != MD_INITALIAS) 34519784Seric { 34619784Seric /* wait for other rebuild to complete */ 34719784Seric (void) flock(fileno(af), LOCK_EX); 34819784Seric } 34923108Seric (void) fclose(af); 35019784Seric errno = 0; 35119784Seric return; 35219784Seric } 35319784Seric # endif FLOCK 35419784Seric # endif DBM 35519784Seric 3564314Seric /* 35719784Seric ** If initializing, create the new DBM files. 35819784Seric */ 35919784Seric 36019784Seric if (init) 36119784Seric { 36219784Seric oldsigint = signal(SIGINT, SIG_IGN); 36319784Seric (void) strcpy(line, aliasfile); 36419784Seric (void) strcat(line, ".dir"); 36519784Seric if (close(creat(line, DBMMODE)) < 0) 36619784Seric { 36719784Seric syserr("cannot make %s", line); 36819784Seric (void) signal(SIGINT, oldsigint); 36919784Seric return; 37019784Seric } 37119784Seric (void) strcpy(line, aliasfile); 37219784Seric (void) strcat(line, ".pag"); 37319784Seric if (close(creat(line, DBMMODE)) < 0) 37419784Seric { 37519784Seric syserr("cannot make %s", line); 37619784Seric (void) signal(SIGINT, oldsigint); 37719784Seric return; 37819784Seric } 37926501Seric dbminit(aliasfile); 38019784Seric } 38119784Seric 38219784Seric /* 3834314Seric ** Read and interpret lines 3844314Seric */ 3854314Seric 3869368Seric FileName = aliasfile; 3879368Seric LineNumber = 0; 3884322Seric naliases = bytes = longest = 0; 3894098Seric skipping = FALSE; 3904098Seric while (fgets(line, sizeof (line), af) != NULL) 3914098Seric { 3924322Seric int lhssize, rhssize; 3934322Seric 3949368Seric LineNumber++; 39525278Seric p = index(line, '\n'); 39625278Seric if (p != NULL) 39725278Seric *p = '\0'; 3984098Seric switch (line[0]) 3994098Seric { 4004098Seric case '#': 4014098Seric case '\0': 4024098Seric skipping = FALSE; 4034098Seric continue; 4044065Seric 4054098Seric case ' ': 4064098Seric case '\t': 4074098Seric if (!skipping) 4089368Seric syserr("Non-continuation line starts with space"); 4094098Seric skipping = TRUE; 4104097Seric continue; 4114098Seric } 4124098Seric skipping = FALSE; 4131874Seric 4144314Seric /* 4154314Seric ** Process the LHS 4164314Seric ** Find the final colon, and parse the address. 41716898Seric ** It should resolve to a local name -- this will 41816898Seric ** be checked later (we want to optionally do 41916898Seric ** parsing of the RHS first to maximize error 42016898Seric ** detection). 4214314Seric */ 4224314Seric 4234098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 4244097Seric continue; 42516898Seric if (*p++ != ':') 4264098Seric { 4279368Seric syserr("missing colon"); 4284097Seric continue; 4294098Seric } 43016898Seric if (parseaddr(line, &al, 1, ':') == NULL) 4314098Seric { 43216898Seric syserr("illegal alias name"); 43316898Seric continue; 4344098Seric } 43516898Seric loweraddr(&al); 4364314Seric 4374314Seric /* 4384314Seric ** Process the RHS. 4394314Seric ** 'al' is the internal form of the LHS address. 4404314Seric ** 'p' points to the text of the RHS. 4414314Seric */ 4424314Seric 4434098Seric rhs = p; 4444098Seric for (;;) 4454098Seric { 4464098Seric register char c; 4471515Seric 44825821Seric if (init && CheckAliases) 4494098Seric { 4504157Seric /* do parsing & compression of addresses */ 45125278Seric while (*p != '\0') 4524098Seric { 45325278Seric extern char *DelimChar; 45425278Seric 45525278Seric while (isspace(*p) || *p == ',') 4564157Seric p++; 45725278Seric if (*p == '\0') 45825278Seric break; 45925278Seric if (parseaddr(p, &bl, -1, ',') == NULL) 46025278Seric usrerr("%s... bad address", p); 46125278Seric p = DelimChar; 4624098Seric } 4634098Seric } 4644157Seric else 46515769Seric { 46616898Seric p = &p[strlen(p)]; 46716898Seric if (p[-1] == '\n') 46816898Seric *--p = '\0'; 46915769Seric } 4701515Seric 4714098Seric /* see if there should be a continuation line */ 4724106Seric c = fgetc(af); 4734106Seric if (!feof(af)) 4744314Seric (void) ungetc(c, af); 4754106Seric if (c != ' ' && c != '\t') 4764098Seric break; 4774098Seric 4784098Seric /* read continuation line */ 4794098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4804098Seric break; 4819368Seric LineNumber++; 4824098Seric } 48316898Seric if (al.q_mailer != LocalMailer) 48416898Seric { 48516898Seric syserr("cannot alias non-local names"); 48616898Seric continue; 48716898Seric } 4884314Seric 4894314Seric /* 4904314Seric ** Insert alias into symbol table or DBM file 4914314Seric */ 4924314Seric 49316898Seric lhssize = strlen(al.q_user) + 1; 4944322Seric rhssize = strlen(rhs) + 1; 4954322Seric 4964157Seric # ifdef DBM 4974157Seric if (init) 4984157Seric { 4994157Seric DATUM key, content; 5004157Seric 5014322Seric key.dsize = lhssize; 5024157Seric key.dptr = al.q_user; 5034322Seric content.dsize = rhssize; 5044157Seric content.dptr = rhs; 5054157Seric store(key, content); 5064157Seric } 5074157Seric else 5084157Seric # endif DBM 5094157Seric { 5104157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 5114157Seric s->s_alias = newstr(rhs); 5124157Seric } 5134322Seric 5144322Seric /* statistics */ 5154322Seric naliases++; 5164322Seric bytes += lhssize + rhssize; 5174322Seric if (rhssize > longest) 5184322Seric longest = rhssize; 5191515Seric } 52019784Seric 52119784Seric # ifdef DBM 52219784Seric if (init) 52319784Seric { 52419784Seric /* add the distinquished alias "@" */ 52519784Seric DATUM key; 52619784Seric 52719784Seric key.dsize = 2; 52819784Seric key.dptr = "@"; 52919784Seric store(key, key); 53019784Seric 53119784Seric /* restore the old signal */ 53219784Seric (void) signal(SIGINT, oldsigint); 53319784Seric } 53419784Seric # endif DBM 53519784Seric 53619784Seric /* closing the alias file drops the lock */ 5374098Seric (void) fclose(af); 5386898Seric CurEnv->e_to = NULL; 5399368Seric FileName = NULL; 5407051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 5414322Seric naliases, longest, bytes); 54224944Seric # ifdef LOG 54324944Seric if (LogLevel >= 8) 54424944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 54524944Seric naliases, longest, bytes); 54624944Seric # endif LOG 547292Seric } 548292Seric /* 549292Seric ** FORWARD -- Try to forward mail 550292Seric ** 551292Seric ** This is similar but not identical to aliasing. 552292Seric ** 553292Seric ** Parameters: 5544314Seric ** user -- the name of the user who's mail we would like 5554314Seric ** to forward to. It must have been verified -- 5564314Seric ** i.e., the q_home field must have been filled 5574314Seric ** in. 5584999Seric ** sendq -- a pointer to the head of the send queue to 5594999Seric ** put this user's aliases in. 560292Seric ** 561292Seric ** Returns: 5624098Seric ** none. 563292Seric ** 564292Seric ** Side Effects: 5653185Seric ** New names are added to send queues. 566292Seric */ 567292Seric 5684999Seric forward(user, sendq) 5692966Seric ADDRESS *user; 5704999Seric ADDRESS **sendq; 571292Seric { 5724078Seric char buf[60]; 5734536Seric extern bool safefile(); 5744069Seric 5754098Seric # ifdef DEBUG 5767671Seric if (tTd(27, 1)) 5774098Seric printf("forward(%s)\n", user->q_paddr); 5784098Seric # endif DEBUG 5794098Seric 5804594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 5814098Seric return; 5824314Seric # ifdef DEBUG 5834314Seric if (user->q_home == NULL) 5844314Seric syserr("forward: no home"); 5854314Seric # endif DEBUG 5864069Seric 5874069Seric /* good address -- look for .forward file in home */ 5889368Seric define('z', user->q_home, CurEnv); 58916154Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 5904536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 5914098Seric return; 5924069Seric 5934069Seric /* we do have an address to forward to -- do it */ 5944999Seric include(buf, "forwarding", user, sendq); 595292Seric } 596