1292Seric # include <pwd.h> 24212Seric # include <sys/types.h> 34212Seric # include <sys/stat.h> 48437Seric # include <signal.h> 53309Seric # include "sendmail.h" 6292Seric 74106Seric # ifdef DBM 8*8928Seric SCCSID(@(#)alias.c 3.39 10/28/82 (with DBM)); 94106Seric # else DBM 10*8928Seric SCCSID(@(#)alias.c 3.39 10/28/82 (without DBM)); 114106Seric # endif DBM 12402Seric 13292Seric /* 14292Seric ** ALIAS -- Compute aliases. 15292Seric ** 164098Seric ** Scans the file /usr/lib/aliases for a set of aliases. 173185Seric ** If found, it arranges to deliver to them. Uses libdbm 183185Seric ** database if -DDBM. 19292Seric ** 20292Seric ** Parameters: 214097Seric ** a -- address to alias. 224999Seric ** sendq -- a pointer to the head of the send queue 234999Seric ** to put the aliases in. 24292Seric ** 25292Seric ** Returns: 26292Seric ** none 27292Seric ** 28292Seric ** Side Effects: 293185Seric ** Aliases found are expanded. 30292Seric ** 31292Seric ** Files: 324098Seric ** /usr/lib/aliases -- the mail aliases. The format is 33569Seric ** a series of lines of the form: 34569Seric ** alias:name1,name2,name3,... 35569Seric ** where 'alias' expands to all of 36569Seric ** 'name[i]'. Continuations begin with 37569Seric ** space or tab. 384098Seric ** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version 391503Smark ** of alias file. Keys are aliases, datums 401503Smark ** (data?) are name1,name2, ... 41292Seric ** 42292Seric ** Notes: 43292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 44292Seric ** done. 45292Seric ** 46292Seric ** Deficiencies: 47292Seric ** It should complain about names that are aliased to 48292Seric ** nothing. 49292Seric ** It is unsophisticated about line overflows. 50292Seric */ 51292Seric 52292Seric 531503Smark #ifdef DBM 542966Seric typedef struct 552966Seric { 562966Seric char *dptr; 574157Seric int dsize; 584157Seric } DATUM; 594157Seric extern DATUM fetch(); 601503Smark #endif DBM 61292Seric 624999Seric alias(a, sendq) 634097Seric register ADDRESS *a; 644999Seric ADDRESS **sendq; 65292Seric { 664081Seric register char *p; 675701Seric extern char *aliaslookup(); 68292Seric 69292Seric if (NoAlias) 70292Seric return; 71292Seric # ifdef DEBUG 727671Seric if (tTd(27, 1)) 734098Seric printf("alias(%s)\n", a->q_paddr); 74292Seric # endif 75292Seric 764098Seric /* don't realias already aliased names */ 774098Seric if (bitset(QDONTSEND, a->q_flags)) 784098Seric return; 794098Seric 806898Seric CurEnv->e_to = a->q_paddr; 814098Seric 824314Seric /* 834314Seric ** Look up this name 844314Seric */ 854314Seric 865701Seric p = aliaslookup(a->q_user); 874098Seric if (p == NULL) 884098Seric return; 89292Seric 90292Seric /* 914098Seric ** Match on Alias. 924098Seric ** Deliver to the target list. 931515Seric */ 941515Seric 954098Seric # ifdef DEBUG 967671Seric if (tTd(27, 1)) 974098Seric printf("%s (%s, %s) aliased to %s\n", 984098Seric a->q_paddr, a->q_host, a->q_user, p); 994098Seric # endif 1007051Seric message(Arpa_Info, "aliased to %s", p); 1014098Seric AliasLevel++; 1028076Seric sendto(p, 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 { 1678437Seric int atcnt; 1684322Seric char buf[MAXNAME]; 1694322Seric struct stat stb; 1704322Seric time_t modtime; 1718437Seric int (*oldsigint)(); 1724322Seric 1738437Seric if (stat(aliasfile, &stb) < 0) 1748437Seric { 1758437Seric NoAlias = TRUE; 1768437Seric return; 1778437Seric } 1788437Seric 179*8928Seric # ifdef DBM 1804322Seric /* 1818437Seric ** Check to see that the alias file is complete. 1828437Seric ** If not, we will assume that someone died, and it is up 1838437Seric ** to us to rebuild it. 1848437Seric */ 1858437Seric 1868437Seric dbminit(aliasfile); 187*8928Seric atcnt = 10; 188*8928Seric while (SafeAlias && !init && atcnt-- >= 0 && aliaslookup("@") == NULL) 1898437Seric sleep(30); 1908437Seric 1918437Seric /* 1924322Seric ** See if the DBM version of the file is out of date with 1934322Seric ** the text version. If so, go into 'init' mode automatically. 1944322Seric ** This only happens if our effective userid owns the DBM 1954325Seric ** version or if the mode of the database is 666 -- this 1964322Seric ** is an attempt to avoid protection problems. Note the 1974322Seric ** unpalatable hack to see if the stat succeeded. 1984322Seric */ 1994322Seric 2004322Seric modtime = stb.st_mtime; 2014322Seric (void) strcpy(buf, aliasfile); 2024322Seric (void) strcat(buf, ".pag"); 2034322Seric stb.st_ino = 0; 2048437Seric if ((stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0) && 2058437Seric !init) 2064322Seric { 2074322Seric if (stb.st_ino != 0 && 2084325Seric ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid())) 2094322Seric { 2104322Seric init = TRUE; 2117051Seric message(Arpa_Info, "rebuilding alias database"); 2124322Seric } 2134322Seric else 2144322Seric { 2157051Seric bool oldverb = Verbose; 2167051Seric 2177051Seric Verbose = TRUE; 2184322Seric message(Arpa_Info, "Warning: alias database out of date"); 2197051Seric Verbose = oldverb; 2204322Seric } 2214322Seric } 2224322Seric 2234322Seric /* 2244322Seric ** If initializing, create the new files. 2254322Seric ** We should lock the alias file here to prevent other 2264322Seric ** instantiations of sendmail from reading an incomplete 2274322Seric ** file -- or worse yet, doing a concurrent initialize. 2284322Seric */ 2294322Seric 2304157Seric if (init) 2314157Seric { 2328437Seric oldsigint = signal(SIGINT, SIG_IGN); 2334157Seric (void) strcpy(buf, aliasfile); 2344157Seric (void) strcat(buf, ".dir"); 2354157Seric if (close(creat(buf, DBMMODE)) < 0) 2364157Seric { 2374157Seric syserr("cannot make %s", buf); 2384157Seric return; 2394157Seric } 2404157Seric (void) strcpy(buf, aliasfile); 2414157Seric (void) strcat(buf, ".pag"); 2424157Seric if (close(creat(buf, DBMMODE)) < 0) 2434157Seric { 2444157Seric syserr("cannot make %s", buf); 2454157Seric return; 2464157Seric } 2474157Seric } 2484322Seric 2494322Seric /* 2508437Seric ** If necessary, load the DBM file. 2514322Seric ** If running without DBM, load the symbol table. 2528437Seric ** After loading the DBM file, add the distinquished alias "@". 2534322Seric */ 2544322Seric 2554157Seric if (init) 2568437Seric { 2578437Seric DATUM key; 2588437Seric 2594157Seric readaliases(aliasfile, TRUE); 2608437Seric key.dsize = 2; 2618437Seric key.dptr = "@"; 2628437Seric store(key, key); 2638437Seric (void) signal(SIGINT, oldsigint); 2648437Seric } 2654098Seric # else DBM 2664157Seric readaliases(aliasfile, init); 2674157Seric # endif DBM 2684157Seric } 2694157Seric /* 2708437Seric ** DBMCLOSE -- close the dbm file. 2718437Seric ** 2728437Seric ** This is highly implementation dependent. It should be in the 2738437Seric ** DBM library rather than here. So why isn't it? 2748437Seric ** 2758437Seric ** This is really only needed to save file descriptors. It can be 2768437Seric ** safely (??) replaced by the null routine. 2778437Seric ** 2788437Seric ** Parameters: 2798437Seric ** none. 2808437Seric ** 2818437Seric ** Returns: 2828437Seric ** none. 2838437Seric ** 2848437Seric ** Side Effects: 2858437Seric ** Closes the DBM file. 2868437Seric */ 2878437Seric 2888437Seric dbmclose() 2898437Seric { 2908437Seric /* hack attack!! -- see comment above */ 2918437Seric extern int pagf, dirf; 2928437Seric 2938437Seric (void) close(pagf); 2948437Seric (void) close(dirf); 2958437Seric } 2968437Seric /* 2974157Seric ** READALIASES -- read and process the alias file. 2984157Seric ** 2994157Seric ** This routine implements the part of initaliases that occurs 3004157Seric ** when we are not going to use the DBM stuff. 3014157Seric ** 3024157Seric ** Parameters: 3034157Seric ** aliasfile -- the pathname of the alias file master. 3044157Seric ** init -- if set, initialize the DBM stuff. 3054157Seric ** 3064157Seric ** Returns: 3074157Seric ** none. 3084157Seric ** 3094157Seric ** Side Effects: 3104157Seric ** Reads aliasfile into the symbol table. 3114157Seric ** Optionally, builds the .dir & .pag files. 3124157Seric */ 3134157Seric 3144157Seric static 3154157Seric readaliases(aliasfile, init) 3164157Seric char *aliasfile; 3174157Seric bool init; 3184157Seric { 3194098Seric char line[BUFSIZ]; 3204098Seric register char *p; 3214098Seric char *p2; 3224098Seric char *rhs; 3234098Seric bool skipping; 3244098Seric ADDRESS al, bl; 3254106Seric FILE *af; 3264106Seric int lineno; 3274106Seric register STAB *s; 3284322Seric int naliases, bytes, longest; 3294098Seric 3304098Seric if ((af = fopen(aliasfile, "r")) == NULL) 3311515Seric { 3324098Seric # ifdef DEBUG 3337671Seric if (tTd(27, 1)) 3344106Seric printf("Can't open %s\n", aliasfile); 3354098Seric # endif 3364098Seric errno = 0; 3374098Seric NoAlias++; 3384098Seric return; 3394098Seric } 3404314Seric 3414314Seric /* 3424314Seric ** Read and interpret lines 3434314Seric */ 3444314Seric 3454098Seric lineno = 0; 3464322Seric naliases = bytes = longest = 0; 3474098Seric skipping = FALSE; 3484098Seric while (fgets(line, sizeof (line), af) != NULL) 3494098Seric { 3504322Seric int lhssize, rhssize; 3514322Seric 3524098Seric lineno++; 3534098Seric switch (line[0]) 3544098Seric { 3554098Seric case '#': 3564098Seric case '\n': 3574098Seric case '\0': 3584098Seric skipping = FALSE; 3594098Seric continue; 3604065Seric 3614098Seric case ' ': 3624098Seric case '\t': 3634098Seric if (!skipping) 3644098Seric syserr("aliases: %d: Non-continuation line starts with space", lineno); 3654098Seric skipping = TRUE; 3664097Seric continue; 3674098Seric } 3684098Seric skipping = FALSE; 3691874Seric 3704314Seric /* 3714314Seric ** Process the LHS 3724314Seric ** Find the final colon, and parse the address. 3734314Seric ** It should resolve to a local name -- this will 3744314Seric ** be checked later (we want to optionally do 3754314Seric ** parsing of the RHS first to maximize error 3764314Seric ** detection). 3774314Seric */ 3784314Seric 3794098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3804097Seric continue; 3814098Seric if (*p == '\0' || *p == '\n') 3824098Seric { 3834098Seric syntaxerr: 3847048Seric syserr("aliases: %d: missing colon", lineno); 3854097Seric continue; 3864098Seric } 3874098Seric *p++ = '\0'; 3884098Seric if (parse(line, &al, 1) == NULL) 3894098Seric { 3904098Seric *--p = ':'; 3914098Seric goto syntaxerr; 3924098Seric } 3934314Seric 3944314Seric /* 3954314Seric ** Process the RHS. 3964314Seric ** 'al' is the internal form of the LHS address. 3974314Seric ** 'p' points to the text of the RHS. 3984314Seric */ 3994314Seric 4004098Seric rhs = p; 4014098Seric for (;;) 4024098Seric { 4034098Seric register char c; 4041515Seric 4054157Seric if (init) 4064098Seric { 4074157Seric /* do parsing & compression of addresses */ 4084098Seric c = *p; 4094157Seric while (c != '\0') 4104098Seric { 4114157Seric p2 = p; 4124157Seric while (*p != '\n' && *p != ',' && *p != '\0') 4134157Seric p++; 4144157Seric c = *p; 4154157Seric *p++ = '\0'; 4164322Seric if (c == '\n') 4174322Seric c = '\0'; 4184157Seric if (*p2 == '\0') 4194157Seric { 4204157Seric p[-1] = c; 4214157Seric continue; 4224157Seric } 4234314Seric (void) parse(p2, &bl, -1); 4244098Seric p[-1] = c; 4254157Seric while (isspace(*p)) 4264157Seric p++; 4274098Seric } 4284098Seric } 4294157Seric else 4304157Seric p = &p[strlen(p)]; 4311515Seric 4324098Seric /* see if there should be a continuation line */ 4334106Seric c = fgetc(af); 4344106Seric if (!feof(af)) 4354314Seric (void) ungetc(c, af); 4364106Seric if (c != ' ' && c != '\t') 4374098Seric break; 4384098Seric 4394098Seric /* read continuation line */ 4404098Seric p--; 4414098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4424098Seric break; 4434098Seric lineno++; 4444098Seric } 4454594Seric if (al.q_mailer != LocalMailer) 4464098Seric { 4474098Seric syserr("aliases: %d: cannot alias non-local names", lineno); 4484098Seric continue; 4494098Seric } 4504314Seric 4514314Seric /* 4524314Seric ** Insert alias into symbol table or DBM file 4534314Seric */ 4544314Seric 4554322Seric lhssize = strlen(al.q_user) + 1; 4564322Seric rhssize = strlen(rhs) + 1; 4574322Seric 4584157Seric # ifdef DBM 4594157Seric if (init) 4604157Seric { 4614157Seric DATUM key, content; 4624157Seric 4634322Seric key.dsize = lhssize; 4644157Seric key.dptr = al.q_user; 4654322Seric content.dsize = rhssize; 4664157Seric content.dptr = rhs; 4674157Seric store(key, content); 4684157Seric } 4694157Seric else 4704157Seric # endif DBM 4714157Seric { 4724157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4734157Seric s->s_alias = newstr(rhs); 4744157Seric } 4754322Seric 4764322Seric /* statistics */ 4774322Seric naliases++; 4784322Seric bytes += lhssize + rhssize; 4794322Seric if (rhssize > longest) 4804322Seric longest = rhssize; 4811515Seric } 4824098Seric (void) fclose(af); 4836898Seric CurEnv->e_to = NULL; 4847051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4854322Seric naliases, longest, bytes); 486292Seric } 487292Seric /* 488292Seric ** FORWARD -- Try to forward mail 489292Seric ** 490292Seric ** This is similar but not identical to aliasing. 491292Seric ** 492292Seric ** Parameters: 4934314Seric ** user -- the name of the user who's mail we would like 4944314Seric ** to forward to. It must have been verified -- 4954314Seric ** i.e., the q_home field must have been filled 4964314Seric ** in. 4974999Seric ** sendq -- a pointer to the head of the send queue to 4984999Seric ** put this user's aliases in. 499292Seric ** 500292Seric ** Returns: 5014098Seric ** none. 502292Seric ** 503292Seric ** Side Effects: 5043185Seric ** New names are added to send queues. 505292Seric */ 506292Seric 5074999Seric forward(user, sendq) 5082966Seric ADDRESS *user; 5094999Seric ADDRESS **sendq; 510292Seric { 5114078Seric char buf[60]; 5124536Seric extern bool safefile(); 5134069Seric 5144098Seric # ifdef DEBUG 5157671Seric if (tTd(27, 1)) 5164098Seric printf("forward(%s)\n", user->q_paddr); 5174098Seric # endif DEBUG 5184098Seric 5194594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 5204098Seric return; 5214314Seric # ifdef DEBUG 5224314Seric if (user->q_home == NULL) 5234314Seric syserr("forward: no home"); 5244314Seric # endif DEBUG 5254069Seric 5264069Seric /* good address -- look for .forward file in home */ 5274104Seric define('z', user->q_home); 5286973Seric expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 5294536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 5304098Seric return; 5314069Seric 5324069Seric /* we do have an address to forward to -- do it */ 5334999Seric include(buf, "forwarding", user, sendq); 534292Seric } 535