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