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