1292Seric # include <pwd.h> 24212Seric # include <sys/types.h> 34212Seric # include <sys/stat.h> 43309Seric # include "sendmail.h" 5292Seric 64106Seric # ifdef DBM 7*7051Seric SCCSID(@(#)alias.c 3.35 06/07/82 (with DBM)); 84106Seric # else DBM 9*7051Seric SCCSID(@(#)alias.c 3.35 06/07/82 (without DBM)); 104106Seric # endif DBM 11402Seric 12292Seric /* 13292Seric ** ALIAS -- Compute aliases. 14292Seric ** 154098Seric ** Scans the file /usr/lib/aliases for a set of aliases. 163185Seric ** If found, it arranges to deliver to them. Uses libdbm 173185Seric ** database if -DDBM. 18292Seric ** 19292Seric ** Parameters: 204097Seric ** a -- address to alias. 214999Seric ** sendq -- a pointer to the head of the send queue 224999Seric ** to put the aliases in. 23292Seric ** 24292Seric ** Returns: 25292Seric ** none 26292Seric ** 27292Seric ** Side Effects: 283185Seric ** Aliases found are expanded. 29292Seric ** 30292Seric ** Files: 314098Seric ** /usr/lib/aliases -- the mail aliases. The format is 32569Seric ** a series of lines of the form: 33569Seric ** alias:name1,name2,name3,... 34569Seric ** where 'alias' expands to all of 35569Seric ** 'name[i]'. Continuations begin with 36569Seric ** space or tab. 374098Seric ** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version 381503Smark ** of alias file. Keys are aliases, datums 391503Smark ** (data?) are name1,name2, ... 40292Seric ** 41292Seric ** Notes: 42292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 43292Seric ** done. 44292Seric ** 45292Seric ** Deficiencies: 46292Seric ** It should complain about names that are aliased to 47292Seric ** nothing. 48292Seric ** It is unsophisticated about line overflows. 49292Seric */ 50292Seric 51292Seric 521503Smark #ifdef DBM 532966Seric typedef struct 542966Seric { 552966Seric char *dptr; 564157Seric int dsize; 574157Seric } DATUM; 584157Seric extern DATUM fetch(); 591503Smark #endif DBM 60292Seric 614999Seric alias(a, sendq) 624097Seric register ADDRESS *a; 634999Seric ADDRESS **sendq; 64292Seric { 654081Seric register char *p; 665701Seric extern char *aliaslookup(); 67292Seric 68292Seric if (NoAlias) 69292Seric return; 70292Seric # ifdef DEBUG 71292Seric if (Debug) 724098Seric printf("alias(%s)\n", a->q_paddr); 73292Seric # endif 74292Seric 754098Seric /* don't realias already aliased names */ 764098Seric if (bitset(QDONTSEND, a->q_flags)) 774098Seric return; 784098Seric 796898Seric CurEnv->e_to = a->q_paddr; 804098Seric 814314Seric /* 824314Seric ** Look up this name 834314Seric */ 844314Seric 855701Seric p = aliaslookup(a->q_user); 864098Seric if (p == NULL) 874098Seric return; 88292Seric 89292Seric /* 904098Seric ** Match on Alias. 914098Seric ** Deliver to the target list. 921515Seric */ 931515Seric 944098Seric # ifdef DEBUG 954098Seric if (Debug) 964098Seric printf("%s (%s, %s) aliased to %s\n", 974098Seric a->q_paddr, a->q_host, a->q_user, p); 984098Seric # endif 99*7051Seric message(Arpa_Info, "aliased to %s", p); 1004098Seric AliasLevel++; 1014999Seric sendto(p, 1, a, sendq); 1024098Seric AliasLevel--; 1034098Seric } 1044098Seric /* 1055701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1065701Seric ** 1075701Seric ** Parameters: 1085701Seric ** name -- the name to look up. 1095701Seric ** 1105701Seric ** Returns: 1115701Seric ** the value of name. 1125701Seric ** NULL if unknown. 1135701Seric ** 1145701Seric ** Side Effects: 1155701Seric ** none. 1165701Seric ** 1175701Seric ** Warnings: 1185701Seric ** The return value will be trashed across calls. 1195701Seric */ 1205701Seric 1215701Seric char * 1225701Seric aliaslookup(name) 1235701Seric char *name; 1245701Seric { 1255701Seric # ifdef DBM 1265701Seric DATUM rhs, lhs; 1275701Seric 1285701Seric /* create a key for fetch */ 1295701Seric lhs.dptr = name; 1305701Seric lhs.dsize = strlen(name) + 1; 1315701Seric rhs = fetch(lhs); 1325701Seric return (rhs.dptr); 1335701Seric # else DBM 1345701Seric register STAB *s; 1355701Seric 1365701Seric s = stab(name, ST_ALIAS, ST_FIND); 1375701Seric if (s == NULL) 1385701Seric return (NULL); 1395701Seric return (s->s_alias); 1405701Seric # endif DBM 1415701Seric } 1425701Seric /* 1434098Seric ** INITALIASES -- initialize for aliasing 1444098Seric ** 1454098Seric ** Very different depending on whether we are running DBM or not. 1464098Seric ** 1474098Seric ** Parameters: 1484098Seric ** aliasfile -- location of aliases. 1494157Seric ** init -- if set and if DBM, initialize the DBM files. 1504098Seric ** 1514098Seric ** Returns: 1524098Seric ** none. 1534098Seric ** 1544098Seric ** Side Effects: 1554098Seric ** initializes aliases: 1564098Seric ** if DBM: opens the database. 1574098Seric ** if ~DBM: reads the aliases into the symbol table. 1584098Seric */ 1594098Seric 1604157Seric # define DBMMODE 0666 1614157Seric 1624157Seric initaliases(aliasfile, init) 1634098Seric char *aliasfile; 1644157Seric bool init; 1654098Seric { 1664322Seric char buf[MAXNAME]; 1674322Seric struct stat stb; 1684322Seric time_t modtime; 1694322Seric 1704322Seric /* 1714322Seric ** See if the DBM version of the file is out of date with 1724322Seric ** the text version. If so, go into 'init' mode automatically. 1734322Seric ** This only happens if our effective userid owns the DBM 1744325Seric ** version or if the mode of the database is 666 -- this 1754322Seric ** is an attempt to avoid protection problems. Note the 1764322Seric ** unpalatable hack to see if the stat succeeded. 1774322Seric */ 1784322Seric 1794322Seric if (stat(aliasfile, &stb) < 0) 1804322Seric return; 1814098Seric # ifdef DBM 1824322Seric modtime = stb.st_mtime; 1834322Seric (void) strcpy(buf, aliasfile); 1844322Seric (void) strcat(buf, ".pag"); 1854322Seric stb.st_ino = 0; 1864322Seric if ((stat(buf, &stb) < 0 || stb.st_mtime < modtime) && !init) 1874322Seric { 1884322Seric if (stb.st_ino != 0 && 1894325Seric ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid())) 1904322Seric { 1914322Seric init = TRUE; 192*7051Seric message(Arpa_Info, "rebuilding alias database"); 1934322Seric } 1944322Seric else 1954322Seric { 196*7051Seric bool oldverb = Verbose; 197*7051Seric 198*7051Seric Verbose = TRUE; 1994322Seric message(Arpa_Info, "Warning: alias database out of date"); 200*7051Seric Verbose = oldverb; 2014322Seric } 2024322Seric } 2034322Seric # endif DBM 2044322Seric 2054322Seric /* 2064322Seric ** If initializing, create the new files. 2074322Seric ** We should lock the alias file here to prevent other 2084322Seric ** instantiations of sendmail from reading an incomplete 2094322Seric ** file -- or worse yet, doing a concurrent initialize. 2104322Seric */ 2114322Seric 2124322Seric # ifdef DBM 2134157Seric if (init) 2144157Seric { 2154157Seric (void) strcpy(buf, aliasfile); 2164157Seric (void) strcat(buf, ".dir"); 2174157Seric if (close(creat(buf, DBMMODE)) < 0) 2184157Seric { 2194157Seric syserr("cannot make %s", buf); 2204157Seric return; 2214157Seric } 2224157Seric (void) strcpy(buf, aliasfile); 2234157Seric (void) strcat(buf, ".pag"); 2244157Seric if (close(creat(buf, DBMMODE)) < 0) 2254157Seric { 2264157Seric syserr("cannot make %s", buf); 2274157Seric return; 2284157Seric } 2294157Seric } 2304322Seric 2314322Seric /* 2324322Seric ** Open and, if necessary, load the DBM file. 2334322Seric ** If running without DBM, load the symbol table. 2344322Seric */ 2354322Seric 2364098Seric dbminit(aliasfile); 2374157Seric if (init) 2384157Seric readaliases(aliasfile, TRUE); 2394098Seric # else DBM 2404157Seric readaliases(aliasfile, init); 2414157Seric # endif DBM 2424157Seric } 2434157Seric /* 2444157Seric ** READALIASES -- read and process the alias file. 2454157Seric ** 2464157Seric ** This routine implements the part of initaliases that occurs 2474157Seric ** when we are not going to use the DBM stuff. 2484157Seric ** 2494157Seric ** Parameters: 2504157Seric ** aliasfile -- the pathname of the alias file master. 2514157Seric ** init -- if set, initialize the DBM stuff. 2524157Seric ** 2534157Seric ** Returns: 2544157Seric ** none. 2554157Seric ** 2564157Seric ** Side Effects: 2574157Seric ** Reads aliasfile into the symbol table. 2584157Seric ** Optionally, builds the .dir & .pag files. 2594157Seric */ 2604157Seric 2614157Seric static 2624157Seric readaliases(aliasfile, init) 2634157Seric char *aliasfile; 2644157Seric bool init; 2654157Seric { 2664098Seric char line[BUFSIZ]; 2674098Seric register char *p; 2684098Seric char *p2; 2694098Seric char *rhs; 2704098Seric bool skipping; 2714098Seric ADDRESS al, bl; 2724106Seric FILE *af; 2734106Seric int lineno; 2744106Seric register STAB *s; 2754322Seric int naliases, bytes, longest; 2764098Seric 2774098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2781515Seric { 2794098Seric # ifdef DEBUG 2804098Seric if (Debug) 2814106Seric printf("Can't open %s\n", aliasfile); 2824098Seric # endif 2834098Seric errno = 0; 2844098Seric NoAlias++; 2854098Seric return; 2864098Seric } 2874314Seric 2884314Seric /* 2894314Seric ** Read and interpret lines 2904314Seric */ 2914314Seric 2924098Seric lineno = 0; 2934322Seric naliases = bytes = longest = 0; 2944098Seric skipping = FALSE; 2954098Seric while (fgets(line, sizeof (line), af) != NULL) 2964098Seric { 2974322Seric int lhssize, rhssize; 2984322Seric 2994098Seric lineno++; 3004098Seric switch (line[0]) 3014098Seric { 3024098Seric case '#': 3034098Seric case '\n': 3044098Seric case '\0': 3054098Seric skipping = FALSE; 3064098Seric continue; 3074065Seric 3084098Seric case ' ': 3094098Seric case '\t': 3104098Seric if (!skipping) 3114098Seric syserr("aliases: %d: Non-continuation line starts with space", lineno); 3124098Seric skipping = TRUE; 3134097Seric continue; 3144098Seric } 3154098Seric skipping = FALSE; 3161874Seric 3174314Seric /* 3184314Seric ** Process the LHS 3194314Seric ** Find the final colon, and parse the address. 3204314Seric ** It should resolve to a local name -- this will 3214314Seric ** be checked later (we want to optionally do 3224314Seric ** parsing of the RHS first to maximize error 3234314Seric ** detection). 3244314Seric */ 3254314Seric 3264098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3274097Seric continue; 3284098Seric if (*p == '\0' || *p == '\n') 3294098Seric { 3304098Seric syntaxerr: 3317048Seric syserr("aliases: %d: missing colon", lineno); 3324097Seric continue; 3334098Seric } 3344098Seric *p++ = '\0'; 3354098Seric if (parse(line, &al, 1) == NULL) 3364098Seric { 3374098Seric *--p = ':'; 3384098Seric goto syntaxerr; 3394098Seric } 3404314Seric 3414314Seric /* 3424314Seric ** Process the RHS. 3434314Seric ** 'al' is the internal form of the LHS address. 3444314Seric ** 'p' points to the text of the RHS. 3454314Seric */ 3464314Seric 3474098Seric rhs = p; 3484098Seric for (;;) 3494098Seric { 3504098Seric register char c; 3511515Seric 3524157Seric if (init) 3534098Seric { 3544157Seric /* do parsing & compression of addresses */ 3554098Seric c = *p; 3564157Seric while (c != '\0') 3574098Seric { 3584157Seric p2 = p; 3594157Seric while (*p != '\n' && *p != ',' && *p != '\0') 3604157Seric p++; 3614157Seric c = *p; 3624157Seric *p++ = '\0'; 3634322Seric if (c == '\n') 3644322Seric c = '\0'; 3654157Seric if (*p2 == '\0') 3664157Seric { 3674157Seric p[-1] = c; 3684157Seric continue; 3694157Seric } 3704314Seric (void) parse(p2, &bl, -1); 3714098Seric p[-1] = c; 3724157Seric while (isspace(*p)) 3734157Seric p++; 3744098Seric } 3754098Seric } 3764157Seric else 3774157Seric p = &p[strlen(p)]; 3781515Seric 3794098Seric /* see if there should be a continuation line */ 3804106Seric c = fgetc(af); 3814106Seric if (!feof(af)) 3824314Seric (void) ungetc(c, af); 3834106Seric if (c != ' ' && c != '\t') 3844098Seric break; 3854098Seric 3864098Seric /* read continuation line */ 3874098Seric p--; 3884098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 3894098Seric break; 3904098Seric lineno++; 3914098Seric } 3924594Seric if (al.q_mailer != LocalMailer) 3934098Seric { 3944098Seric syserr("aliases: %d: cannot alias non-local names", lineno); 3954098Seric continue; 3964098Seric } 3974314Seric 3984314Seric /* 3994314Seric ** Insert alias into symbol table or DBM file 4004314Seric */ 4014314Seric 4024322Seric lhssize = strlen(al.q_user) + 1; 4034322Seric rhssize = strlen(rhs) + 1; 4044322Seric 4054157Seric # ifdef DBM 4064157Seric if (init) 4074157Seric { 4084157Seric DATUM key, content; 4094157Seric 4104322Seric key.dsize = lhssize; 4114157Seric key.dptr = al.q_user; 4124322Seric content.dsize = rhssize; 4134157Seric content.dptr = rhs; 4144157Seric store(key, content); 4154157Seric } 4164157Seric else 4174157Seric # endif DBM 4184157Seric { 4194157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4204157Seric s->s_alias = newstr(rhs); 4214157Seric } 4224322Seric 4234322Seric /* statistics */ 4244322Seric naliases++; 4254322Seric bytes += lhssize + rhssize; 4264322Seric if (rhssize > longest) 4274322Seric longest = rhssize; 4281515Seric } 4294098Seric (void) fclose(af); 4306898Seric CurEnv->e_to = NULL; 431*7051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4324322Seric naliases, longest, bytes); 433292Seric } 434292Seric /* 435292Seric ** FORWARD -- Try to forward mail 436292Seric ** 437292Seric ** This is similar but not identical to aliasing. 438292Seric ** 439292Seric ** Parameters: 4404314Seric ** user -- the name of the user who's mail we would like 4414314Seric ** to forward to. It must have been verified -- 4424314Seric ** i.e., the q_home field must have been filled 4434314Seric ** in. 4444999Seric ** sendq -- a pointer to the head of the send queue to 4454999Seric ** put this user's aliases in. 446292Seric ** 447292Seric ** Returns: 4484098Seric ** none. 449292Seric ** 450292Seric ** Side Effects: 4513185Seric ** New names are added to send queues. 452292Seric */ 453292Seric 4544999Seric forward(user, sendq) 4552966Seric ADDRESS *user; 4564999Seric ADDRESS **sendq; 457292Seric { 4584078Seric char buf[60]; 4594536Seric extern bool safefile(); 4604069Seric 4614098Seric # ifdef DEBUG 4624098Seric if (Debug) 4634098Seric printf("forward(%s)\n", user->q_paddr); 4644098Seric # endif DEBUG 4654098Seric 4664594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 4674098Seric return; 4684314Seric # ifdef DEBUG 4694314Seric if (user->q_home == NULL) 4704314Seric syserr("forward: no home"); 4714314Seric # endif DEBUG 4724069Seric 4734069Seric /* good address -- look for .forward file in home */ 4744104Seric define('z', user->q_home); 4756973Seric expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 4764536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 4774098Seric return; 4784069Seric 4794069Seric /* we do have an address to forward to -- do it */ 4804999Seric include(buf, "forwarding", user, sendq); 481292Seric } 482