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