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