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