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