1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 * Copyright (c) 1988, 1993 10 * The Regents of the University of California. All rights reserved. 11 */ 12 13 # include "sendmail.h" 14 15 #ifndef lint 16 static char sccsid[] = "@(#)alias.c 8.96 (Berkeley) 12/18/1998"; 17 #endif /* not lint */ 18 19 20 MAP *AliasFileMap = NULL; /* the actual aliases.files map */ 21 int NAliasFileMaps; /* the number of entries in AliasFileMap */ 22 /* 23 ** ALIAS -- Compute aliases. 24 ** 25 ** Scans the alias file for an alias for the given address. 26 ** If found, it arranges to deliver to the alias list instead. 27 ** Uses libdbm database if -DDBM. 28 ** 29 ** Parameters: 30 ** a -- address to alias. 31 ** sendq -- a pointer to the head of the send queue 32 ** to put the aliases in. 33 ** aliaslevel -- the current alias nesting depth. 34 ** e -- the current envelope. 35 ** 36 ** Returns: 37 ** none 38 ** 39 ** Side Effects: 40 ** Aliases found are expanded. 41 ** 42 ** Deficiencies: 43 ** It should complain about names that are aliased to 44 ** nothing. 45 */ 46 47 void 48 alias(a, sendq, aliaslevel, e) 49 register ADDRESS *a; 50 ADDRESS **sendq; 51 int aliaslevel; 52 register ENVELOPE *e; 53 { 54 register char *p; 55 char *owner; 56 auto int stat = EX_OK; 57 char obuf[MAXNAME + 7]; 58 extern char *aliaslookup __P((char *, int *, ENVELOPE *)); 59 60 if (tTd(27, 1)) 61 printf("alias(%s)\n", a->q_user); 62 63 /* don't realias already aliased names */ 64 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 65 return; 66 67 if (NoAlias) 68 return; 69 70 e->e_to = a->q_paddr; 71 72 /* 73 ** Look up this name. 74 ** 75 ** If the map was unavailable, we will queue this message 76 ** until the map becomes available; otherwise, we could 77 ** bounce messages inappropriately. 78 */ 79 80 p = aliaslookup(a->q_user, &stat, e); 81 if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE) 82 { 83 a->q_flags |= QQUEUEUP; 84 if (e->e_message == NULL) 85 e->e_message = newstr("alias database unavailable"); 86 return; 87 } 88 if (p == NULL) 89 return; 90 91 /* 92 ** Match on Alias. 93 ** Deliver to the target list. 94 */ 95 96 if (tTd(27, 1)) 97 printf("%s (%s, %s) aliased to %s\n", 98 a->q_paddr, a->q_host, a->q_user, p); 99 if (bitset(EF_VRFYONLY, e->e_flags)) 100 { 101 a->q_flags |= QVERIFIED; 102 return; 103 } 104 message("aliased to %s", shortenstring(p, MAXSHORTSTR)); 105 if (LogLevel > 9) 106 sm_syslog(LOG_INFO, e->e_id, 107 "alias %.100s => %s", 108 a->q_paddr, shortenstring(p, MAXSHORTSTR)); 109 a->q_flags &= ~QSELFREF; 110 if (tTd(27, 5)) 111 { 112 printf("alias: QDONTSEND "); 113 printaddr(a, FALSE); 114 } 115 a->q_flags |= QDONTSEND; 116 (void) sendtolist(p, a, sendq, aliaslevel + 1, e); 117 if (bitset(QSELFREF, a->q_flags)) 118 a->q_flags &= ~QDONTSEND; 119 120 /* 121 ** Look for owner of alias 122 */ 123 124 (void) strcpy(obuf, "owner-"); 125 if (strncmp(a->q_user, "owner-", 6) == 0 || 126 strlen(a->q_user) > (SIZE_T) sizeof obuf - 7) 127 (void) strcat(obuf, "owner"); 128 else 129 (void) strcat(obuf, a->q_user); 130 owner = aliaslookup(obuf, &stat, e); 131 if (owner == NULL) 132 return; 133 134 /* reflect owner into envelope sender */ 135 if (strpbrk(owner, ",:/|\"") != NULL) 136 owner = obuf; 137 a->q_owner = newstr(owner); 138 139 /* announce delivery to this alias; NORECEIPT bit set later */ 140 if (e->e_xfp != NULL) 141 fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 142 a->q_paddr); 143 e->e_flags |= EF_SENDRECEIPT; 144 a->q_flags |= QDELIVERED|QEXPANDED; 145 } 146 /* 147 ** ALIASLOOKUP -- look up a name in the alias file. 148 ** 149 ** Parameters: 150 ** name -- the name to look up. 151 ** pstat -- a pointer to a place to put the status. 152 ** e -- the current envelope. 153 ** 154 ** Returns: 155 ** the value of name. 156 ** NULL if unknown. 157 ** 158 ** Side Effects: 159 ** none. 160 ** 161 ** Warnings: 162 ** The return value will be trashed across calls. 163 */ 164 165 char * 166 aliaslookup(name, pstat, e) 167 char *name; 168 int *pstat; 169 ENVELOPE *e; 170 { 171 static MAP *map = NULL; 172 173 if (map == NULL) 174 { 175 STAB *s = stab("aliases", ST_MAP, ST_FIND); 176 177 if (s == NULL) 178 return NULL; 179 map = &s->s_map; 180 } 181 if (!bitset(MF_OPEN, map->map_mflags)) 182 return NULL; 183 184 /* special case POstMastER -- always use lower case */ 185 if (strcasecmp(name, "postmaster") == 0) 186 name = "postmaster"; 187 188 return (*map->map_class->map_lookup)(map, name, NULL, pstat); 189 } 190 /* 191 ** SETALIAS -- set up an alias map 192 ** 193 ** Called when reading configuration file. 194 ** 195 ** Parameters: 196 ** spec -- the alias specification 197 ** 198 ** Returns: 199 ** none. 200 */ 201 202 void 203 setalias(spec) 204 char *spec; 205 { 206 register char *p; 207 register MAP *map; 208 char *class; 209 STAB *s; 210 211 if (tTd(27, 8)) 212 printf("setalias(%s)\n", spec); 213 214 for (p = spec; p != NULL; ) 215 { 216 char buf[50]; 217 218 while (isascii(*p) && isspace(*p)) 219 p++; 220 if (*p == '\0') 221 break; 222 spec = p; 223 224 if (NAliasFileMaps >= MAXMAPSTACK) 225 { 226 syserr("Too many alias databases defined, %d max", 227 MAXMAPSTACK); 228 return; 229 } 230 if (AliasFileMap == NULL) 231 { 232 strcpy(buf, "aliases.files sequence"); 233 AliasFileMap = makemapentry(buf); 234 if (AliasFileMap == NULL) 235 { 236 syserr("setalias: cannot create aliases.files map"); 237 return; 238 } 239 } 240 (void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps); 241 s = stab(buf, ST_MAP, ST_ENTER); 242 map = &s->s_map; 243 bzero(map, sizeof *map); 244 map->map_mname = s->s_name; 245 246 p = strpbrk(p, " ,/:"); 247 if (p != NULL && *p == ':') 248 { 249 /* map name */ 250 *p++ = '\0'; 251 class = spec; 252 spec = p; 253 } 254 else 255 { 256 class = "implicit"; 257 map->map_mflags = MF_INCLNULL; 258 } 259 260 /* find end of spec */ 261 if (p != NULL) 262 p = strchr(p, ','); 263 if (p != NULL) 264 *p++ = '\0'; 265 266 if (tTd(27, 20)) 267 printf(" map %s:%s %s\n", class, s->s_name, spec); 268 269 /* look up class */ 270 s = stab(class, ST_MAPCLASS, ST_FIND); 271 if (s == NULL) 272 { 273 syserr("setalias: unknown alias class %s", class); 274 } 275 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 276 { 277 syserr("setalias: map class %s can't handle aliases", 278 class); 279 } 280 else 281 { 282 map->map_class = &s->s_mapclass; 283 if (map->map_class->map_parse(map, spec)) 284 { 285 map->map_mflags |= MF_VALID|MF_ALIAS; 286 AliasFileMap->map_stack[NAliasFileMaps++] = map; 287 } 288 } 289 } 290 } 291 /* 292 ** ALIASWAIT -- wait for distinguished @:@ token to appear. 293 ** 294 ** This can decide to reopen or rebuild the alias file 295 ** 296 ** Parameters: 297 ** map -- a pointer to the map descriptor for this alias file. 298 ** ext -- the filename extension (e.g., ".db") for the 299 ** database file. 300 ** isopen -- if set, the database is already open, and we 301 ** should check for validity; otherwise, we are 302 ** just checking to see if it should be created. 303 ** 304 ** Returns: 305 ** TRUE -- if the database is open when we return. 306 ** FALSE -- if the database is closed when we return. 307 */ 308 309 bool 310 aliaswait(map, ext, isopen) 311 MAP *map; 312 char *ext; 313 int isopen; 314 { 315 bool attimeout = FALSE; 316 time_t mtime; 317 struct stat stb; 318 char buf[MAXNAME + 1]; 319 320 if (tTd(27, 3)) 321 printf("aliaswait(%s:%s)\n", 322 map->map_class->map_cname, map->map_file); 323 if (bitset(MF_ALIASWAIT, map->map_mflags)) 324 return isopen; 325 map->map_mflags |= MF_ALIASWAIT; 326 327 if (SafeAlias > 0) 328 { 329 auto int st; 330 time_t toolong = curtime() + SafeAlias; 331 unsigned int sleeptime = 2; 332 333 while (isopen && 334 map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 335 { 336 if (curtime() > toolong) 337 { 338 /* we timed out */ 339 attimeout = TRUE; 340 break; 341 } 342 343 /* 344 ** Close and re-open the alias database in case 345 ** the one is mv'ed instead of cp'ed in. 346 */ 347 348 if (tTd(27, 2)) 349 printf("aliaswait: sleeping for %d seconds\n", 350 sleeptime); 351 352 map->map_class->map_close(map); 353 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 354 sleep(sleeptime); 355 sleeptime *= 2; 356 if (sleeptime > 60) 357 sleeptime = 60; 358 isopen = map->map_class->map_open(map, O_RDONLY); 359 } 360 } 361 362 /* see if we need to go into auto-rebuild mode */ 363 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 364 { 365 if (tTd(27, 3)) 366 printf("aliaswait: not rebuildable\n"); 367 map->map_mflags &= ~MF_ALIASWAIT; 368 return isopen; 369 } 370 if (stat(map->map_file, &stb) < 0) 371 { 372 if (tTd(27, 3)) 373 printf("aliaswait: no source file\n"); 374 map->map_mflags &= ~MF_ALIASWAIT; 375 return isopen; 376 } 377 mtime = stb.st_mtime; 378 snprintf(buf, sizeof buf, "%s%s", 379 map->map_file, ext == NULL ? "" : ext); 380 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 381 { 382 /* database is out of date */ 383 if (AutoRebuild && stb.st_ino != 0 && 384 (stb.st_uid == geteuid() || 385 (geteuid() == 0 && stb.st_uid == TrustedUid))) 386 { 387 bool oldSuprErrs; 388 389 message("auto-rebuilding alias database %s", buf); 390 oldSuprErrs = SuprErrs; 391 SuprErrs = TRUE; 392 if (isopen) 393 { 394 map->map_class->map_close(map); 395 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 396 } 397 (void) rebuildaliases(map, TRUE); 398 isopen = map->map_class->map_open(map, O_RDONLY); 399 SuprErrs = oldSuprErrs; 400 } 401 else 402 { 403 if (LogLevel > 3) 404 sm_syslog(LOG_INFO, NOQID, 405 "alias database %s out of date", 406 buf); 407 message("Warning: alias database %s out of date", buf); 408 } 409 } 410 map->map_mflags &= ~MF_ALIASWAIT; 411 return isopen; 412 } 413 /* 414 ** REBUILDALIASES -- rebuild the alias database. 415 ** 416 ** Parameters: 417 ** map -- the database to rebuild. 418 ** automatic -- set if this was automatically generated. 419 ** 420 ** Returns: 421 ** TRUE if successful; FALSE otherwise. 422 ** 423 ** Side Effects: 424 ** Reads the text version of the database, builds the 425 ** DBM or DB version. 426 */ 427 428 bool 429 rebuildaliases(map, automatic) 430 register MAP *map; 431 bool automatic; 432 { 433 FILE *af; 434 bool nolock = FALSE; 435 bool success = FALSE; 436 int sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; 437 sigfunc_t oldsigint, oldsigquit; 438 #ifdef SIGTSTP 439 sigfunc_t oldsigtstp; 440 #endif 441 442 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 443 return FALSE; 444 445 if (!bitset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) 446 sff |= SFF_NOWLINK; 447 if (!bitset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) 448 sff |= SFF_NOGWFILES; 449 if (!bitset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) 450 sff |= SFF_NOWWFILES; 451 452 /* try to lock the source file */ 453 if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL) 454 { 455 struct stat stb; 456 457 if ((errno != EACCES && errno != EROFS) || automatic || 458 (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL) 459 { 460 int saveerr = errno; 461 462 if (tTd(27, 1)) 463 printf("Can't open %s: %s\n", 464 map->map_file, errstring(saveerr)); 465 if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 466 message("newaliases: cannot open %s: %s", 467 map->map_file, errstring(saveerr)); 468 errno = 0; 469 return FALSE; 470 } 471 nolock = TRUE; 472 if (tTd(27, 1) || 473 fstat(fileno(af), &stb) < 0 || 474 bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode)) 475 message("warning: cannot lock %s: %s", 476 map->map_file, errstring(errno)); 477 } 478 479 /* see if someone else is rebuilding the alias file */ 480 if (!nolock && 481 !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 482 { 483 /* yes, they are -- wait until done */ 484 message("Alias file %s is locked (maybe being rebuilt)", 485 map->map_file); 486 if (OpMode != MD_INITALIAS) 487 { 488 /* wait for other rebuild to complete */ 489 (void) lockfile(fileno(af), map->map_file, NULL, 490 LOCK_EX); 491 } 492 (void) xfclose(af, "rebuildaliases1", map->map_file); 493 errno = 0; 494 return FALSE; 495 } 496 497 oldsigint = setsignal(SIGINT, SIG_IGN); 498 oldsigquit = setsignal(SIGQUIT, SIG_IGN); 499 #ifdef SIGTSTP 500 oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 501 #endif 502 503 if (map->map_class->map_open(map, O_RDWR)) 504 { 505 if (LogLevel > 7) 506 { 507 sm_syslog(LOG_NOTICE, NOQID, 508 "alias database %s %srebuilt by %s", 509 map->map_file, automatic ? "auto" : "", 510 username()); 511 } 512 map->map_mflags |= MF_OPEN|MF_WRITABLE; 513 map->map_pid = getpid(); 514 readaliases(map, af, !automatic, TRUE); 515 success = TRUE; 516 } 517 else 518 { 519 if (tTd(27, 1)) 520 printf("Can't create database for %s: %s\n", 521 map->map_file, errstring(errno)); 522 if (!automatic) 523 syserr("Cannot create database for alias file %s", 524 map->map_file); 525 } 526 527 /* close the file, thus releasing locks */ 528 xfclose(af, "rebuildaliases2", map->map_file); 529 530 /* add distinguished entries and close the database */ 531 if (bitset(MF_OPEN, map->map_mflags)) 532 { 533 map->map_class->map_close(map); 534 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 535 } 536 537 /* restore the old signals */ 538 (void) setsignal(SIGINT, oldsigint); 539 (void) setsignal(SIGQUIT, oldsigquit); 540 #ifdef SIGTSTP 541 (void) setsignal(SIGTSTP, oldsigtstp); 542 #endif 543 return success; 544 } 545 /* 546 ** READALIASES -- read and process the alias file. 547 ** 548 ** This routine implements the part of initaliases that occurs 549 ** when we are not going to use the DBM stuff. 550 ** 551 ** Parameters: 552 ** map -- the alias database descriptor. 553 ** af -- file to read the aliases from. 554 ** announcestats -- anounce statistics regarding number of 555 ** aliases, longest alias, etc. 556 ** logstats -- lot the same info. 557 ** 558 ** Returns: 559 ** none. 560 ** 561 ** Side Effects: 562 ** Reads aliasfile into the symbol table. 563 ** Optionally, builds the .dir & .pag files. 564 */ 565 566 void 567 readaliases(map, af, announcestats, logstats) 568 register MAP *map; 569 FILE *af; 570 bool announcestats; 571 bool logstats; 572 { 573 register char *p; 574 char *rhs; 575 bool skipping; 576 long naliases, bytes, longest; 577 ADDRESS al, bl; 578 char line[BUFSIZ]; 579 580 /* 581 ** Read and interpret lines 582 */ 583 584 FileName = map->map_file; 585 LineNumber = 0; 586 naliases = bytes = longest = 0; 587 skipping = FALSE; 588 while (fgets(line, sizeof (line), af) != NULL) 589 { 590 int lhssize, rhssize; 591 int c; 592 593 LineNumber++; 594 p = strchr(line, '\n'); 595 #if _FFR_BACKSLASH_IN_ALIASES 596 while (p != NULL && p > line && p[-1] == '\\') 597 { 598 p--; 599 if (fgets(p, SPACELEFT(line, p), af) == NULL) 600 break; 601 LineNumber++; 602 p = strchr(p, '\n'); 603 } 604 #endif 605 if (p != NULL) 606 *p = '\0'; 607 else if (!feof(af)) 608 { 609 syserr("554 alias line too long"); 610 611 /* flush to end of line */ 612 while ((c = getc(af)) != EOF && c != '\n') 613 continue; 614 615 /* skip any continuation lines */ 616 skipping = TRUE; 617 continue; 618 } 619 switch (line[0]) 620 { 621 case '#': 622 case '\0': 623 skipping = FALSE; 624 continue; 625 626 case ' ': 627 case '\t': 628 if (!skipping) 629 syserr("554 Non-continuation line starts with space"); 630 skipping = TRUE; 631 continue; 632 } 633 skipping = FALSE; 634 635 /* 636 ** Process the LHS 637 ** Find the colon separator, and parse the address. 638 ** It should resolve to a local name -- this will 639 ** be checked later (we want to optionally do 640 ** parsing of the RHS first to maximize error 641 ** detection). 642 */ 643 644 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 645 continue; 646 if (*p++ != ':') 647 { 648 syserr("554 missing colon"); 649 continue; 650 } 651 if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 652 { 653 syserr("554 %.40s... illegal alias name", line); 654 continue; 655 } 656 657 /* 658 ** Process the RHS. 659 ** 'al' is the internal form of the LHS address. 660 ** 'p' points to the text of the RHS. 661 */ 662 663 while (isascii(*p) && isspace(*p)) 664 p++; 665 rhs = p; 666 for (;;) 667 { 668 register char *nlp; 669 670 nlp = &p[strlen(p)]; 671 if (nlp[-1] == '\n') 672 *--nlp = '\0'; 673 674 if (CheckAliases) 675 { 676 /* do parsing & compression of addresses */ 677 while (*p != '\0') 678 { 679 auto char *delimptr; 680 681 while ((isascii(*p) && isspace(*p)) || 682 *p == ',') 683 p++; 684 if (*p == '\0') 685 break; 686 if (parseaddr(p, &bl, RF_COPYNONE, ',', 687 &delimptr, CurEnv) == NULL) 688 usrerr("553 %s... bad address", p); 689 p = delimptr; 690 } 691 } 692 else 693 { 694 p = nlp; 695 } 696 697 /* see if there should be a continuation line */ 698 c = getc(af); 699 if (!feof(af)) 700 (void) ungetc(c, af); 701 if (c != ' ' && c != '\t') 702 break; 703 704 /* read continuation line */ 705 if (fgets(p, sizeof line - (p - line), af) == NULL) 706 break; 707 LineNumber++; 708 709 /* check for line overflow */ 710 if (strchr(p, '\n') == NULL && !feof(af)) 711 { 712 usrerr("554 alias too long"); 713 while ((c = fgetc(af)) != EOF && c != '\n') 714 continue; 715 skipping = TRUE; 716 break; 717 } 718 } 719 720 if (skipping) 721 continue; 722 723 if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 724 { 725 syserr("554 %s... cannot alias non-local names", 726 al.q_paddr); 727 continue; 728 } 729 730 /* 731 ** Insert alias into symbol table or database file. 732 ** 733 ** Special case pOStmaStER -- always make it lower case. 734 */ 735 736 if (strcasecmp(al.q_user, "postmaster") == 0) 737 makelower(al.q_user); 738 739 lhssize = strlen(al.q_user); 740 rhssize = strlen(rhs); 741 map->map_class->map_store(map, al.q_user, rhs); 742 743 if (al.q_paddr != NULL) 744 free(al.q_paddr); 745 if (al.q_host != NULL) 746 free(al.q_host); 747 if (al.q_user != NULL) 748 free(al.q_user); 749 750 /* statistics */ 751 naliases++; 752 bytes += lhssize + rhssize; 753 if (rhssize > longest) 754 longest = rhssize; 755 } 756 757 CurEnv->e_to = NULL; 758 FileName = NULL; 759 if (Verbose || announcestats) 760 message("%s: %d aliases, longest %d bytes, %d bytes total", 761 map->map_file, naliases, longest, bytes); 762 if (LogLevel > 7 && logstats) 763 sm_syslog(LOG_INFO, NOQID, 764 "%s: %d aliases, longest %d bytes, %d bytes total", 765 map->map_file, naliases, longest, bytes); 766 } 767 /* 768 ** FORWARD -- Try to forward mail 769 ** 770 ** This is similar but not identical to aliasing. 771 ** 772 ** Parameters: 773 ** user -- the name of the user who's mail we would like 774 ** to forward to. It must have been verified -- 775 ** i.e., the q_home field must have been filled 776 ** in. 777 ** sendq -- a pointer to the head of the send queue to 778 ** put this user's aliases in. 779 ** aliaslevel -- the current alias nesting depth. 780 ** e -- the current envelope. 781 ** 782 ** Returns: 783 ** none. 784 ** 785 ** Side Effects: 786 ** New names are added to send queues. 787 */ 788 789 void 790 forward(user, sendq, aliaslevel, e) 791 ADDRESS *user; 792 ADDRESS **sendq; 793 int aliaslevel; 794 register ENVELOPE *e; 795 { 796 char *pp; 797 char *ep; 798 bool got_transient; 799 800 if (tTd(27, 1)) 801 printf("forward(%s)\n", user->q_paddr); 802 803 if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 804 bitset(QBADADDR, user->q_flags)) 805 return; 806 if (user->q_home == NULL) 807 { 808 syserr("554 forward: no home"); 809 user->q_home = "/no/such/directory"; 810 } 811 812 /* good address -- look for .forward file in home */ 813 define('z', user->q_home, e); 814 define('u', user->q_user, e); 815 define('h', user->q_host, e); 816 if (ForwardPath == NULL) 817 ForwardPath = newstr("\201z/.forward"); 818 819 got_transient = FALSE; 820 for (pp = ForwardPath; pp != NULL; pp = ep) 821 { 822 int err; 823 char buf[MAXPATHLEN+1]; 824 825 ep = strchr(pp, ':'); 826 if (ep != NULL) 827 *ep = '\0'; 828 expand(pp, buf, sizeof buf, e); 829 if (ep != NULL) 830 *ep++ = ':'; 831 if (buf[0] == '\0') 832 continue; 833 if (tTd(27, 3)) 834 printf("forward: trying %s\n", buf); 835 836 err = include(buf, TRUE, user, sendq, aliaslevel, e); 837 if (err == 0) 838 break; 839 else if (transienterror(err)) 840 { 841 /* we may have to suspend this message */ 842 got_transient = TRUE; 843 if (tTd(27, 2)) 844 printf("forward: transient error on %s\n", buf); 845 if (LogLevel > 2) 846 sm_syslog(LOG_ERR, e->e_id, 847 "forward %s: transient error: %s", 848 buf, errstring(err)); 849 } 850 else 851 { 852 switch (err) 853 { 854 case ENOENT: 855 break; 856 857 #if _FFR_FORWARD_SYSERR 858 case E_SM_NOSLINK: 859 case E_SM_NOHLINK: 860 case E_SM_REGONLY: 861 case E_SM_ISEXEC: 862 case E_SM_WWDIR: 863 case E_SM_GWDIR: 864 case E_SM_WWFILE: 865 case E_SM_GWFILE: 866 syserr("forward: %s: %s", buf, errstring(err)); 867 break; 868 #endif 869 870 default: 871 if (LogLevel > (RunAsUid == 0 ? 2 : 10)) 872 sm_syslog(LOG_WARNING, e->e_id, 873 "forward %s: %s", buf, 874 errstring(err)); 875 if (Verbose) 876 message("forward: %s: %s", 877 buf, 878 errstring(err)); 879 break; 880 } 881 } 882 } 883 if (pp == NULL && got_transient) 884 { 885 /* 886 ** There was no successful .forward open and at least one 887 ** transient open. We have to defer this address for 888 ** further delivery. 889 */ 890 891 message("transient .forward open error: message queued"); 892 user->q_flags |= QQUEUEUP; 893 return; 894 } 895 } 896