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