1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 # include <signal.h> 11 # include <pwd.h> 12 # ifdef DBM 13 ERROR: DBM is no longer supported -- use NDBM instead. 14 # endif 15 # ifdef NEWDB 16 # include <db.h> 17 # endif 18 # ifdef NDBM 19 # include <ndbm.h> 20 # endif 21 # ifdef NIS_ALIASES 22 # include <rpcsvc/ypclnt.h> 23 # endif 24 25 #ifndef lint 26 #ifdef NEWDB 27 #ifdef NDBM 28 static char sccsid[] = "@(#)alias.c 6.45 (Berkeley) 05/06/93 (with NEWDB and NDBM)"; 29 #else 30 static char sccsid[] = "@(#)alias.c 6.45 (Berkeley) 05/06/93 (with NEWDB)"; 31 #endif 32 #else 33 #ifdef NDBM 34 static char sccsid[] = "@(#)alias.c 6.45 (Berkeley) 05/06/93 (with NDBM)"; 35 #else 36 static char sccsid[] = "@(#)alias.c 6.45 (Berkeley) 05/06/93 (without NEWDB or NDBM)"; 37 #endif 38 #endif 39 #endif /* not lint */ 40 /* 41 ** Alias data structures 42 */ 43 #define ALIASDB struct _aliasdb 44 45 46 ALIASDB 47 { 48 ALIASCLASS *ad_class; /* class of this database */ 49 char *ad_name; /* name of alias file */ 50 char *ad_domain; /* name of (NIS) domain */ 51 void *ad_dbp; /* ndbm/nis database pointer */ 52 #ifdef NEWDB 53 DB *ad_ndbp; /* newdb database pointer */ 54 #endif 55 short ad_flags; /* flag bits */ 56 }; 57 58 /* bits for ad_flags */ 59 #define ADF_VALID 0x0001 /* database initialized */ 60 #define ADF_WRITABLE 0x0002 /* open for write */ 61 #define ADF_IMPLHASH 0x0004 /* IMPL: underlying hash database */ 62 #define ADF_IMPLNDBM 0x0008 /* IMPL: underlying NDBM database */ 63 64 65 ALIASCLASS 66 { 67 char *ac_name; /* name of alias class */ 68 char *(*ac_lookup)__P((ALIASDB *, char *, ENVELOPE *)); 69 /* lookup func */ 70 void (*ac_store)__P((ALIASDB *, char *, char *, ENVELOPE *)); 71 /* database store func */ 72 bool (*ac_init)__P((ALIASDB *, ENVELOPE *)); 73 /* initialization func */ 74 void (*ac_rebuild)__P((ALIASDB *, FILE *, int, ENVELOPE *)); 75 /* initialization func */ 76 void (*ac_close)__P((ALIASDB *, ENVELOPE *)); 77 /* close function */ 78 short ac_flags; /* flag bits */ 79 }; 80 81 /* bits for ac_flags */ 82 #define ACF_BUILDABLE 0x0001 /* can build a cached version */ 83 84 85 ALIASDB AliasDB[MAXALIASDB + 1]; /* actual database list */ 86 int NAliasDBs; /* number of alias databases */ 87 /* 88 ** ALIAS -- Compute aliases. 89 ** 90 ** Scans the alias file for an alias for the given address. 91 ** If found, it arranges to deliver to the alias list instead. 92 ** Uses libdbm database if -DDBM. 93 ** 94 ** Parameters: 95 ** a -- address to alias. 96 ** sendq -- a pointer to the head of the send queue 97 ** to put the aliases in. 98 ** e -- the current envelope. 99 ** 100 ** Returns: 101 ** none 102 ** 103 ** Side Effects: 104 ** Aliases found are expanded. 105 ** 106 ** Deficiencies: 107 ** It should complain about names that are aliased to 108 ** nothing. 109 */ 110 111 alias(a, sendq, e) 112 register ADDRESS *a; 113 ADDRESS **sendq; 114 register ENVELOPE *e; 115 { 116 register char *p; 117 int naliases; 118 char *owner; 119 char obuf[MAXNAME + 6]; 120 extern char *aliaslookup(); 121 122 if (tTd(27, 1)) 123 printf("alias(%s)\n", a->q_paddr); 124 125 /* don't realias already aliased names */ 126 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 127 return; 128 129 if (NoAlias) 130 return; 131 132 e->e_to = a->q_paddr; 133 134 /* 135 ** Look up this name 136 */ 137 138 p = aliaslookup(a->q_user, e); 139 if (p == NULL) 140 return; 141 142 /* 143 ** Match on Alias. 144 ** Deliver to the target list. 145 */ 146 147 if (tTd(27, 1)) 148 printf("%s (%s, %s) aliased to %s\n", 149 a->q_paddr, a->q_host, a->q_user, p); 150 if (bitset(EF_VRFYONLY, e->e_flags)) 151 { 152 a->q_flags |= QVERIFIED; 153 e->e_nrcpts++; 154 return; 155 } 156 message("aliased to %s", p); 157 #ifdef LOG 158 if (LogLevel > 9) 159 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 160 #endif 161 a->q_flags &= ~QSELFREF; 162 AliasLevel++; 163 naliases = sendtolist(p, a, sendq, e); 164 AliasLevel--; 165 if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 166 { 167 if (tTd(27, 5)) 168 { 169 printf("alias: QDONTSEND "); 170 printaddr(a, FALSE); 171 } 172 a->q_flags |= QDONTSEND; 173 } 174 175 /* 176 ** Look for owner of alias 177 */ 178 179 (void) strcpy(obuf, "owner-"); 180 if (strncmp(a->q_user, "owner-", 6) == 0) 181 (void) strcat(obuf, "owner"); 182 else 183 (void) strcat(obuf, a->q_user); 184 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 185 makelower(obuf); 186 owner = aliaslookup(obuf, e); 187 if (owner != NULL) 188 { 189 if (strchr(owner, ',') != NULL) 190 owner = obuf; 191 a->q_owner = newstr(owner); 192 } 193 } 194 /* 195 ** ALIASLOOKUP -- look up a name in the alias file. 196 ** 197 ** Parameters: 198 ** name -- the name to look up. 199 ** 200 ** Returns: 201 ** the value of name. 202 ** NULL if unknown. 203 ** 204 ** Side Effects: 205 ** none. 206 ** 207 ** Warnings: 208 ** The return value will be trashed across calls. 209 */ 210 211 char * 212 aliaslookup(name, e) 213 char *name; 214 ENVELOPE *e; 215 { 216 register int dbno; 217 register ALIASDB *ad; 218 register char *p; 219 220 for (dbno = 0; dbno < NAliasDBs; dbno++) 221 { 222 ad = &AliasDB[dbno]; 223 if (!bitset(ADF_VALID, ad->ad_flags)) 224 continue; 225 p = (*ad->ad_class->ac_lookup)(ad, name, e); 226 if (p != NULL) 227 return p; 228 } 229 return NULL; 230 } 231 /* 232 ** SETALIAS -- set up an alias map 233 ** 234 ** Called when reading configuration file. 235 ** 236 ** Parameters: 237 ** spec -- the alias specification 238 ** 239 ** Returns: 240 ** none. 241 */ 242 243 setalias(spec) 244 char *spec; 245 { 246 register char *p; 247 register ALIASDB *ad; 248 char *class; 249 STAB *s; 250 251 if (tTd(27, 8)) 252 printf("setalias(%s)\n", spec); 253 254 for (p = spec; p != NULL; ) 255 { 256 while (isspace(*p)) 257 p++; 258 if (*p == NULL) 259 break; 260 spec = p; 261 262 if (NAliasDBs >= MAXALIASDB) 263 { 264 syserr("Too many alias databases defined, %d max", MAXALIASDB); 265 return; 266 } 267 ad = &AliasDB[NAliasDBs]; 268 269 p = strpbrk(p, " ,/:"); 270 if (p != NULL && *p == ':') 271 { 272 /* explicit class listed */ 273 *p++ = '\0'; 274 class = spec; 275 spec = p; 276 } 277 else 278 { 279 /* implicit class */ 280 class = "implicit"; 281 } 282 283 /* find end of spec */ 284 if (p != NULL) 285 p = strchr(p, ','); 286 if (p != NULL) 287 *p++ = '\0'; 288 289 /* look up class */ 290 s = stab(class, ST_ALIASCLASS, ST_FIND); 291 if (s == NULL) 292 { 293 if (tTd(27, 1)) 294 printf("Unknown alias class %s\n", class); 295 } 296 else 297 { 298 ad->ad_class = s->s_aliasclass; 299 ad->ad_name = newstr(spec); 300 NAliasDBs++; 301 } 302 } 303 } 304 /* 305 ** INITALIASES -- initialize for aliasing 306 ** 307 ** Very different depending on whether we are running NDBM or not. 308 ** 309 ** Parameters: 310 ** rebuild -- if TRUE, this rebuilds the cached versions. 311 ** e -- current envelope. 312 ** 313 ** Returns: 314 ** none. 315 ** 316 ** Side Effects: 317 ** initializes aliases: 318 ** if NDBM: opens the database. 319 ** if ~NDBM: reads the aliases into the symbol table. 320 */ 321 322 # define DBMMODE 0644 323 324 initaliases(rebuild, e) 325 bool rebuild; 326 register ENVELOPE *e; 327 { 328 int dbno; 329 register ALIASDB *ad; 330 331 for (dbno = 0; dbno < NAliasDBs; dbno++) 332 { 333 ad = &AliasDB[dbno]; 334 335 if (tTd(27, 2)) 336 printf("initaliases(%s:%s)\n", 337 ad->ad_class->ac_name, ad->ad_name); 338 339 if (rebuild) 340 { 341 rebuildaliases(ad, FALSE, e); 342 } 343 else 344 { 345 if (ad->ad_class->ac_init(ad, e)) 346 { 347 if (tTd(27, 4)) 348 printf("%s:%s: valid\n", 349 ad->ad_class->ac_name, 350 ad->ad_name); 351 ad->ad_flags |= ADF_VALID; 352 } 353 else if (tTd(27, 4)) 354 printf("%s:%s: invalid: %s\n", 355 ad->ad_class->ac_name, ad->ad_name, 356 errstring(errno)); 357 } 358 } 359 } 360 /* 361 ** ALIASWAIT -- wait for distinguished @:@ token to appear. 362 ** 363 ** This can decide to reopen or rebuild the alias file 364 */ 365 366 aliaswait(ad, ext, e) 367 ALIASDB *ad; 368 char *ext; 369 ENVELOPE *e; 370 { 371 int atcnt; 372 time_t mtime; 373 struct stat stb; 374 char buf[MAXNAME]; 375 376 if (tTd(27, 3)) 377 printf("aliaswait\n"); 378 379 atcnt = SafeAlias * 2; 380 if (atcnt > 0) 381 { 382 while (atcnt-- >= 0 && 383 ad->ad_class->ac_lookup(ad, "@", e) == NULL) 384 { 385 /* 386 ** Close and re-open the alias database in case 387 ** the one is mv'ed instead of cp'ed in. 388 */ 389 390 if (tTd(27, 2)) 391 printf("aliaswait: sleeping\n"); 392 393 ad->ad_class->ac_close(ad, e); 394 sleep(30); 395 ad->ad_class->ac_init(ad, e); 396 } 397 } 398 399 /* see if we need to go into auto-rebuild mode */ 400 if (stat(ad->ad_name, &stb) < 0) 401 return; 402 mtime = stb.st_mtime; 403 (void) strcpy(buf, ad->ad_name); 404 (void) strcat(buf, ext); 405 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0) 406 { 407 /* database is out of date */ 408 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 409 { 410 message("auto-rebuilding alias database %s", 411 ad->ad_name); 412 rebuildaliases(ad, TRUE, e); 413 } 414 else 415 { 416 #ifdef LOG 417 if (LogLevel > 3) 418 syslog(LOG_INFO, "alias database %s out of date", 419 ad->ad_name); 420 #endif /* LOG */ 421 message("Warning: alias database %s out of date", 422 ad->ad_name); 423 } 424 } 425 } 426 /* 427 ** REBUILDALIASES -- rebuild the alias database. 428 ** 429 ** Parameters: 430 ** ad -- the database to rebuild. 431 ** automatic -- set if this was automatically generated. 432 ** e -- current envelope. 433 ** 434 ** Returns: 435 ** none. 436 ** 437 ** Side Effects: 438 ** Reads the text version of the database, builds the 439 ** DBM or DB version. 440 */ 441 442 rebuildaliases(ad, automatic, e) 443 register ALIASDB *ad; 444 bool automatic; 445 register ENVELOPE *e; 446 { 447 FILE *af; 448 void (*oldsigint)(); 449 450 if (!bitset(ACF_BUILDABLE, ad->ad_class->ac_flags)) 451 return; 452 453 #ifdef LOG 454 if (LogLevel > 7) 455 { 456 extern char *username(); 457 458 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 459 ad->ad_name, automatic ? "auto" : "", username()); 460 } 461 #endif /* LOG */ 462 463 /* try to lock the source file */ 464 if ((af = fopen(ad->ad_name, "r+")) == NULL) 465 { 466 if (tTd(27, 1)) 467 printf("Can't open %s: %s\n", 468 ad->ad_name, errstring(errno)); 469 ad->ad_flags &= ~ADF_VALID; 470 errno = 0; 471 return; 472 } 473 474 /* see if someone else is rebuilding the alias file */ 475 if (!lockfile(fileno(af), ad->ad_name, LOCK_EX|LOCK_NB)) 476 { 477 /* yes, they are -- wait until done */ 478 message("Alias file %s is already being rebuilt", 479 ad->ad_name); 480 if (OpMode != MD_INITALIAS) 481 { 482 /* wait for other rebuild to complete */ 483 (void) lockfile(fileno(af), ad->ad_name, 484 LOCK_EX); 485 } 486 (void) fclose(af); 487 errno = 0; 488 return; 489 } 490 491 oldsigint = signal(SIGINT, SIG_IGN); 492 493 ad->ad_class->ac_rebuild(ad, af, automatic, e); 494 495 /* close the file, thus releasing locks */ 496 fclose(af); 497 498 /* add distinguished entries and close the database */ 499 if (bitset(ADF_VALID, ad->ad_flags)) 500 ad->ad_class->ac_close(ad, e); 501 502 /* restore the old signal */ 503 (void) signal(SIGINT, oldsigint); 504 } 505 /* 506 ** READALIASES -- read and process the alias file. 507 ** 508 ** This routine implements the part of initaliases that occurs 509 ** when we are not going to use the DBM stuff. 510 ** 511 ** Parameters: 512 ** ad -- the alias database descriptor. 513 ** af -- file to read the aliases from. 514 ** automatic -- set if this was an automatic rebuild. 515 ** e -- the current alias file. 516 ** 517 ** Returns: 518 ** none. 519 ** 520 ** Side Effects: 521 ** Reads aliasfile into the symbol table. 522 ** Optionally, builds the .dir & .pag files. 523 */ 524 525 static 526 readaliases(ad, af, automatic, e) 527 register ALIASDB *ad; 528 FILE *af; 529 int automatic; 530 register ENVELOPE *e; 531 { 532 register char *p; 533 char *rhs; 534 bool skipping; 535 long naliases, bytes, longest; 536 ADDRESS al, bl; 537 register STAB *s; 538 char line[BUFSIZ]; 539 540 /* 541 ** Read and interpret lines 542 */ 543 544 FileName = ad->ad_name; 545 LineNumber = 0; 546 naliases = bytes = longest = 0; 547 skipping = FALSE; 548 while (fgets(line, sizeof (line), af) != NULL) 549 { 550 int lhssize, rhssize; 551 552 LineNumber++; 553 p = strchr(line, '\n'); 554 if (p != NULL) 555 *p = '\0'; 556 switch (line[0]) 557 { 558 case '#': 559 case '\0': 560 skipping = FALSE; 561 continue; 562 563 case ' ': 564 case '\t': 565 if (!skipping) 566 syserr("554 Non-continuation line starts with space"); 567 skipping = TRUE; 568 continue; 569 } 570 skipping = FALSE; 571 572 /* 573 ** Process the LHS 574 ** Find the colon separator, and parse the address. 575 ** It should resolve to a local name -- this will 576 ** be checked later (we want to optionally do 577 ** parsing of the RHS first to maximize error 578 ** detection). 579 */ 580 581 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 582 continue; 583 if (*p++ != ':') 584 { 585 syserr("554 missing colon"); 586 continue; 587 } 588 if (parseaddr(line, &al, 1, ':', NULL, e) == NULL) 589 { 590 syserr("554 illegal alias name"); 591 continue; 592 } 593 594 /* 595 ** Process the RHS. 596 ** 'al' is the internal form of the LHS address. 597 ** 'p' points to the text of the RHS. 598 */ 599 600 while (isascii(*p) && isspace(*p)) 601 p++; 602 rhs = p; 603 for (;;) 604 { 605 register char c; 606 register char *nlp; 607 608 nlp = &p[strlen(p)]; 609 if (nlp[-1] == '\n') 610 *--nlp = '\0'; 611 612 if (CheckAliases) 613 { 614 /* do parsing & compression of addresses */ 615 while (*p != '\0') 616 { 617 auto char *delimptr; 618 619 while ((isascii(*p) && isspace(*p)) || 620 *p == ',') 621 p++; 622 if (*p == '\0') 623 break; 624 if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 625 usrerr("553 %s... bad address", p); 626 p = delimptr; 627 } 628 } 629 else 630 { 631 p = nlp; 632 } 633 634 /* see if there should be a continuation line */ 635 c = fgetc(af); 636 if (!feof(af)) 637 (void) ungetc(c, af); 638 if (c != ' ' && c != '\t') 639 break; 640 641 /* read continuation line */ 642 if (fgets(p, sizeof line - (p - line), af) == NULL) 643 break; 644 LineNumber++; 645 646 /* check for line overflow */ 647 if (strchr(p, '\n') == NULL) 648 { 649 usrerr("554 alias too long"); 650 break; 651 } 652 } 653 if (al.q_mailer != LocalMailer) 654 { 655 syserr("554 cannot alias non-local names"); 656 continue; 657 } 658 659 /* 660 ** Insert alias into symbol table or DBM file 661 */ 662 663 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 664 makelower(al.q_user); 665 666 lhssize = strlen(al.q_user); 667 rhssize = strlen(rhs); 668 ad->ad_class->ac_store(ad, al.q_user, rhs, e); 669 670 if (al.q_paddr != NULL) 671 free(al.q_paddr); 672 if (al.q_host != NULL) 673 free(al.q_host); 674 if (al.q_user != NULL) 675 free(al.q_user); 676 677 /* statistics */ 678 naliases++; 679 bytes += lhssize + rhssize; 680 if (rhssize > longest) 681 longest = rhssize; 682 } 683 684 e->e_to = NULL; 685 FileName = NULL; 686 if (Verbose || !automatic) 687 message("%s: %d aliases, longest %d bytes, %d bytes total", 688 ad->ad_name, naliases, longest, bytes); 689 # ifdef LOG 690 if (LogLevel > 7) 691 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 692 ad->ad_name, naliases, longest, bytes); 693 # endif /* LOG */ 694 } 695 /* 696 ** NDBM modules 697 */ 698 699 #ifdef NDBM 700 701 /* 702 ** NDBM_ALOOKUP -- look up alias in ndbm file 703 */ 704 705 char * 706 ndbm_alookup(ad, name, e) 707 register ALIASDB *ad; 708 char *name; 709 ENVELOPE *e; 710 { 711 int i; 712 datum rhs, lhs; 713 char keybuf[MAXNAME + 1]; 714 715 if (tTd(27, 20)) 716 printf("ndbm_lookup(%s)\n", name); 717 718 /* create a key for fetch */ 719 i = strlen(name) + 1; 720 if (i > sizeof keybuf) 721 i = sizeof keybuf; 722 bcopy(name, keybuf, i); 723 if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 724 makelower(keybuf); 725 726 lhs.dsize = i; 727 lhs.dptr = keybuf; 728 rhs = dbm_fetch((DBM *) ad->ad_dbp, lhs); 729 return (rhs.dptr); 730 } 731 732 733 /* 734 ** NDBM_ASTORE -- store a datum in the database 735 */ 736 737 void 738 ndbm_astore(ad, lhs, rhs, e) 739 register ALIASDB *ad; 740 char *lhs; 741 char *rhs; 742 ENVELOPE *e; 743 { 744 datum key; 745 datum data; 746 int stat; 747 748 key.dsize = strlen(lhs) + 1; 749 key.dptr = lhs; 750 751 data.dsize = strlen(rhs) + 1; 752 data.dptr = rhs; 753 754 stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_INSERT); 755 if (stat > 0) 756 { 757 usrerr("050 Warning: duplicate alias name %s", lhs); 758 stat = dbm_store((DBM *) ad->ad_dbp, key, data, DBM_REPLACE); 759 } 760 if (stat != 0) 761 syserr("readaliases: dbm put (%s)", lhs); 762 } 763 764 765 /* 766 ** NDBM_AINIT -- initialize DBM database 767 */ 768 769 bool 770 ndbm_ainit(ad, e) 771 register ALIASDB *ad; 772 ENVELOPE *e; 773 { 774 char buf[MAXNAME]; 775 776 if (tTd(27, 2)) 777 printf("ndbm_ainit(%s)\n", ad->ad_name); 778 779 /* open the database */ 780 ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDONLY, DBMMODE); 781 if (ad->ad_dbp == NULL) 782 return FALSE; 783 784 /* wait for @:@ to appear */ 785 aliaswait(ad, ".pag", e); 786 787 return TRUE; 788 } 789 790 791 /* 792 ** NDBM_AREBUILD -- rebuild hash database 793 */ 794 795 void 796 ndbm_arebuild(ad, fp, automatic, e) 797 register ALIASDB *ad; 798 FILE *fp; 799 int automatic; 800 ENVELOPE *e; 801 { 802 register DBM *db; 803 int i; 804 char buf[MAXNAME]; 805 806 if (tTd(27, 2)) 807 printf("ndbm_arebuild(%s)\n", ad->ad_name); 808 809 db = dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 810 if (db == NULL) 811 { 812 syserr("ndbm_arebuild: cannot create %s", buf); 813 return; 814 } 815 ad->ad_dbp = (void *) db; 816 ad->ad_flags |= ADF_WRITABLE|ADF_VALID; 817 818 /* read and store the aliases */ 819 readaliases(ad, fp, automatic, e); 820 } 821 822 /* 823 ** NDBM_ACLOSE -- close the database 824 */ 825 826 void 827 ndbm_aclose(ad, e) 828 register ALIASDB *ad; 829 ENVELOPE *e; 830 { 831 if (bitset(ADF_WRITABLE, ad->ad_flags)) 832 { 833 #ifdef YPCOMPAT 834 char buf[200]; 835 836 (void) sprintf(buf, "%010ld", curtime()); 837 ndbm_astore(ad, "YP_LAST_MODIFIED", buf, e); 838 839 (void) myhostname(buf, sizeof buf); 840 ndbm_astore(ad, "YP_MASTER_NAME", buf, e); 841 #endif 842 843 /* write out the distinguished alias */ 844 ndbm_astore(ad, "@", "@", e); 845 } 846 dbm_close((DBM *) ad->ad_dbp); 847 } 848 849 #endif 850 /* 851 ** HASH (NEWDB) Modules 852 */ 853 854 #ifdef NEWDB 855 856 /* 857 ** HASH_ALOOKUP -- look up alias in hash file 858 */ 859 860 char * 861 hash_alookup(ad, name, e) 862 register ALIASDB *ad; 863 char *name; 864 ENVELOPE *e; 865 { 866 int i; 867 DBT rhs, lhs; 868 int s; 869 char keybuf[MAXNAME + 1]; 870 871 if (tTd(27, 20)) 872 printf("hash_alookup(%s)\n", name); 873 874 /* create a key for fetch */ 875 i = strlen(name) + 1; 876 if (i > sizeof keybuf) 877 i = sizeof keybuf; 878 bcopy(name, keybuf, i); 879 if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 880 makelower(keybuf); 881 882 lhs.size = i; 883 lhs.data = keybuf; 884 i = ad->ad_ndbp->get(ad->ad_ndbp, &lhs, &rhs, 0); 885 if (i == 0) 886 return (rhs.data); 887 return (NULL); 888 } 889 890 891 /* 892 ** HASH_ASTORE -- store a datum in the database 893 */ 894 895 void 896 hash_astore(ad, lhs, rhs, e) 897 register ALIASDB *ad; 898 char *lhs; 899 char *rhs; 900 ENVELOPE *e; 901 { 902 int stat; 903 DBT key; 904 DBT data; 905 906 if (tTd(27, 20)) 907 printf("hash_astore(%s, %s)\n", lhs, rhs); 908 909 key.size = strlen(lhs) + 1; 910 key.data = lhs; 911 912 data.size = strlen(rhs) + 1; 913 data.data = rhs; 914 915 stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, R_NOOVERWRITE); 916 if (stat > 0) 917 { 918 usrerr("050 Warning: duplicate alias name %s", lhs); 919 stat = ad->ad_ndbp->put(ad->ad_ndbp, &key, &data, 0); 920 } 921 if (stat != 0) 922 syserr("readaliases: db put (%s)", lhs); 923 } 924 925 926 /* 927 ** HASH_AINIT -- initialize hash database 928 */ 929 930 bool 931 hash_ainit(ad, e) 932 register ALIASDB *ad; 933 ENVELOPE *e; 934 { 935 char buf[MAXNAME]; 936 937 if (tTd(27, 2)) 938 printf("hash_ainit(%s)\n", ad->ad_name); 939 940 /* open the database */ 941 (void) strcpy(buf, ad->ad_name); 942 (void) strcat(buf, ".db"); 943 ad->ad_ndbp = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 944 if (ad->ad_ndbp == NULL) 945 return FALSE; 946 947 /* wait for @:@ to appear */ 948 aliaswait(ad, ".db", e); 949 return TRUE; 950 } 951 952 953 /* 954 ** HASH_AREBUILD -- rebuild hash database 955 */ 956 957 void 958 hash_arebuild(ad, fp, automatic, e) 959 register ALIASDB *ad; 960 FILE *fp; 961 int automatic; 962 ENVELOPE *e; 963 { 964 register DB *db; 965 char buf[MAXNAME]; 966 967 if (tTd(27, 2)) 968 printf("hash_arebuild(%s)\n", ad->ad_name); 969 970 (void) strcpy(buf, ad->ad_name); 971 (void) strcat(buf, ".db"); 972 db = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 973 if (db == NULL) 974 { 975 syserr("hash_arebuild: cannot create %s", buf); 976 return; 977 } 978 ad->ad_ndbp = db; 979 ad->ad_flags |= ADF_WRITABLE|ADF_VALID; 980 981 /* read and store the aliases */ 982 readaliases(ad, fp, automatic, e); 983 } 984 985 986 /* 987 ** HASH_ACLOSE -- add distinguished entries and close the database 988 */ 989 990 void 991 hash_aclose(ad, e) 992 ALIASDB *ad; 993 ENVELOPE *e; 994 { 995 if (tTd(27, 9)) 996 printf("hash_aclose(%x)\n", ad->ad_flags); 997 998 if (bitset(ADF_WRITABLE, ad->ad_flags)) 999 { 1000 /* write out the distinguished alias */ 1001 hash_astore(ad, "@", "@", e); 1002 } 1003 1004 if (ad->ad_ndbp->close(ad->ad_ndbp) != 0) 1005 syserr("readaliases: db close failure"); 1006 } 1007 1008 #endif 1009 /* 1010 ** STAB (Symbol Table) Modules 1011 */ 1012 1013 1014 /* 1015 ** STAB_ALOOKUP -- look up alias in symbol table 1016 */ 1017 1018 char * 1019 stab_alookup(ad, name, e) 1020 register ALIASDB *ad; 1021 char *name; 1022 ENVELOPE *e; 1023 { 1024 register STAB *s; 1025 1026 if (tTd(27, 20)) 1027 printf("stab_lookup(%s)\n", name); 1028 1029 s = stab(name, ST_ALIAS, ST_FIND); 1030 if (s != NULL) 1031 return (s->s_alias); 1032 return (NULL); 1033 } 1034 1035 1036 /* 1037 ** STAB_ASTORE -- store in symtab (actually using during init, not rebuild) 1038 */ 1039 1040 void 1041 stab_astore(ad, lhs, rhs, e) 1042 register ALIASDB *ad; 1043 char *lhs; 1044 char *rhs; 1045 ENVELOPE *e; 1046 { 1047 register STAB *s; 1048 1049 s = stab(lhs, ST_ALIAS, ST_ENTER); 1050 s->s_alias = newstr(rhs); 1051 } 1052 1053 1054 /* 1055 ** STAB_AINIT -- initialize (reads data file) 1056 */ 1057 1058 bool 1059 stab_ainit(ad, e) 1060 register ALIASDB *ad; 1061 ENVELOPE *e; 1062 { 1063 FILE *af; 1064 1065 if (tTd(27, 2)) 1066 printf("stab_ainit(%s)\n", ad->ad_name); 1067 1068 af = fopen(ad->ad_name, "r"); 1069 if (af == NULL) 1070 return FALSE; 1071 1072 readaliases(ad, af, TRUE, e); 1073 } 1074 1075 1076 /* 1077 ** STAB_AREBUILD -- rebuild alias file 1078 */ 1079 1080 void 1081 stab_arebuild(ad, fp, automatic, e) 1082 ALIASDB *ad; 1083 FILE *fp; 1084 int automatic; 1085 ENVELOPE *e; 1086 { 1087 if (tTd(27, 2)) 1088 printf("stab_arebuild(%s)\n", ad->ad_name); 1089 1090 ad->ad_flags |= ADF_WRITABLE|ADF_VALID; 1091 } 1092 1093 1094 /* 1095 ** STAB_ACLOSE -- close symbol table (???) 1096 */ 1097 1098 void 1099 stab_aclose(ad, e) 1100 ALIASDB *ad; 1101 ENVELOPE *e; 1102 { 1103 /* ignore it */ 1104 } 1105 /* 1106 ** NIS Modules 1107 */ 1108 1109 #ifdef NIS_ALIASES 1110 1111 /* 1112 ** NIS_ALOOKUP 1113 */ 1114 1115 char * 1116 nis_alookup(ad, name, e) 1117 ALIASDB *ad; 1118 char *name; 1119 ENVELOPE *e; 1120 { 1121 auto char *vp; 1122 auto int vsize; 1123 int yperr; 1124 int keylen; 1125 1126 if (tTd(27, 20)) 1127 printf("nis_lookup(%s)\n", name); 1128 1129 keylen = strlen(name); 1130 yperr = yp_match(ad->ad_domain, ad->ad_name, name, keylen, 1131 &vp, &vsize); 1132 if (yperr == YPERR_KEY) 1133 yperr = yp_match(ad->ad_domain, ad->ad_name, name, ++keylen, 1134 &vp, &vsize); 1135 if (yperr == 0) 1136 return vp; 1137 1138 if (tTd(27, 10)) 1139 printf("nis_alookup: yp_match(%s, %s, %s) => %s\n", 1140 ad->ad_domain, ad->ad_name, name, yperr_string(yperr)); 1141 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1142 ad->ad_flags &= ~ADF_VALID; 1143 return NULL; 1144 } 1145 1146 /* 1147 ** NIS_ASTORE 1148 */ 1149 1150 void 1151 nis_astore(ad, lhs, rhs, e) 1152 ALIASDB *ad; 1153 char *lhs; 1154 char *rhs; 1155 ENVELOPE *e; 1156 { 1157 /* nothing */ 1158 } 1159 1160 /* 1161 ** NIS_AINIT 1162 */ 1163 1164 bool 1165 nis_ainit(ad, e) 1166 ALIASDB *ad; 1167 ENVELOPE *e; 1168 { 1169 register char *p; 1170 int yperr; 1171 auto char *vp; 1172 auto int vsize; 1173 1174 if (tTd(27, 2)) 1175 printf("nis_ainit(%s)\n", ad->ad_name); 1176 1177 p = strchr(ad->ad_name, '@'); 1178 if (p != NULL) 1179 { 1180 *p++ = '\0'; 1181 if (*p != '\0') 1182 ad->ad_domain = p; 1183 } 1184 if (ad->ad_domain == NULL) 1185 yp_get_default_domain(&ad->ad_domain); 1186 1187 if (*ad->ad_name == '\0') 1188 ad->ad_name = "mail.aliases"; 1189 1190 yperr = yp_match(ad->ad_domain, ad->ad_name, "@", 1, 1191 &vp, &vsize); 1192 if (tTd(27, 10)) 1193 printf("nis_ainit: yp_match(%s, %s) => %s\n", 1194 ad->ad_domain, ad->ad_name, yperr_string(yperr)); 1195 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1196 return TRUE; 1197 return FALSE; 1198 } 1199 1200 /* 1201 ** NIS_AREBUILD 1202 */ 1203 1204 void 1205 nis_arebuild(ad, fp, automatic, e) 1206 ALIASDB *ad; 1207 FILE *fp; 1208 int automatic; 1209 ENVELOPE *e; 1210 { 1211 if (tTd(27, 2)) 1212 printf("nis_arebuild(%s)\n", ad->ad_name); 1213 } 1214 1215 1216 /* 1217 ** NIS_ACLOSE 1218 */ 1219 1220 void 1221 nis_aclose(ad, e) 1222 ALIASDB *ad; 1223 ENVELOPE *e; 1224 { 1225 /* nothing */ 1226 } 1227 1228 #endif /* NIS_ALIASES */ 1229 /* 1230 ** Implicit Modules 1231 ** 1232 ** Tries several types. For back compatibility. 1233 */ 1234 1235 /* 1236 ** IMPL_ALOOKUP -- lookup in best open database 1237 */ 1238 1239 char * 1240 impl_alookup(ad, name, e) 1241 ALIASDB *ad; 1242 char *name; 1243 ENVELOPE *e; 1244 { 1245 if (tTd(27, 20)) 1246 printf("impl_lookup(%s)\n", name); 1247 1248 #ifdef NEWDB 1249 if (bitset(ADF_IMPLHASH, ad->ad_flags)) 1250 return hash_alookup(ad, name, e); 1251 #endif 1252 #ifdef NDBM 1253 if (bitset(ADF_IMPLNDBM, ad->ad_flags)) 1254 return ndbm_alookup(ad, name, e); 1255 #endif 1256 return stab_alookup(ad, name, e); 1257 } 1258 1259 /* 1260 ** IMPL_ASTORE -- store in open databases 1261 */ 1262 1263 void 1264 impl_astore(ad, lhs, rhs, e) 1265 ALIASDB *ad; 1266 char *lhs; 1267 char *rhs; 1268 ENVELOPE *e; 1269 { 1270 #ifdef NEWDB 1271 if (bitset(ADF_IMPLHASH, ad->ad_flags)) 1272 hash_astore(ad, lhs, rhs, e); 1273 #endif 1274 #ifdef NDBM 1275 if (bitset(ADF_IMPLNDBM, ad->ad_flags)) 1276 ndbm_astore(ad, lhs, rhs, e); 1277 #endif 1278 stab_astore(ad, lhs, rhs, e); 1279 } 1280 1281 /* 1282 ** IMPL_AINIT -- implicit database lookup 1283 */ 1284 1285 bool 1286 impl_ainit(ad, e) 1287 ALIASDB *ad; 1288 ENVELOPE *e; 1289 { 1290 struct stat stb; 1291 1292 if (tTd(27, 2)) 1293 printf("impl_ainit(%s)\n", ad->ad_name); 1294 1295 if (stat(ad->ad_name, &stb) < 0) 1296 { 1297 /* no alias file at all */ 1298 return FALSE; 1299 } 1300 1301 #ifdef NEWDB 1302 ad->ad_flags |= ADF_IMPLHASH; 1303 if (hash_ainit(ad, e)) 1304 { 1305 return TRUE; 1306 } 1307 ad->ad_flags &= ~ADF_IMPLHASH; 1308 #endif 1309 #ifdef NDBM 1310 ad->ad_flags |= ADF_IMPLNDBM; 1311 if (ndbm_ainit(ad, e)) 1312 { 1313 return TRUE; 1314 } 1315 ad->ad_flags &= ~ADF_IMPLNDBM; 1316 #endif 1317 1318 if (Verbose) 1319 message("WARNING: cannot open alias database %s", ad->ad_name); 1320 1321 if (stab_ainit(ad, e)) 1322 { 1323 return TRUE; 1324 } 1325 1326 return FALSE; 1327 } 1328 1329 /* 1330 ** IMPL_AREBUILD -- rebuild alias database 1331 */ 1332 1333 void 1334 impl_arebuild(ad, fp, automatic, e) 1335 ALIASDB *ad; 1336 FILE *fp; 1337 int automatic; 1338 ENVELOPE *e; 1339 { 1340 #ifdef NEWDB 1341 DB *ndb; 1342 char buf[MAXNAME]; 1343 #endif 1344 1345 if (tTd(27, 2)) 1346 printf("impl_arebuild(%s)\n", ad->ad_name); 1347 1348 #ifdef NEWDB 1349 (void) strcpy(buf, ad->ad_name); 1350 (void) strcat(buf, ".db"); 1351 ndb = dbopen(buf, O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 1352 if (ndb == NULL) 1353 { 1354 syserr("rebuildaliases: cannot create %s", buf); 1355 } 1356 else 1357 { 1358 ad->ad_ndbp = ndb; 1359 ad->ad_flags |= ADF_IMPLHASH; 1360 #if defined(NDBM) && defined(YPCOMPAT) 1361 if (access("/var/yp/Makefile", R_OK) != 0) 1362 #endif 1363 goto readem; 1364 } 1365 #endif 1366 1367 #ifdef NDBM 1368 ad->ad_dbp = (void *) dbm_open(ad->ad_name, O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 1369 if (ad->ad_dbp == NULL) 1370 { 1371 syserr("rebuildaliases: cannot create %s.{pag,dir}", 1372 ad->ad_name); 1373 } 1374 else 1375 { 1376 ad->ad_flags |= ADF_IMPLNDBM; 1377 } 1378 #endif 1379 1380 if (!bitset(ADF_IMPLHASH|ADF_IMPLNDBM, ad->ad_flags)) 1381 return; 1382 1383 readem: 1384 ad->ad_flags |= ADF_WRITABLE|ADF_VALID; 1385 1386 /* read and store aliases */ 1387 readaliases(ad, fp, automatic, e); 1388 } 1389 1390 1391 /* 1392 ** IMPL_ACLOSE -- close any open database(s) 1393 */ 1394 1395 void 1396 impl_aclose(ad, e) 1397 ALIASDB *ad; 1398 ENVELOPE *e; 1399 { 1400 #ifdef NEWDB 1401 if (bitset(ADF_IMPLHASH, ad->ad_flags)) 1402 hash_aclose(ad, e); 1403 #endif 1404 1405 #ifdef NDBM 1406 if (bitset(ADF_IMPLNDBM, ad->ad_flags)) 1407 ndbm_aclose(ad, e); 1408 #endif 1409 } 1410 /* 1411 ** SETUPALIASES -- set up aliases classes 1412 */ 1413 1414 #ifdef NEWDB 1415 ALIASCLASS HashAClass = 1416 { 1417 "hash", hash_alookup, hash_astore, 1418 hash_ainit, hash_arebuild, hash_aclose, 1419 ACF_BUILDABLE 1420 }; 1421 #endif 1422 1423 #ifdef NDBM 1424 ALIASCLASS DbmAClass = 1425 { 1426 "dbm", ndbm_alookup, ndbm_astore, 1427 ndbm_ainit, ndbm_arebuild, ndbm_aclose, 1428 ACF_BUILDABLE 1429 }; 1430 #endif 1431 1432 #ifdef NIS_ALIASES 1433 ALIASCLASS NisAClass = 1434 { 1435 "nis", nis_alookup, nis_astore, 1436 nis_ainit, nis_arebuild, nis_aclose, 1437 0 1438 }; 1439 #endif 1440 1441 ALIASCLASS StabAClass = 1442 { 1443 "stab", stab_alookup, stab_astore, 1444 stab_ainit, stab_arebuild, stab_aclose, 1445 0 1446 }; 1447 1448 ALIASCLASS ImplAClass = 1449 { 1450 "implicit", impl_alookup, impl_astore, 1451 impl_ainit, impl_arebuild, impl_aclose, 1452 ACF_BUILDABLE 1453 }; 1454 1455 setupaliases() 1456 { 1457 register STAB *s; 1458 1459 #ifdef NEWDB 1460 s = stab("hash", ST_ALIASCLASS, ST_ENTER); 1461 s->s_aliasclass = &HashAClass; 1462 #endif 1463 1464 #ifdef NDBM 1465 s = stab("dbm", ST_ALIASCLASS, ST_ENTER); 1466 s->s_aliasclass = &DbmAClass; 1467 #endif 1468 1469 #ifdef NIS_ALIASES 1470 s = stab("nis", ST_ALIASCLASS, ST_ENTER); 1471 s->s_aliasclass = &NisAClass; 1472 #endif 1473 1474 #if !defined(NEWDB) && !defined(NDBM) 1475 s = stab("stab", ST_ALIASCLASS, ST_ENTER); 1476 s->s_aliasclass = &StabAClass; 1477 #endif 1478 1479 s = stab("implicit", ST_ALIASCLASS, ST_ENTER); 1480 s->s_aliasclass = &ImplAClass; 1481 } 1482 /* 1483 ** FORWARD -- Try to forward mail 1484 ** 1485 ** This is similar but not identical to aliasing. 1486 ** 1487 ** Parameters: 1488 ** user -- the name of the user who's mail we would like 1489 ** to forward to. It must have been verified -- 1490 ** i.e., the q_home field must have been filled 1491 ** in. 1492 ** sendq -- a pointer to the head of the send queue to 1493 ** put this user's aliases in. 1494 ** 1495 ** Returns: 1496 ** none. 1497 ** 1498 ** Side Effects: 1499 ** New names are added to send queues. 1500 */ 1501 1502 forward(user, sendq, e) 1503 ADDRESS *user; 1504 ADDRESS **sendq; 1505 register ENVELOPE *e; 1506 { 1507 char *pp; 1508 char *ep; 1509 1510 if (tTd(27, 1)) 1511 printf("forward(%s)\n", user->q_paddr); 1512 1513 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 1514 return; 1515 if (user->q_home == NULL) 1516 { 1517 syserr("554 forward: no home"); 1518 user->q_home = "/nosuchdirectory"; 1519 } 1520 1521 /* good address -- look for .forward file in home */ 1522 define('z', user->q_home, e); 1523 define('u', user->q_user, e); 1524 define('h', user->q_host, e); 1525 if (ForwardPath == NULL) 1526 ForwardPath = newstr("\201z/.forward"); 1527 1528 for (pp = ForwardPath; pp != NULL; pp = ep) 1529 { 1530 int err; 1531 char buf[MAXPATHLEN+1]; 1532 1533 ep = strchr(pp, ':'); 1534 if (ep != NULL) 1535 *ep = '\0'; 1536 expand(pp, buf, &buf[sizeof buf - 1], e); 1537 if (ep != NULL) 1538 *ep++ = ':'; 1539 if (tTd(27, 3)) 1540 printf("forward: trying %s\n", buf); 1541 err = include(buf, TRUE, user, sendq, e); 1542 if (err == 0) 1543 break; 1544 if (transienterror(err)) 1545 { 1546 /* we have to suspend this message */ 1547 if (tTd(27, 2)) 1548 printf("forward: transient error on %s\n", buf); 1549 #ifdef LOG 1550 if (LogLevel > 2) 1551 syslog(LOG_ERR, "%s: forward %s: transient error: %s", 1552 e->e_id, buf, errstring(err)); 1553 #endif 1554 message("%s: %s: message queued", buf, errstring(err)); 1555 user->q_flags |= QQUEUEUP|QDONTSEND; 1556 return; 1557 } 1558 } 1559 } 1560