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