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