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