1292Seric # include <pwd.h> 24212Seric # include <sys/types.h> 34212Seric # include <sys/stat.h> 43309Seric # include "sendmail.h" 5292Seric 64106Seric # ifdef DBM 7*4314Seric static char SccsId[] = "@(#)alias.c 3.19 09/06/81 (with DBM)"; 84106Seric # else DBM 9*4314Seric static char SccsId[] = "@(#)alias.c 3.19 09/06/81 (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. 21292Seric ** 22292Seric ** Returns: 23292Seric ** none 24292Seric ** 25292Seric ** Side Effects: 263185Seric ** Aliases found are expanded. 27292Seric ** 28292Seric ** Files: 294098Seric ** /usr/lib/aliases -- the mail aliases. The format is 30569Seric ** a series of lines of the form: 31569Seric ** alias:name1,name2,name3,... 32569Seric ** where 'alias' expands to all of 33569Seric ** 'name[i]'. Continuations begin with 34569Seric ** space or tab. 354098Seric ** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version 361503Smark ** of alias file. Keys are aliases, datums 371503Smark ** (data?) are name1,name2, ... 38292Seric ** 39292Seric ** Notes: 40292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 41292Seric ** done. 42292Seric ** 43292Seric ** Deficiencies: 44292Seric ** It should complain about names that are aliased to 45292Seric ** nothing. 46292Seric ** It is unsophisticated about line overflows. 47292Seric */ 48292Seric 49292Seric 501503Smark #ifdef DBM 512966Seric typedef struct 522966Seric { 532966Seric char *dptr; 544157Seric int dsize; 554157Seric } DATUM; 564157Seric DATUM lhs, rhs; 574157Seric extern DATUM fetch(); 581503Smark #endif DBM 59292Seric 604097Seric alias(a) 614097Seric register ADDRESS *a; 62292Seric { 634081Seric register char *p; 644081Seric # ifndef DBM 654098Seric register STAB *s; 664081Seric # endif DBM 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 794098Seric To = a->q_paddr; 804098Seric 81*4314Seric /* 82*4314Seric ** Look up this name 83*4314Seric */ 84*4314Seric 854097Seric # ifdef DBM 864098Seric /* create a key for fetch */ 874098Seric lhs.dptr = a->q_user; 884098Seric lhs.dsize = strlen(a->q_user) + 1; 894098Seric rhs = fetch(lhs); 904098Seric 914098Seric /* find this alias? */ 924098Seric p = rhs.dptr; 934098Seric if (p == NULL) 944098Seric return; 954098Seric # else DBM 964098Seric s = stab(a->q_user, ST_ALIAS, ST_FIND); 974098Seric if (s == NULL) 984098Seric return; 994098Seric p = s->s_alias; 1004097Seric # endif DBM 101292Seric 102292Seric /* 1034098Seric ** Match on Alias. 1044098Seric ** Deliver to the target list. 1051515Seric */ 1061515Seric 1074098Seric # ifdef DEBUG 1084098Seric if (Debug) 1094098Seric printf("%s (%s, %s) aliased to %s\n", 1104098Seric a->q_paddr, a->q_host, a->q_user, p); 1114098Seric # endif 1124098Seric if (Verbose) 1134165Seric message(Arpa_Info, "aliased to %s", p); 1144098Seric a->q_flags |= QDONTSEND; 1154098Seric AliasLevel++; 1164098Seric sendto(p, 1); 1174098Seric AliasLevel--; 1184098Seric } 1194098Seric /* 1204098Seric ** INITALIASES -- initialize for aliasing 1214098Seric ** 1224098Seric ** Very different depending on whether we are running DBM or not. 1234098Seric ** 1244098Seric ** Parameters: 1254098Seric ** aliasfile -- location of aliases. 1264157Seric ** init -- if set and if DBM, initialize the DBM files. 1274098Seric ** 1284098Seric ** Returns: 1294098Seric ** none. 1304098Seric ** 1314098Seric ** Side Effects: 1324098Seric ** initializes aliases: 1334098Seric ** if DBM: opens the database. 1344098Seric ** if ~DBM: reads the aliases into the symbol table. 1354098Seric */ 1364098Seric 1374157Seric # define DBMMODE 0666 1384157Seric 1394157Seric initaliases(aliasfile, init) 1404098Seric char *aliasfile; 1414157Seric bool init; 1424098Seric { 1434098Seric # ifdef DBM 1444157Seric if (init) 1454157Seric { 1464157Seric char buf[MAXNAME]; 1474157Seric 1484157Seric (void) strcpy(buf, aliasfile); 1494157Seric (void) strcat(buf, ".dir"); 1504157Seric if (close(creat(buf, DBMMODE)) < 0) 1514157Seric { 1524157Seric syserr("cannot make %s", buf); 1534157Seric return; 1544157Seric } 1554157Seric (void) strcpy(buf, aliasfile); 1564157Seric (void) strcat(buf, ".pag"); 1574157Seric if (close(creat(buf, DBMMODE)) < 0) 1584157Seric { 1594157Seric syserr("cannot make %s", buf); 1604157Seric return; 1614157Seric } 1624157Seric } 1634098Seric dbminit(aliasfile); 1644157Seric if (init) 1654157Seric readaliases(aliasfile, TRUE); 1664098Seric # else DBM 1674157Seric readaliases(aliasfile, init); 1684157Seric # endif DBM 1694157Seric } 1704157Seric /* 1714157Seric ** READALIASES -- read and process the alias file. 1724157Seric ** 1734157Seric ** This routine implements the part of initaliases that occurs 1744157Seric ** when we are not going to use the DBM stuff. 1754157Seric ** 1764157Seric ** Parameters: 1774157Seric ** aliasfile -- the pathname of the alias file master. 1784157Seric ** init -- if set, initialize the DBM stuff. 1794157Seric ** 1804157Seric ** Returns: 1814157Seric ** none. 1824157Seric ** 1834157Seric ** Side Effects: 1844157Seric ** Reads aliasfile into the symbol table. 1854157Seric ** Optionally, builds the .dir & .pag files. 1864157Seric */ 1874157Seric 1884157Seric static 1894157Seric readaliases(aliasfile, init) 1904157Seric char *aliasfile; 1914157Seric bool init; 1924157Seric { 1934098Seric char line[BUFSIZ]; 1944098Seric register char *p; 1954098Seric char *p2; 1964098Seric char *rhs; 1974098Seric bool skipping; 1984098Seric ADDRESS al, bl; 1994106Seric FILE *af; 2004106Seric int lineno; 2014106Seric register STAB *s; 2024098Seric 2034098Seric if ((af = fopen(aliasfile, "r")) == NULL) 2041515Seric { 2054098Seric # ifdef DEBUG 2064098Seric if (Debug) 2074106Seric printf("Can't open %s\n", aliasfile); 2084098Seric # endif 2094098Seric errno = 0; 2104098Seric NoAlias++; 2114098Seric return; 2124098Seric } 213*4314Seric 214*4314Seric /* 215*4314Seric ** Read and interpret lines 216*4314Seric */ 217*4314Seric 2184098Seric lineno = 0; 2194098Seric skipping = FALSE; 2204098Seric while (fgets(line, sizeof (line), af) != NULL) 2214098Seric { 2224098Seric lineno++; 2234098Seric switch (line[0]) 2244098Seric { 2254098Seric case '#': 2264098Seric case '\n': 2274098Seric case '\0': 2284098Seric skipping = FALSE; 2294098Seric continue; 2304065Seric 2314098Seric case ' ': 2324098Seric case '\t': 2334098Seric if (!skipping) 2344098Seric syserr("aliases: %d: Non-continuation line starts with space", lineno); 2354098Seric skipping = TRUE; 2364097Seric continue; 2374098Seric } 2384098Seric skipping = FALSE; 2391874Seric 240*4314Seric /* 241*4314Seric ** Process the LHS 242*4314Seric ** Find the final colon, and parse the address. 243*4314Seric ** It should resolve to a local name -- this will 244*4314Seric ** be checked later (we want to optionally do 245*4314Seric ** parsing of the RHS first to maximize error 246*4314Seric ** detection). 247*4314Seric */ 248*4314Seric 2494098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 2504097Seric continue; 2514098Seric if (*p == '\0' || *p == '\n') 2524098Seric { 2534098Seric syntaxerr: 2544098Seric syserr("aliases: %d: missing colon", lineno); 2554097Seric continue; 2564098Seric } 2574098Seric *p++ = '\0'; 2584098Seric if (parse(line, &al, 1) == NULL) 2594098Seric { 2604098Seric *--p = ':'; 2614098Seric goto syntaxerr; 2624098Seric } 263*4314Seric 264*4314Seric /* 265*4314Seric ** Process the RHS. 266*4314Seric ** 'al' is the internal form of the LHS address. 267*4314Seric ** 'p' points to the text of the RHS. 268*4314Seric */ 269*4314Seric 2704098Seric rhs = p; 2714098Seric for (;;) 2724098Seric { 2734098Seric register char c; 2741515Seric 2754157Seric if (init) 2764098Seric { 2774157Seric /* do parsing & compression of addresses */ 2784098Seric c = *p; 2794157Seric while (c != '\0') 2804098Seric { 2814157Seric p2 = p; 2824157Seric while (*p != '\n' && *p != ',' && *p != '\0') 2834157Seric p++; 2844157Seric c = *p; 2854157Seric *p++ = '\0'; 2864157Seric if (*p2 == '\0') 2874157Seric { 2884157Seric p[-1] = c; 2894157Seric continue; 2904157Seric } 291*4314Seric (void) parse(p2, &bl, -1); 2924098Seric p[-1] = c; 2934157Seric while (isspace(*p)) 2944157Seric p++; 2954098Seric } 2964098Seric } 2974157Seric else 2984157Seric p = &p[strlen(p)]; 2991515Seric 3004098Seric /* see if there should be a continuation line */ 3014106Seric c = fgetc(af); 3024106Seric if (!feof(af)) 303*4314Seric (void) ungetc(c, af); 3044106Seric if (c != ' ' && c != '\t') 3054098Seric break; 3064098Seric 3074098Seric /* read continuation line */ 3084098Seric p--; 3094098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 3104098Seric break; 3114098Seric lineno++; 3124098Seric } 3134193Seric if (al.q_mailer != MN_LOCAL) 3144098Seric { 3154098Seric syserr("aliases: %d: cannot alias non-local names", lineno); 3164098Seric continue; 3174098Seric } 318*4314Seric 319*4314Seric /* 320*4314Seric ** Insert alias into symbol table or DBM file 321*4314Seric */ 322*4314Seric 3234157Seric # ifdef DBM 3244157Seric if (init) 3254157Seric { 3264157Seric DATUM key, content; 3274157Seric 3284157Seric key.dsize = strlen(al.q_user) + 1; 3294157Seric key.dptr = al.q_user; 3304157Seric content.dsize = strlen(rhs) + 1; 3314157Seric content.dptr = rhs; 3324157Seric store(key, content); 3334157Seric } 3344157Seric else 3354157Seric # endif DBM 3364157Seric { 3374157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 3384157Seric s->s_alias = newstr(rhs); 3394157Seric } 3401515Seric } 3414098Seric (void) fclose(af); 342292Seric } 343292Seric /* 344292Seric ** FORWARD -- Try to forward mail 345292Seric ** 346292Seric ** This is similar but not identical to aliasing. 347292Seric ** 348292Seric ** Parameters: 349*4314Seric ** user -- the name of the user who's mail we would like 350*4314Seric ** to forward to. It must have been verified -- 351*4314Seric ** i.e., the q_home field must have been filled 352*4314Seric ** in. 353292Seric ** 354292Seric ** Returns: 3554098Seric ** none. 356292Seric ** 357292Seric ** Side Effects: 3583185Seric ** New names are added to send queues. 3594098Seric ** Sets the QDONTSEND bit in addresses that are forwarded. 360292Seric */ 361292Seric 362292Seric forward(user) 3632966Seric ADDRESS *user; 364292Seric { 3654078Seric char buf[60]; 3664212Seric struct stat stbuf; 3674069Seric 3684098Seric # ifdef DEBUG 3694098Seric if (Debug) 3704098Seric printf("forward(%s)\n", user->q_paddr); 3714098Seric # endif DEBUG 3724098Seric 3734193Seric if (user->q_mailer != MN_LOCAL || bitset(QBADADDR, user->q_flags)) 3744098Seric return; 375*4314Seric # ifdef DEBUG 376*4314Seric if (user->q_home == NULL) 377*4314Seric syserr("forward: no home"); 378*4314Seric # endif DEBUG 3794069Seric 3804069Seric /* good address -- look for .forward file in home */ 3814104Seric define('z', user->q_home); 3824081Seric (void) expand("$z/.forward", buf, &buf[sizeof buf - 1]); 3834212Seric if (stat(buf, &stbuf) < 0 || stbuf.st_uid != user->q_uid || 3844212Seric !bitset(S_IREAD, stbuf.st_mode)) 3854098Seric return; 3864069Seric 3874069Seric /* we do have an address to forward to -- do it */ 3884098Seric user->q_flags |= QDONTSEND; 3894177Seric include(buf, "forwarding"); 390292Seric } 391