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*9150Seric SCCSID(@(#)alias.c 3.40 11/13/82 (with DBM)); 94106Seric # else DBM 10*9150Seric SCCSID(@(#)alias.c 3.40 11/13/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 1798928Seric # 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); 1878928Seric atcnt = 10; 1888928Seric 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; 204*9150Seric if (!init && (atcnt < 0 || stat(buf, &stb) < 0 || stb.st_mtime < modtime)) 2054322Seric { 206*9150Seric if (AutoRebuild && stb.st_ino != 0 && 2074325Seric ((stb.st_mode & 0666) == 0666 || stb.st_uid == geteuid())) 2084322Seric { 2094322Seric init = TRUE; 2107051Seric message(Arpa_Info, "rebuilding alias database"); 2114322Seric } 2124322Seric else 2134322Seric { 2147051Seric bool oldverb = Verbose; 2157051Seric 2167051Seric Verbose = TRUE; 2174322Seric message(Arpa_Info, "Warning: alias database out of date"); 2187051Seric Verbose = oldverb; 2194322Seric } 2204322Seric } 2214322Seric 2224322Seric /* 2234322Seric ** If initializing, create the new files. 2244322Seric ** We should lock the alias file here to prevent other 2254322Seric ** instantiations of sendmail from reading an incomplete 2264322Seric ** file -- or worse yet, doing a concurrent initialize. 2274322Seric */ 2284322Seric 2294157Seric if (init) 2304157Seric { 2318437Seric oldsigint = signal(SIGINT, SIG_IGN); 2324157Seric (void) strcpy(buf, aliasfile); 2334157Seric (void) strcat(buf, ".dir"); 2344157Seric if (close(creat(buf, DBMMODE)) < 0) 2354157Seric { 2364157Seric syserr("cannot make %s", buf); 2374157Seric return; 2384157Seric } 2394157Seric (void) strcpy(buf, aliasfile); 2404157Seric (void) strcat(buf, ".pag"); 2414157Seric if (close(creat(buf, DBMMODE)) < 0) 2424157Seric { 2434157Seric syserr("cannot make %s", buf); 2444157Seric return; 2454157Seric } 2464157Seric } 2474322Seric 2484322Seric /* 2498437Seric ** If necessary, load the DBM file. 2504322Seric ** If running without DBM, load the symbol table. 2518437Seric ** After loading the DBM file, add the distinquished alias "@". 2524322Seric */ 2534322Seric 2544157Seric if (init) 2558437Seric { 2568437Seric DATUM key; 2578437Seric 2584157Seric readaliases(aliasfile, TRUE); 2598437Seric key.dsize = 2; 2608437Seric key.dptr = "@"; 2618437Seric store(key, key); 2628437Seric (void) signal(SIGINT, oldsigint); 2638437Seric } 2644098Seric # else DBM 2654157Seric readaliases(aliasfile, init); 2664157Seric # endif DBM 2674157Seric } 2684157Seric /* 2698437Seric ** DBMCLOSE -- close the dbm file. 2708437Seric ** 2718437Seric ** This is highly implementation dependent. It should be in the 2728437Seric ** DBM library rather than here. So why isn't it? 2738437Seric ** 2748437Seric ** This is really only needed to save file descriptors. It can be 2758437Seric ** safely (??) replaced by the null routine. 2768437Seric ** 2778437Seric ** Parameters: 2788437Seric ** none. 2798437Seric ** 2808437Seric ** Returns: 2818437Seric ** none. 2828437Seric ** 2838437Seric ** Side Effects: 2848437Seric ** Closes the DBM file. 2858437Seric */ 2868437Seric 2878437Seric dbmclose() 2888437Seric { 2898437Seric /* hack attack!! -- see comment above */ 2908437Seric extern int pagf, dirf; 2918437Seric 2928437Seric (void) close(pagf); 2938437Seric (void) close(dirf); 2948437Seric } 2958437Seric /* 2964157Seric ** READALIASES -- read and process the alias file. 2974157Seric ** 2984157Seric ** This routine implements the part of initaliases that occurs 2994157Seric ** when we are not going to use the DBM stuff. 3004157Seric ** 3014157Seric ** Parameters: 3024157Seric ** aliasfile -- the pathname of the alias file master. 3034157Seric ** init -- if set, initialize the DBM stuff. 3044157Seric ** 3054157Seric ** Returns: 3064157Seric ** none. 3074157Seric ** 3084157Seric ** Side Effects: 3094157Seric ** Reads aliasfile into the symbol table. 3104157Seric ** Optionally, builds the .dir & .pag files. 3114157Seric */ 3124157Seric 3134157Seric static 3144157Seric readaliases(aliasfile, init) 3154157Seric char *aliasfile; 3164157Seric bool init; 3174157Seric { 3184098Seric char line[BUFSIZ]; 3194098Seric register char *p; 3204098Seric char *p2; 3214098Seric char *rhs; 3224098Seric bool skipping; 3234098Seric ADDRESS al, bl; 3244106Seric FILE *af; 3254106Seric int lineno; 3264106Seric register STAB *s; 3274322Seric int naliases, bytes, longest; 3284098Seric 3294098Seric if ((af = fopen(aliasfile, "r")) == NULL) 3301515Seric { 3314098Seric # ifdef DEBUG 3327671Seric if (tTd(27, 1)) 3334106Seric printf("Can't open %s\n", aliasfile); 3344098Seric # endif 3354098Seric errno = 0; 3364098Seric NoAlias++; 3374098Seric return; 3384098Seric } 3394314Seric 3404314Seric /* 3414314Seric ** Read and interpret lines 3424314Seric */ 3434314Seric 3444098Seric lineno = 0; 3454322Seric naliases = bytes = longest = 0; 3464098Seric skipping = FALSE; 3474098Seric while (fgets(line, sizeof (line), af) != NULL) 3484098Seric { 3494322Seric int lhssize, rhssize; 3504322Seric 3514098Seric lineno++; 3524098Seric switch (line[0]) 3534098Seric { 3544098Seric case '#': 3554098Seric case '\n': 3564098Seric case '\0': 3574098Seric skipping = FALSE; 3584098Seric continue; 3594065Seric 3604098Seric case ' ': 3614098Seric case '\t': 3624098Seric if (!skipping) 3634098Seric syserr("aliases: %d: Non-continuation line starts with space", lineno); 3644098Seric skipping = TRUE; 3654097Seric continue; 3664098Seric } 3674098Seric skipping = FALSE; 3681874Seric 3694314Seric /* 3704314Seric ** Process the LHS 3714314Seric ** Find the final colon, and parse the address. 3724314Seric ** It should resolve to a local name -- this will 3734314Seric ** be checked later (we want to optionally do 3744314Seric ** parsing of the RHS first to maximize error 3754314Seric ** detection). 3764314Seric */ 3774314Seric 3784098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3794097Seric continue; 3804098Seric if (*p == '\0' || *p == '\n') 3814098Seric { 3824098Seric syntaxerr: 3837048Seric syserr("aliases: %d: missing colon", lineno); 3844097Seric continue; 3854098Seric } 3864098Seric *p++ = '\0'; 3874098Seric if (parse(line, &al, 1) == NULL) 3884098Seric { 3894098Seric *--p = ':'; 3904098Seric goto syntaxerr; 3914098Seric } 3924314Seric 3934314Seric /* 3944314Seric ** Process the RHS. 3954314Seric ** 'al' is the internal form of the LHS address. 3964314Seric ** 'p' points to the text of the RHS. 3974314Seric */ 3984314Seric 3994098Seric rhs = p; 4004098Seric for (;;) 4014098Seric { 4024098Seric register char c; 4031515Seric 4044157Seric if (init) 4054098Seric { 4064157Seric /* do parsing & compression of addresses */ 4074098Seric c = *p; 4084157Seric while (c != '\0') 4094098Seric { 4104157Seric p2 = p; 4114157Seric while (*p != '\n' && *p != ',' && *p != '\0') 4124157Seric p++; 4134157Seric c = *p; 4144157Seric *p++ = '\0'; 4154322Seric if (c == '\n') 4164322Seric c = '\0'; 4174157Seric if (*p2 == '\0') 4184157Seric { 4194157Seric p[-1] = c; 4204157Seric continue; 4214157Seric } 4224314Seric (void) parse(p2, &bl, -1); 4234098Seric p[-1] = c; 4244157Seric while (isspace(*p)) 4254157Seric p++; 4264098Seric } 4274098Seric } 4284157Seric else 4294157Seric p = &p[strlen(p)]; 4301515Seric 4314098Seric /* see if there should be a continuation line */ 4324106Seric c = fgetc(af); 4334106Seric if (!feof(af)) 4344314Seric (void) ungetc(c, af); 4354106Seric if (c != ' ' && c != '\t') 4364098Seric break; 4374098Seric 4384098Seric /* read continuation line */ 4394098Seric p--; 4404098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4414098Seric break; 4424098Seric lineno++; 4434098Seric } 4444594Seric if (al.q_mailer != LocalMailer) 4454098Seric { 4464098Seric syserr("aliases: %d: cannot alias non-local names", lineno); 4474098Seric continue; 4484098Seric } 4494314Seric 4504314Seric /* 4514314Seric ** Insert alias into symbol table or DBM file 4524314Seric */ 4534314Seric 4544322Seric lhssize = strlen(al.q_user) + 1; 4554322Seric rhssize = strlen(rhs) + 1; 4564322Seric 4574157Seric # ifdef DBM 4584157Seric if (init) 4594157Seric { 4604157Seric DATUM key, content; 4614157Seric 4624322Seric key.dsize = lhssize; 4634157Seric key.dptr = al.q_user; 4644322Seric content.dsize = rhssize; 4654157Seric content.dptr = rhs; 4664157Seric store(key, content); 4674157Seric } 4684157Seric else 4694157Seric # endif DBM 4704157Seric { 4714157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4724157Seric s->s_alias = newstr(rhs); 4734157Seric } 4744322Seric 4754322Seric /* statistics */ 4764322Seric naliases++; 4774322Seric bytes += lhssize + rhssize; 4784322Seric if (rhssize > longest) 4794322Seric longest = rhssize; 4801515Seric } 4814098Seric (void) fclose(af); 4826898Seric CurEnv->e_to = NULL; 4837051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4844322Seric naliases, longest, bytes); 485292Seric } 486292Seric /* 487292Seric ** FORWARD -- Try to forward mail 488292Seric ** 489292Seric ** This is similar but not identical to aliasing. 490292Seric ** 491292Seric ** Parameters: 4924314Seric ** user -- the name of the user who's mail we would like 4934314Seric ** to forward to. It must have been verified -- 4944314Seric ** i.e., the q_home field must have been filled 4954314Seric ** in. 4964999Seric ** sendq -- a pointer to the head of the send queue to 4974999Seric ** put this user's aliases in. 498292Seric ** 499292Seric ** Returns: 5004098Seric ** none. 501292Seric ** 502292Seric ** Side Effects: 5033185Seric ** New names are added to send queues. 504292Seric */ 505292Seric 5064999Seric forward(user, sendq) 5072966Seric ADDRESS *user; 5084999Seric ADDRESS **sendq; 509292Seric { 5104078Seric char buf[60]; 5114536Seric extern bool safefile(); 5124069Seric 5134098Seric # ifdef DEBUG 5147671Seric if (tTd(27, 1)) 5154098Seric printf("forward(%s)\n", user->q_paddr); 5164098Seric # endif DEBUG 5174098Seric 5184594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 5194098Seric return; 5204314Seric # ifdef DEBUG 5214314Seric if (user->q_home == NULL) 5224314Seric syserr("forward: no home"); 5234314Seric # endif DEBUG 5244069Seric 5254069Seric /* good address -- look for .forward file in home */ 5264104Seric define('z', user->q_home); 5276973Seric expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 5284536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 5294098Seric return; 5304069Seric 5314069Seric /* we do have an address to forward to -- do it */ 5324999Seric include(buf, "forwarding", user, sendq); 533292Seric } 534