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.15 (Berkeley) 03/20/95 (with USERDB)"; 14 #else 15 static char sccsid [] = "@(#)udb.c 8.15 (Berkeley) 03/20/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 e->e_flags |= EF_SENDRECEIPT; 278 } 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 = 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