|
|
1.1 ! root 1: # include <pwd.h> ! 2: # include <sys/types.h> ! 3: # include <sys/stat.h> ! 4: # include <signal.h> ! 5: # include "sendmail.h" ! 6: ! 7: # ifdef DBM ! 8: SCCSID(@(#)alias.c 4.1 7/25/83 (with DBM)); ! 9: # else DBM ! 10: SCCSID(@(#)alias.c 4.1 7/25/83 (without DBM)); ! 11: # endif DBM ! 12: ! 13: /* ! 14: ** ALIAS -- Compute aliases. ! 15: ** ! 16: ** Scans the alias file for an alias for the given address. ! 17: ** If found, it arranges to deliver to the alias list instead. ! 18: ** Uses libdbm database if -DDBM. ! 19: ** ! 20: ** Parameters: ! 21: ** a -- address to alias. ! 22: ** sendq -- a pointer to the head of the send queue ! 23: ** to put the aliases in. ! 24: ** ! 25: ** Returns: ! 26: ** none ! 27: ** ! 28: ** Side Effects: ! 29: ** Aliases found are expanded. ! 30: ** ! 31: ** Notes: ! 32: ** If NoAlias (the "-n" flag) is set, no aliasing is ! 33: ** done. ! 34: ** ! 35: ** Deficiencies: ! 36: ** It should complain about names that are aliased to ! 37: ** nothing. ! 38: */ ! 39: ! 40: ! 41: #ifdef DBM ! 42: typedef struct ! 43: { ! 44: char *dptr; ! 45: int dsize; ! 46: } DATUM; ! 47: extern DATUM fetch(); ! 48: #endif DBM ! 49: ! 50: alias(a, sendq) ! 51: register ADDRESS *a; ! 52: ADDRESS **sendq; ! 53: { ! 54: register char *p; ! 55: extern char *aliaslookup(); ! 56: ! 57: if (NoAlias) ! 58: return; ! 59: # ifdef DEBUG ! 60: if (tTd(27, 1)) ! 61: printf("alias(%s)\n", a->q_paddr); ! 62: # endif ! 63: ! 64: /* don't realias already aliased names */ ! 65: if (bitset(QDONTSEND, a->q_flags)) ! 66: return; ! 67: ! 68: CurEnv->e_to = a->q_paddr; ! 69: ! 70: /* ! 71: ** Look up this name ! 72: */ ! 73: ! 74: p = aliaslookup(a->q_user); ! 75: if (p == NULL) ! 76: return; ! 77: ! 78: /* ! 79: ** Match on Alias. ! 80: ** Deliver to the target list. ! 81: */ ! 82: ! 83: # ifdef DEBUG ! 84: if (tTd(27, 1)) ! 85: printf("%s (%s, %s) aliased to %s\n", ! 86: a->q_paddr, a->q_host, a->q_user, p); ! 87: # endif ! 88: message(Arpa_Info, "aliased to %s", p); ! 89: AliasLevel++; ! 90: sendtolist(p, a, sendq); ! 91: AliasLevel--; ! 92: } ! 93: /* ! 94: ** ALIASLOOKUP -- look up a name in the alias file. ! 95: ** ! 96: ** Parameters: ! 97: ** name -- the name to look up. ! 98: ** ! 99: ** Returns: ! 100: ** the value of name. ! 101: ** NULL if unknown. ! 102: ** ! 103: ** Side Effects: ! 104: ** none. ! 105: ** ! 106: ** Warnings: ! 107: ** The return value will be trashed across calls. ! 108: */ ! 109: ! 110: char * ! 111: aliaslookup(name) ! 112: char *name; ! 113: { ! 114: # ifdef DBM ! 115: DATUM rhs, lhs; ! 116: ! 117: /* create a key for fetch */ ! 118: lhs.dptr = name; ! 119: lhs.dsize = strlen(name) + 1; ! 120: rhs = fetch(lhs); ! 121: return (rhs.dptr); ! 122: # else DBM ! 123: register STAB *s; ! 124: ! 125: s = stab(name, ST_ALIAS, ST_FIND); ! 126: if (s == NULL) ! 127: return (NULL); ! 128: return (s->s_alias); ! 129: # endif DBM ! 130: } ! 131: /* ! 132: ** INITALIASES -- initialize for aliasing ! 133: ** ! 134: ** Very different depending on whether we are running DBM or not. ! 135: ** ! 136: ** Parameters: ! 137: ** aliasfile -- location of aliases. ! 138: ** init -- if set and if DBM, initialize the DBM files. ! 139: ** ! 140: ** Returns: ! 141: ** none. ! 142: ** ! 143: ** Side Effects: ! 144: ** initializes aliases: ! 145: ** if DBM: opens the database. ! 146: ** if ~DBM: reads the aliases into the symbol table. ! 147: */ ! 148: ! 149: # define DBMMODE 0666 ! 150: ! 151: initaliases(aliasfile, init) ! 152: char *aliasfile; ! 153: bool init; ! 154: { ! 155: #ifdef DBM ! 156: int atcnt; ! 157: char buf[MAXNAME]; ! 158: time_t modtime; ! 159: int (*oldsigint)(); ! 160: #endif DBM ! 161: struct stat stb; ! 162: ! 163: if (stat(aliasfile, &stb) < 0) ! 164: { ! 165: NoAlias = TRUE; ! 166: errno = 0; ! 167: return; ! 168: } ! 169: ! 170: # ifdef DBM ! 171: /* ! 172: ** Check to see that the alias file is complete. ! 173: ** If not, we will assume that someone died, and it is up ! 174: ** to us to rebuild it. ! 175: */ ! 176: ! 177: dbminit(aliasfile); ! 178: atcnt = 10; ! 179: while (SafeAlias && !init && atcnt-- >= 0 && aliaslookup("@") == NULL) ! 180: sleep(30); ! 181: ! 182: /* ! 183: ** See if the DBM version of the file is out of date with ! 184: ** the text version. If so, go into 'init' mode automatically. ! 185: ** This only happens if our effective userid owns the DBM ! 186: ** version or if the mode of the database is 666 -- this ! 187: ** is an attempt to avoid protection problems. Note the ! 188: ** unpalatable hack to see if the stat succeeded. ! 189: */ ! 190: ! 191: modtime = stb.st_mtime; ! 192: (void) strcpy(buf, aliasfile); ! 193: (void) strcat(buf, ".pag"); ! 194: stb.st_ino = 0; ! 195: if (!init && (atcnt < 0 || stat(buf, &stb) < 0 || stb.st_mtime < modtime)) ! 196: { ! 197: errno = 0; ! 198: if (AutoRebuild && stb.st_ino != 0 && ! 199: ((stb.st_mode & 0777) == 0666 || stb.st_uid == geteuid())) ! 200: { ! 201: init = TRUE; ! 202: message(Arpa_Info, "rebuilding alias database"); ! 203: } ! 204: else ! 205: { ! 206: bool oldverb = Verbose; ! 207: ! 208: Verbose = TRUE; ! 209: message(Arpa_Info, "Warning: alias database out of date"); ! 210: Verbose = oldverb; ! 211: } ! 212: } ! 213: ! 214: /* ! 215: ** If initializing, create the new files. ! 216: ** We should lock the alias file here to prevent other ! 217: ** instantiations of sendmail from reading an incomplete ! 218: ** file -- or worse yet, doing a concurrent initialize. ! 219: */ ! 220: ! 221: if (init) ! 222: { ! 223: oldsigint = signal(SIGINT, SIG_IGN); ! 224: (void) strcpy(buf, aliasfile); ! 225: (void) strcat(buf, ".dir"); ! 226: if (close(creat(buf, DBMMODE)) < 0) ! 227: { ! 228: syserr("cannot make %s", buf); ! 229: (void) signal(SIGINT, oldsigint); ! 230: return; ! 231: } ! 232: (void) strcpy(buf, aliasfile); ! 233: (void) strcat(buf, ".pag"); ! 234: if (close(creat(buf, DBMMODE)) < 0) ! 235: { ! 236: syserr("cannot make %s", buf); ! 237: (void) signal(SIGINT, oldsigint); ! 238: return; ! 239: } ! 240: } ! 241: ! 242: /* ! 243: ** If necessary, load the DBM file. ! 244: ** If running without DBM, load the symbol table. ! 245: ** After loading the DBM file, add the distinquished alias "@". ! 246: */ ! 247: ! 248: if (init) ! 249: { ! 250: DATUM key; ! 251: ! 252: readaliases(aliasfile, TRUE); ! 253: key.dsize = 2; ! 254: key.dptr = "@"; ! 255: store(key, key); ! 256: (void) signal(SIGINT, oldsigint); ! 257: } ! 258: # else DBM ! 259: readaliases(aliasfile, init); ! 260: # endif DBM ! 261: } ! 262: /* ! 263: ** READALIASES -- read and process the alias file. ! 264: ** ! 265: ** This routine implements the part of initaliases that occurs ! 266: ** when we are not going to use the DBM stuff. ! 267: ** ! 268: ** Parameters: ! 269: ** aliasfile -- the pathname of the alias file master. ! 270: ** init -- if set, initialize the DBM stuff. ! 271: ** ! 272: ** Returns: ! 273: ** none. ! 274: ** ! 275: ** Side Effects: ! 276: ** Reads aliasfile into the symbol table. ! 277: ** Optionally, builds the .dir & .pag files. ! 278: */ ! 279: ! 280: static ! 281: readaliases(aliasfile, init) ! 282: char *aliasfile; ! 283: bool init; ! 284: { ! 285: register char *p; ! 286: char *p2; ! 287: char *rhs; ! 288: bool skipping; ! 289: int naliases, bytes, longest; ! 290: FILE *af; ! 291: ADDRESS al, bl; ! 292: register STAB *s; ! 293: char line[BUFSIZ]; ! 294: ! 295: if ((af = fopen(aliasfile, "r")) == NULL) ! 296: { ! 297: # ifdef DEBUG ! 298: if (tTd(27, 1)) ! 299: printf("Can't open %s\n", aliasfile); ! 300: # endif ! 301: errno = 0; ! 302: NoAlias++; ! 303: return; ! 304: } ! 305: ! 306: /* ! 307: ** Read and interpret lines ! 308: */ ! 309: ! 310: FileName = aliasfile; ! 311: LineNumber = 0; ! 312: naliases = bytes = longest = 0; ! 313: skipping = FALSE; ! 314: while (fgets(line, sizeof (line), af) != NULL) ! 315: { ! 316: int lhssize, rhssize; ! 317: ! 318: LineNumber++; ! 319: switch (line[0]) ! 320: { ! 321: case '#': ! 322: case '\n': ! 323: case '\0': ! 324: skipping = FALSE; ! 325: continue; ! 326: ! 327: case ' ': ! 328: case '\t': ! 329: if (!skipping) ! 330: syserr("Non-continuation line starts with space"); ! 331: skipping = TRUE; ! 332: continue; ! 333: } ! 334: skipping = FALSE; ! 335: ! 336: /* ! 337: ** Process the LHS ! 338: ** Find the final colon, and parse the address. ! 339: ** It should resolve to a local name -- this will ! 340: ** be checked later (we want to optionally do ! 341: ** parsing of the RHS first to maximize error ! 342: ** detection). ! 343: */ ! 344: ! 345: for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) ! 346: continue; ! 347: if (*p++ != ':') ! 348: { ! 349: syserr("missing colon"); ! 350: continue; ! 351: } ! 352: if (parseaddr(line, &al, 1, ':') == NULL) ! 353: { ! 354: syserr("illegal alias name"); ! 355: continue; ! 356: } ! 357: ! 358: /* ! 359: ** Process the RHS. ! 360: ** 'al' is the internal form of the LHS address. ! 361: ** 'p' points to the text of the RHS. ! 362: */ ! 363: ! 364: rhs = p; ! 365: for (;;) ! 366: { ! 367: register char c; ! 368: ! 369: if (init) ! 370: { ! 371: /* do parsing & compression of addresses */ ! 372: c = *p; ! 373: while (c != '\0') ! 374: { ! 375: p2 = p; ! 376: while (*p != '\n' && *p != ',' && *p != '\0') ! 377: p++; ! 378: c = *p; ! 379: *p++ = '\0'; ! 380: if (c == '\n') ! 381: c = '\0'; ! 382: if (*p2 == '\0') ! 383: { ! 384: p[-1] = c; ! 385: continue; ! 386: } ! 387: (void) parseaddr(p2, &bl, -1, ','); ! 388: p[-1] = c; ! 389: while (isspace(*p)) ! 390: p++; ! 391: } ! 392: } ! 393: else ! 394: p = &p[strlen(p)]; ! 395: ! 396: /* see if there should be a continuation line */ ! 397: c = fgetc(af); ! 398: if (!feof(af)) ! 399: (void) ungetc(c, af); ! 400: if (c != ' ' && c != '\t') ! 401: break; ! 402: ! 403: /* read continuation line */ ! 404: p--; ! 405: if (fgets(p, sizeof line - (p - line), af) == NULL) ! 406: break; ! 407: LineNumber++; ! 408: } ! 409: if (al.q_mailer != LocalMailer) ! 410: { ! 411: syserr("cannot alias non-local names"); ! 412: continue; ! 413: } ! 414: ! 415: /* ! 416: ** Insert alias into symbol table or DBM file ! 417: */ ! 418: ! 419: lhssize = strlen(al.q_user) + 1; ! 420: rhssize = strlen(rhs) + 1; ! 421: ! 422: # ifdef DBM ! 423: if (init) ! 424: { ! 425: DATUM key, content; ! 426: ! 427: key.dsize = lhssize; ! 428: key.dptr = al.q_user; ! 429: content.dsize = rhssize; ! 430: content.dptr = rhs; ! 431: store(key, content); ! 432: } ! 433: else ! 434: # endif DBM ! 435: { ! 436: s = stab(al.q_user, ST_ALIAS, ST_ENTER); ! 437: s->s_alias = newstr(rhs); ! 438: } ! 439: ! 440: /* statistics */ ! 441: naliases++; ! 442: bytes += lhssize + rhssize; ! 443: if (rhssize > longest) ! 444: longest = rhssize; ! 445: } ! 446: (void) fclose(af); ! 447: CurEnv->e_to = NULL; ! 448: FileName = NULL; ! 449: message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", ! 450: naliases, longest, bytes); ! 451: } ! 452: /* ! 453: ** FORWARD -- Try to forward mail ! 454: ** ! 455: ** This is similar but not identical to aliasing. ! 456: ** ! 457: ** Parameters: ! 458: ** user -- the name of the user who's mail we would like ! 459: ** to forward to. It must have been verified -- ! 460: ** i.e., the q_home field must have been filled ! 461: ** in. ! 462: ** sendq -- a pointer to the head of the send queue to ! 463: ** put this user's aliases in. ! 464: ** ! 465: ** Returns: ! 466: ** none. ! 467: ** ! 468: ** Side Effects: ! 469: ** New names are added to send queues. ! 470: */ ! 471: ! 472: forward(user, sendq) ! 473: ADDRESS *user; ! 474: ADDRESS **sendq; ! 475: { ! 476: char buf[60]; ! 477: extern bool safefile(); ! 478: ! 479: # ifdef DEBUG ! 480: if (tTd(27, 1)) ! 481: printf("forward(%s)\n", user->q_paddr); ! 482: # endif DEBUG ! 483: ! 484: if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) ! 485: return; ! 486: # ifdef DEBUG ! 487: if (user->q_home == NULL) ! 488: syserr("forward: no home"); ! 489: # endif DEBUG ! 490: ! 491: /* good address -- look for .forward file in home */ ! 492: define('z', user->q_home, CurEnv); ! 493: expand("$z/.forward", buf, &buf[sizeof buf - 1], CurEnv); ! 494: if (!safefile(buf, user->q_uid, S_IREAD)) ! 495: return; ! 496: ! 497: /* we do have an address to forward to -- do it */ ! 498: include(buf, "forwarding", user, sendq); ! 499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.