1*22694Sdist /* 2*22694Sdist ** Sendmail 3*22694Sdist ** Copyright (c) 1983 Eric P. Allman 4*22694Sdist ** Berkeley, California 5*22694Sdist ** 6*22694Sdist ** Copyright (c) 1983 Regents of the University of California. 7*22694Sdist ** All rights reserved. The Berkeley software License Agreement 8*22694Sdist ** specifies the terms and conditions for redistribution. 9*22694Sdist */ 10*22694Sdist 11*22694Sdist #ifndef lint 12*22694Sdist static char SccsId[] = "@(#)alias.c 5.1 (Berkeley) 06/07/85"; 13*22694Sdist #endif not lint 14*22694Sdist 15292Seric # include <pwd.h> 164212Seric # include <sys/types.h> 174212Seric # include <sys/stat.h> 188437Seric # include <signal.h> 1919784Seric # include <errno.h> 203309Seric # include "sendmail.h" 2119784Seric # ifdef FLOCK 2219784Seric # include <sys/file.h> 2319784Seric # endif FLOCK 24292Seric 254106Seric # ifdef DBM 26*22694Sdist SCCSID(@(#)alias.c 5.1 06/07/85 (with DBM)); 274106Seric # else DBM 28*22694Sdist SCCSID(@(#)alias.c 5.1 06/07/85 (without DBM)); 294106Seric # endif DBM 30402Seric 31292Seric /* 32292Seric ** ALIAS -- Compute aliases. 33292Seric ** 349368Seric ** Scans the alias file for an alias for the given address. 359368Seric ** If found, it arranges to deliver to the alias list instead. 369368Seric ** Uses libdbm database if -DDBM. 37292Seric ** 38292Seric ** Parameters: 394097Seric ** a -- address to alias. 404999Seric ** sendq -- a pointer to the head of the send queue 414999Seric ** to put the aliases in. 42292Seric ** 43292Seric ** Returns: 44292Seric ** none 45292Seric ** 46292Seric ** Side Effects: 473185Seric ** Aliases found are expanded. 48292Seric ** 49292Seric ** Notes: 50292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 51292Seric ** done. 52292Seric ** 53292Seric ** Deficiencies: 54292Seric ** It should complain about names that are aliased to 55292Seric ** nothing. 56292Seric */ 57292Seric 58292Seric 591503Smark #ifdef DBM 602966Seric typedef struct 612966Seric { 622966Seric char *dptr; 634157Seric int dsize; 644157Seric } DATUM; 654157Seric extern DATUM fetch(); 661503Smark #endif DBM 67292Seric 684999Seric alias(a, sendq) 694097Seric register ADDRESS *a; 704999Seric ADDRESS **sendq; 71292Seric { 724081Seric register char *p; 735701Seric extern char *aliaslookup(); 74292Seric 75292Seric if (NoAlias) 76292Seric return; 77292Seric # ifdef DEBUG 787671Seric if (tTd(27, 1)) 794098Seric printf("alias(%s)\n", a->q_paddr); 80292Seric # endif 81292Seric 824098Seric /* don't realias already aliased names */ 834098Seric if (bitset(QDONTSEND, a->q_flags)) 844098Seric return; 854098Seric 866898Seric CurEnv->e_to = a->q_paddr; 874098Seric 884314Seric /* 894314Seric ** Look up this name 904314Seric */ 914314Seric 925701Seric p = aliaslookup(a->q_user); 934098Seric if (p == NULL) 944098Seric return; 95292Seric 96292Seric /* 974098Seric ** Match on Alias. 984098Seric ** Deliver to the target list. 991515Seric */ 1001515Seric 1014098Seric # ifdef DEBUG 1027671Seric if (tTd(27, 1)) 1034098Seric printf("%s (%s, %s) aliased to %s\n", 1044098Seric a->q_paddr, a->q_host, a->q_user, p); 1054098Seric # endif 1067051Seric message(Arpa_Info, "aliased to %s", p); 1074098Seric AliasLevel++; 1089614Seric sendtolist(p, a, sendq); 1094098Seric AliasLevel--; 1104098Seric } 1114098Seric /* 1125701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1135701Seric ** 1145701Seric ** Parameters: 1155701Seric ** name -- the name to look up. 1165701Seric ** 1175701Seric ** Returns: 1185701Seric ** the value of name. 1195701Seric ** NULL if unknown. 1205701Seric ** 1215701Seric ** Side Effects: 1225701Seric ** none. 1235701Seric ** 1245701Seric ** Warnings: 1255701Seric ** The return value will be trashed across calls. 1265701Seric */ 1275701Seric 1285701Seric char * 1295701Seric aliaslookup(name) 1305701Seric char *name; 1315701Seric { 1325701Seric # ifdef DBM 1335701Seric DATUM rhs, lhs; 1345701Seric 1355701Seric /* create a key for fetch */ 1365701Seric lhs.dptr = name; 1375701Seric lhs.dsize = strlen(name) + 1; 1385701Seric rhs = fetch(lhs); 1395701Seric return (rhs.dptr); 1405701Seric # else DBM 1415701Seric register STAB *s; 1425701Seric 1435701Seric s = stab(name, ST_ALIAS, ST_FIND); 1445701Seric if (s == NULL) 1455701Seric return (NULL); 1465701Seric return (s->s_alias); 1475701Seric # endif DBM 1485701Seric } 1495701Seric /* 1504098Seric ** INITALIASES -- initialize for aliasing 1514098Seric ** 1524098Seric ** Very different depending on whether we are running DBM or not. 1534098Seric ** 1544098Seric ** Parameters: 1554098Seric ** aliasfile -- location of aliases. 1564157Seric ** init -- if set and if DBM, initialize the DBM files. 1574098Seric ** 1584098Seric ** Returns: 1594098Seric ** none. 1604098Seric ** 1614098Seric ** Side Effects: 1624098Seric ** initializes aliases: 1634098Seric ** if DBM: opens the database. 1644098Seric ** if ~DBM: reads the aliases into the symbol table. 1654098Seric */ 1664098Seric 1674157Seric # define DBMMODE 0666 1684157Seric 1694157Seric initaliases(aliasfile, init) 1704098Seric char *aliasfile; 1714157Seric bool init; 1724098Seric { 1739368Seric #ifdef DBM 1748437Seric int atcnt; 1754322Seric char buf[MAXNAME]; 1764322Seric time_t modtime; 1779368Seric #endif DBM 1789368Seric struct stat stb; 1794322Seric 18017984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 1818437Seric { 1828437Seric NoAlias = TRUE; 18311937Seric errno = 0; 1848437Seric return; 1858437Seric } 1868437Seric 1878928Seric # ifdef DBM 1884322Seric /* 1898437Seric ** Check to see that the alias file is complete. 1908437Seric ** If not, we will assume that someone died, and it is up 1918437Seric ** to us to rebuild it. 1928437Seric */ 1938437Seric 1948437Seric dbminit(aliasfile); 19517471Seric atcnt = SafeAlias * 2; 19617471Seric if (atcnt > 0) 19717471Seric { 19817471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 19917471Seric sleep(30); 20017471Seric } 20117471Seric else 20217471Seric atcnt = 1; 2038437Seric 2048437Seric /* 2054322Seric ** See if the DBM version of the file is out of date with 2064322Seric ** the text version. If so, go into 'init' mode automatically. 2074322Seric ** This only happens if our effective userid owns the DBM 2084325Seric ** version or if the mode of the database is 666 -- this 2094322Seric ** is an attempt to avoid protection problems. Note the 2104322Seric ** unpalatable hack to see if the stat succeeded. 2114322Seric */ 2124322Seric 2134322Seric modtime = stb.st_mtime; 2144322Seric (void) strcpy(buf, aliasfile); 2154322Seric (void) strcat(buf, ".pag"); 2164322Seric stb.st_ino = 0; 21719039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 2184322Seric { 21911937Seric errno = 0; 2209150Seric if (AutoRebuild && stb.st_ino != 0 && 2219368Seric ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) 2224322Seric { 2234322Seric init = TRUE; 2247051Seric message(Arpa_Info, "rebuilding alias database"); 2254322Seric } 2264322Seric else 2274322Seric { 22819039Seric #ifdef LOG 22919039Seric syslog(LOG_INFO, "alias database out of date"); 23019039Seric #endif LOG 2314322Seric message(Arpa_Info, "Warning: alias database out of date"); 2324322Seric } 2334322Seric } 2344322Seric 2354322Seric 2364322Seric /* 2378437Seric ** If necessary, load the DBM file. 2384322Seric ** If running without DBM, load the symbol table. 2394322Seric */ 2404322Seric 2414157Seric if (init) 2428437Seric { 2434157Seric readaliases(aliasfile, TRUE); 2448437Seric } 2454098Seric # else DBM 2464157Seric readaliases(aliasfile, init); 2474157Seric # endif DBM 2484157Seric } 2494157Seric /* 2504157Seric ** READALIASES -- read and process the alias file. 2514157Seric ** 2524157Seric ** This routine implements the part of initaliases that occurs 2534157Seric ** when we are not going to use the DBM stuff. 2544157Seric ** 2554157Seric ** Parameters: 2564157Seric ** aliasfile -- the pathname of the alias file master. 2574157Seric ** init -- if set, initialize the DBM stuff. 2584157Seric ** 2594157Seric ** Returns: 2604157Seric ** none. 2614157Seric ** 2624157Seric ** Side Effects: 2634157Seric ** Reads aliasfile into the symbol table. 2644157Seric ** Optionally, builds the .dir & .pag files. 2654157Seric */ 2664157Seric 2674157Seric static 2684157Seric readaliases(aliasfile, init) 2694157Seric char *aliasfile; 2704157Seric bool init; 2714157Seric { 2724098Seric register char *p; 2734098Seric char *p2; 2744098Seric char *rhs; 2754098Seric bool skipping; 2769368Seric int naliases, bytes, longest; 2779368Seric FILE *af; 27819784Seric int (*oldsigint)(); 2794098Seric ADDRESS al, bl; 2804106Seric register STAB *s; 2819368Seric char line[BUFSIZ]; 2824098Seric 2834098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2841515Seric { 2854098Seric # ifdef DEBUG 2867671Seric if (tTd(27, 1)) 2874106Seric printf("Can't open %s\n", aliasfile); 2884098Seric # endif 2894098Seric errno = 0; 2904098Seric NoAlias++; 2914098Seric return; 2924098Seric } 2934314Seric 29419784Seric # ifdef DBM 29519784Seric # ifdef FLOCK 29619784Seric /* see if someone else is rebuilding the alias file already */ 29719784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 29819784Seric { 29919784Seric /* yes, they are -- wait until done and then return */ 30019784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 30119784Seric if (OpMode != MD_INITALIAS) 30219784Seric { 30319784Seric /* wait for other rebuild to complete */ 30419784Seric (void) flock(fileno(af), LOCK_EX); 30519784Seric } 30619784Seric fclose(af); 30719784Seric errno = 0; 30819784Seric return; 30919784Seric } 31019784Seric # endif FLOCK 31119784Seric # endif DBM 31219784Seric 3134314Seric /* 31419784Seric ** If initializing, create the new DBM files. 31519784Seric */ 31619784Seric 31719784Seric if (init) 31819784Seric { 31919784Seric oldsigint = signal(SIGINT, SIG_IGN); 32019784Seric (void) strcpy(line, aliasfile); 32119784Seric (void) strcat(line, ".dir"); 32219784Seric if (close(creat(line, DBMMODE)) < 0) 32319784Seric { 32419784Seric syserr("cannot make %s", line); 32519784Seric (void) signal(SIGINT, oldsigint); 32619784Seric return; 32719784Seric } 32819784Seric (void) strcpy(line, aliasfile); 32919784Seric (void) strcat(line, ".pag"); 33019784Seric if (close(creat(line, DBMMODE)) < 0) 33119784Seric { 33219784Seric syserr("cannot make %s", line); 33319784Seric (void) signal(SIGINT, oldsigint); 33419784Seric return; 33519784Seric } 33619784Seric } 33719784Seric 33819784Seric /* 3394314Seric ** Read and interpret lines 3404314Seric */ 3414314Seric 3429368Seric FileName = aliasfile; 3439368Seric LineNumber = 0; 3444322Seric naliases = bytes = longest = 0; 3454098Seric skipping = FALSE; 3464098Seric while (fgets(line, sizeof (line), af) != NULL) 3474098Seric { 3484322Seric int lhssize, rhssize; 3494322Seric 3509368Seric LineNumber++; 3514098Seric switch (line[0]) 3524098Seric { 3534098Seric case '#': 3544098Seric case '\n': 3554098Seric case '\0': 3564098Seric skipping = FALSE; 3574098Seric continue; 3584065Seric 3594098Seric case ' ': 3604098Seric case '\t': 3614098Seric if (!skipping) 3629368Seric syserr("Non-continuation line starts with space"); 3634098Seric skipping = TRUE; 3644097Seric continue; 3654098Seric } 3664098Seric skipping = FALSE; 3671874Seric 3684314Seric /* 3694314Seric ** Process the LHS 3704314Seric ** Find the final colon, and parse the address. 37116898Seric ** It should resolve to a local name -- this will 37216898Seric ** be checked later (we want to optionally do 37316898Seric ** parsing of the RHS first to maximize error 37416898Seric ** detection). 3754314Seric */ 3764314Seric 3774098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3784097Seric continue; 37916898Seric if (*p++ != ':') 3804098Seric { 3819368Seric syserr("missing colon"); 3824097Seric continue; 3834098Seric } 38416898Seric if (parseaddr(line, &al, 1, ':') == NULL) 3854098Seric { 38616898Seric syserr("illegal alias name"); 38716898Seric continue; 3884098Seric } 38916898Seric loweraddr(&al); 3904314Seric 3914314Seric /* 3924314Seric ** Process the RHS. 3934314Seric ** 'al' is the internal form of the LHS address. 3944314Seric ** 'p' points to the text of the RHS. 3954314Seric */ 3964314Seric 3974098Seric rhs = p; 3984098Seric for (;;) 3994098Seric { 4004098Seric register char c; 4011515Seric 4024157Seric if (init) 4034098Seric { 4044157Seric /* do parsing & compression of addresses */ 4054098Seric c = *p; 4064157Seric while (c != '\0') 4074098Seric { 4084157Seric p2 = p; 4094157Seric while (*p != '\n' && *p != ',' && *p != '\0') 4104157Seric p++; 4114157Seric c = *p; 4124322Seric if (c == '\n') 4134322Seric c = '\0'; 41417199Seric *p = '\0'; 41517199Seric if (*p2 != '\0') 41617199Seric (void) parseaddr(p2, &bl, -1, ','); 41717199Seric if (c != '\0') 41817199Seric *p++ = c; 4194098Seric } 4204098Seric } 4214157Seric else 42215769Seric { 42316898Seric p = &p[strlen(p)]; 42416898Seric if (p[-1] == '\n') 42516898Seric *--p = '\0'; 42615769Seric } 4271515Seric 4284098Seric /* see if there should be a continuation line */ 4294106Seric c = fgetc(af); 4304106Seric if (!feof(af)) 4314314Seric (void) ungetc(c, af); 4324106Seric if (c != ' ' && c != '\t') 4334098Seric break; 4344098Seric 4354098Seric /* read continuation line */ 4364098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4374098Seric break; 4389368Seric LineNumber++; 4394098Seric } 44016898Seric if (al.q_mailer != LocalMailer) 44116898Seric { 44216898Seric syserr("cannot alias non-local names"); 44316898Seric continue; 44416898Seric } 4454314Seric 4464314Seric /* 4474314Seric ** Insert alias into symbol table or DBM file 4484314Seric */ 4494314Seric 45016898Seric lhssize = strlen(al.q_user) + 1; 4514322Seric rhssize = strlen(rhs) + 1; 4524322Seric 4534157Seric # ifdef DBM 4544157Seric if (init) 4554157Seric { 4564157Seric DATUM key, content; 4574157Seric 4584322Seric key.dsize = lhssize; 4594157Seric key.dptr = al.q_user; 4604322Seric content.dsize = rhssize; 4614157Seric content.dptr = rhs; 4624157Seric store(key, content); 4634157Seric } 4644157Seric else 4654157Seric # endif DBM 4664157Seric { 4674157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4684157Seric s->s_alias = newstr(rhs); 4694157Seric } 4704322Seric 4714322Seric /* statistics */ 4724322Seric naliases++; 4734322Seric bytes += lhssize + rhssize; 4744322Seric if (rhssize > longest) 4754322Seric longest = rhssize; 4761515Seric } 47719784Seric 47819784Seric # ifdef DBM 47919784Seric if (init) 48019784Seric { 48119784Seric /* add the distinquished alias "@" */ 48219784Seric DATUM key; 48319784Seric 48419784Seric key.dsize = 2; 48519784Seric key.dptr = "@"; 48619784Seric store(key, key); 48719784Seric 48819784Seric /* restore the old signal */ 48919784Seric (void) signal(SIGINT, oldsigint); 49019784Seric } 49119784Seric # endif DBM 49219784Seric 49319784Seric /* closing the alias file drops the lock */ 4944098Seric (void) fclose(af); 4956898Seric CurEnv->e_to = NULL; 4969368Seric FileName = NULL; 4977051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4984322Seric naliases, longest, bytes); 499292Seric } 500292Seric /* 501292Seric ** FORWARD -- Try to forward mail 502292Seric ** 503292Seric ** This is similar but not identical to aliasing. 504292Seric ** 505292Seric ** Parameters: 5064314Seric ** user -- the name of the user who's mail we would like 5074314Seric ** to forward to. It must have been verified -- 5084314Seric ** i.e., the q_home field must have been filled 5094314Seric ** in. 5104999Seric ** sendq -- a pointer to the head of the send queue to 5114999Seric ** put this user's aliases in. 512292Seric ** 513292Seric ** Returns: 5144098Seric ** none. 515292Seric ** 516292Seric ** Side Effects: 5173185Seric ** New names are added to send queues. 518292Seric */ 519292Seric 5204999Seric forward(user, sendq) 5212966Seric ADDRESS *user; 5224999Seric ADDRESS **sendq; 523292Seric { 5244078Seric char buf[60]; 5254536Seric extern bool safefile(); 5264069Seric 5274098Seric # ifdef DEBUG 5287671Seric if (tTd(27, 1)) 5294098Seric printf("forward(%s)\n", user->q_paddr); 5304098Seric # endif DEBUG 5314098Seric 5324594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 5334098Seric return; 5344314Seric # ifdef DEBUG 5354314Seric if (user->q_home == NULL) 5364314Seric syserr("forward: no home"); 5374314Seric # endif DEBUG 5384069Seric 5394069Seric /* good address -- look for .forward file in home */ 5409368Seric define('z', user->q_home, CurEnv); 54116154Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 5424536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 5434098Seric return; 5444069Seric 5454069Seric /* we do have an address to forward to -- do it */ 5464999Seric include(buf, "forwarding", user, sendq); 547292Seric } 548