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 <sys/stat.h> 11 # include <signal.h> 12 # include <pwd.h> 13 14 # ifdef DBM 15 ERROR: DBM is no longer supported -- use NDBM instead. 16 # endif 17 18 # ifdef NEWDB 19 # include <db.h> 20 # endif 21 22 # ifdef NDBM 23 # include <ndbm.h> 24 # endif 25 26 #ifndef lint 27 #ifdef NEWDB 28 #ifdef NDBM 29 static char sccsid[] = "@(#)alias.c 6.29 (Berkeley) 03/30/93 (with NEWDB and NDBM)"; 30 #else 31 static char sccsid[] = "@(#)alias.c 6.29 (Berkeley) 03/30/93 (with NEWDB)"; 32 #endif 33 #else 34 #ifdef NDBM 35 static char sccsid[] = "@(#)alias.c 6.29 (Berkeley) 03/30/93 (with NDBM)"; 36 #else 37 static char sccsid[] = "@(#)alias.c 6.29 (Berkeley) 03/30/93 (without NEWDB or NDBM)"; 38 #endif 39 #endif 40 #endif /* not lint */ 41 /* 42 ** ALIAS -- Compute aliases. 43 ** 44 ** Scans the alias file for an alias for the given address. 45 ** If found, it arranges to deliver to the alias list instead. 46 ** Uses libdbm database if -DDBM. 47 ** 48 ** Parameters: 49 ** a -- address to alias. 50 ** sendq -- a pointer to the head of the send queue 51 ** to put the aliases in. 52 ** e -- the current envelope. 53 ** 54 ** Returns: 55 ** none 56 ** 57 ** Side Effects: 58 ** Aliases found are expanded. 59 ** 60 ** Notes: 61 ** If NoAlias (the "-n" flag) is set, no aliasing is 62 ** done. 63 ** 64 ** Deficiencies: 65 ** It should complain about names that are aliased to 66 ** nothing. 67 */ 68 69 70 /* 71 ** Sun YP servers read the dbm files directly, so we have to build them 72 ** even if NEWDB 73 */ 74 75 #ifdef NDBM 76 # ifndef NEWDB 77 # define IF_MAKEDBMFILES 78 # else 79 # ifdef YPCOMPAT 80 # define IF_MAKEDBMFILES if (makedbmfiles) 81 # endif 82 # endif 83 #endif 84 85 typedef union 86 { 87 #ifdef NDBM 88 datum dbm; 89 #endif 90 #ifdef NEWDB 91 DBT dbt; 92 #endif 93 struct 94 { 95 char *data; 96 int size; 97 } xx; 98 } DBdatum; 99 100 #ifdef NEWDB 101 static DB *AliasDBptr; 102 #endif 103 #ifdef NDBM 104 static DBM *AliasDBMptr; 105 #endif 106 107 alias(a, sendq, e) 108 register ADDRESS *a; 109 ADDRESS **sendq; 110 register ENVELOPE *e; 111 { 112 register char *p; 113 int naliases; 114 char *owner; 115 char obuf[MAXNAME + 6]; 116 extern char *aliaslookup(); 117 118 if (tTd(27, 1)) 119 printf("alias(%s)\n", a->q_paddr); 120 121 /* don't realias already aliased names */ 122 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 123 return; 124 125 e->e_to = a->q_paddr; 126 127 /* 128 ** Look up this name 129 */ 130 131 if (NoAlias) 132 p = NULL; 133 else 134 p = aliaslookup(a->q_user); 135 if (p == NULL) 136 return; 137 138 /* 139 ** Match on Alias. 140 ** Deliver to the target list. 141 */ 142 143 if (tTd(27, 1)) 144 printf("%s (%s, %s) aliased to %s\n", 145 a->q_paddr, a->q_host, a->q_user, p); 146 if (bitset(EF_VRFYONLY, e->e_flags)) 147 { 148 a->q_flags |= QVERIFIED; 149 e->e_nrcpts++; 150 return; 151 } 152 message("aliased to %s", p); 153 #ifdef LOG 154 if (LogLevel > 9) 155 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 156 #endif 157 a->q_flags &= ~QSELFREF; 158 AliasLevel++; 159 naliases = sendtolist(p, a, sendq, e); 160 AliasLevel--; 161 if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 162 { 163 if (tTd(27, 5)) 164 { 165 printf("alias: QDONTSEND "); 166 printaddr(a, FALSE); 167 } 168 a->q_flags |= QDONTSEND; 169 } 170 171 /* 172 ** Look for owner of alias 173 */ 174 175 (void) strcpy(obuf, "owner-"); 176 if (strncmp(a->q_user, "owner-", 6) == 0) 177 (void) strcat(obuf, "owner"); 178 else 179 (void) strcat(obuf, a->q_user); 180 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 181 makelower(obuf); 182 owner = aliaslookup(obuf); 183 if (owner != NULL) 184 { 185 if (strchr(owner, ',') != NULL) 186 owner = obuf; 187 a->q_owner = newstr(owner); 188 } 189 } 190 /* 191 ** ALIASLOOKUP -- look up a name in the alias file. 192 ** 193 ** Parameters: 194 ** name -- the name to look up. 195 ** 196 ** Returns: 197 ** the value of name. 198 ** NULL if unknown. 199 ** 200 ** Side Effects: 201 ** none. 202 ** 203 ** Warnings: 204 ** The return value will be trashed across calls. 205 */ 206 207 char * 208 aliaslookup(name) 209 char *name; 210 { 211 int i; 212 char keybuf[MAXNAME + 1]; 213 # if defined(NEWDB) || defined(NDBM) 214 DBdatum rhs, lhs; 215 int s; 216 # else /* neither NEWDB nor NDBM */ 217 register STAB *s; 218 # endif 219 220 /* create a key for fetch */ 221 i = strlen(name) + 1; 222 if (i > sizeof keybuf) 223 i = sizeof keybuf; 224 bcopy(name, keybuf, i); 225 if (!bitnset(M_USR_UPPER, LocalMailer->m_flags)) 226 makelower(keybuf); 227 228 # if defined(NEWDB) || defined(NDBM) 229 lhs.xx.size = i; 230 lhs.xx.data = keybuf; 231 # ifdef NEWDB 232 if (AliasDBptr != NULL) 233 { 234 i = AliasDBptr->get(AliasDBptr, &lhs.dbt, &rhs.dbt, 0); 235 if (i == 0) 236 return (rhs.dbt.data); 237 } 238 # ifdef NDBM 239 else if (AliasDBMptr != NULL) 240 { 241 rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 242 return (rhs.dbm.dptr); 243 } 244 # endif /* NDBM */ 245 return (NULL); 246 # else /* not NEWDB */ 247 rhs.dbm = dbm_fetch(AliasDBMptr, lhs.dbm); 248 return (rhs.dbm.dptr); 249 # endif /* NEWDB */ 250 # else /* neither NEWDB nor NDBM */ 251 s = stab(keybuf, ST_ALIAS, ST_FIND); 252 if (s != NULL) 253 return (s->s_alias); 254 return (NULL); 255 # endif 256 } 257 /* 258 ** INITALIASES -- initialize for aliasing 259 ** 260 ** Very different depending on whether we are running NDBM or not. 261 ** 262 ** Parameters: 263 ** aliasfile -- location of aliases. 264 ** init -- if set and if NDBM, initialize the NDBM files. 265 ** 266 ** Returns: 267 ** none. 268 ** 269 ** Side Effects: 270 ** initializes aliases: 271 ** if NDBM: opens the database. 272 ** if ~NDBM: reads the aliases into the symbol table. 273 */ 274 275 # define DBMMODE 0644 276 277 initaliases(aliasfile, init, e) 278 char *aliasfile; 279 bool init; 280 register ENVELOPE *e; 281 { 282 #if defined(NDBM) || defined(NEWDB) 283 int atcnt; 284 time_t modtime; 285 bool automatic = FALSE; 286 char buf[MAXNAME]; 287 #endif 288 struct stat stb; 289 static bool initialized = FALSE; 290 static int readaliases(); 291 292 if (initialized) 293 return; 294 initialized = TRUE; 295 296 if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 297 { 298 if (aliasfile != NULL && init) 299 syserr("554 Cannot open %s", aliasfile); 300 NoAlias = TRUE; 301 errno = 0; 302 return; 303 } 304 305 # if defined(NDBM) || defined(NEWDB) 306 /* 307 ** Check to see that the alias file is complete. 308 ** If not, we will assume that someone died, and it is up 309 ** to us to rebuild it. 310 */ 311 312 if (!init) 313 { 314 # ifdef NEWDB 315 (void) strcpy(buf, aliasfile); 316 (void) strcat(buf, ".db"); 317 AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 318 if (AliasDBptr == NULL) 319 { 320 # ifdef NDBM 321 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 322 if (AliasDBMptr == NULL) 323 { 324 syserr("initaliases: cannot open %s", buf); 325 NoAlias = TRUE; 326 return; 327 } 328 # else 329 syserr("initaliases: cannot open %s", buf); 330 NoAlias = TRUE; 331 return; 332 # endif 333 } 334 # else 335 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 336 if (AliasDBMptr == NULL) 337 { 338 syserr("initaliases: cannot open DBM database %s.{pag,dir}", 339 aliasfile); 340 NoAlias = TRUE; 341 return; 342 } 343 # endif 344 } 345 atcnt = SafeAlias * 2; 346 if (atcnt > 0) 347 { 348 while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 349 { 350 /* 351 ** Reinitialize alias file in case the new 352 ** one is mv'ed in instead of cp'ed in. 353 ** 354 ** Only works with new DBM -- old one will 355 ** just consume file descriptors forever. 356 ** If you have a dbmclose() it can be 357 ** added before the sleep(30). 358 */ 359 360 # ifdef NEWDB 361 if (AliasDBptr != NULL) 362 AliasDBptr->close(AliasDBptr); 363 # endif 364 # ifdef NDBM 365 if (AliasDBMptr != NULL) 366 dbm_close(AliasDBMptr); 367 # endif 368 369 sleep(30); 370 # ifdef NEWDB 371 (void) strcpy(buf, aliasfile); 372 (void) strcat(buf, ".db"); 373 AliasDBptr = 374 dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 375 if (AliasDBptr == NULL) 376 { 377 # ifdef NDBM 378 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 379 # else 380 syserr("initaliases: cannot open %s", buf); 381 NoAlias = TRUE; 382 return; 383 # endif 384 } 385 # else 386 # ifdef NDBM 387 AliasDBMptr = dbm_open(aliasfile, O_RDONLY, DBMMODE); 388 if (AliasDBMptr == NULL) 389 { 390 syserr("initaliases: cannot open DBM database %s.{pag,dir}", 391 aliasfile); 392 NoAlias = TRUE; 393 return; 394 } 395 # endif 396 # endif 397 } 398 } 399 else 400 atcnt = 1; 401 402 /* 403 ** See if the NDBM version of the file is out of date with 404 ** the text version. If so, go into 'init' mode automatically. 405 ** This only happens if our effective userid owns the DBM. 406 ** Note the unpalatable hack to see if the stat succeeded. 407 */ 408 409 modtime = stb.st_mtime; 410 (void) strcpy(buf, aliasfile); 411 # ifdef NEWDB 412 (void) strcat(buf, ".db"); 413 # else 414 (void) strcat(buf, ".pag"); 415 # endif 416 stb.st_ino = 0; 417 if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 418 { 419 errno = 0; 420 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 421 { 422 init = TRUE; 423 automatic = TRUE; 424 message("rebuilding alias database"); 425 #ifdef LOG 426 if (LogLevel > 14) 427 syslog(LOG_INFO, "rebuilding alias database"); 428 #endif /* LOG */ 429 } 430 else 431 { 432 #ifdef LOG 433 if (LogLevel > 3) 434 syslog(LOG_INFO, "alias database out of date"); 435 #endif /* LOG */ 436 message("Warning: alias database out of date"); 437 } 438 } 439 440 441 /* 442 ** If necessary, load the NDBM file. 443 ** If running without NDBM, load the symbol table. 444 */ 445 446 if (init) 447 { 448 #ifdef LOG 449 if (LogLevel > 7) 450 { 451 extern char *username(); 452 453 syslog(LOG_NOTICE, "alias database %srebuilt by %s", 454 automatic ? "auto" : "", username()); 455 } 456 #endif /* LOG */ 457 readaliases(aliasfile, TRUE, e); 458 } 459 # else /* NDBM */ 460 readaliases(aliasfile, init, e); 461 # endif /* NDBM */ 462 } 463 /* 464 ** READALIASES -- read and process the alias file. 465 ** 466 ** This routine implements the part of initaliases that occurs 467 ** when we are not going to use the DBM stuff. 468 ** 469 ** Parameters: 470 ** aliasfile -- the pathname of the alias file master. 471 ** init -- if set, initialize the NDBM stuff. 472 ** 473 ** Returns: 474 ** none. 475 ** 476 ** Side Effects: 477 ** Reads aliasfile into the symbol table. 478 ** Optionally, builds the .dir & .pag files. 479 */ 480 481 static 482 readaliases(aliasfile, init, e) 483 char *aliasfile; 484 bool init; 485 register ENVELOPE *e; 486 { 487 register char *p; 488 char *rhs; 489 bool skipping; 490 int naliases, bytes, longest; 491 FILE *af; 492 bool makedbmfiles; 493 void (*oldsigint)(); 494 ADDRESS al, bl; 495 register STAB *s; 496 # ifdef NEWDB 497 DB *dbp; 498 # endif 499 # ifdef NDBM 500 DBM *dbmp; 501 # endif 502 char line[BUFSIZ]; 503 extern bool lockfile(); 504 505 if ((af = fopen(aliasfile, "r+")) == NULL) 506 { 507 if (init) 508 syserr("554 Can't open %s", aliasfile); 509 else if (tTd(27, 1)) 510 printf("Can't open %s\n", aliasfile); 511 errno = 0; 512 NoAlias++; 513 return; 514 } 515 516 # if defined(NDBM) || defined(NEWDB) 517 /* see if someone else is rebuilding the alias file already */ 518 if (!lockfile(fileno(af), aliasfile, LOCK_EX|LOCK_NB)) 519 { 520 /* yes, they are -- wait until done and then return */ 521 message("Alias file is already being rebuilt"); 522 if (OpMode != MD_INITALIAS) 523 { 524 /* wait for other rebuild to complete */ 525 (void) lockfile(fileno(af), aliasfile, LOCK_EX); 526 } 527 (void) fclose(af); 528 errno = 0; 529 return; 530 } 531 # endif /* NDBM */ 532 533 /* 534 ** If initializing, create the new DBM files. 535 */ 536 537 if (init) 538 { 539 oldsigint = signal(SIGINT, SIG_IGN); 540 # ifdef NEWDB 541 (void) strcpy(line, aliasfile); 542 (void) strcat(line, ".db"); 543 dbp = dbopen(line, 544 O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 545 if (dbp == NULL) 546 { 547 syserr("readaliases: cannot create %s", line); 548 (void) signal(SIGINT, oldsigint); 549 return; 550 } 551 # endif 552 # ifdef IF_MAKEDBMFILES 553 # ifdef NEWDB 554 makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 555 # endif 556 IF_MAKEDBMFILES 557 { 558 dbmp = dbm_open(aliasfile, 559 O_RDWR|O_CREAT|O_TRUNC, DBMMODE); 560 if (dbmp == NULL) 561 { 562 syserr("readaliases: cannot create %s.{dir,pag}", 563 aliasfile); 564 (void) signal(SIGINT, oldsigint); 565 return; 566 } 567 } 568 # endif 569 } 570 571 /* 572 ** Read and interpret lines 573 */ 574 575 FileName = aliasfile; 576 LineNumber = 0; 577 naliases = bytes = longest = 0; 578 skipping = FALSE; 579 while (fgets(line, sizeof (line), af) != NULL) 580 { 581 int lhssize, rhssize; 582 583 LineNumber++; 584 p = strchr(line, '\n'); 585 if (p != NULL) 586 *p = '\0'; 587 switch (line[0]) 588 { 589 case '#': 590 case '\0': 591 skipping = FALSE; 592 continue; 593 594 case ' ': 595 case '\t': 596 if (!skipping) 597 syserr("554 Non-continuation line starts with space"); 598 skipping = TRUE; 599 continue; 600 } 601 skipping = FALSE; 602 603 /* 604 ** Process the LHS 605 ** Find the colon separator, and parse the address. 606 ** It should resolve to a local name -- this will 607 ** be checked later (we want to optionally do 608 ** parsing of the RHS first to maximize error 609 ** detection). 610 */ 611 612 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 613 continue; 614 if (*p++ != ':') 615 { 616 syserr("554 missing colon"); 617 continue; 618 } 619 if (parseaddr(line, &al, 1, ':', NULL, e) == NULL) 620 { 621 syserr("554 illegal alias name"); 622 continue; 623 } 624 625 /* 626 ** Process the RHS. 627 ** 'al' is the internal form of the LHS address. 628 ** 'p' points to the text of the RHS. 629 */ 630 631 rhs = p; 632 for (;;) 633 { 634 register char c; 635 register char *nlp; 636 637 nlp = &p[strlen(p)]; 638 if (nlp[-1] == '\n') 639 *--nlp = '\0'; 640 641 if (init && CheckAliases) 642 { 643 /* do parsing & compression of addresses */ 644 while (*p != '\0') 645 { 646 auto char *delimptr; 647 648 while ((isascii(*p) && isspace(*p)) || 649 *p == ',') 650 p++; 651 if (*p == '\0') 652 break; 653 if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 654 usrerr("553 %s... bad address", p); 655 p = delimptr; 656 } 657 } 658 else 659 { 660 p = nlp; 661 } 662 663 /* see if there should be a continuation line */ 664 c = fgetc(af); 665 if (!feof(af)) 666 (void) ungetc(c, af); 667 if (c != ' ' && c != '\t') 668 break; 669 670 /* read continuation line */ 671 if (fgets(p, sizeof line - (p - line), af) == NULL) 672 break; 673 LineNumber++; 674 675 /* check for line overflow */ 676 if (strchr(p, '\n') == NULL) 677 { 678 usrerr("554 alias too long"); 679 break; 680 } 681 } 682 if (al.q_mailer != LocalMailer) 683 { 684 syserr("554 cannot alias non-local names"); 685 continue; 686 } 687 688 /* 689 ** Insert alias into symbol table or DBM file 690 */ 691 692 lhssize = strlen(al.q_user) + 1; 693 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 694 makelower(al.q_user); 695 rhssize = strlen(rhs) + 1; 696 697 # if defined(NDBM) || defined(NEWDB) 698 if (init) 699 { 700 DBdatum key, content; 701 int putstat; 702 703 key.xx.size = lhssize; 704 key.xx.data = al.q_user; 705 content.xx.size = rhssize; 706 content.xx.data = rhs; 707 # ifdef NEWDB 708 putstat = dbp->put(dbp, &key.dbt, &content.dbt, 709 R_NOOVERWRITE); 710 if (putstat > 0) 711 { 712 usrerr("050 Warning: duplicate alias name %s", 713 al.q_user); 714 putstat = dbp->put(dbp, &key.dbt, 715 &content.dbt, 0); 716 } 717 if (putstat != 0) 718 syserr("readaliases: db put (%s)", al.q_user); 719 # endif 720 # ifdef IF_MAKEDBMFILES 721 IF_MAKEDBMFILES 722 { 723 putstat = dbm_store(dbmp, key.dbm, content.dbm, 724 DBM_INSERT); 725 if (putstat > 0) 726 { 727 usrerr("050 Warning: duplicate alias name %s", 728 al.q_user); 729 putstat = dbm_store(dbmp, key.dbm, 730 content.dbm, DBM_REPLACE); 731 } 732 if (putstat != 0) 733 syserr("readaliases: dbm store (%s)", 734 al.q_user); 735 } 736 # endif 737 if (al.q_paddr != NULL) 738 free(al.q_paddr); 739 if (al.q_host != NULL) 740 free(al.q_host); 741 if (al.q_user != NULL) 742 free(al.q_user); 743 } 744 else 745 # endif /* NDBM */ 746 { 747 s = stab(al.q_user, ST_ALIAS, ST_ENTER); 748 s->s_alias = newstr(rhs); 749 } 750 751 /* statistics */ 752 naliases++; 753 bytes += lhssize + rhssize; 754 if (rhssize > longest) 755 longest = rhssize; 756 } 757 758 # if defined(NDBM) || defined(NEWDB) 759 if (init) 760 { 761 /* add the distinquished alias "@" */ 762 DBdatum key; 763 764 key.xx.size = 2; 765 key.xx.data = "@"; 766 # ifdef NEWDB 767 if (dbp->sync(dbp) != 0 || 768 dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 769 dbp->close(dbp) != 0) 770 syserr("readaliases: db close failure"); 771 # endif 772 # ifdef IF_MAKEDBMFILES 773 IF_MAKEDBMFILES 774 { 775 #ifdef YPCOMPAT 776 static void nis_magic P((DBM *dbmp)); 777 778 nis_magic(dbmp); 779 #endif 780 if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 781 dbm_error(dbmp)) 782 syserr("readaliases: dbm close failure"); 783 dbm_close(dbmp); 784 } 785 # endif 786 787 /* restore the old signal */ 788 (void) signal(SIGINT, oldsigint); 789 } 790 # endif /* NDBM */ 791 792 /* closing the alias file drops the lock */ 793 (void) fclose(af); 794 e->e_to = NULL; 795 FileName = NULL; 796 message("%d aliases, longest %d bytes, %d bytes total", 797 naliases, longest, bytes); 798 # ifdef LOG 799 if (LogLevel > 7) 800 syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 801 naliases, longest, bytes); 802 # endif /* LOG */ 803 } 804 /* 805 ** NIS_MAGIC -- Add NIS magic dbm data 806 ** 807 ** This adds the magic entries needed by SunOS to make this a valid 808 ** NIS map. 809 ** 810 ** Parameters: 811 ** dbmp -- a pointer to the DBM structure. 812 ** 813 ** Returns: 814 ** none. 815 */ 816 817 # ifdef YPCOMPAT 818 819 static void 820 nis_magic(dbmp) 821 DBM *dbmp; 822 { 823 int i; 824 static datum key[2] = 825 { 826 { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 }, 827 { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 }, 828 }; 829 datum contents[2]; 830 char tbuf[12]; 831 char hbuf[MAXHOSTNAMELEN]; 832 833 (void) sprintf(tbuf, "%010ld", curtime()); 834 contents[0].dptr = tbuf; 835 contents[0].dsize = strlen(tbuf); 836 837 (void) myhostname(hbuf, sizeof hbuf); 838 contents[1].dptr = hbuf; 839 contents[1].dsize = strlen(hbuf); 840 841 for (i = 0; i < sizeof key / sizeof *key; i++) 842 { 843 if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 || 844 dbm_error(dbmp)) 845 syserr("nis_magic: dbm_store failure"); 846 } 847 } 848 849 # endif 850 /* 851 ** FORWARD -- Try to forward mail 852 ** 853 ** This is similar but not identical to aliasing. 854 ** 855 ** Parameters: 856 ** user -- the name of the user who's mail we would like 857 ** to forward to. It must have been verified -- 858 ** i.e., the q_home field must have been filled 859 ** in. 860 ** sendq -- a pointer to the head of the send queue to 861 ** put this user's aliases in. 862 ** 863 ** Returns: 864 ** none. 865 ** 866 ** Side Effects: 867 ** New names are added to send queues. 868 */ 869 870 forward(user, sendq, e) 871 ADDRESS *user; 872 ADDRESS **sendq; 873 register ENVELOPE *e; 874 { 875 char *pp; 876 char *ep; 877 878 if (tTd(27, 1)) 879 printf("forward(%s)\n", user->q_paddr); 880 881 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 882 return; 883 if (user->q_home == NULL) 884 { 885 syserr("554 forward: no home"); 886 user->q_home = "/nosuchdirectory"; 887 } 888 889 /* good address -- look for .forward file in home */ 890 define('z', user->q_home, e); 891 define('u', user->q_user, e); 892 define('h', user->q_host, e); 893 if (ForwardPath == NULL) 894 ForwardPath = newstr("\201z/.forward"); 895 896 for (pp = ForwardPath; pp != NULL; pp = ep) 897 { 898 int err; 899 char buf[MAXPATHLEN+1]; 900 901 ep = strchr(pp, ':'); 902 if (ep != NULL) 903 *ep = '\0'; 904 expand(pp, buf, &buf[sizeof buf - 1], e); 905 if (ep != NULL) 906 *ep++ = ':'; 907 if (tTd(27, 3)) 908 printf("forward: trying %s\n", buf); 909 err = include(buf, TRUE, user, sendq, e); 910 if (err == 0) 911 break; 912 if (transienterror(err)) 913 { 914 /* we have to suspend this message */ 915 user->q_flags |= QQUEUEUP|QDONTSEND; 916 return; 917 } 918 } 919 } 920