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 13 # ifdef DBM 14 ERROR: DBM is no longer supported -- use NDBM instead. 15 # endif 16 17 # ifdef NEWDB 18 # include <db.h> 19 # endif 20 21 # ifdef NDBM 22 # include <ndbm.h> 23 # endif 24 25 #ifndef lint 26 #ifdef NEWDB 27 #ifdef NDBM 28 static char sccsid[] = "@(#)alias.c 6.33 (Berkeley) 04/27/93 (with NEWDB and NDBM)"; 29 #else 30 static char sccsid[] = "@(#)alias.c 6.33 (Berkeley) 04/27/93 (with NEWDB)"; 31 #endif 32 #else 33 #ifdef NDBM 34 static char sccsid[] = "@(#)alias.c 6.33 (Berkeley) 04/27/93 (with NDBM)"; 35 #else 36 static char sccsid[] = "@(#)alias.c 6.33 (Berkeley) 04/27/93 (without NEWDB or NDBM)"; 37 #endif 38 #endif 39 #endif /* not lint */ 40 /* 41 ** ALIAS -- Compute aliases. 42 ** 43 ** Scans the alias file for an alias for the given address. 44 ** If found, it arranges to deliver to the alias list instead. 45 ** Uses libdbm database if -DDBM. 46 ** 47 ** Parameters: 48 ** a -- address to alias. 49 ** sendq -- a pointer to the head of the send queue 50 ** to put the aliases in. 51 ** e -- the current envelope. 52 ** 53 ** Returns: 54 ** none 55 ** 56 ** Side Effects: 57 ** Aliases found are expanded. 58 ** 59 ** Notes: 60 ** If NoAlias (the "-n" flag) is set, no aliasing is 61 ** done. 62 ** 63 ** Deficiencies: 64 ** It should complain about names that are aliased to 65 ** nothing. 66 */ 67 68 69 /* 70 ** Sun YP servers read the dbm files directly, so we have to build them 71 ** even if NEWDB 72 */ 73 74 #ifdef NDBM 75 # ifndef NEWDB 76 # define IF_MAKEDBMFILES 77 # else 78 # ifdef YPCOMPAT 79 # define IF_MAKEDBMFILES if (makedbmfiles) 80 # endif 81 # endif 82 #endif 83 84 typedef union 85 { 86 #ifdef NDBM 87 datum dbm; 88 #endif 89 #ifdef NEWDB 90 DBT dbt; 91 #endif 92 struct 93 { 94 char *data; 95 int size; 96 } xx; 97 } DBdatum; 98 99 #ifdef NEWDB 100 static DB *AliasDBptr; 101 #endif 102 #ifdef NDBM 103 static DBM *AliasDBMptr; 104 #endif 105 106 alias(a, sendq, e) 107 register ADDRESS *a; 108 ADDRESS **sendq; 109 register ENVELOPE *e; 110 { 111 register char *p; 112 int naliases; 113 char *owner; 114 char obuf[MAXNAME + 6]; 115 extern char *aliaslookup(); 116 117 if (tTd(27, 1)) 118 printf("alias(%s)\n", a->q_paddr); 119 120 /* don't realias already aliased names */ 121 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 122 return; 123 124 e->e_to = a->q_paddr; 125 126 /* 127 ** Look up this name 128 */ 129 130 if (NoAlias) 131 p = NULL; 132 else 133 p = aliaslookup(a->q_user); 134 if (p == NULL) 135 return; 136 137 /* 138 ** Match on Alias. 139 ** Deliver to the target list. 140 */ 141 142 if (tTd(27, 1)) 143 printf("%s (%s, %s) aliased to %s\n", 144 a->q_paddr, a->q_host, a->q_user, p); 145 if (bitset(EF_VRFYONLY, e->e_flags)) 146 { 147 a->q_flags |= QVERIFIED; 148 e->e_nrcpts++; 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("WARNING: initaliases: cannot open %s", buf); 324 NoAlias = TRUE; 325 return; 326 } 327 # else 328 syserr("WARNING: 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("WARNING: 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("WARNING: 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("WARNING: 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 while (isascii(*p) && isspace(*p)) 631 p++; 632 rhs = p; 633 for (;;) 634 { 635 register char c; 636 register char *nlp; 637 638 nlp = &p[strlen(p)]; 639 if (nlp[-1] == '\n') 640 *--nlp = '\0'; 641 642 if (init && CheckAliases) 643 { 644 /* do parsing & compression of addresses */ 645 while (*p != '\0') 646 { 647 auto char *delimptr; 648 649 while ((isascii(*p) && isspace(*p)) || 650 *p == ',') 651 p++; 652 if (*p == '\0') 653 break; 654 if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 655 usrerr("553 %s... bad address", p); 656 p = delimptr; 657 } 658 } 659 else 660 { 661 p = nlp; 662 } 663 664 /* see if there should be a continuation line */ 665 c = fgetc(af); 666 if (!feof(af)) 667 (void) ungetc(c, af); 668 if (c != ' ' && c != '\t') 669 break; 670 671 /* read continuation line */ 672 if (fgets(p, sizeof line - (p - line), af) == NULL) 673 break; 674 LineNumber++; 675 676 /* check for line overflow */ 677 if (strchr(p, '\n') == NULL) 678 { 679 usrerr("554 alias too long"); 680 break; 681 } 682 } 683 if (al.q_mailer != LocalMailer) 684 { 685 syserr("554 cannot alias non-local names"); 686 continue; 687 } 688 689 /* 690 ** Insert alias into symbol table or DBM file 691 */ 692 693 lhssize = strlen(al.q_user) + 1; 694 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 695 makelower(al.q_user); 696 rhssize = strlen(rhs) + 1; 697 698 # if defined(NDBM) || defined(NEWDB) 699 if (init) 700 { 701 DBdatum key, content; 702 int putstat; 703 704 key.xx.size = lhssize; 705 key.xx.data = al.q_user; 706 content.xx.size = rhssize; 707 content.xx.data = rhs; 708 # ifdef NEWDB 709 putstat = dbp->put(dbp, &key.dbt, &content.dbt, 710 R_NOOVERWRITE); 711 if (putstat > 0) 712 { 713 usrerr("050 Warning: duplicate alias name %s", 714 al.q_user); 715 putstat = dbp->put(dbp, &key.dbt, 716 &content.dbt, 0); 717 } 718 if (putstat != 0) 719 syserr("readaliases: db put (%s)", al.q_user); 720 # endif 721 # ifdef IF_MAKEDBMFILES 722 IF_MAKEDBMFILES 723 { 724 putstat = dbm_store(dbmp, key.dbm, content.dbm, 725 DBM_INSERT); 726 if (putstat > 0) 727 { 728 usrerr("050 Warning: duplicate alias name %s", 729 al.q_user); 730 putstat = dbm_store(dbmp, key.dbm, 731 content.dbm, DBM_REPLACE); 732 } 733 if (putstat != 0) 734 syserr("readaliases: dbm store (%s)", 735 al.q_user); 736 } 737 # endif 738 if (al.q_paddr != NULL) 739 free(al.q_paddr); 740 if (al.q_host != NULL) 741 free(al.q_host); 742 if (al.q_user != NULL) 743 free(al.q_user); 744 } 745 else 746 # endif /* NDBM */ 747 { 748 s = stab(al.q_user, ST_ALIAS, ST_ENTER); 749 s->s_alias = newstr(rhs); 750 } 751 752 /* statistics */ 753 naliases++; 754 bytes += lhssize + rhssize; 755 if (rhssize > longest) 756 longest = rhssize; 757 } 758 759 # if defined(NDBM) || defined(NEWDB) 760 if (init) 761 { 762 /* add the distinquished alias "@" */ 763 DBdatum key; 764 765 key.xx.size = 2; 766 key.xx.data = "@"; 767 # ifdef NEWDB 768 if (dbp->sync(dbp) != 0 || 769 dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 770 dbp->close(dbp) != 0) 771 syserr("readaliases: db close failure"); 772 # endif 773 # ifdef IF_MAKEDBMFILES 774 IF_MAKEDBMFILES 775 { 776 #ifdef YPCOMPAT 777 static void nis_magic __P((DBM *dbmp)); 778 779 nis_magic(dbmp); 780 #endif 781 if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 782 dbm_error(dbmp)) 783 syserr("readaliases: dbm close failure"); 784 dbm_close(dbmp); 785 } 786 # endif 787 788 /* restore the old signal */ 789 (void) signal(SIGINT, oldsigint); 790 } 791 # endif /* NDBM */ 792 793 /* closing the alias file drops the lock */ 794 (void) fclose(af); 795 e->e_to = NULL; 796 FileName = NULL; 797 message("%d aliases, longest %d bytes, %d bytes total", 798 naliases, longest, bytes); 799 # ifdef LOG 800 if (LogLevel > 7) 801 syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 802 naliases, longest, bytes); 803 # endif /* LOG */ 804 } 805 /* 806 ** NIS_MAGIC -- Add NIS magic dbm data 807 ** 808 ** This adds the magic entries needed by SunOS to make this a valid 809 ** NIS map. 810 ** 811 ** Parameters: 812 ** dbmp -- a pointer to the DBM structure. 813 ** 814 ** Returns: 815 ** none. 816 */ 817 818 # ifdef YPCOMPAT 819 820 static void 821 nis_magic(dbmp) 822 DBM *dbmp; 823 { 824 int i; 825 static datum key[2] = 826 { 827 { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 }, 828 { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 }, 829 }; 830 datum contents[2]; 831 char tbuf[12]; 832 char hbuf[MAXHOSTNAMELEN]; 833 834 (void) sprintf(tbuf, "%010ld", curtime()); 835 contents[0].dptr = tbuf; 836 contents[0].dsize = strlen(tbuf); 837 838 (void) myhostname(hbuf, sizeof hbuf); 839 contents[1].dptr = hbuf; 840 contents[1].dsize = strlen(hbuf); 841 842 for (i = 0; i < sizeof key / sizeof *key; i++) 843 { 844 if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 || 845 dbm_error(dbmp)) 846 syserr("nis_magic: dbm_store failure"); 847 } 848 } 849 850 # endif 851 /* 852 ** FORWARD -- Try to forward mail 853 ** 854 ** This is similar but not identical to aliasing. 855 ** 856 ** Parameters: 857 ** user -- the name of the user who's mail we would like 858 ** to forward to. It must have been verified -- 859 ** i.e., the q_home field must have been filled 860 ** in. 861 ** sendq -- a pointer to the head of the send queue to 862 ** put this user's aliases in. 863 ** 864 ** Returns: 865 ** none. 866 ** 867 ** Side Effects: 868 ** New names are added to send queues. 869 */ 870 871 forward(user, sendq, e) 872 ADDRESS *user; 873 ADDRESS **sendq; 874 register ENVELOPE *e; 875 { 876 char *pp; 877 char *ep; 878 879 if (tTd(27, 1)) 880 printf("forward(%s)\n", user->q_paddr); 881 882 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 883 return; 884 if (user->q_home == NULL) 885 { 886 syserr("554 forward: no home"); 887 user->q_home = "/nosuchdirectory"; 888 } 889 890 /* good address -- look for .forward file in home */ 891 define('z', user->q_home, e); 892 define('u', user->q_user, e); 893 define('h', user->q_host, e); 894 if (ForwardPath == NULL) 895 ForwardPath = newstr("\201z/.forward"); 896 897 for (pp = ForwardPath; pp != NULL; pp = ep) 898 { 899 int err; 900 char buf[MAXPATHLEN+1]; 901 902 ep = strchr(pp, ':'); 903 if (ep != NULL) 904 *ep = '\0'; 905 expand(pp, buf, &buf[sizeof buf - 1], e); 906 if (ep != NULL) 907 *ep++ = ':'; 908 if (tTd(27, 3)) 909 printf("forward: trying %s\n", buf); 910 err = include(buf, TRUE, user, sendq, e); 911 if (err == 0) 912 break; 913 if (transienterror(err)) 914 { 915 /* we have to suspend this message */ 916 user->q_flags |= QQUEUEUP|QDONTSEND; 917 return; 918 } 919 } 920 } 921