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