1292Seric # include <pwd.h> 24212Seric # include <sys/types.h> 34212Seric # include <sys/stat.h> 43309Seric # include "sendmail.h" 5292Seric 64106Seric # ifdef DBM 7*6898Seric SCCSID(@(#)alias.c 3.31 05/22/82 (with DBM)); 84106Seric # else DBM 9*6898Seric SCCSID(@(#)alias.c 3.31 05/22/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 79*6898Seric 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 994098Seric if (Verbose) 1004165Seric message(Arpa_Info, "aliased to %s", p); 1014098Seric AliasLevel++; 1024999Seric sendto(p, 1, a, sendq); 1034098Seric AliasLevel--; 1044098Seric } 1054098Seric /* 1065701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1075701Seric ** 1085701Seric ** Parameters: 1095701Seric ** name -- the name to look up. 1105701Seric ** 1115701Seric ** Returns: 1125701Seric ** the value of name. 1135701Seric ** NULL if unknown. 1145701Seric ** 1155701Seric ** Side Effects: 1165701Seric ** none. 1175701Seric ** 1185701Seric ** Warnings: 1195701Seric ** The return value will be trashed across calls. 1205701Seric */ 1215701Seric 1225701Seric char * 1235701Seric aliaslookup(name) 1245701Seric char *name; 1255701Seric { 1265701Seric # ifdef DBM 1275701Seric DATUM rhs, lhs; 1285701Seric 1295701Seric /* create a key for fetch */ 1305701Seric lhs.dptr = name; 1315701Seric lhs.dsize = strlen(name) + 1; 1325701Seric rhs = fetch(lhs); 1335701Seric return (rhs.dptr); 1345701Seric # else DBM 1355701Seric register STAB *s; 1365701Seric 1375701Seric s = stab(name, ST_ALIAS, ST_FIND); 1385701Seric if (s == NULL) 1395701Seric return (NULL); 1405701Seric return (s->s_alias); 1415701Seric # endif DBM 1425701Seric } 1435701Seric /* 1444098Seric ** INITALIASES -- initialize for aliasing 1454098Seric ** 1464098Seric ** Very different depending on whether we are running DBM or not. 1474098Seric ** 1484098Seric ** Parameters: 1494098Seric ** aliasfile -- location of aliases. 1504157Seric ** init -- if set and if DBM, initialize the DBM files. 1514098Seric ** 1524098Seric ** Returns: 1534098Seric ** none. 1544098Seric ** 1554098Seric ** Side Effects: 1564098Seric ** initializes aliases: 1574098Seric ** if DBM: opens the database. 1584098Seric ** if ~DBM: reads the aliases into the symbol table. 1594098Seric */ 1604098Seric 1614157Seric # define DBMMODE 0666 1624157Seric 1634157Seric initaliases(aliasfile, init) 1644098Seric char *aliasfile; 1654157Seric bool init; 1664098Seric { 1674322Seric char buf[MAXNAME]; 1684322Seric struct stat stb; 1694322Seric time_t modtime; 1704322Seric 1714322Seric /* 1724322Seric ** See if the DBM version of the file is out of date with 1734322Seric ** the text version. If so, go into 'init' mode automatically. 1744322Seric ** This only happens if our effective userid owns the DBM 1754325Seric ** version or if the mode of the database is 666 -- this 1764322Seric ** is an attempt to avoid protection problems. Note the 1774322Seric ** unpalatable hack to see if the stat succeeded. 1784322Seric */ 1794322Seric 1804322Seric if (stat(aliasfile, &stb) < 0) 1814322Seric return; 1824098Seric # ifdef DBM 1834322Seric modtime = stb.st_mtime; 1844322Seric (void) strcpy(buf, aliasfile); 1854322Seric (void) strcat(buf, ".pag"); 1864322Seric stb.st_ino = 0; 1874322Seric if ((stat(buf, &stb) < 0 || stb.st_mtime < modtime) && !init) 1884322Seric { 1894322Seric if (stb.st_ino != 0 && 1904325Seric ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid())) 1914322Seric { 1924322Seric init = TRUE; 1934322Seric if (Verbose) 1944322Seric message(Arpa_Info, "rebuilding alias database"); 1954322Seric } 1964322Seric else 1974322Seric { 1984322Seric message(Arpa_Info, "Warning: alias database out of date"); 1994322Seric } 2004322Seric } 2014322Seric # endif DBM 2024322Seric 2034322Seric /* 2044322Seric ** If initializing, create the new files. 2054322Seric ** We should lock the alias file here to prevent other 2064322Seric ** instantiations of sendmail from reading an incomplete 2074322Seric ** file -- or worse yet, doing a concurrent initialize. 2084322Seric */ 2094322Seric 2104322Seric # ifdef DBM 2114157Seric if (init) 2124157Seric { 2134157Seric (void) strcpy(buf, aliasfile); 2144157Seric (void) strcat(buf, ".dir"); 2154157Seric if (close(creat(buf, DBMMODE)) < 0) 2164157Seric { 2174157Seric syserr("cannot make %s", buf); 2184157Seric return; 2194157Seric } 2204157Seric (void) strcpy(buf, aliasfile); 2214157Seric (void) strcat(buf, ".pag"); 2224157Seric if (close(creat(buf, DBMMODE)) < 0) 2234157Seric { 2244157Seric syserr("cannot make %s", buf); 2254157Seric return; 2264157Seric } 2274157Seric } 2284322Seric 2294322Seric /* 2304322Seric ** Open and, if necessary, load the DBM file. 2314322Seric ** If running without DBM, load the symbol table. 2324322Seric */ 2334322Seric 2344098Seric dbminit(aliasfile); 2354157Seric if (init) 2364157Seric readaliases(aliasfile, TRUE); 2374098Seric # else DBM 2384157Seric readaliases(aliasfile, init); 2394157Seric # endif DBM 2404157Seric } 2414157Seric /* 2424157Seric ** READALIASES -- read and process the alias file. 2434157Seric ** 2444157Seric ** This routine implements the part of initaliases that occurs 2454157Seric ** when we are not going to use the DBM stuff. 2464157Seric ** 2474157Seric ** Parameters: 2484157Seric ** aliasfile -- the pathname of the alias file master. 2494157Seric ** init -- if set, initialize the DBM stuff. 2504157Seric ** 2514157Seric ** Returns: 2524157Seric ** none. 2534157Seric ** 2544157Seric ** Side Effects: 2554157Seric ** Reads aliasfile into the symbol table. 2564157Seric ** Optionally, builds the .dir & .pag files. 2574157Seric */ 2584157Seric 2594157Seric static 2604157Seric readaliases(aliasfile, init) 2614157Seric char *aliasfile; 2624157Seric bool init; 2634157Seric { 2644098Seric char line[BUFSIZ]; 2654098Seric register char *p; 2664098Seric char *p2; 2674098Seric char *rhs; 2684098Seric bool skipping; 2694098Seric ADDRESS al, bl; 2704106Seric FILE *af; 2714106Seric int lineno; 2724106Seric register STAB *s; 2734322Seric int naliases, bytes, longest; 2744098Seric 2754098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2761515Seric { 2774098Seric # ifdef DEBUG 2784098Seric if (Debug) 2794106Seric printf("Can't open %s\n", aliasfile); 2804098Seric # endif 2814098Seric errno = 0; 2824098Seric NoAlias++; 2834098Seric return; 2844098Seric } 2854314Seric 2864314Seric /* 2874314Seric ** Read and interpret lines 2884314Seric */ 2894314Seric 2904098Seric lineno = 0; 2914322Seric naliases = bytes = longest = 0; 2924098Seric skipping = FALSE; 2934098Seric while (fgets(line, sizeof (line), af) != NULL) 2944098Seric { 2954322Seric int lhssize, rhssize; 2964322Seric 2974098Seric lineno++; 2984098Seric switch (line[0]) 2994098Seric { 3004098Seric case '#': 3014098Seric case '\n': 3024098Seric case '\0': 3034098Seric skipping = FALSE; 3044098Seric continue; 3054065Seric 3064098Seric case ' ': 3074098Seric case '\t': 3084098Seric if (!skipping) 3094098Seric syserr("aliases: %d: Non-continuation line starts with space", lineno); 3104098Seric skipping = TRUE; 3114097Seric continue; 3124098Seric } 3134098Seric skipping = FALSE; 3141874Seric 3154314Seric /* 3164314Seric ** Process the LHS 3174314Seric ** Find the final colon, and parse the address. 3184314Seric ** It should resolve to a local name -- this will 3194314Seric ** be checked later (we want to optionally do 3204314Seric ** parsing of the RHS first to maximize error 3214314Seric ** detection). 3224314Seric */ 3234314Seric 3244098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3254097Seric continue; 3264098Seric if (*p == '\0' || *p == '\n') 3274098Seric { 3284098Seric syntaxerr: 3294098Seric syserr("aliases: %d: missing colon", lineno); 3304097Seric continue; 3314098Seric } 3324098Seric *p++ = '\0'; 3334098Seric if (parse(line, &al, 1) == NULL) 3344098Seric { 3354098Seric *--p = ':'; 3364098Seric goto syntaxerr; 3374098Seric } 3384314Seric 3394314Seric /* 3404314Seric ** Process the RHS. 3414314Seric ** 'al' is the internal form of the LHS address. 3424314Seric ** 'p' points to the text of the RHS. 3434314Seric */ 3444314Seric 3454098Seric rhs = p; 3464098Seric for (;;) 3474098Seric { 3484098Seric register char c; 3491515Seric 3504157Seric if (init) 3514098Seric { 3524157Seric /* do parsing & compression of addresses */ 3534098Seric c = *p; 3544157Seric while (c != '\0') 3554098Seric { 3564157Seric p2 = p; 3574157Seric while (*p != '\n' && *p != ',' && *p != '\0') 3584157Seric p++; 3594157Seric c = *p; 3604157Seric *p++ = '\0'; 3614322Seric if (c == '\n') 3624322Seric c = '\0'; 3634157Seric if (*p2 == '\0') 3644157Seric { 3654157Seric p[-1] = c; 3664157Seric continue; 3674157Seric } 3684314Seric (void) parse(p2, &bl, -1); 3694098Seric p[-1] = c; 3704157Seric while (isspace(*p)) 3714157Seric p++; 3724098Seric } 3734098Seric } 3744157Seric else 3754157Seric p = &p[strlen(p)]; 3761515Seric 3774098Seric /* see if there should be a continuation line */ 3784106Seric c = fgetc(af); 3794106Seric if (!feof(af)) 3804314Seric (void) ungetc(c, af); 3814106Seric if (c != ' ' && c != '\t') 3824098Seric break; 3834098Seric 3844098Seric /* read continuation line */ 3854098Seric p--; 3864098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 3874098Seric break; 3884098Seric lineno++; 3894098Seric } 3904594Seric if (al.q_mailer != LocalMailer) 3914098Seric { 3924098Seric syserr("aliases: %d: cannot alias non-local names", lineno); 3934098Seric continue; 3944098Seric } 3954314Seric 3964314Seric /* 3974314Seric ** Insert alias into symbol table or DBM file 3984314Seric */ 3994314Seric 4004322Seric lhssize = strlen(al.q_user) + 1; 4014322Seric rhssize = strlen(rhs) + 1; 4024322Seric 4034157Seric # ifdef DBM 4044157Seric if (init) 4054157Seric { 4064157Seric DATUM key, content; 4074157Seric 4084322Seric key.dsize = lhssize; 4094157Seric key.dptr = al.q_user; 4104322Seric content.dsize = rhssize; 4114157Seric content.dptr = rhs; 4124157Seric store(key, content); 4134157Seric } 4144157Seric else 4154157Seric # endif DBM 4164157Seric { 4174157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4184157Seric s->s_alias = newstr(rhs); 4194157Seric } 4204322Seric 4214322Seric /* statistics */ 4224322Seric naliases++; 4234322Seric bytes += lhssize + rhssize; 4244322Seric if (rhssize > longest) 4254322Seric longest = rhssize; 4261515Seric } 4274098Seric (void) fclose(af); 428*6898Seric CurEnv->e_to = NULL; 4294322Seric if (Verbose) 4304322Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4314322Seric naliases, longest, bytes); 432292Seric } 433292Seric /* 434292Seric ** FORWARD -- Try to forward mail 435292Seric ** 436292Seric ** This is similar but not identical to aliasing. 437292Seric ** 438292Seric ** Parameters: 4394314Seric ** user -- the name of the user who's mail we would like 4404314Seric ** to forward to. It must have been verified -- 4414314Seric ** i.e., the q_home field must have been filled 4424314Seric ** in. 4434999Seric ** sendq -- a pointer to the head of the send queue to 4444999Seric ** put this user's aliases in. 445292Seric ** 446292Seric ** Returns: 4474098Seric ** none. 448292Seric ** 449292Seric ** Side Effects: 4503185Seric ** New names are added to send queues. 451292Seric */ 452292Seric 4534999Seric forward(user, sendq) 4542966Seric ADDRESS *user; 4554999Seric ADDRESS **sendq; 456292Seric { 4574078Seric char buf[60]; 4584536Seric extern bool safefile(); 4594069Seric 4604098Seric # ifdef DEBUG 4614098Seric if (Debug) 4624098Seric printf("forward(%s)\n", user->q_paddr); 4634098Seric # endif DEBUG 4644098Seric 4654594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 4664098Seric return; 4674314Seric # ifdef DEBUG 4684314Seric if (user->q_home == NULL) 4694314Seric syserr("forward: no home"); 4704314Seric # endif DEBUG 4714069Seric 4724069Seric /* good address -- look for .forward file in home */ 4734104Seric define('z', user->q_home); 4744081Seric (void) expand("$z/.forward", buf, &buf[sizeof buf - 1]); 4754536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 4764098Seric return; 4774069Seric 4784069Seric /* we do have an address to forward to -- do it */ 4794999Seric include(buf, "forwarding", user, sendq); 480292Seric } 4815701Seric /* 4825701Seric ** HOSTALIAS -- alias a host name 4835701Seric ** 4845701Seric ** Given a host name, look it up in the host alias table 4855701Seric ** and return it's value. If nothing, return NULL. 4865701Seric ** 4875701Seric ** Parameters: 4885701Seric ** a -- address to alias. 4895701Seric ** 4905701Seric ** Returns: 4915701Seric ** text result of aliasing. 4925701Seric ** NULL if none. 4935701Seric ** 4945701Seric ** Side Effects: 4955701Seric ** none. 4965701Seric */ 4975701Seric 4985701Seric char * 4995701Seric hostalias(a) 5005701Seric register ADDRESS *a; 5015701Seric { 5025701Seric char buf[MAXNAME+2]; 5035701Seric register char *p; 5045701Seric 5055701Seric strcpy(buf, "/"); 5065701Seric strcat(buf, a->q_host); 5075701Seric makelower(buf); 5085701Seric 5095701Seric p = aliaslookup(buf); 5105701Seric if (p == NULL) 5115701Seric return (NULL); 5125844Seric (void) sprintf(buf, p, a->q_user); 5135701Seric return (newstr(buf)); 5145701Seric } 515