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