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