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