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