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