1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * PSARC/2004/154 nfsmapid DNS enhancements implementation. 31 * 32 * As per RFC 3050, file owner and group attributes in version 4 of the 33 * NFS protocol are no longer exchanged between client and server as 32 34 * bit integral values. Instead, owner and group file attributes are 35 * exchanged between client and server as UTF8 strings of form 36 * 37 * 'user@domain' (ie. "joeblow@central.sun.com") 38 * 'group@domain' (ie. "staff@central.sun.com") 39 * 40 * This NFSv4 feature is far beyond anything NFSv2/v3 ever provided, as 41 * being able to describe a user with a unique string identifier provides 42 * a much more powerful and administrative friendly way of dealing with 43 * overlaps in the uid/gid number spaces. That notwithstanding, dealing 44 * with issues of correctly mapping user and group ownership in a cross- 45 * domain environment has proven a difficult problem to solve, since 46 * dealing with different permutations of client naming configurations 47 * (ie. NIS only, LDAP only, etc.) have bloated the problem. Thus, users 48 * utilizing clients and servers that have the 'domain' portion of the 49 * UTF8 attribute string configured differently than its peer server and 50 * client accordingly, will experience watching their files owned by the 51 * 'nobody' user and group. This is due to the fact that the 'domain's 52 * don't match and the nfsmapid daemon treats the attribute strings as 53 * unknown user(s) or group(s) (even though the actual uid/gid's may exist 54 * in the executing daemon's system). Please refer to PSARC/2004/154 for 55 * further background and motivation for these enhancements. 56 * 57 * The latest implementation of the nfsmapid daemon relies on a DNS TXT 58 * record. The behavior of nfsmapid is to first use the NFSMAPID_DOMAIN 59 * configuration option in /etc/default/nfs. If the option has not been 60 * set, then the nfsmapid daemon queries the configured DNS domain server 61 * for the _nfsv4idmapdomain TXT record. If the record exists, then the 62 * record's value is used as the 'domain' portion of the UTF8 attribute 63 * strings. If the TXT record has not been configured in the DNS server, 64 * then the daemon falls back to using the DNS domain name itself as the 65 * 'domain' portion of the attribute strings. Lastly, if the configured 66 * DNS server is unresponsive, the nfsmapid daemon falls back to using 67 * the DNS domain name as the 'domain' portion of the attribute strings, 68 * and fires up a query thread to keep contacting the DNS server until 69 * it responds with either a TXT record, or a lack thereof, in which 70 * case, nfsmapid just continues to utilize the DNS domain name. 71 */ 72 #define __NFSMAPID_RES_IMPL 73 #include "nfsmapid_resolv.h" 74 75 /* 76 * DEBUG Only 77 * Decode any resolver errors and print out message to log 78 */ 79 static int 80 resolv_error(void) 81 { 82 static uint64_t msg_done[NS_ERRS] = {0}; 83 84 switch (h_errno) { 85 case NETDB_INTERNAL: 86 IDMAP_DBG(EMSG_NETDB_INTERNAL, strerror(errno), NULL); 87 break; 88 89 case HOST_NOT_FOUND: 90 (void) rw_rdlock(&s_dns_impl_lock); 91 msg_done[h_errno]++; 92 #ifdef DEBUG 93 if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 94 IDMAP_DBG(EMSG_HOST_NOT_FOUND, s_dname, NULL); 95 #endif 96 (void) rw_unlock(&s_dns_impl_lock); 97 break; 98 99 case TRY_AGAIN: 100 /* 101 * Nameserver is not responding. 102 * Try again after a given timeout. 103 */ 104 (void) rw_rdlock(&s_dns_impl_lock); 105 msg_done[h_errno]++; 106 #ifdef DEBUG 107 if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 108 IDMAP_DBG(EMSG_TRY_AGAIN, s_dname, NULL); 109 #endif 110 (void) rw_unlock(&s_dns_impl_lock); 111 break; 112 113 case NO_RECOVERY: 114 /* 115 * This msg only really happens once, due 116 * to s_dns_disabled flag (see below) 117 */ 118 IDMAP_DBG(EMSG_NO_RECOVERY, hstrerror(h_errno), NULL); 119 break; 120 121 case NO_DATA: 122 /* 123 * No entries in the nameserver for 124 * the specific record or record type. 125 */ 126 (void) rw_rdlock(&s_dns_impl_lock); 127 msg_done[h_errno]++; 128 #ifdef DEBUG 129 if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 130 IDMAP_DBG(EMSG_NO_DATA, NFSMAPID_DNS_RR, 131 s_dname); 132 #endif 133 (void) rw_unlock(&s_dns_impl_lock); 134 break; 135 136 case NETDB_SUCCESS: 137 default: 138 break; 139 } 140 return (h_errno); 141 } 142 143 /* 144 * Reset the global state variables used for the TXT record. 145 * Having these values reset to zero helps nfsmapid confirm 146 * that a valid DNS TXT record was not found; in which case, 147 * it would fall back to using the configured DNS domain name. 148 * 149 * If a valid DNS TXT record _was_ found, but subsequent contact 150 * to the DNS server is somehow hindered, the previous DNS TXT 151 * RR value continues to be used. Thus, in such instances, we 152 * forego clearing the global config variables so nfsmapid can 153 * continue to use a valid DNS TXT RR while contact to the DNS 154 * server is reestablished. 155 */ 156 static void 157 resolv_txt_reset(void) 158 { 159 (void) rw_wrlock(&s_dns_impl_lock); 160 bzero(s_txt_rr, sizeof (s_txt_rr)); 161 (void) rw_unlock(&s_dns_impl_lock); 162 163 (void) rw_wrlock(&dns_data_lock); 164 if (!dns_txt_cached) { 165 dns_txt_domain_len = 0; 166 bzero(dns_txt_domain, DNAMEMAX); 167 } 168 (void) rw_unlock(&dns_data_lock); 169 } 170 171 /* 172 * Initialize resolver and populate &s_res struct 173 * 174 * DNS Domain is saved off sysdns_domain in case we 175 * need to fall back to using the DNS domain name as 176 * the v4 attribute string domain. 177 */ 178 int 179 resolv_init(void) 180 { 181 size_t len; 182 int n; 183 struct __res_state res; 184 185 (void) mutex_lock(&s_res_lock); 186 bzero(&s_res, sizeof (struct __res_state)); 187 n = h_errno = errno = 0; 188 if ((n = res_ninit(&s_res)) < 0) { 189 (void) mutex_unlock(&s_res_lock); 190 (void) resolv_error(); 191 return (n); 192 } 193 res = s_res; 194 (void) mutex_unlock(&s_res_lock); 195 196 len = strlen(res.defdname) + 1; 197 (void) rw_wrlock(&s_dns_impl_lock); 198 bzero(s_dname, sizeof (s_dname)); 199 (void) snprintf(s_dname, len, "%s", res.defdname); 200 (void) rw_unlock(&s_dns_impl_lock); 201 202 (void) rw_wrlock(&dns_data_lock); 203 (void) snprintf(sysdns_domain, len, "%s", res.defdname); 204 (void) rw_unlock(&dns_data_lock); 205 206 return (0); 207 } 208 209 /* 210 * Search criteria assumptions: 211 * 212 * The onus will fall on the sysadmins to correctly configure the TXT 213 * record in the DNS domain where the box currently resides in order 214 * for the record to be found. However, if they sysadmin chooses to 215 * add the 'search' key to /etc/resolv.conf, then resolv_search() 216 * _will_ traverse up the DNS tree as specified in the 'search' key. 217 * Otherwise, we'll default the domain to the DNS domain itself. 218 */ 219 static int 220 resolv_search(void) 221 { 222 int len; 223 ans_t ans = {0}; 224 struct __res_state res; 225 int type = T_TXT; 226 int class = C_IN; 227 228 (void) mutex_lock(&s_res_lock); 229 res = s_res; 230 (void) mutex_unlock(&s_res_lock); 231 232 /* 233 * Avoid holding locks across the res_nsearch() call to 234 * prevent stalling threads during network partitions. 235 */ 236 len = h_errno = errno = 0; 237 if ((len = res_nsearch(&res, NFSMAPID_DNS_RR, class, type, 238 ans.buf, sizeof (ans))) < 0) 239 return (resolv_error()); 240 241 (void) rw_wrlock(&s_dns_impl_lock); 242 s_ans = ans; 243 s_anslen = len; 244 (void) rw_unlock(&s_dns_impl_lock); 245 246 return (NETDB_SUCCESS); 247 } 248 249 /* 250 * Skip one DNS record 251 */ 252 static uchar_t * 253 resolv_skip_rr(uchar_t *p, uchar_t *eom) 254 { 255 int t; 256 int dlen; 257 258 /* 259 * Skip compressed name 260 */ 261 errno = 0; 262 if ((t = dn_skipname(p, eom)) < 0) { 263 IDMAP_DBG("%s", strerror(errno), NULL); 264 return (NULL); 265 } 266 267 /* 268 * Advance pointer and make sure 269 * we're still within the message 270 */ 271 p += t; 272 if ((p + RRFIXEDSZ) > eom) 273 return (NULL); 274 275 /* 276 * Now, just skip over the rr fields 277 */ 278 p += INT16SZ; /* type */ 279 p += INT16SZ; /* class */ 280 p += INT32SZ; /* ttl */ 281 NS_GET16(dlen, p); 282 p += dlen; /* dlen */ 283 if (p > eom) 284 return (NULL); 285 286 return (p); 287 } 288 289 /* 290 * Process one TXT record. 291 * 292 * nfsmapid queries the DNS server for the specific _nfsv4idmapdomain 293 * TXT record. Thus, if the TXT record exists, the answer section of 294 * the DNS response carries the TXT record's value. Thus, we check that 295 * the value is indeed a valid domain and set the modular s_txt_rr 296 * global to the domain value. 297 */ 298 static void 299 resolve_process_txt(uchar_t *p, int dlen) 300 { 301 char *rr_base = (char *)(p + 1); 302 char *rr_end = (char *)(p + dlen); 303 size_t len = rr_end - rr_base; 304 static uint64_t msg_done = 0; 305 char tmp_txt_rr[DNAMEMAX]; 306 307 if (len >= DNAMEMAX) 308 return; /* process next TXT RR */ 309 310 /* 311 * make sure we have a clean buf since 312 * we may've processed several TXT rr's 313 */ 314 (void) rw_wrlock(&s_dns_impl_lock); 315 bzero(s_txt_rr, sizeof (s_txt_rr)); 316 (void) rw_unlock(&s_dns_impl_lock); 317 318 (void) strncpy(tmp_txt_rr, rr_base, len); 319 tmp_txt_rr[len] = '\0'; 320 321 /* 322 * If there is a record and it's a valid domain, we're done. 323 */ 324 if (rr_base[0] != '\0' && standard_domain_str(tmp_txt_rr)) { 325 (void) rw_wrlock(&s_dns_impl_lock); 326 (void) strncpy(s_txt_rr, rr_base, len); 327 (void) rw_unlock(&s_dns_impl_lock); 328 IDMAP_DBG("TXT (Rec):\t%s", s_txt_rr, NULL); 329 330 } else if (!(msg_done++ % NFSMAPID_SLOG_RATE)) { 331 /* 332 * Otherwise, log the error 333 */ 334 (void) rw_rdlock(&s_dns_impl_lock); 335 IDMAP_DBG(EMSG_DNS_RR_INVAL, NFSMAPID_DNS_RR, s_dname); 336 (void) rw_unlock(&s_dns_impl_lock); 337 } 338 } 339 340 /* 341 * Decode any answer received from the DNS server. This interface is 342 * capable of much more than just decoding TXT records. We maintain 343 * focus on TXT rr's for now, but this will probably change once we 344 * get the IETF approved application specific DNS RR. 345 * 346 * Here's an example of the TXT record we're decoding (as would appear 347 * in the DNS zone file): 348 * 349 * _nfsv4idmapdomain IN TXT "sun.com" 350 * 351 * Once the IETF application specific DNS RR is granted, we should only 352 * be changing the record flavor, but all should pretty much stay the 353 * same. 354 */ 355 static void 356 resolv_decode(void) 357 { 358 uchar_t *buf; 359 HEADER *hp; 360 uchar_t name[DNAMEMAX]; 361 uchar_t *eom; 362 uchar_t *p; 363 int n; 364 uint_t qd_cnt; 365 uint_t an_cnt; 366 uint_t ns_cnt; 367 uint_t ar_cnt; 368 uint_t cnt; 369 uint_t type; 370 uint_t class; 371 int dlen; 372 ulong_t ttl; 373 ans_t answer = {0}; 374 int answer_len = 0; 375 376 /* 377 * Check the HEADER for any signs of errors 378 * and extract the answer counts for later. 379 */ 380 (void) rw_rdlock(&s_dns_impl_lock); 381 answer = s_ans; 382 answer_len = s_anslen; 383 (void) rw_unlock(&s_dns_impl_lock); 384 385 buf = (uchar_t *)&answer.buf; 386 hp = (HEADER *)&answer.hdr; 387 eom = (uchar_t *)(buf + answer_len); 388 if (hp->rcode != NOERROR) { 389 IDMAP_DBG("errno: %s", strerror(errno), NULL); 390 IDMAP_DBG("h_errno: %s", hstrerror(h_errno), NULL); 391 return; 392 } 393 qd_cnt = ntohs(hp->qdcount); 394 an_cnt = ntohs(hp->ancount); 395 ns_cnt = ntohs(hp->nscount); 396 ar_cnt = ntohs(hp->arcount); 397 398 /* 399 * skip query entries 400 */ 401 p = (uchar_t *)(buf + HFIXEDSZ); 402 errno = 0; 403 while (qd_cnt-- > 0) { 404 n = dn_skipname(p, eom); 405 if (n < 0) { 406 IDMAP_DBG("%s", strerror(errno), NULL); 407 return; 408 } 409 p += n; 410 p += INT16SZ; /* type */ 411 p += INT16SZ; /* class */ 412 } 413 414 #ifdef DEBUG 415 /* 416 * If debugging... print query only once. 417 * NOTE: Don't advance pointer... this is done 418 * in while() loop on a per record basis ! 419 */ 420 n = h_errno = errno = 0; 421 n = dn_expand(buf, eom, p, (char *)name, sizeof (name)); 422 if (n < 0) { 423 (void) resolv_error(); 424 return; 425 } 426 IDMAP_DBG("Query:\t\t%-30s", name, NULL); 427 #endif 428 429 /* 430 * Process actual answer(s). 431 */ 432 cnt = an_cnt; 433 while (cnt-- > 0 && p < eom) { 434 /* skip the name field */ 435 n = dn_expand(buf, eom, p, (char *)name, sizeof (name)); 436 if (n < 0) { 437 (void) resolv_error(); 438 return; 439 } 440 p += n; 441 442 if ((p + 3 * INT16SZ + INT32SZ) > eom) 443 return; 444 445 NS_GET16(type, p); 446 NS_GET16(class, p); 447 NS_GET32(ttl, p); 448 NS_GET16(dlen, p); 449 450 if ((p + dlen) > eom) 451 return; 452 453 switch (type) { 454 case T_TXT: 455 resolve_process_txt(p, dlen); 456 break; 457 458 default: 459 /* 460 * Advance to next answer record for any 461 * other record types. Again, this will 462 * probably change (see block comment). 463 */ 464 p += dlen; 465 break; 466 } 467 } 468 469 /* 470 * Skip name server and additional records for now. 471 */ 472 cnt = ns_cnt + ar_cnt; 473 if (cnt > 0) { 474 while (--cnt != 0 && p < eom) { 475 p = resolv_skip_rr(p, eom); 476 if (p == NULL) 477 return; 478 } 479 } 480 } 481 482 /* 483 * If a valid TXT record entry exists, s_txt_rr contains the domain 484 * value (as set in resolv_process_txt) and we extract the value into 485 * dns_txt_domain (the exported global). If there was _no_ valid TXT 486 * entry, we simply return and check_domain() will default to the 487 * DNS domain since we did resolv_txt_reset() first. 488 */ 489 static void 490 resolv_get_txt_data() 491 { 492 (void) rw_rdlock(&s_dns_impl_lock); 493 if (s_txt_rr[0] != '\0') { 494 (void) rw_wrlock(&dns_data_lock); 495 (void) snprintf(dns_txt_domain, strlen(s_txt_rr) + 1, "%s", 496 s_txt_rr); 497 dns_txt_domain_len = strlen(dns_txt_domain); 498 dns_txt_cached = 1; 499 (void) rw_unlock(&dns_data_lock); 500 } 501 (void) rw_unlock(&s_dns_impl_lock); 502 } 503 504 /* 505 * Thread to keep pinging DNS server for TXT record if nfsmapid's 506 * initial attempt at contact with server failed. We could potentially 507 * have a substantial number of NFSv4 clients and having all of them 508 * hammering on an already unresponsive DNS server would not help 509 * things. So, we limit the number of live query threads to at most 510 * 1 at any one time to keep things from getting out of hand. 511 */ 512 /* ARGSUSED */ 513 void * 514 resolv_query_thread(void *arg) 515 { 516 #ifdef DEBUG 517 char *whoami = "query_thread"; 518 #endif 519 uint32_t nap_time; 520 521 IDMAP_DBG("query_thread active !", NULL, NULL); 522 (void) rw_rdlock(&s_dns_impl_lock); 523 nap_time = s_dns_tout; 524 (void) rw_unlock(&s_dns_impl_lock); 525 526 for (;;) { 527 (void) sleep(nap_time); 528 529 resolv_txt_reset(); 530 (void) resolv_init(); 531 switch (resolv_search()) { 532 case NETDB_SUCCESS: 533 IDMAP_DBG("%s: DNS replied", whoami, NULL); 534 resolv_decode(); 535 resolv_get_txt_data(); 536 537 /* 538 * This is a bit different than what we 539 * do in get_dns_txt_domain(). Here, the 540 * thread _must_ update the global state 541 * if a new TXT record was found. 542 */ 543 (void) rw_rdlock(&dns_data_lock); 544 if (dns_txt_domain_len != 0) { 545 /* 546 * Update global state and only 547 * flush the cache if there were 548 * any updates to cur_domain 549 */ 550 (void) rw_wrlock(&domain_cfg_lock); 551 (void) strncpy(cur_domain, 552 dns_txt_domain, 553 DNAMEMAX-1); 554 cur_domain_len = dns_txt_domain_len; 555 update_diag_file(cur_domain); 556 DTRACE_PROBE1(nfsmapid, thread__domain, 557 cur_domain); 558 (void) rw_unlock(&domain_cfg_lock); 559 idmap_kcall(-1); 560 } 561 (void) rw_unlock(&dns_data_lock); 562 goto thr_okay; 563 564 case NO_DATA: 565 /* 566 * DNS is up now, but does not have 567 * the NFSV4IDMAPDOMAIN TXT record. 568 */ 569 IDMAP_DBG("%s: DNS has no TXT Record", whoami, 570 NULL); 571 goto thr_reset; 572 573 case NO_RECOVERY: 574 /* 575 * Non-Recoverable error occurred. No sense 576 * in keep pinging the DNS server at this 577 * point, so we disable any further contact. 578 */ 579 IDMAP_DBG(EMSG_DNS_DISABLE, whoami, NULL); 580 (void) rw_wrlock(&s_dns_impl_lock); 581 s_dns_disabled = TRUE; 582 (void) rw_unlock(&s_dns_impl_lock); 583 goto thr_reset; 584 585 case HOST_NOT_FOUND: 586 /* 587 * Authoritative NS not responding... 588 * keep trying for non-authoritative reply 589 */ 590 /*FALLTHROUGH*/ 591 592 case TRY_AGAIN: 593 /* keep trying */ 594 IDMAP_DBG("%s: retrying...", whoami, NULL); 595 break; 596 597 case NETDB_INTERNAL: 598 default: 599 IDMAP_DBG("%s: Internal resolver error: %s", 600 whoami, strerror(errno)); 601 goto thr_reset; 602 } 603 } 604 thr_reset: 605 (void) rw_wrlock(&dns_data_lock); 606 dns_txt_cached = 0; 607 (void) rw_unlock(&dns_data_lock); 608 resolv_txt_reset(); 609 610 thr_okay: 611 /* mark thread as done */ 612 (void) rw_wrlock(&s_dns_impl_lock); 613 s_dns_qthr_created = FALSE; 614 (void) rw_unlock(&s_dns_impl_lock); 615 616 (void) thr_exit(NULL); 617 /*NOTREACHED*/ 618 return (NULL); 619 } 620 621 /* 622 * nfsmapid's interface into the resolver for getting the TXT record. 623 * 624 * Key concepts: 625 * 626 * o If the DNS server is available and the TXT record is found, we 627 * simply decode the output and fill the exported dns_txt_domain 628 * global, so our caller can configure the daemon appropriately. 629 * 630 * o If the TXT record is not found, then having done resolv_txt_reset() 631 * first will allow our caller to recognize that the exported globals 632 * are empty and thus configure nfsmapid to use the default DNS domain. 633 * 634 * o Having no /etc/resolv.conf file is pretty much a show stopper, since 635 * there is no name server address information. We return since we've 636 * already have reset the TXT global state. 637 * 638 * o If a previous call to the DNS server resulted in an unrecoverable 639 * error, then we disable further contact to the DNS server and return. 640 * Having the TXT global state already reset guarantees that our caller 641 * will fall back to the right configuration. 642 * 643 * o Query thread creation is throttled by s_dns_qthr_created. We mitigate 644 * the problem of an already unresponsive DNS server by allowing at most 645 * 1 outstanding query thread since we could potentially have a substantial 646 * amount of clients hammering on the same DNS server attempting to get 647 * the TXT record. 648 */ 649 void 650 get_dns_txt_domain(int sighup) 651 { 652 int err; 653 #ifdef DEBUG 654 static uint64_t msg_done = 0; 655 char *whoami = "get_dns_txt_domain"; 656 #endif 657 long thr_flags = THR_DETACHED; 658 struct stat st; 659 660 /* 661 * We reset TXT variables first in case /etc/resolv.conf 662 * is missing or we've had unrecoverable resolver errors, 663 * we'll default to get_dns_domain(). If a previous DNS 664 * TXT RR was found, don't clear it until we're certain 665 * that contact can be made to the DNS server (see block 666 * comment atop resolv_txt_reset). If we're responding to 667 * a SIGHUP signal, force a reset of the cached copy. 668 */ 669 if (sighup) { 670 (void) rw_wrlock(&dns_data_lock); 671 dns_txt_cached = 0; 672 (void) rw_unlock(&dns_data_lock); 673 } 674 resolv_txt_reset(); 675 676 errno = 0; 677 if (stat(_PATH_RESCONF, &st) < 0 && errno == ENOENT) { 678 /* 679 * If /etc/resolv.conf is not there, then we'll 680 * get the domain from domainname(1M). No real 681 * reason to query DNS or fire a thread since we 682 * have no nameserver addresses. 683 */ 684 goto txtclear; 685 } 686 687 (void) rw_rdlock(&s_dns_impl_lock); 688 if (s_dns_disabled) { 689 /* 690 * If there were non-recoverable problems with DNS, 691 * we have stopped querying DNS entirely. See 692 * NO_RECOVERY clause below. 693 */ 694 IDMAP_DBG("%s: DNS queries disabled", whoami, NULL); 695 (void) rw_unlock(&s_dns_impl_lock); 696 return; 697 } 698 (void) rw_unlock(&s_dns_impl_lock); 699 700 (void) resolv_init(); 701 switch (resolv_search()) { 702 case NETDB_SUCCESS: 703 /* 704 * If there _is_ a TXT record, we let 705 * our caller set the global state. 706 */ 707 resolv_decode(); 708 resolv_get_txt_data(); 709 return; 710 711 case TRY_AGAIN: 712 (void) rw_wrlock(&s_dns_impl_lock); 713 if (s_dns_qthr_created) { 714 /* 715 * We may have lots of clients, so we don't 716 * want to bog down the DNS server with tons 717 * of requests... lest it becomes even more 718 * unresponsive, so limit 1 thread to query 719 * DNS at a time. 720 */ 721 IDMAP_DBG("%s: query thread already active", 722 whoami, NULL); 723 (void) rw_unlock(&s_dns_impl_lock); 724 return; 725 } 726 727 /* 728 * DNS did not respond ! Set timeout and kick off 729 * thread to try op again after s_dns_tout seconds. 730 * We've made sure that we don't have an already 731 * running thread above. 732 */ 733 s_dns_tout = NFSMAPID_DNS_TOUT_SECS; 734 err = thr_create(NULL, 0, resolv_query_thread, NULL, 735 thr_flags, &s_dns_qthread); 736 if (!err) { 737 s_dns_qthr_created = TRUE; 738 } 739 #ifdef DEBUG 740 else { 741 msg_done++; 742 if (!(msg_done % NFSMAPID_SLOG_RATE)) 743 IDMAP_DBG(EMSG_DNS_THREAD_ERROR, NULL, 744 NULL); 745 } 746 #endif 747 (void) rw_unlock(&s_dns_impl_lock); 748 return; 749 750 case NO_RECOVERY: 751 IDMAP_DBG(EMSG_DNS_DISABLE, whoami, NULL); 752 (void) rw_wrlock(&s_dns_impl_lock); 753 s_dns_disabled = TRUE; 754 (void) rw_unlock(&s_dns_impl_lock); 755 756 /*FALLTHROUGH*/ 757 default: 758 /* 759 * For any other errors... DNS is responding, but 760 * either it has no data, or some other problem is 761 * occuring. At any rate, the TXT domain should not 762 * be used, so we default to the DNS domain. 763 */ 764 break; 765 } 766 767 txtclear: 768 (void) rw_wrlock(&dns_data_lock); 769 dns_txt_cached = 0; 770 (void) rw_unlock(&dns_data_lock); 771 resolv_txt_reset(); 772 } 773