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