1 /* 2 * Copyright (c) 1983, 1995 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 11 #ifndef lint 12 #if !USERDB 13 static char sccsid [] = "@(#)udb.c 8.22 (Berkeley) 05/27/95 (with USERDB)"; 14 #else 15 static char sccsid [] = "@(#)udb.c 8.22 (Berkeley) 05/27/95 (without USERDB)"; 16 #endif 17 #endif 18 19 #if USERDB 20 21 #include <errno.h> 22 23 #ifdef NEWDB 24 # include <db.h> 25 #else 26 # define DBT struct _data_base_thang_ 27 DBT 28 { 29 void *data; /* pointer to data */ 30 size_t size; /* length of data */ 31 }; 32 #endif 33 34 #ifdef HESIOD 35 # include <hesiod.h> 36 #endif /* HESIOD */ 37 38 /* 39 ** UDB.C -- interface between sendmail and Berkeley User Data Base. 40 ** 41 ** This depends on the 4.4BSD db package. 42 */ 43 44 45 struct udbent 46 { 47 char *udb_spec; /* string version of spec */ 48 int udb_type; /* type of entry */ 49 char *udb_default; /* default host for outgoing mail */ 50 union 51 { 52 /* type UE_REMOTE -- do remote call for lookup */ 53 struct 54 { 55 struct sockaddr_in _udb_addr; /* address */ 56 int _udb_timeout; /* timeout */ 57 } udb_remote; 58 #define udb_addr udb_u.udb_remote._udb_addr 59 #define udb_timeout udb_u.udb_remote._udb_timeout 60 61 /* type UE_FORWARD -- forward message to remote */ 62 struct 63 { 64 char *_udb_fwdhost; /* name of forward host */ 65 } udb_forward; 66 #define udb_fwdhost udb_u.udb_forward._udb_fwdhost 67 68 #ifdef NEWDB 69 /* type UE_FETCH -- lookup in local database */ 70 struct 71 { 72 char *_udb_dbname; /* pathname of database */ 73 DB *_udb_dbp; /* open database ptr */ 74 } udb_lookup; 75 #define udb_dbname udb_u.udb_lookup._udb_dbname 76 #define udb_dbp udb_u.udb_lookup._udb_dbp 77 #endif 78 } udb_u; 79 }; 80 81 #define UDB_EOLIST 0 /* end of list */ 82 #define UDB_SKIP 1 /* skip this entry */ 83 #define UDB_REMOTE 2 /* look up in remote database */ 84 #define UDB_DBFETCH 3 /* look up in local database */ 85 #define UDB_FORWARD 4 /* forward to remote host */ 86 #define UDB_HESIOD 5 /* look up via hesiod */ 87 88 #define MAXUDBENT 10 /* maximum number of UDB entries */ 89 90 91 struct option 92 { 93 char *name; 94 char *val; 95 }; 96 /* 97 ** UDBEXPAND -- look up user in database and expand 98 ** 99 ** Parameters: 100 ** a -- address to expand. 101 ** sendq -- pointer to head of sendq to put the expansions in. 102 ** aliaslevel -- the current alias nesting depth. 103 ** e -- the current envelope. 104 ** 105 ** Returns: 106 ** EX_TEMPFAIL -- if something "odd" happened -- probably due 107 ** to accessing a file on an NFS server that is down. 108 ** EX_OK -- otherwise. 109 ** 110 ** Side Effects: 111 ** Modifies sendq. 112 */ 113 114 int UdbPort = 1616; 115 int UdbTimeout = 10; 116 117 struct udbent UdbEnts[MAXUDBENT + 1]; 118 int UdbSock = -1; 119 bool UdbInitialized = FALSE; 120 121 int 122 udbexpand(a, sendq, aliaslevel, e) 123 register ADDRESS *a; 124 ADDRESS **sendq; 125 int aliaslevel; 126 register ENVELOPE *e; 127 { 128 int i; 129 register char *p; 130 DBT key; 131 DBT info; 132 bool breakout; 133 register struct udbent *up; 134 int keylen; 135 int naddrs; 136 char keybuf[MAXKEY]; 137 char buf[BUFSIZ]; 138 139 if (tTd(28, 1)) 140 printf("udbexpand(%s)\n", a->q_paddr); 141 142 /* make certain we are supposed to send to this address */ 143 if (bitset(QDONTSEND|QVERIFIED, a->q_flags)) 144 return EX_OK; 145 e->e_to = a->q_paddr; 146 147 /* on first call, locate the database */ 148 if (!UdbInitialized) 149 { 150 extern int _udbx_init(); 151 152 if (_udbx_init() == EX_TEMPFAIL) 153 return EX_TEMPFAIL; 154 } 155 156 /* short circuit the process if no chance of a match */ 157 if (UdbSpec == NULL || UdbSpec[0] == '\0') 158 return EX_OK; 159 160 /* short circuit name begins with '\\' since it can't possibly match */ 161 if (a->q_user[0] == '\\') 162 return EX_OK; 163 164 /* if name is too long, assume it won't match */ 165 if (strlen(a->q_user) > sizeof keybuf - 12) 166 return EX_OK; 167 168 /* if name begins with a colon, it indicates our metadata */ 169 if (a->q_user[0] == ':') 170 return EX_OK; 171 172 /* build actual database key */ 173 (void) strcpy(keybuf, a->q_user); 174 (void) strcat(keybuf, ":maildrop"); 175 keylen = strlen(keybuf); 176 177 breakout = FALSE; 178 for (up = UdbEnts; !breakout; up++) 179 { 180 char *user; 181 182 /* 183 ** Select action based on entry type. 184 ** 185 ** On dropping out of this switch, "class" should 186 ** explain the type of the data, and "user" should 187 ** contain the user information. 188 */ 189 190 switch (up->udb_type) 191 { 192 #ifdef NEWDB 193 case UDB_DBFETCH: 194 key.data = keybuf; 195 key.size = keylen; 196 if (tTd(28, 80)) 197 printf("udbexpand: trying %s (%d) via db\n", 198 keybuf, keylen); 199 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR); 200 if (i > 0 || info.size <= 0) 201 { 202 if (tTd(28, 2)) 203 printf("udbexpand: no match on %s (%d)\n", 204 keybuf, keylen); 205 continue; 206 } 207 if (tTd(28, 80)) 208 printf("udbexpand: match %.*s: %.*s\n", 209 key.size, key.data, info.size, info.data); 210 211 naddrs = 0; 212 a->q_flags &= ~QSELFREF; 213 while (i == 0 && key.size == keylen && 214 bcmp(key.data, keybuf, keylen) == 0) 215 { 216 if (bitset(EF_VRFYONLY, e->e_flags)) 217 { 218 a->q_flags |= QVERIFIED; 219 e->e_nrcpts++; 220 return EX_OK; 221 } 222 223 breakout = TRUE; 224 if (info.size < sizeof buf) 225 user = buf; 226 else 227 user = xalloc(info.size + 1); 228 bcopy(info.data, user, info.size); 229 user[info.size] = '\0'; 230 231 message("expanded to %s", user); 232 #ifdef LOG 233 if (LogLevel >= 10) 234 syslog(LOG_INFO, "%s: expand %s => %s", 235 e->e_id, e->e_to, user); 236 #endif 237 naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e); 238 239 if (user != buf) 240 free(user); 241 242 /* get the next record */ 243 i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); 244 } 245 246 /* if nothing ever matched, try next database */ 247 if (!breakout) 248 continue; 249 250 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 251 { 252 if (tTd(28, 5)) 253 { 254 printf("udbexpand: QDONTSEND "); 255 printaddr(a, FALSE); 256 } 257 a->q_flags |= QDONTSEND; 258 } 259 if (i < 0) 260 { 261 syserr("udbexpand: db-get %.*s stat %d", 262 key.size, key.data, i); 263 return EX_TEMPFAIL; 264 } 265 266 /* 267 ** If this address has a -request address, reflect 268 ** it into the envelope. 269 */ 270 271 (void) strcpy(keybuf, a->q_user); 272 (void) strcat(keybuf, ":mailsender"); 273 keylen = strlen(keybuf); 274 key.data = keybuf; 275 key.size = keylen; 276 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 277 if (i != 0 || info.size <= 0) 278 break; 279 a->q_owner = xalloc(info.size + 1); 280 bcopy(info.data, a->q_owner, info.size); 281 a->q_owner[info.size] = '\0'; 282 283 /* announce delivery; NORECEIPT bit set later */ 284 if (e->e_xfp != NULL) 285 { 286 fprintf(e->e_xfp, 287 "Message delivered to mailing list %s\n", 288 a->q_paddr); 289 } 290 e->e_flags |= EF_SENDRECEIPT; 291 a->q_flags |= QDELIVERED|QEXPANDED; 292 break; 293 #endif 294 295 #ifdef HESIOD 296 case UDB_HESIOD: 297 key.data = keybuf; 298 key.size = keylen; 299 if (tTd(28, 80)) 300 printf("udbexpand: trying %s (%d) via hesiod\n", 301 keybuf, keylen); 302 /* look up the key via hesiod */ 303 i = hes_udb_get(&key, &info); 304 if (i < 0) 305 { 306 syserr("udbexpand: hesiod-get %.*s stat %d", 307 key.size, key.data, i); 308 return EX_TEMPFAIL; 309 } 310 else if (i > 0 || info.size <= 0) 311 { 312 if (tTd(28, 2)) 313 printf("udbexpand: no match on %s (%d)\n", 314 keybuf, keylen); 315 continue; 316 } 317 if (tTd(28, 80)) 318 printf("udbexpand: match %.*s: %.*s\n", 319 key.size, key.data, info.size, info.data); 320 a->q_flags &= ~QSELFREF; 321 322 if (bitset(EF_VRFYONLY, e->e_flags)) 323 { 324 a->q_flags |= QVERIFIED; 325 e->e_nrcpts++; 326 return EX_OK; 327 } 328 329 breakout = TRUE; 330 if (info.size < sizeof buf) 331 user = buf; 332 else 333 user = xalloc(info.size + 1); 334 bcopy(info.data, user, info.size); 335 user[info.size] = '\0'; 336 337 message("hesioded to %s", user); 338 #ifdef LOG 339 if (LogLevel >= 10) 340 syslog(LOG_INFO, "%s: hesiod %s => %s", 341 e->e_id, e->e_to, user); 342 #endif 343 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 344 345 if (user != buf) 346 free(user); 347 348 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 349 { 350 if (tTd(28, 5)) 351 { 352 printf("udbexpand: QDONTSEND "); 353 printaddr(a, FALSE); 354 } 355 a->q_flags |= QDONTSEND; 356 } 357 358 /* 359 ** If this address has a -request address, reflect 360 ** it into the envelope. 361 */ 362 363 (void) strcpy(keybuf, a->q_user); 364 (void) strcat(keybuf, ":mailsender"); 365 keylen = strlen(keybuf); 366 key.data = keybuf; 367 key.size = keylen; 368 i = hes_udb_get(&key, &info); 369 if (i != 0 || info.size <= 0) 370 break; 371 a->q_owner = xalloc(info.size + 1); 372 bcopy(info.data, a->q_owner, info.size); 373 a->q_owner[info.size] = '\0'; 374 break; 375 #endif /* HESIOD */ 376 377 case UDB_REMOTE: 378 /* not yet implemented */ 379 continue; 380 381 case UDB_FORWARD: 382 if (bitset(EF_VRFYONLY, e->e_flags)) 383 return EX_OK; 384 i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; 385 if (i < sizeof buf) 386 user = buf; 387 else 388 user = xalloc(i + 1); 389 (void) sprintf(user, "%s@%s", a->q_user, up->udb_fwdhost); 390 message("expanded to %s", user); 391 a->q_flags &= ~QSELFREF; 392 naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); 393 if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) 394 { 395 if (tTd(28, 5)) 396 { 397 printf("udbexpand: QDONTSEND "); 398 printaddr(a, FALSE); 399 } 400 a->q_flags |= QDONTSEND; 401 } 402 if (user != buf) 403 free(user); 404 breakout = TRUE; 405 break; 406 407 case UDB_EOLIST: 408 breakout = TRUE; 409 continue; 410 411 default: 412 /* unknown entry type */ 413 continue; 414 } 415 } 416 return EX_OK; 417 } 418 /* 419 ** UDBSENDER -- return canonical external name of sender, given local name 420 ** 421 ** Parameters: 422 ** sender -- the name of the sender on the local machine. 423 ** 424 ** Returns: 425 ** The external name for this sender, if derivable from the 426 ** database. 427 ** NULL -- if nothing is changed from the database. 428 ** 429 ** Side Effects: 430 ** none. 431 */ 432 433 char * 434 udbsender(sender) 435 char *sender; 436 { 437 extern char *udbmatch(); 438 439 return udbmatch(sender, "mailname"); 440 } 441 442 443 char * 444 udbmatch(user, field) 445 char *user; 446 char *field; 447 { 448 register char *p; 449 register struct udbent *up; 450 int i; 451 int keylen; 452 DBT key, info; 453 char keybuf[MAXKEY]; 454 455 if (tTd(28, 1)) 456 printf("udbmatch(%s, %s)\n", user, field); 457 458 if (!UdbInitialized) 459 { 460 if (_udbx_init() == EX_TEMPFAIL) 461 return NULL; 462 } 463 464 /* short circuit if no spec */ 465 if (UdbSpec == NULL || UdbSpec[0] == '\0') 466 return NULL; 467 468 /* short circuit name begins with '\\' since it can't possibly match */ 469 if (user[0] == '\\') 470 return NULL; 471 472 /* long names can never match and are a pain to deal with */ 473 if ((strlen(user) + strlen(field)) > sizeof keybuf - 4) 474 return NULL; 475 476 /* names beginning with colons indicate metadata */ 477 if (user[0] == ':') 478 return NULL; 479 480 /* build database key */ 481 (void) strcpy(keybuf, user); 482 (void) strcat(keybuf, ":"); 483 (void) strcat(keybuf, field); 484 keylen = strlen(keybuf); 485 486 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 487 { 488 /* 489 ** Select action based on entry type. 490 */ 491 492 switch (up->udb_type) 493 { 494 #ifdef NEWDB 495 case UDB_DBFETCH: 496 key.data = keybuf; 497 key.size = keylen; 498 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 499 if (i != 0 || info.size <= 0) 500 { 501 if (tTd(28, 2)) 502 printf("udbmatch: no match on %s (%d) via db\n", 503 keybuf, keylen); 504 continue; 505 } 506 507 p = xalloc(info.size + 1); 508 bcopy(info.data, p, info.size); 509 p[info.size] = '\0'; 510 if (tTd(28, 1)) 511 printf("udbmatch ==> %s\n", p); 512 return p; 513 break; 514 #endif 515 516 #ifdef HESIOD 517 case UDB_HESIOD: 518 key.data = keybuf; 519 key.size = keylen; 520 i = hes_udb_get(&key, &info); 521 if (i != 0 || info.size <= 0) 522 { 523 if (tTd(28, 2)) 524 printf("udbmatch: no match on %s (%d) via hesiod\n", 525 keybuf, keylen); 526 continue; 527 } 528 529 p = xalloc(info.size + 1); 530 bcopy(info.data, p, info.size); 531 p[info.size] = '\0'; 532 if (tTd(28, 1)) 533 printf("udbmatch ==> %s\n", p); 534 return p; 535 #endif /* HESIOD */ 536 } 537 } 538 539 if (strcmp(field, "mailname") != 0) 540 return NULL; 541 542 /* 543 ** Nothing yet. Search again for a default case. But only 544 ** use it if we also have a forward (:maildrop) pointer already 545 ** in the database. 546 */ 547 548 /* build database key */ 549 (void) strcpy(keybuf, user); 550 (void) strcat(keybuf, ":maildrop"); 551 keylen = strlen(keybuf); 552 553 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 554 { 555 switch (up->udb_type) 556 { 557 #ifdef NEWDB 558 case UDB_DBFETCH: 559 /* get the default case for this database */ 560 if (up->udb_default == NULL) 561 { 562 key.data = ":default:mailname"; 563 key.size = strlen(key.data); 564 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 565 if (i != 0 || info.size <= 0) 566 { 567 /* no default case */ 568 up->udb_default = ""; 569 continue; 570 } 571 572 /* save the default case */ 573 up->udb_default = xalloc(info.size + 1); 574 bcopy(info.data, up->udb_default, info.size); 575 up->udb_default[info.size] = '\0'; 576 } 577 else if (up->udb_default[0] == '\0') 578 continue; 579 580 /* we have a default case -- verify user:maildrop */ 581 key.data = keybuf; 582 key.size = keylen; 583 i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0); 584 if (i != 0 || info.size <= 0) 585 { 586 /* nope -- no aliasing for this user */ 587 continue; 588 } 589 590 /* they exist -- build the actual address */ 591 p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 592 (void) strcpy(p, user); 593 (void) strcat(p, "@"); 594 (void) strcat(p, up->udb_default); 595 if (tTd(28, 1)) 596 printf("udbmatch ==> %s\n", p); 597 return p; 598 break; 599 #endif 600 601 #ifdef HESIOD 602 case UDB_HESIOD: 603 /* get the default case for this database */ 604 if (up->udb_default == NULL) 605 { 606 key.data = ":default:mailname"; 607 key.size = strlen(key.data); 608 i = hes_udb_get(&key, &info); 609 610 if (i != 0 || info.size <= 0) 611 { 612 /* no default case */ 613 up->udb_default = ""; 614 continue; 615 } 616 617 /* save the default case */ 618 up->udb_default = xalloc(info.size + 1); 619 bcopy(info.data, up->udb_default, info.size); 620 up->udb_default[info.size] = '\0'; 621 } 622 else if (up->udb_default[0] == '\0') 623 continue; 624 625 /* we have a default case -- verify user:maildrop */ 626 key.data = keybuf; 627 key.size = keylen; 628 i = hes_udb_get(&key, &info); 629 if (i != 0 || info.size <= 0) 630 { 631 /* nope -- no aliasing for this user */ 632 continue; 633 } 634 635 /* they exist -- build the actual address */ 636 p = xalloc(strlen(user) + strlen(up->udb_default) + 2); 637 (void) strcpy(p, user); 638 (void) strcat(p, "@"); 639 (void) strcat(p, up->udb_default); 640 if (tTd(28, 1)) 641 printf("udbmatch ==> %s\n", p); 642 return p; 643 break; 644 #endif /* HESIOD */ 645 } 646 } 647 648 /* still nothing.... too bad */ 649 return NULL; 650 } 651 /* 652 ** UDB_MAP_LOOKUP -- look up arbitrary entry in user database map 653 ** 654 ** Parameters: 655 ** map -- the map being queried. 656 ** name -- the name to look up. 657 ** av -- arguments to the map lookup. 658 ** statp -- to get any error status. 659 ** 660 ** Returns: 661 ** NULL if name not found in map. 662 ** The rewritten name otherwise. 663 */ 664 665 char * 666 udb_map_lookup(map, name, av, statp) 667 MAP *map; 668 char *name; 669 char **av; 670 int *statp; 671 { 672 char *val; 673 674 if (tTd(38, 20)) 675 printf("udb_map_lookup(%s, %s)\n", map->map_mname, name); 676 val = udbmatch(name, map->map_file); 677 if (val == NULL) 678 return NULL; 679 if (bitset(MF_MATCHONLY, map->map_mflags)) 680 return map_rewrite(map, name, strlen(name), NULL); 681 else 682 return map_rewrite(map, val, strlen(val), av); 683 } 684 /* 685 ** _UDBX_INIT -- parse the UDB specification, opening any valid entries. 686 ** 687 ** Parameters: 688 ** none. 689 ** 690 ** Returns: 691 ** EX_TEMPFAIL -- if it appeared it couldn't get hold of a 692 ** database due to a host being down or some similar 693 ** (recoverable) situation. 694 ** EX_OK -- otherwise. 695 ** 696 ** Side Effects: 697 ** Fills in the UdbEnts structure from UdbSpec. 698 */ 699 700 #define MAXUDBOPTS 27 701 702 int 703 _udbx_init() 704 { 705 register char *p; 706 int i; 707 register struct udbent *up; 708 char buf[BUFSIZ]; 709 710 if (UdbInitialized) 711 return EX_OK; 712 713 # ifdef UDB_DEFAULT_SPEC 714 if (UdbSpec == NULL) 715 UdbSpec = UDB_DEFAULT_SPEC; 716 # endif 717 718 p = UdbSpec; 719 up = UdbEnts; 720 while (p != NULL) 721 { 722 char *spec; 723 auto int rcode; 724 int nopts; 725 int nmx; 726 register struct hostent *h; 727 char *mxhosts[MAXMXHOSTS + 1]; 728 struct option opts[MAXUDBOPTS + 1]; 729 730 while (*p == ' ' || *p == '\t' || *p == ',') 731 p++; 732 if (*p == '\0') 733 break; 734 spec = p; 735 p = strchr(p, ','); 736 if (p != NULL) 737 *p++ = '\0'; 738 739 /* extract options */ 740 nopts = _udb_parsespec(spec, opts, MAXUDBOPTS); 741 742 /* 743 ** Decode database specification. 744 ** 745 ** In the sendmail tradition, the leading character 746 ** defines the semantics of the rest of the entry. 747 ** 748 ** +hostname -- send a datagram to the udb server 749 ** on host "hostname" asking for the 750 ** home mail server for this user. 751 ** *hostname -- similar to +hostname, except that the 752 ** hostname is searched as an MX record; 753 ** resulting hosts are searched as for 754 ** +mxhostname. If no MX host is found, 755 ** this is the same as +hostname. 756 ** @hostname -- forward email to the indicated host. 757 ** This should be the last in the list, 758 ** since it always matches the input. 759 ** /dbname -- search the named database on the local 760 ** host using the Berkeley db package. 761 */ 762 763 switch (*spec) 764 { 765 #if 0 766 case '+': /* search remote database */ 767 case '*': /* search remote database (expand MX) */ 768 if (*spec == '*') 769 { 770 #if NAMED_BIND 771 nmx = getmxrr(spec + 1, mxhosts, FALSE, &rcode); 772 #else 773 mxhosts[0] = spec + 1; 774 nmx = 1; 775 rcode = 0; 776 #endif 777 if (tTd(28, 16)) 778 { 779 int i; 780 781 printf("getmxrr(%s): %d", spec + 1, nmx); 782 for (i = 0; i <= nmx; i++) 783 printf(" %s", mxhosts[i]); 784 printf("\n"); 785 } 786 } 787 else 788 { 789 nmx = 1; 790 mxhosts[0] = spec + 1; 791 } 792 793 for (i = 0; i < nmx; i++) 794 { 795 h = sm_gethostbyname(mxhosts[i]); 796 if (h == NULL) 797 continue; 798 up->udb_type = UDB_REMOTE; 799 up->udb_addr.sin_family = h->h_addrtype; 800 bcopy(h->h_addr_list[0], 801 (char *) &up->udb_addr.sin_addr, 802 INADDRSZ); 803 up->udb_addr.sin_port = UdbPort; 804 up->udb_timeout = UdbTimeout; 805 up++; 806 } 807 808 /* set up a datagram socket */ 809 if (UdbSock < 0) 810 { 811 UdbSock = socket(AF_INET, SOCK_DGRAM, 0); 812 (void) fcntl(UdbSock, F_SETFD, 1); 813 } 814 break; 815 #endif 816 817 case '@': /* forward to remote host */ 818 up->udb_type = UDB_FORWARD; 819 up->udb_fwdhost = spec + 1; 820 up++; 821 break; 822 823 #ifdef HESIOD 824 case 'h': /* use hesiod */ 825 case 'H': 826 if (strcasecmp(spec, "hesiod") != 0) 827 goto badspec; 828 up->udb_type = UDB_HESIOD; 829 up++; 830 break; 831 #endif /* HESIOD */ 832 833 #ifdef NEWDB 834 case '/': /* look up remote name */ 835 up->udb_dbname = spec; 836 errno = 0; 837 up->udb_dbp = dbopen(spec, O_RDONLY, 0644, DB_BTREE, NULL); 838 if (up->udb_dbp == NULL) 839 { 840 if (tTd(28, 1)) 841 { 842 int saveerrno = errno; 843 844 printf("dbopen(%s): %s", 845 spec, errstring(errno)); 846 errno = saveerrno; 847 } 848 if (errno != ENOENT && errno != EACCES) 849 { 850 #ifdef LOG 851 if (LogLevel > 2) 852 syslog(LOG_ERR, "dbopen(%s): %s", 853 spec, errstring(errno)); 854 #endif 855 up->udb_type = UDB_EOLIST; 856 goto tempfail; 857 } 858 break; 859 } 860 up->udb_type = UDB_DBFETCH; 861 up++; 862 break; 863 #endif 864 865 default: 866 badspec: 867 syserr("Unknown UDB spec %s", spec); 868 break; 869 } 870 } 871 up->udb_type = UDB_EOLIST; 872 873 if (tTd(28, 4)) 874 { 875 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 876 { 877 switch (up->udb_type) 878 { 879 case UDB_REMOTE: 880 printf("REMOTE: addr %s, timeo %d\n", 881 anynet_ntoa((SOCKADDR *) &up->udb_addr), 882 up->udb_timeout); 883 break; 884 885 case UDB_DBFETCH: 886 #ifdef NEWDB 887 printf("FETCH: file %s\n", 888 up->udb_dbname); 889 #else 890 printf("FETCH\n"); 891 #endif 892 break; 893 894 case UDB_FORWARD: 895 printf("FORWARD: host %s\n", 896 up->udb_fwdhost); 897 break; 898 899 case UDB_HESIOD: 900 printf("HESIOD\n"); 901 break; 902 903 default: 904 printf("UNKNOWN\n"); 905 break; 906 } 907 } 908 } 909 910 UdbInitialized = TRUE; 911 errno = 0; 912 return EX_OK; 913 914 /* 915 ** On temporary failure, back out anything we've already done 916 */ 917 918 tempfail: 919 #ifdef NEWDB 920 for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++) 921 { 922 if (up->udb_type == UDB_DBFETCH) 923 { 924 (*up->udb_dbp->close)(up->udb_dbp); 925 } 926 } 927 #endif 928 return EX_TEMPFAIL; 929 } 930 931 int 932 _udb_parsespec(udbspec, opt, maxopts) 933 char *udbspec; 934 struct option opt[]; 935 int maxopts; 936 { 937 register char *spec; 938 register char *spec_end; 939 register int optnum; 940 941 spec_end = strchr(udbspec, ':'); 942 for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++) 943 { 944 register char *p; 945 946 while (isascii(*spec) && isspace(*spec)) 947 spec++; 948 spec_end = strchr(spec, ':'); 949 if (spec_end != NULL) 950 *spec_end++ = '\0'; 951 952 opt[optnum].name = spec; 953 opt[optnum].val = NULL; 954 p = strchr(spec, '='); 955 if (p != NULL) 956 opt[optnum].val = ++p; 957 } 958 return optnum; 959 } 960 961 #ifdef HESIOD 962 963 int 964 hes_udb_get(key, info) 965 DBT *key; 966 DBT *info; 967 { 968 char *name, *type; 969 char *p, **hp; 970 char kbuf[MAXKEY + 1]; 971 972 strcpy(kbuf, key->data); 973 name = kbuf; 974 type = strchr(name, ':'); 975 if (type == NULL) 976 return 1; 977 *type++ = '\0'; 978 979 if (tTd(28, 1)) 980 printf("hes_udb_get(%s, %s)\n", name, type); 981 982 /* make the hesiod query */ 983 hp = hes_resolve(name, type); 984 *--type = ':'; 985 if (hp == NULL) 986 { 987 /* network problem or timeout */ 988 if (hes_error() == HES_ER_NET) 989 return -1; 990 991 return 1; 992 } 993 else 994 { 995 /* 996 ** If there are multiple matches, just return the 997 ** first one. 998 ** 999 ** XXX These should really be returned; for example, 1000 ** XXX it is legal for :maildrop to be multi-valued. 1001 */ 1002 1003 info->data = hp[0]; 1004 info->size = (size_t) strlen(info->data); 1005 } 1006 1007 return 0; 1008 } 1009 #endif /* HESIOD */ 1010 1011 #else /* not USERDB */ 1012 1013 int 1014 udbexpand(a, sendq, aliaslevel, e) 1015 ADDRESS *a; 1016 ADDRESS **sendq; 1017 int aliaslevel; 1018 ENVELOPE *e; 1019 { 1020 return EX_OK; 1021 } 1022 1023 #endif /* USERDB */ 1024