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.22 (Berkeley) 03/07/93 (with NEWDB and NDBM)"; 32 #else 33 static char sccsid[] = "@(#)alias.c 6.22 (Berkeley) 03/07/93 (with NEWDB)"; 34 #endif 35 #else 36 #ifdef NDBM 37 static char sccsid[] = "@(#)alias.c 6.22 (Berkeley) 03/07/93 (with NDBM)"; 38 #else 39 static char sccsid[] = "@(#)alias.c 6.22 (Berkeley) 03/07/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 650 if (init && CheckAliases) 651 { 652 /* do parsing & compression of addresses */ 653 while (*p != '\0') 654 { 655 auto char *delimptr; 656 657 while ((isascii(*p) && isspace(*p)) || 658 *p == ',') 659 p++; 660 if (*p == '\0') 661 break; 662 if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 663 usrerr("553 %s... bad address", p); 664 p = delimptr; 665 } 666 } 667 else 668 { 669 p = &p[strlen(p)]; 670 if (p[-1] == '\n') 671 *--p = '\0'; 672 } 673 674 /* see if there should be a continuation line */ 675 c = fgetc(af); 676 if (!feof(af)) 677 (void) ungetc(c, af); 678 if (c != ' ' && c != '\t') 679 break; 680 681 /* read continuation line */ 682 if (fgets(p, sizeof line - (p - line), af) == NULL) 683 break; 684 LineNumber++; 685 686 /* check for line overflow */ 687 if (strchr(p, '\n') == NULL) 688 { 689 usrerr("554 alias too long"); 690 break; 691 } 692 } 693 if (al.q_mailer != LocalMailer) 694 { 695 syserr("554 cannot alias non-local names"); 696 continue; 697 } 698 699 /* 700 ** Insert alias into symbol table or DBM file 701 */ 702 703 lhssize = strlen(al.q_user) + 1; 704 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 705 makelower(al.q_user); 706 rhssize = strlen(rhs) + 1; 707 708 # if defined(NDBM) || defined(NEWDB) 709 if (init) 710 { 711 DBdatum key, content; 712 int putstat; 713 714 key.xx.size = lhssize; 715 key.xx.data = al.q_user; 716 content.xx.size = rhssize; 717 content.xx.data = rhs; 718 # ifdef NEWDB 719 putstat = dbp->put(dbp, &key.dbt, &content.dbt, 720 R_NOOVERWRITE); 721 if (putstat > 0) 722 { 723 usrerr("050 Warning: duplicate alias name %s", 724 al.q_user); 725 putstat = dbp->put(dbp, &key.dbt, 726 &content.dbt, 0); 727 } 728 if (putstat != 0) 729 syserr("readaliases: db put (%s)", al.q_user); 730 # endif 731 # ifdef IF_MAKEDBMFILES 732 IF_MAKEDBMFILES 733 { 734 putstat = dbm_store(dbmp, key.dbm, content.dbm, 735 DBM_INSERT); 736 if (putstat > 0) 737 { 738 usrerr("050 Warning: duplicate alias name %s", 739 al.q_user); 740 putstat = dbm_store(dbmp, key.dbm, 741 content.dbm, DBM_REPLACE); 742 } 743 if (putstat != 0) 744 syserr("readaliases: dbm store (%s)", 745 al.q_user); 746 } 747 # endif 748 if (al.q_paddr != NULL) 749 free(al.q_paddr); 750 if (al.q_host != NULL) 751 free(al.q_host); 752 if (al.q_user != NULL) 753 free(al.q_user); 754 } 755 else 756 # endif /* NDBM */ 757 { 758 s = stab(al.q_user, ST_ALIAS, ST_ENTER); 759 s->s_alias = newstr(rhs); 760 } 761 762 /* statistics */ 763 naliases++; 764 bytes += lhssize + rhssize; 765 if (rhssize > longest) 766 longest = rhssize; 767 } 768 769 # if defined(NDBM) || defined(NEWDB) 770 if (init) 771 { 772 /* add the distinquished alias "@" */ 773 DBdatum key; 774 775 key.xx.size = 2; 776 key.xx.data = "@"; 777 # ifdef NEWDB 778 if (dbp->sync(dbp) != 0 || 779 dbp->put(dbp, &key.dbt, &key.dbt, 0) != 0 || 780 dbp->close(dbp) != 0) 781 syserr("readaliases: db close failure"); 782 # endif 783 # ifdef IF_MAKEDBMFILES 784 IF_MAKEDBMFILES 785 { 786 #ifdef YPCOMPAT 787 nis_magic(dbmp); 788 #endif 789 if (dbm_store(dbmp, key.dbm, key.dbm, DBM_REPLACE) != 0 || 790 dbm_error(dbmp)) 791 syserr("readaliases: dbm close failure"); 792 dbm_close(dbmp); 793 } 794 # endif 795 796 /* restore the old signal */ 797 (void) signal(SIGINT, oldsigint); 798 } 799 # endif /* NDBM */ 800 801 /* closing the alias file drops the lock */ 802 (void) fclose(af); 803 e->e_to = NULL; 804 FileName = NULL; 805 message("%d aliases, longest %d bytes, %d bytes total", 806 naliases, longest, bytes); 807 # ifdef LOG 808 if (LogLevel > 7) 809 syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 810 naliases, longest, bytes); 811 # endif /* LOG */ 812 } 813 /* 814 ** NIS_MAGIC -- Add NIS magic dbm data 815 ** 816 ** This adds the magic entries needed by SunOS to make this a valid 817 ** NIS map. 818 ** 819 ** Parameters: 820 ** dbmp -- a pointer to the DBM structure. 821 ** 822 ** Returns: 823 ** none. 824 */ 825 826 # ifdef YPCOMPAT 827 828 static void 829 nis_magic(dbmp) 830 DBM *dbmp; 831 { 832 int i; 833 static datum key[2] = 834 { 835 { "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 }, 836 { "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 }, 837 }; 838 datum contents[2]; 839 char tbuf[12]; 840 char hbuf[MAXHOSTNAMELEN]; 841 842 (void) sprintf(tbuf, "%010ld", curtime()); 843 contents[0].dptr = tbuf; 844 contents[0].dsize = strlen(tbuf); 845 846 (void) myhostname(hbuf, sizeof hbuf); 847 contents[1].dptr = hbuf; 848 contents[1].dptr = strlen(hbuf); 849 850 for (i = 0; i < sizeof key / sizeof *key; i++) 851 { 852 if (dbm_store(dbmp, key[i], contents[i], DBM_REPLACE) != 0 || 853 dbm_error(dbmp)) 854 syserr("nis_magic: dbm_store failure"); 855 } 856 } 857 858 # endif 859 /* 860 ** FORWARD -- Try to forward mail 861 ** 862 ** This is similar but not identical to aliasing. 863 ** 864 ** Parameters: 865 ** user -- the name of the user who's mail we would like 866 ** to forward to. It must have been verified -- 867 ** i.e., the q_home field must have been filled 868 ** in. 869 ** sendq -- a pointer to the head of the send queue to 870 ** put this user's aliases in. 871 ** 872 ** Returns: 873 ** none. 874 ** 875 ** Side Effects: 876 ** New names are added to send queues. 877 */ 878 879 forward(user, sendq, e) 880 ADDRESS *user; 881 ADDRESS **sendq; 882 register ENVELOPE *e; 883 { 884 char *pp; 885 char *ep; 886 887 if (tTd(27, 1)) 888 printf("forward(%s)\n", user->q_paddr); 889 890 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 891 return; 892 if (user->q_home == NULL) 893 { 894 syserr("554 forward: no home"); 895 user->q_home = "/nosuchdirectory"; 896 } 897 898 /* good address -- look for .forward file in home */ 899 define('z', user->q_home, e); 900 define('u', user->q_user, e); 901 define('h', user->q_host, e); 902 if (ForwardPath == NULL) 903 ForwardPath = newstr("\201z/.forward"); 904 905 for (pp = ForwardPath; pp != NULL; pp = ep) 906 { 907 int err; 908 char buf[MAXPATHLEN+1]; 909 910 ep = strchr(pp, ':'); 911 if (ep != NULL) 912 *ep = '\0'; 913 expand(pp, buf, &buf[sizeof buf - 1], e); 914 if (ep != NULL) 915 *ep++ = ':'; 916 if (tTd(27, 3)) 917 printf("forward: trying %s\n", buf); 918 err = include(buf, TRUE, user, sendq, e); 919 if (err == 0) 920 break; 921 if (transienterror(err)) 922 { 923 /* we have to suspend this message */ 924 user->q_flags |= QQUEUEUP|QDONTSEND; 925 return; 926 } 927 } 928 } 929