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