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.31 (Berkeley) 11/22/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 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 message("auto-rebuilding alias database %s", buf); 377 if (isopen) 378 map->map_class->map_close(map); 379 rebuildaliases(map, TRUE); 380 isopen = map->map_class->map_open(map, O_RDONLY); 381 } 382 else 383 { 384 #ifdef LOG 385 if (LogLevel > 3) 386 syslog(LOG_INFO, "alias database %s out of date", 387 buf); 388 #endif /* LOG */ 389 message("Warning: alias database %s out of date", buf); 390 } 391 } 392 map->map_mflags &= ~MF_ALIASWAIT; 393 return isopen; 394 } 395 /* 396 ** REBUILDALIASES -- rebuild the alias database. 397 ** 398 ** Parameters: 399 ** map -- the database to rebuild. 400 ** automatic -- set if this was automatically generated. 401 ** 402 ** Returns: 403 ** none. 404 ** 405 ** Side Effects: 406 ** Reads the text version of the database, builds the 407 ** DBM or DB version. 408 */ 409 410 rebuildaliases(map, automatic) 411 register MAP *map; 412 bool automatic; 413 { 414 FILE *af; 415 bool nolock = FALSE; 416 sigfunc_t oldsigint, oldsigquit; 417 #ifdef SIGTSTP 418 sigfunc_t oldsigtstp; 419 #endif 420 421 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 422 return; 423 424 /* try to lock the source file */ 425 if ((af = fopen(map->map_file, "r+")) == NULL) 426 { 427 if ((errno != EACCES && errno != EROFS) || automatic || 428 (af = fopen(map->map_file, "r")) == NULL) 429 { 430 int saveerr = errno; 431 432 if (tTd(27, 1)) 433 printf("Can't open %s: %s\n", 434 map->map_file, errstring(saveerr)); 435 if (!automatic) 436 message("newaliases: cannot open %s: %s", 437 map->map_file, errstring(saveerr)); 438 errno = 0; 439 return; 440 } 441 nolock = TRUE; 442 message("warning: cannot lock %s: %s", 443 map->map_file, errstring(errno)); 444 } 445 446 /* see if someone else is rebuilding the alias file */ 447 if (!nolock && 448 !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 449 { 450 /* yes, they are -- wait until done */ 451 message("Alias file %s is already being rebuilt", 452 map->map_file); 453 if (OpMode != MD_INITALIAS) 454 { 455 /* wait for other rebuild to complete */ 456 (void) lockfile(fileno(af), map->map_file, NULL, 457 LOCK_EX); 458 } 459 (void) xfclose(af, "rebuildaliases1", map->map_file); 460 errno = 0; 461 return; 462 } 463 464 /* avoid denial-of-service attacks */ 465 resetlimits(); 466 oldsigint = setsignal(SIGINT, SIG_IGN); 467 oldsigquit = setsignal(SIGQUIT, SIG_IGN); 468 #ifdef SIGTSTP 469 oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 470 #endif 471 472 if (map->map_class->map_open(map, O_RDWR)) 473 { 474 #ifdef LOG 475 if (LogLevel > 7) 476 { 477 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 478 map->map_file, automatic ? "auto" : "", 479 username()); 480 } 481 #endif /* LOG */ 482 map->map_mflags |= MF_OPEN|MF_WRITABLE; 483 readaliases(map, af, !automatic, TRUE); 484 } 485 else 486 { 487 if (tTd(27, 1)) 488 printf("Can't create database for %s: %s\n", 489 map->map_file, errstring(errno)); 490 if (!automatic) 491 syserr("Cannot create database for alias file %s", 492 map->map_file); 493 } 494 495 /* close the file, thus releasing locks */ 496 xfclose(af, "rebuildaliases2", map->map_file); 497 498 /* add distinguished entries and close the database */ 499 if (bitset(MF_OPEN, map->map_mflags)) 500 map->map_class->map_close(map); 501 502 /* restore the old signals */ 503 (void) setsignal(SIGINT, oldsigint); 504 (void) setsignal(SIGQUIT, oldsigquit); 505 #ifdef SIGTSTP 506 (void) setsignal(SIGTSTP, oldsigtstp); 507 #endif 508 } 509 /* 510 ** READALIASES -- read and process the alias file. 511 ** 512 ** This routine implements the part of initaliases that occurs 513 ** when we are not going to use the DBM stuff. 514 ** 515 ** Parameters: 516 ** map -- the alias database descriptor. 517 ** af -- file to read the aliases from. 518 ** announcestats -- anounce statistics regarding number of 519 ** aliases, longest alias, etc. 520 ** logstats -- lot the same info. 521 ** 522 ** Returns: 523 ** none. 524 ** 525 ** Side Effects: 526 ** Reads aliasfile into the symbol table. 527 ** Optionally, builds the .dir & .pag files. 528 */ 529 530 readaliases(map, af, announcestats, logstats) 531 register MAP *map; 532 FILE *af; 533 bool announcestats; 534 bool logstats; 535 { 536 register char *p; 537 char *rhs; 538 bool skipping; 539 long naliases, bytes, longest; 540 ADDRESS al, bl; 541 char line[BUFSIZ]; 542 543 /* 544 ** Read and interpret lines 545 */ 546 547 FileName = map->map_file; 548 LineNumber = 0; 549 naliases = bytes = longest = 0; 550 skipping = FALSE; 551 while (fgets(line, sizeof (line), af) != NULL) 552 { 553 int lhssize, rhssize; 554 555 LineNumber++; 556 p = strchr(line, '\n'); 557 if (p != NULL) 558 *p = '\0'; 559 switch (line[0]) 560 { 561 case '#': 562 case '\0': 563 skipping = FALSE; 564 continue; 565 566 case ' ': 567 case '\t': 568 if (!skipping) 569 syserr("554 Non-continuation line starts with space"); 570 skipping = TRUE; 571 continue; 572 } 573 skipping = FALSE; 574 575 /* 576 ** Process the LHS 577 ** Find the colon separator, and parse the address. 578 ** It should resolve to a local name -- this will 579 ** be checked later (we want to optionally do 580 ** parsing of the RHS first to maximize error 581 ** detection). 582 */ 583 584 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 585 continue; 586 if (*p++ != ':') 587 { 588 syserr("554 missing colon"); 589 continue; 590 } 591 if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 592 { 593 syserr("554 %.40s... illegal alias name", line); 594 continue; 595 } 596 597 /* 598 ** Process the RHS. 599 ** 'al' is the internal form of the LHS address. 600 ** 'p' points to the text of the RHS. 601 */ 602 603 while (isascii(*p) && isspace(*p)) 604 p++; 605 rhs = p; 606 for (;;) 607 { 608 register char c; 609 register char *nlp; 610 611 nlp = &p[strlen(p)]; 612 if (nlp[-1] == '\n') 613 *--nlp = '\0'; 614 615 if (CheckAliases) 616 { 617 /* do parsing & compression of addresses */ 618 while (*p != '\0') 619 { 620 auto char *delimptr; 621 622 while ((isascii(*p) && isspace(*p)) || 623 *p == ',') 624 p++; 625 if (*p == '\0') 626 break; 627 if (parseaddr(p, &bl, RF_COPYNONE, ',', 628 &delimptr, CurEnv) == NULL) 629 usrerr("553 %s... bad address", p); 630 p = delimptr; 631 } 632 } 633 else 634 { 635 p = nlp; 636 } 637 638 /* see if there should be a continuation line */ 639 c = fgetc(af); 640 if (!feof(af)) 641 (void) ungetc(c, af); 642 if (c != ' ' && c != '\t') 643 break; 644 645 /* read continuation line */ 646 if (fgets(p, sizeof line - (p - line), af) == NULL) 647 break; 648 LineNumber++; 649 650 /* check for line overflow */ 651 if (strchr(p, '\n') == NULL) 652 { 653 usrerr("554 alias too long"); 654 break; 655 } 656 } 657 if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 658 { 659 syserr("554 %s... cannot alias non-local names", 660 al.q_paddr); 661 continue; 662 } 663 664 /* 665 ** Insert alias into symbol table or DBM file 666 */ 667 668 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 669 makelower(al.q_user); 670 671 lhssize = strlen(al.q_user); 672 rhssize = strlen(rhs); 673 map->map_class->map_store(map, al.q_user, rhs); 674 675 if (al.q_paddr != NULL) 676 free(al.q_paddr); 677 if (al.q_host != NULL) 678 free(al.q_host); 679 if (al.q_user != NULL) 680 free(al.q_user); 681 682 /* statistics */ 683 naliases++; 684 bytes += lhssize + rhssize; 685 if (rhssize > longest) 686 longest = rhssize; 687 } 688 689 CurEnv->e_to = NULL; 690 FileName = NULL; 691 if (Verbose || announcestats) 692 message("%s: %d aliases, longest %d bytes, %d bytes total", 693 map->map_file, naliases, longest, bytes); 694 # ifdef LOG 695 if (LogLevel > 7 && logstats) 696 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 697 map->map_file, naliases, longest, bytes); 698 # endif /* LOG */ 699 } 700 /* 701 ** FORWARD -- Try to forward mail 702 ** 703 ** This is similar but not identical to aliasing. 704 ** 705 ** Parameters: 706 ** user -- the name of the user who's mail we would like 707 ** to forward to. It must have been verified -- 708 ** i.e., the q_home field must have been filled 709 ** in. 710 ** sendq -- a pointer to the head of the send queue to 711 ** put this user's aliases in. 712 ** 713 ** Returns: 714 ** none. 715 ** 716 ** Side Effects: 717 ** New names are added to send queues. 718 */ 719 720 forward(user, sendq, e) 721 ADDRESS *user; 722 ADDRESS **sendq; 723 register ENVELOPE *e; 724 { 725 char *pp; 726 char *ep; 727 728 if (tTd(27, 1)) 729 printf("forward(%s)\n", user->q_paddr); 730 731 if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 732 bitset(QBADADDR, user->q_flags)) 733 return; 734 if (user->q_home == NULL) 735 { 736 syserr("554 forward: no home"); 737 user->q_home = "/nosuchdirectory"; 738 } 739 740 /* good address -- look for .forward file in home */ 741 define('z', user->q_home, e); 742 define('u', user->q_user, e); 743 define('h', user->q_host, e); 744 if (ForwardPath == NULL) 745 ForwardPath = newstr("\201z/.forward"); 746 747 for (pp = ForwardPath; pp != NULL; pp = ep) 748 { 749 int err; 750 char buf[MAXPATHLEN+1]; 751 752 ep = strchr(pp, ':'); 753 if (ep != NULL) 754 *ep = '\0'; 755 expand(pp, buf, &buf[sizeof buf - 1], e); 756 if (ep != NULL) 757 *ep++ = ':'; 758 if (tTd(27, 3)) 759 printf("forward: trying %s\n", buf); 760 761 err = include(buf, TRUE, user, sendq, e); 762 if (err == 0) 763 break; 764 else if (transienterror(err)) 765 { 766 /* we have to suspend this message */ 767 if (tTd(27, 2)) 768 printf("forward: transient error on %s\n", buf); 769 #ifdef LOG 770 if (LogLevel > 2) 771 syslog(LOG_ERR, "%s: forward %s: transient error: %s", 772 e->e_id == NULL ? "NOQUEUE" : e->e_id, 773 buf, errstring(err)); 774 #endif 775 message("%s: %s: message queued", buf, errstring(err)); 776 user->q_flags |= QQUEUEUP; 777 return; 778 } 779 } 780 } 781