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