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*16898Seric SCCSID(@(#)alias.c 4.5 08/11/84 (with DBM)); 94106Seric # else DBM 10*16898Seric SCCSID(@(#)alias.c 4.5 08/11/84 (without DBM)); 114106Seric # endif DBM 12402Seric 13292Seric /* 14292Seric ** ALIAS -- Compute aliases. 15292Seric ** 169368Seric ** Scans the alias file for an alias for the given address. 179368Seric ** If found, it arranges to deliver to the alias list instead. 189368Seric ** Uses libdbm 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 ** Notes: 32292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 33292Seric ** done. 34292Seric ** 35292Seric ** Deficiencies: 36292Seric ** It should complain about names that are aliased to 37292Seric ** nothing. 38292Seric */ 39292Seric 40292Seric 411503Smark #ifdef DBM 422966Seric typedef struct 432966Seric { 442966Seric char *dptr; 454157Seric int dsize; 464157Seric } DATUM; 474157Seric extern DATUM fetch(); 481503Smark #endif DBM 49292Seric 504999Seric alias(a, sendq) 514097Seric register ADDRESS *a; 524999Seric ADDRESS **sendq; 53292Seric { 544081Seric register char *p; 555701Seric extern char *aliaslookup(); 56292Seric 57292Seric if (NoAlias) 58292Seric return; 59292Seric # ifdef DEBUG 607671Seric if (tTd(27, 1)) 614098Seric printf("alias(%s)\n", a->q_paddr); 62292Seric # endif 63292Seric 644098Seric /* don't realias already aliased names */ 654098Seric if (bitset(QDONTSEND, a->q_flags)) 664098Seric return; 674098Seric 686898Seric CurEnv->e_to = a->q_paddr; 694098Seric 704314Seric /* 714314Seric ** Look up this name 724314Seric */ 734314Seric 745701Seric p = aliaslookup(a->q_user); 754098Seric if (p == NULL) 764098Seric return; 77292Seric 78292Seric /* 794098Seric ** Match on Alias. 804098Seric ** Deliver to the target list. 811515Seric */ 821515Seric 834098Seric # ifdef DEBUG 847671Seric if (tTd(27, 1)) 854098Seric printf("%s (%s, %s) aliased to %s\n", 864098Seric a->q_paddr, a->q_host, a->q_user, p); 874098Seric # endif 887051Seric message(Arpa_Info, "aliased to %s", p); 894098Seric AliasLevel++; 909614Seric sendtolist(p, a, sendq); 914098Seric AliasLevel--; 924098Seric } 934098Seric /* 945701Seric ** ALIASLOOKUP -- look up a name in the alias file. 955701Seric ** 965701Seric ** Parameters: 975701Seric ** name -- the name to look up. 985701Seric ** 995701Seric ** Returns: 1005701Seric ** the value of name. 1015701Seric ** NULL if unknown. 1025701Seric ** 1035701Seric ** Side Effects: 1045701Seric ** none. 1055701Seric ** 1065701Seric ** Warnings: 1075701Seric ** The return value will be trashed across calls. 1085701Seric */ 1095701Seric 1105701Seric char * 1115701Seric aliaslookup(name) 1125701Seric char *name; 1135701Seric { 1145701Seric # ifdef DBM 1155701Seric DATUM rhs, lhs; 1165701Seric 1175701Seric /* create a key for fetch */ 1185701Seric lhs.dptr = name; 1195701Seric lhs.dsize = strlen(name) + 1; 1205701Seric rhs = fetch(lhs); 1215701Seric return (rhs.dptr); 1225701Seric # else DBM 1235701Seric register STAB *s; 1245701Seric 1255701Seric s = stab(name, ST_ALIAS, ST_FIND); 1265701Seric if (s == NULL) 1275701Seric return (NULL); 1285701Seric return (s->s_alias); 1295701Seric # endif DBM 1305701Seric } 1315701Seric /* 1324098Seric ** INITALIASES -- initialize for aliasing 1334098Seric ** 1344098Seric ** Very different depending on whether we are running DBM or not. 1354098Seric ** 1364098Seric ** Parameters: 1374098Seric ** aliasfile -- location of aliases. 1384157Seric ** init -- if set and if DBM, initialize the DBM files. 1394098Seric ** 1404098Seric ** Returns: 1414098Seric ** none. 1424098Seric ** 1434098Seric ** Side Effects: 1444098Seric ** initializes aliases: 1454098Seric ** if DBM: opens the database. 1464098Seric ** if ~DBM: reads the aliases into the symbol table. 1474098Seric */ 1484098Seric 1494157Seric # define DBMMODE 0666 1504157Seric 1514157Seric initaliases(aliasfile, init) 1524098Seric char *aliasfile; 1534157Seric bool init; 1544098Seric { 1559368Seric #ifdef DBM 1568437Seric int atcnt; 1574322Seric char buf[MAXNAME]; 1584322Seric time_t modtime; 1598437Seric int (*oldsigint)(); 1609368Seric #endif DBM 1619368Seric struct stat stb; 1624322Seric 1638437Seric if (stat(aliasfile, &stb) < 0) 1648437Seric { 1658437Seric NoAlias = TRUE; 16611937Seric errno = 0; 1678437Seric return; 1688437Seric } 1698437Seric 1708928Seric # ifdef DBM 1714322Seric /* 1728437Seric ** Check to see that the alias file is complete. 1738437Seric ** If not, we will assume that someone died, and it is up 1748437Seric ** to us to rebuild it. 1758437Seric */ 1768437Seric 1778437Seric dbminit(aliasfile); 1788928Seric atcnt = 10; 1798928Seric while (SafeAlias && !init && atcnt-- >= 0 && aliaslookup("@") == NULL) 1808437Seric sleep(30); 1818437Seric 1828437Seric /* 1834322Seric ** See if the DBM version of the file is out of date with 1844322Seric ** the text version. If so, go into 'init' mode automatically. 1854322Seric ** This only happens if our effective userid owns the DBM 1864325Seric ** version or if the mode of the database is 666 -- this 1874322Seric ** is an attempt to avoid protection problems. Note the 1884322Seric ** unpalatable hack to see if the stat succeeded. 1894322Seric */ 1904322Seric 1914322Seric modtime = stb.st_mtime; 1924322Seric (void) strcpy(buf, aliasfile); 1934322Seric (void) strcat(buf, ".pag"); 1944322Seric stb.st_ino = 0; 1959150Seric if (!init && (atcnt < 0 || stat(buf, &stb) < 0 || stb.st_mtime < modtime)) 1964322Seric { 19711937Seric errno = 0; 1989150Seric if (AutoRebuild && stb.st_ino != 0 && 1999368Seric ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) 2004322Seric { 2014322Seric init = TRUE; 2027051Seric message(Arpa_Info, "rebuilding alias database"); 2034322Seric } 2044322Seric else 2054322Seric { 2067051Seric bool oldverb = Verbose; 2077051Seric 2087051Seric Verbose = TRUE; 2094322Seric message(Arpa_Info, "Warning: alias database out of date"); 2107051Seric Verbose = oldverb; 2114322Seric } 2124322Seric } 2134322Seric 2144322Seric /* 2154322Seric ** If initializing, create the new files. 2164322Seric ** We should lock the alias file here to prevent other 2174322Seric ** instantiations of sendmail from reading an incomplete 2184322Seric ** file -- or worse yet, doing a concurrent initialize. 2194322Seric */ 2204322Seric 2214157Seric if (init) 2224157Seric { 2238437Seric oldsigint = signal(SIGINT, SIG_IGN); 2244157Seric (void) strcpy(buf, aliasfile); 2254157Seric (void) strcat(buf, ".dir"); 2264157Seric if (close(creat(buf, DBMMODE)) < 0) 2274157Seric { 2284157Seric syserr("cannot make %s", buf); 2299368Seric (void) signal(SIGINT, oldsigint); 2304157Seric return; 2314157Seric } 2324157Seric (void) strcpy(buf, aliasfile); 2334157Seric (void) strcat(buf, ".pag"); 2344157Seric if (close(creat(buf, DBMMODE)) < 0) 2354157Seric { 2364157Seric syserr("cannot make %s", buf); 2379368Seric (void) signal(SIGINT, oldsigint); 2384157Seric return; 2394157Seric } 2404157Seric } 2414322Seric 2424322Seric /* 2438437Seric ** If necessary, load the DBM file. 2444322Seric ** If running without DBM, load the symbol table. 2458437Seric ** After loading the DBM file, add the distinquished alias "@". 2464322Seric */ 2474322Seric 2484157Seric if (init) 2498437Seric { 2508437Seric DATUM key; 2518437Seric 2524157Seric readaliases(aliasfile, TRUE); 2538437Seric key.dsize = 2; 2548437Seric key.dptr = "@"; 2558437Seric store(key, key); 2568437Seric (void) signal(SIGINT, oldsigint); 2578437Seric } 2584098Seric # else DBM 2594157Seric readaliases(aliasfile, init); 2604157Seric # endif DBM 2614157Seric } 2624157Seric /* 2634157Seric ** READALIASES -- read and process the alias file. 2644157Seric ** 2654157Seric ** This routine implements the part of initaliases that occurs 2664157Seric ** when we are not going to use the DBM stuff. 2674157Seric ** 2684157Seric ** Parameters: 2694157Seric ** aliasfile -- the pathname of the alias file master. 2704157Seric ** init -- if set, initialize the DBM stuff. 2714157Seric ** 2724157Seric ** Returns: 2734157Seric ** none. 2744157Seric ** 2754157Seric ** Side Effects: 2764157Seric ** Reads aliasfile into the symbol table. 2774157Seric ** Optionally, builds the .dir & .pag files. 2784157Seric */ 2794157Seric 2804157Seric static 2814157Seric readaliases(aliasfile, init) 2824157Seric char *aliasfile; 2834157Seric bool init; 2844157Seric { 2854098Seric register char *p; 2864098Seric char *p2; 2874098Seric char *rhs; 2884098Seric bool skipping; 2899368Seric int naliases, bytes, longest; 2909368Seric FILE *af; 2914098Seric ADDRESS al, bl; 2924106Seric register STAB *s; 2939368Seric char line[BUFSIZ]; 2944098Seric 2954098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2961515Seric { 2974098Seric # ifdef DEBUG 2987671Seric if (tTd(27, 1)) 2994106Seric printf("Can't open %s\n", aliasfile); 3004098Seric # endif 3014098Seric errno = 0; 3024098Seric NoAlias++; 3034098Seric return; 3044098Seric } 3054314Seric 3064314Seric /* 3074314Seric ** Read and interpret lines 3084314Seric */ 3094314Seric 3109368Seric FileName = aliasfile; 3119368Seric LineNumber = 0; 3124322Seric naliases = bytes = longest = 0; 3134098Seric skipping = FALSE; 3144098Seric while (fgets(line, sizeof (line), af) != NULL) 3154098Seric { 3164322Seric int lhssize, rhssize; 3174322Seric 3189368Seric LineNumber++; 3194098Seric switch (line[0]) 3204098Seric { 3214098Seric case '#': 3224098Seric case '\n': 3234098Seric case '\0': 3244098Seric skipping = FALSE; 3254098Seric continue; 3264065Seric 3274098Seric case ' ': 3284098Seric case '\t': 3294098Seric if (!skipping) 3309368Seric syserr("Non-continuation line starts with space"); 3314098Seric skipping = TRUE; 3324097Seric continue; 3334098Seric } 3344098Seric skipping = FALSE; 3351874Seric 3364314Seric /* 3374314Seric ** Process the LHS 3384314Seric ** Find the final colon, and parse the address. 339*16898Seric ** It should resolve to a local name -- this will 340*16898Seric ** be checked later (we want to optionally do 341*16898Seric ** parsing of the RHS first to maximize error 342*16898Seric ** detection). 3434314Seric */ 3444314Seric 3454098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 3464097Seric continue; 347*16898Seric if (*p++ != ':') 3484098Seric { 3499368Seric syserr("missing colon"); 3504097Seric continue; 3514098Seric } 352*16898Seric if (parseaddr(line, &al, 1, ':') == NULL) 3534098Seric { 354*16898Seric syserr("illegal alias name"); 355*16898Seric continue; 3564098Seric } 357*16898Seric loweraddr(&al); 3584314Seric 3594314Seric /* 3604314Seric ** Process the RHS. 3614314Seric ** 'al' is the internal form of the LHS address. 3624314Seric ** 'p' points to the text of the RHS. 3634314Seric */ 3644314Seric 3654098Seric rhs = p; 3664098Seric for (;;) 3674098Seric { 3684098Seric register char c; 3691515Seric 3704157Seric if (init) 3714098Seric { 3724157Seric /* do parsing & compression of addresses */ 3734098Seric c = *p; 3744157Seric while (c != '\0') 3754098Seric { 3764157Seric p2 = p; 3774157Seric while (*p != '\n' && *p != ',' && *p != '\0') 3784157Seric p++; 3794157Seric c = *p; 3804157Seric *p++ = '\0'; 3814322Seric if (c == '\n') 3824322Seric c = '\0'; 3834157Seric if (*p2 == '\0') 3844157Seric { 3854157Seric p[-1] = c; 3864157Seric continue; 3874157Seric } 38811444Seric (void) parseaddr(p2, &bl, -1, ','); 3894098Seric p[-1] = c; 3904157Seric while (isspace(*p)) 3914157Seric p++; 3924098Seric } 3934098Seric } 3944157Seric else 39515769Seric { 396*16898Seric p = &p[strlen(p)]; 397*16898Seric if (p[-1] == '\n') 398*16898Seric *--p = '\0'; 39915769Seric } 4001515Seric 4014098Seric /* see if there should be a continuation line */ 4024106Seric c = fgetc(af); 4034106Seric if (!feof(af)) 4044314Seric (void) ungetc(c, af); 4054106Seric if (c != ' ' && c != '\t') 4064098Seric break; 4074098Seric 4084098Seric /* read continuation line */ 4094098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 4104098Seric break; 4119368Seric LineNumber++; 4124098Seric } 413*16898Seric if (al.q_mailer != LocalMailer) 414*16898Seric { 415*16898Seric syserr("cannot alias non-local names"); 416*16898Seric continue; 417*16898Seric } 4184314Seric 4194314Seric /* 4204314Seric ** Insert alias into symbol table or DBM file 4214314Seric */ 4224314Seric 423*16898Seric lhssize = strlen(al.q_user) + 1; 4244322Seric rhssize = strlen(rhs) + 1; 4254322Seric 4264157Seric # ifdef DBM 4274157Seric if (init) 4284157Seric { 4294157Seric DATUM key, content; 4304157Seric 4314322Seric key.dsize = lhssize; 4324157Seric key.dptr = al.q_user; 4334322Seric content.dsize = rhssize; 4344157Seric content.dptr = rhs; 4354157Seric store(key, content); 4364157Seric } 4374157Seric else 4384157Seric # endif DBM 4394157Seric { 4404157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 4414157Seric s->s_alias = newstr(rhs); 4424157Seric } 4434322Seric 4444322Seric /* statistics */ 4454322Seric naliases++; 4464322Seric bytes += lhssize + rhssize; 4474322Seric if (rhssize > longest) 4484322Seric longest = rhssize; 4491515Seric } 4504098Seric (void) fclose(af); 4516898Seric CurEnv->e_to = NULL; 4529368Seric FileName = NULL; 4537051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 4544322Seric naliases, longest, bytes); 455292Seric } 456292Seric /* 457292Seric ** FORWARD -- Try to forward mail 458292Seric ** 459292Seric ** This is similar but not identical to aliasing. 460292Seric ** 461292Seric ** Parameters: 4624314Seric ** user -- the name of the user who's mail we would like 4634314Seric ** to forward to. It must have been verified -- 4644314Seric ** i.e., the q_home field must have been filled 4654314Seric ** in. 4664999Seric ** sendq -- a pointer to the head of the send queue to 4674999Seric ** put this user's aliases in. 468292Seric ** 469292Seric ** Returns: 4704098Seric ** none. 471292Seric ** 472292Seric ** Side Effects: 4733185Seric ** New names are added to send queues. 474292Seric */ 475292Seric 4764999Seric forward(user, sendq) 4772966Seric ADDRESS *user; 4784999Seric ADDRESS **sendq; 479292Seric { 4804078Seric char buf[60]; 4814536Seric extern bool safefile(); 4824069Seric 4834098Seric # ifdef DEBUG 4847671Seric if (tTd(27, 1)) 4854098Seric printf("forward(%s)\n", user->q_paddr); 4864098Seric # endif DEBUG 4874098Seric 4884594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 4894098Seric return; 4904314Seric # ifdef DEBUG 4914314Seric if (user->q_home == NULL) 4924314Seric syserr("forward: no home"); 4934314Seric # endif DEBUG 4944069Seric 4954069Seric /* good address -- look for .forward file in home */ 4969368Seric define('z', user->q_home, CurEnv); 49716154Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 4984536Seric if (!safefile(buf, user->q_uid, S_IREAD)) 4994098Seric return; 5004069Seric 5014069Seric /* we do have an address to forward to -- do it */ 5024999Seric include(buf, "forwarding", user, sendq); 503292Seric } 504