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