122694Sdist /* 222694Sdist ** Sendmail 322694Sdist ** Copyright (c) 1983 Eric P. Allman 422694Sdist ** Berkeley, California 522694Sdist ** 622694Sdist ** Copyright (c) 1983 Regents of the University of California. 722694Sdist ** All rights reserved. The Berkeley software License Agreement 822694Sdist ** specifies the terms and conditions for redistribution. 922694Sdist */ 1022694Sdist 1122694Sdist #ifndef lint 12*22903Smiriam # ifdef DBM 13*22903Smiriam static char SccsId[] = "@(#)alias.c 5.2 (Berkeley) 06/07/85 (with DBM)"; 14*22903Smiriam # else DBM 15*22903Smiriam static char SccsId[] = "@(#)alias.c 5.2 (Berkeley) 06/07/85 (without DBM)"; 16*22903Smiriam # endif DBM 1722694Sdist #endif not lint 1822694Sdist 19292Seric # include <pwd.h> 204212Seric # include <sys/types.h> 214212Seric # include <sys/stat.h> 228437Seric # include <signal.h> 2319784Seric # include <errno.h> 243309Seric # include "sendmail.h" 2519784Seric # ifdef FLOCK 2619784Seric # include <sys/file.h> 2719784Seric # endif FLOCK 28292Seric 29402Seric 30292Seric /* 31292Seric ** ALIAS -- Compute aliases. 32292Seric ** 339368Seric ** Scans the alias file for an alias for the given address. 349368Seric ** If found, it arranges to deliver to the alias list instead. 359368Seric ** Uses libdbm database if -DDBM. 36292Seric ** 37292Seric ** Parameters: 384097Seric ** a -- address to alias. 394999Seric ** sendq -- a pointer to the head of the send queue 404999Seric ** to put the aliases in. 41292Seric ** 42292Seric ** Returns: 43292Seric ** none 44292Seric ** 45292Seric ** Side Effects: 463185Seric ** Aliases found are expanded. 47292Seric ** 48292Seric ** Notes: 49292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 50292Seric ** done. 51292Seric ** 52292Seric ** Deficiencies: 53292Seric ** It should complain about names that are aliased to 54292Seric ** nothing. 55292Seric */ 56292Seric 57292Seric 581503Smark #ifdef DBM 592966Seric typedef struct 602966Seric { 612966Seric char *dptr; 624157Seric int dsize; 634157Seric } DATUM; 644157Seric extern DATUM fetch(); 651503Smark #endif DBM 66292Seric 674999Seric alias(a, sendq) 684097Seric register ADDRESS *a; 694999Seric ADDRESS **sendq; 70292Seric { 714081Seric register char *p; 725701Seric extern char *aliaslookup(); 73292Seric 74292Seric if (NoAlias) 75292Seric return; 76292Seric # ifdef DEBUG 777671Seric if (tTd(27, 1)) 784098Seric printf("alias(%s)\n", a->q_paddr); 79292Seric # endif 80292Seric 814098Seric /* don't realias already aliased names */ 824098Seric if (bitset(QDONTSEND, a->q_flags)) 834098Seric return; 844098Seric 856898Seric CurEnv->e_to = a->q_paddr; 864098Seric 874314Seric /* 884314Seric ** Look up this name 894314Seric */ 904314Seric 915701Seric p = aliaslookup(a->q_user); 924098Seric if (p == NULL) 934098Seric return; 94292Seric 95292Seric /* 964098Seric ** Match on Alias. 974098Seric ** Deliver to the target list. 981515Seric */ 991515Seric 1004098Seric # ifdef DEBUG 1017671Seric if (tTd(27, 1)) 1024098Seric printf("%s (%s, %s) aliased to %s\n", 1034098Seric a->q_paddr, a->q_host, a->q_user, p); 1044098Seric # endif 1057051Seric message(Arpa_Info, "aliased to %s", p); 1064098Seric AliasLevel++; 1079614Seric sendtolist(p, a, sendq); 1084098Seric AliasLevel--; 1094098Seric } 1104098Seric /* 1115701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1125701Seric ** 1135701Seric ** Parameters: 1145701Seric ** name -- the name to look up. 1155701Seric ** 1165701Seric ** Returns: 1175701Seric ** the value of name. 1185701Seric ** NULL if unknown. 1195701Seric ** 1205701Seric ** Side Effects: 1215701Seric ** none. 1225701Seric ** 1235701Seric ** Warnings: 1245701Seric ** The return value will be trashed across calls. 1255701Seric */ 1265701Seric 1275701Seric char * 1285701Seric aliaslookup(name) 1295701Seric char *name; 1305701Seric { 1315701Seric # ifdef DBM 1325701Seric DATUM rhs, lhs; 1335701Seric 1345701Seric /* create a key for fetch */ 1355701Seric lhs.dptr = name; 1365701Seric lhs.dsize = strlen(name) + 1; 1375701Seric rhs = fetch(lhs); 1385701Seric return (rhs.dptr); 1395701Seric # else DBM 1405701Seric register STAB *s; 1415701Seric 1425701Seric s = stab(name, ST_ALIAS, ST_FIND); 1435701Seric if (s == NULL) 1445701Seric return (NULL); 1455701Seric return (s->s_alias); 1465701Seric # endif DBM 1475701Seric } 1485701Seric /* 1494098Seric ** INITALIASES -- initialize for aliasing 1504098Seric ** 1514098Seric ** Very different depending on whether we are running DBM or not. 1524098Seric ** 1534098Seric ** Parameters: 1544098Seric ** aliasfile -- location of aliases. 1554157Seric ** init -- if set and if DBM, initialize the DBM files. 1564098Seric ** 1574098Seric ** Returns: 1584098Seric ** none. 1594098Seric ** 1604098Seric ** Side Effects: 1614098Seric ** initializes aliases: 1624098Seric ** if DBM: opens the database. 1634098Seric ** if ~DBM: reads the aliases into the symbol table. 1644098Seric */ 1654098Seric 1664157Seric # define DBMMODE 0666 1674157Seric 1684157Seric initaliases(aliasfile, init) 1694098Seric char *aliasfile; 1704157Seric bool init; 1714098Seric { 1729368Seric #ifdef DBM 1738437Seric int atcnt; 1744322Seric char buf[MAXNAME]; 1754322Seric time_t modtime; 1769368Seric #endif DBM 1779368Seric struct stat stb; 1784322Seric 17917984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 1808437Seric { 1818437Seric NoAlias = TRUE; 18211937Seric errno = 0; 1838437Seric return; 1848437Seric } 1858437Seric 1868928Seric # ifdef DBM 1874322Seric /* 1888437Seric ** Check to see that the alias file is complete. 1898437Seric ** If not, we will assume that someone died, and it is up 1908437Seric ** to us to rebuild it. 1918437Seric */ 1928437Seric 1938437Seric dbminit(aliasfile); 19417471Seric atcnt = SafeAlias * 2; 19517471Seric if (atcnt > 0) 19617471Seric { 19717471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 19817471Seric sleep(30); 19917471Seric } 20017471Seric else 20117471Seric atcnt = 1; 2028437Seric 2038437Seric /* 2044322Seric ** See if the DBM version of the file is out of date with 2054322Seric ** the text version. If so, go into 'init' mode automatically. 2064322Seric ** This only happens if our effective userid owns the DBM 2074325Seric ** version or if the mode of the database is 666 -- this 2084322Seric ** is an attempt to avoid protection problems. Note the 2094322Seric ** unpalatable hack to see if the stat succeeded. 2104322Seric */ 2114322Seric 2124322Seric modtime = stb.st_mtime; 2134322Seric (void) strcpy(buf, aliasfile); 2144322Seric (void) strcat(buf, ".pag"); 2154322Seric stb.st_ino = 0; 21619039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 2174322Seric { 21811937Seric errno = 0; 2199150Seric if (AutoRebuild && stb.st_ino != 0 && 2209368Seric ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) 2214322Seric { 2224322Seric init = TRUE; 2237051Seric message(Arpa_Info, "rebuilding alias database"); 2244322Seric } 2254322Seric else 2264322Seric { 22719039Seric #ifdef LOG 22819039Seric syslog(LOG_INFO, "alias database out of date"); 22919039Seric #endif LOG 2304322Seric message(Arpa_Info, "Warning: alias database out of date"); 2314322Seric } 2324322Seric } 2334322Seric 2344322Seric 2354322Seric /* 2368437Seric ** If necessary, load the DBM file. 2374322Seric ** If running without DBM, load the symbol table. 2384322Seric */ 2394322Seric 2404157Seric if (init) 2418437Seric { 2424157Seric readaliases(aliasfile, TRUE); 2438437Seric } 2444098Seric # else DBM 2454157Seric readaliases(aliasfile, init); 2464157Seric # endif DBM 2474157Seric } 2484157Seric /* 2494157Seric ** READALIASES -- read and process the alias file. 2504157Seric ** 2514157Seric ** This routine implements the part of initaliases that occurs 2524157Seric ** when we are not going to use the DBM stuff. 2534157Seric ** 2544157Seric ** Parameters: 2554157Seric ** aliasfile -- the pathname of the alias file master. 2564157Seric ** init -- if set, initialize the DBM stuff. 2574157Seric ** 2584157Seric ** Returns: 2594157Seric ** none. 2604157Seric ** 2614157Seric ** Side Effects: 2624157Seric ** Reads aliasfile into the symbol table. 2634157Seric ** Optionally, builds the .dir & .pag files. 2644157Seric */ 2654157Seric 2664157Seric static 2674157Seric readaliases(aliasfile, init) 2684157Seric char *aliasfile; 2694157Seric bool init; 2704157Seric { 2714098Seric register char *p; 2724098Seric char *p2; 2734098Seric char *rhs; 2744098Seric bool skipping; 2759368Seric int naliases, bytes, longest; 2769368Seric FILE *af; 27719784Seric int (*oldsigint)(); 2784098Seric ADDRESS al, bl; 2794106Seric register STAB *s; 2809368Seric char line[BUFSIZ]; 2814098Seric 2824098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2831515Seric { 2844098Seric # ifdef DEBUG 2857671Seric if (tTd(27, 1)) 2864106Seric printf("Can't open %s\n", aliasfile); 2874098Seric # endif 2884098Seric errno = 0; 2894098Seric NoAlias++; 2904098Seric return; 2914098Seric } 2924314Seric 29319784Seric # ifdef DBM 29419784Seric # ifdef FLOCK 29519784Seric /* see if someone else is rebuilding the alias file already */ 29619784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 29719784Seric { 29819784Seric /* yes, they are -- wait until done and then return */ 29919784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 30019784Seric if (OpMode != MD_INITALIAS) 30119784Seric { 30219784Seric /* wait for other rebuild to complete */ 30319784Seric (void) flock(fileno(af), LOCK_EX); 30419784Seric } 30519784Seric fclose(af); 30619784Seric errno = 0; 30719784Seric return; 30819784Seric } 30919784Seric # endif FLOCK 31019784Seric # endif DBM 31119784Seric 3124314Seric /* 31319784Seric ** If initializing, create the new DBM files. 31419784Seric */ 31519784Seric 31619784Seric if (init) 31719784Seric { 31819784Seric oldsigint = signal(SIGINT, SIG_IGN); 31919784Seric (void) strcpy(line, aliasfile); 32019784Seric (void) strcat(line, ".dir"); 32119784Seric if (close(creat(line, DBMMODE)) < 0) 32219784Seric { 32319784Seric syserr("cannot make %s", line); 32419784Seric (void) signal(SIGINT, oldsigint); 32519784Seric return; 32619784Seric } 32719784Seric (void) strcpy(line, aliasfile); 32819784Seric (void) strcat(line, ".pag"); 32919784Seric if (close(creat(line, DBMMODE)) < 0) 33019784Seric { 33119784Seric syserr("cannot make %s", line); 33219784Seric (void) signal(SIGINT, oldsigint); 33319784Seric return; 33419784Seric } 33519784Seric } 33619784Seric 33719784Seric /* 3384314Seric ** Read and interpret lines 3394314Seric */ 3404314Seric 3419368Seric FileName = aliasfile; 3429368Seric LineNumber = 0; 3434322Seric naliases = bytes = longest = 0; 3444098Seric skipping = FALSE; 3454098Seric while (fgets(line, sizeof (line), af) != NULL) 3464098Seric { 3474322Seric int lhssize, rhssize; 3484322Seric 3499368Seric LineNumber++; 3504098Seric switch (line[0]) 3514098Seric { 3524098Seric case '#': 3534098Seric case '\n': 3544098Seric case '\0': 3554098Seric skipping = FALSE; 3564098Seric continue; 3574065Seric 3584098Seric case ' ': 3594098Seric case '\t': 3604098Seric if (!skipping) 3619368Seric syserr("Non-continuation line starts with space"); 3624098Seric skipping = TRUE; 3634097Seric continue; 3644098Seric } 3654098Seric skipping = FALSE; 3661874Seric 3674314Seric /* 3684314Seric ** Process the LHS 3694314Seric ** Find the final colon, and parse the address. 37016898Seric ** It should resolve to a local name -- this will 37116898Seric ** be checked later (we want to optionally do 37216898Seric ** parsing of the RHS first to maximize error 37316898Seric ** detection). 3744314Seric */ 3754314Seric 3764098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3774097Seric continue; 37816898Seric if (*p++ != ':') 3794098Seric { 3809368Seric syserr("missing colon"); 3814097Seric continue; 3824098Seric } 38316898Seric if (parseaddr(line, &al, 1, ':') == NULL) 3844098Seric { 38516898Seric syserr("illegal alias name"); 38616898Seric continue; 3874098Seric } 38816898Seric loweraddr(&al); 3894314Seric 3904314Seric /* 3914314Seric ** Process the RHS. 3924314Seric ** 'al' is the internal form of the LHS address. 3934314Seric ** 'p' points to the text of the RHS. 3944314Seric */ 3954314Seric 3964098Seric rhs = p; 3974098Seric for (;;) 3984098Seric { 3994098Seric register char c; 4001515Seric 4014157Seric if (init) 4024098Seric { 4034157Seric /* do parsing & compression of addresses */ 4044098Seric c = *p; 4054157Seric while (c != '\0') 4064098Seric { 4074157Seric p2 = p; 4084157Seric while (*p != '\n' && *p != ',' && *p != '\0') 4094157Seric p++; 4104157Seric c = *p; 4114322Seric if (c == '\n') 4124322Seric c = '\0'; 41317199Seric *p = '\0'; 41417199Seric if (*p2 != '\0') 41517199Seric (void) parseaddr(p2, &bl, -1, ','); 41617199Seric if (c != '\0') 41717199Seric *p++ = c; 4184098Seric } 4194098Seric } 4204157Seric else 42115769Seric { 42216898Seric p = &p[strlen(p)]; 42316898Seric if (p[-1] == '\n') 42416898Seric *--p = '\0'; 42515769Seric } 4261515Seric 4274098Seric /* see if there should be a continuation line */ 4284106Seric c = fgetc(af); 4294106Seric if (!feof(af)) 4304314Seric (void) ungetc(c, af); 4314106Seric if (c != ' ' && c != '\t') 4324098Seric break; 4334098Seric 4344098Seric /* read continuation line */ 4354098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4364098Seric break; 4379368Seric LineNumber++; 4384098Seric } 43916898Seric if (al.q_mailer != LocalMailer) 44016898Seric { 44116898Seric syserr("cannot alias non-local names"); 44216898Seric continue; 44316898Seric } 4444314Seric 4454314Seric /* 4464314Seric ** Insert alias into symbol table or DBM file 4474314Seric */ 4484314Seric 44916898Seric lhssize = strlen(al.q_user) + 1; 4504322Seric rhssize = strlen(rhs) + 1; 4514322Seric 4524157Seric # ifdef DBM 4534157Seric if (init) 4544157Seric { 4554157Seric DATUM key, content; 4564157Seric 4574322Seric key.dsize = lhssize; 4584157Seric key.dptr = al.q_user; 4594322Seric content.dsize = rhssize; 4604157Seric content.dptr = rhs; 4614157Seric store(key, content); 4624157Seric } 4634157Seric else 4644157Seric # endif DBM 4654157Seric { 4664157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4674157Seric s->s_alias = newstr(rhs); 4684157Seric } 4694322Seric 4704322Seric /* statistics */ 4714322Seric naliases++; 4724322Seric bytes += lhssize + rhssize; 4734322Seric if (rhssize > longest) 4744322Seric longest = rhssize; 4751515Seric } 47619784Seric 47719784Seric # ifdef DBM 47819784Seric if (init) 47919784Seric { 48019784Seric /* add the distinquished alias "@" */ 48119784Seric DATUM key; 48219784Seric 48319784Seric key.dsize = 2; 48419784Seric key.dptr = "@"; 48519784Seric store(key, key); 48619784Seric 48719784Seric /* restore the old signal */ 48819784Seric (void) signal(SIGINT, oldsigint); 48919784Seric } 49019784Seric # endif DBM 49119784Seric 49219784Seric /* closing the alias file drops the lock */ 4934098Seric (void) fclose(af); 4946898Seric CurEnv->e_to = NULL; 4959368Seric FileName = NULL; 4967051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4974322Seric naliases, longest, bytes); 498292Seric } 499292Seric /* 500292Seric ** FORWARD -- Try to forward mail 501292Seric ** 502292Seric ** This is similar but not identical to aliasing. 503292Seric ** 504292Seric ** Parameters: 5054314Seric ** user -- the name of the user who's mail we would like 5064314Seric ** to forward to. It must have been verified -- 5074314Seric ** i.e., the q_home field must have been filled 5084314Seric ** in. 5094999Seric ** sendq -- a pointer to the head of the send queue to 5104999Seric ** put this user's aliases in. 511292Seric ** 512292Seric ** Returns: 5134098Seric ** none. 514292Seric ** 515292Seric ** Side Effects: 5163185Seric ** New names are added to send queues. 517292Seric */ 518292Seric 5194999Seric forward(user, sendq) 5202966Seric ADDRESS *user; 5214999Seric ADDRESS **sendq; 522292Seric { 5234078Seric char buf[60]; 5244536Seric extern bool safefile(); 5254069Seric 5264098Seric # ifdef DEBUG 5277671Seric if (tTd(27, 1)) 5284098Seric printf("forward(%s)\n", user->q_paddr); 5294098Seric # endif DEBUG 5304098Seric 5314594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 5324098Seric return; 5334314Seric # ifdef DEBUG 5344314Seric if (user->q_home == NULL) 5354314Seric syserr("forward: no home"); 5364314Seric # endif DEBUG 5374069Seric 5384069Seric /* good address -- look for .forward file in home */ 5399368Seric define('z', user->q_home, CurEnv); 54016154Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 5414536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 5424098Seric return; 5434069Seric 5444069Seric /* we do have an address to forward to -- do it */ 5454999Seric include(buf, "forwarding", user, sendq); 546292Seric } 547