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