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