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