18200fe25Srmesta /* 28200fe25Srmesta * CDDL HEADER START 38200fe25Srmesta * 48200fe25Srmesta * The contents of this file are subject to the terms of the 58200fe25Srmesta * Common Development and Distribution License (the "License"). 68200fe25Srmesta * You may not use this file except in compliance with the License. 78200fe25Srmesta * 88200fe25Srmesta * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98200fe25Srmesta * or http://www.opensolaris.org/os/licensing. 108200fe25Srmesta * See the License for the specific language governing permissions 118200fe25Srmesta * and limitations under the License. 128200fe25Srmesta * 138200fe25Srmesta * When distributing Covered Code, include this CDDL HEADER in each 148200fe25Srmesta * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158200fe25Srmesta * If applicable, add the following below this CDDL HEADER, with the 168200fe25Srmesta * fields enclosed by brackets "[]" replaced with your own identifying 178200fe25Srmesta * information: Portions Copyright [yyyy] [name of copyright owner] 188200fe25Srmesta * 198200fe25Srmesta * CDDL HEADER END 208200fe25Srmesta */ 218200fe25Srmesta /* 22*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 238200fe25Srmesta */ 248200fe25Srmesta 258200fe25Srmesta /* 268200fe25Srmesta * PSARC/2004/154 nfsmapid DNS enhancements implementation. 278200fe25Srmesta * 288200fe25Srmesta * As per RFC 3530, file owner and group attributes in version 4 of the 298200fe25Srmesta * NFS protocol are no longer exchanged between client and server as 32 308200fe25Srmesta * bit integral values. Instead, owner and group file attributes are 318200fe25Srmesta * exchanged between client and server as UTF8 strings of form 328200fe25Srmesta * 338200fe25Srmesta * 'user@domain' (ie. "joeblow@central.sun.com") 348200fe25Srmesta * 'group@domain' (ie. "staff@central.sun.com") 358200fe25Srmesta * 368200fe25Srmesta * This NFSv4 feature is far beyond anything NFSv2/v3 ever provided, as 378200fe25Srmesta * being able to describe a user with a unique string identifier provides 388200fe25Srmesta * a much more powerful and administrative friendly way of dealing with 398200fe25Srmesta * overlaps in the uid/gid number spaces. That notwithstanding, dealing 408200fe25Srmesta * with issues of correctly mapping user and group ownership in a cross- 418200fe25Srmesta * domain environment has proven a difficult problem to solve, since 428200fe25Srmesta * dealing with different permutations of client naming configurations 438200fe25Srmesta * (ie. NIS only, LDAP only, etc.) have bloated the problem. Thus, users 448200fe25Srmesta * utilizing clients and servers that have the 'domain' portion of the 458200fe25Srmesta * UTF8 attribute string configured differently than its peer server and 468200fe25Srmesta * client accordingly, will experience watching their files owned by the 478200fe25Srmesta * 'nobody' user and group. This is due to the fact that the 'domain's 488200fe25Srmesta * don't match and the nfsmapid daemon treats the attribute strings as 498200fe25Srmesta * unknown user(s) or group(s) (even though the actual uid/gid's may exist 508200fe25Srmesta * in the executing daemon's system). Please refer to PSARC/2004/154 for 518200fe25Srmesta * further background and motivation for these enhancements. 528200fe25Srmesta * 538200fe25Srmesta * The latest implementation of the nfsmapid daemon relies on a DNS TXT 548200fe25Srmesta * record. The behavior of nfsmapid is to first use the NFSMAPID_DOMAIN 558200fe25Srmesta * configuration option in /etc/default/nfs. If the option has not been 568200fe25Srmesta * set, then the nfsmapid daemon queries the configured DNS domain server 578200fe25Srmesta * for the _nfsv4idmapdomain TXT record. If the record exists, then the 588200fe25Srmesta * record's value is used as the 'domain' portion of the UTF8 attribute 598200fe25Srmesta * strings. If the TXT record has not been configured in the DNS server, 608200fe25Srmesta * then the daemon falls back to using the DNS domain name itself as the 618200fe25Srmesta * 'domain' portion of the attribute strings. Lastly, if the configured 628200fe25Srmesta * DNS server is unresponsive, the nfsmapid daemon falls back to using 638200fe25Srmesta * the DNS domain name as the 'domain' portion of the attribute strings, 648200fe25Srmesta * and fires up a query thread to keep contacting the DNS server until 658200fe25Srmesta * it responds with either a TXT record, or a lack thereof, in which 668200fe25Srmesta * case, nfsmapid just continues to utilize the DNS domain name. 678200fe25Srmesta */ 688200fe25Srmesta #define __LIBMAPID_IMPL 698200fe25Srmesta #include <nfs/mapid.h> 70*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libshare.h> 71*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h> 72*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h> 73*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <rpcsvc/daemon_utils.h> 74*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h" 75*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 768200fe25Srmesta #pragma init(_lib_init) 776d9307f9SVallish Vaidyeshwara #pragma fini(_lib_fini) 788200fe25Srmesta 798200fe25Srmesta /* 808200fe25Srmesta * DEBUG Only 818200fe25Srmesta * Decode any resolver errors and print out message to log 828200fe25Srmesta */ 838200fe25Srmesta static int 848200fe25Srmesta resolv_error(void) 858200fe25Srmesta { 868200fe25Srmesta #ifndef DEBUG 878200fe25Srmesta 888200fe25Srmesta return (h_errno); 898200fe25Srmesta 908200fe25Srmesta #else /* DEBUG */ 918200fe25Srmesta 928200fe25Srmesta static uint64_t msg_done[NS_ERRS] = {0}; 938200fe25Srmesta 948200fe25Srmesta switch (h_errno) { 958200fe25Srmesta case NETDB_INTERNAL: 968200fe25Srmesta syslog(LOG_ERR, EMSG_NETDB_INTERNAL, strerror(errno)); 978200fe25Srmesta break; 988200fe25Srmesta 998200fe25Srmesta case HOST_NOT_FOUND: 1008200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 1018200fe25Srmesta msg_done[h_errno]++; 1028200fe25Srmesta if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 1038200fe25Srmesta syslog(LOG_ERR, EMSG_HOST_NOT_FOUND, s_dname); 1048200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 1058200fe25Srmesta break; 1068200fe25Srmesta 1078200fe25Srmesta case TRY_AGAIN: 1088200fe25Srmesta /* 1098200fe25Srmesta * Nameserver is not responding. 1108200fe25Srmesta * Try again after a given timeout. 1118200fe25Srmesta */ 1128200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 1138200fe25Srmesta msg_done[h_errno]++; 1148200fe25Srmesta if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 1158200fe25Srmesta syslog(LOG_ERR, EMSG_TRY_AGAIN, s_dname); 1168200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 1178200fe25Srmesta break; 1188200fe25Srmesta 1198200fe25Srmesta case NO_RECOVERY: 1208200fe25Srmesta /* 1218200fe25Srmesta * This msg only really happens once, due 1228200fe25Srmesta * to s_dns_disabled flag (see below) 1238200fe25Srmesta */ 1248200fe25Srmesta syslog(LOG_ERR, EMSG_NO_RECOVERY, hstrerror(h_errno)); 1258200fe25Srmesta break; 1268200fe25Srmesta 1278200fe25Srmesta case NO_DATA: 1288200fe25Srmesta /* 1298200fe25Srmesta * No entries in the nameserver for 1308200fe25Srmesta * the specific record or record type. 1318200fe25Srmesta */ 1328200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 1338200fe25Srmesta msg_done[h_errno]++; 1348200fe25Srmesta if (!(msg_done[h_errno] % NFSMAPID_SLOG_RATE)) 1358200fe25Srmesta syslog(LOG_ERR, EMSG_NO_DATA, NFSMAPID_DNS_RR, s_dname); 1368200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 1378200fe25Srmesta break; 1388200fe25Srmesta 1398200fe25Srmesta case NETDB_SUCCESS: 1408200fe25Srmesta default: 1418200fe25Srmesta break; 1428200fe25Srmesta } 1438200fe25Srmesta return (h_errno); 1448200fe25Srmesta 1458200fe25Srmesta #endif /* DEBUG */ 1468200fe25Srmesta } 1478200fe25Srmesta 1488200fe25Srmesta /* 1498200fe25Srmesta * Reset the global state variables used for the TXT record. 1508200fe25Srmesta * Having these values reset to zero helps nfsmapid confirm 1518200fe25Srmesta * that a valid DNS TXT record was not found; in which case, 1528200fe25Srmesta * it would fall back to using the configured DNS domain name. 1538200fe25Srmesta * 1548200fe25Srmesta * If a valid DNS TXT record _was_ found, but subsequent contact 1558200fe25Srmesta * to the DNS server is somehow hindered, the previous DNS TXT 1568200fe25Srmesta * RR value continues to be used. Thus, in such instances, we 1578200fe25Srmesta * forego clearing the global config variables so nfsmapid can 1588200fe25Srmesta * continue to use a valid DNS TXT RR while contact to the DNS 1598200fe25Srmesta * server is reestablished. 1608200fe25Srmesta */ 1618200fe25Srmesta static void 1628200fe25Srmesta resolv_txt_reset(void) 1638200fe25Srmesta { 1648200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 1658200fe25Srmesta bzero(s_txt_rr, sizeof (s_txt_rr)); 1668200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 1678200fe25Srmesta 1688200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 1698200fe25Srmesta if (!dns_txt_cached) { 1708200fe25Srmesta dns_txt_domain_len = 0; 1718200fe25Srmesta bzero(dns_txt_domain, DNAMEMAX); 1728200fe25Srmesta } 1738200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 1748200fe25Srmesta } 1758200fe25Srmesta 1768200fe25Srmesta /* 1778200fe25Srmesta * Initialize resolver and populate &s_res struct 1788200fe25Srmesta * 1798200fe25Srmesta * DNS Domain is saved off sysdns_domain in case we 1808200fe25Srmesta * need to fall back to using the DNS domain name as 1818200fe25Srmesta * the v4 attribute string domain. 1828200fe25Srmesta */ 1838200fe25Srmesta static int 1848200fe25Srmesta resolv_init(void) 1858200fe25Srmesta { 1868200fe25Srmesta size_t len; 1878200fe25Srmesta int n; 1888200fe25Srmesta struct __res_state res; 1898200fe25Srmesta 1908200fe25Srmesta (void) mutex_lock(&s_res_lock); 1918200fe25Srmesta bzero(&s_res, sizeof (struct __res_state)); 1928200fe25Srmesta n = h_errno = errno = 0; 1938200fe25Srmesta if ((n = res_ninit(&s_res)) < 0) { 1948200fe25Srmesta (void) mutex_unlock(&s_res_lock); 1958200fe25Srmesta (void) resolv_error(); 1968200fe25Srmesta return (n); 1978200fe25Srmesta } 1988200fe25Srmesta res = s_res; 1998200fe25Srmesta (void) mutex_unlock(&s_res_lock); 2008200fe25Srmesta 2018200fe25Srmesta len = strlen(res.defdname) + 1; 2028200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 2038200fe25Srmesta bzero(s_dname, sizeof (s_dname)); 2048200fe25Srmesta (void) snprintf(s_dname, len, "%s", res.defdname); 2058200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 2068200fe25Srmesta 2078200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 2088200fe25Srmesta (void) snprintf(sysdns_domain, len, "%s", res.defdname); 2098200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 2108200fe25Srmesta 2118200fe25Srmesta return (0); 2128200fe25Srmesta } 2138200fe25Srmesta 2148200fe25Srmesta /* 2158200fe25Srmesta * Search criteria assumptions: 2168200fe25Srmesta * 2178200fe25Srmesta * The onus will fall on the sysadmins to correctly configure the TXT 2188200fe25Srmesta * record in the DNS domain where the box currently resides in order 2198200fe25Srmesta * for the record to be found. However, if they sysadmin chooses to 2208200fe25Srmesta * add the 'search' key to /etc/resolv.conf, then resolv_search() 2218200fe25Srmesta * _will_ traverse up the DNS tree as specified in the 'search' key. 2228200fe25Srmesta * Otherwise, we'll default the domain to the DNS domain itself. 2238200fe25Srmesta */ 2248200fe25Srmesta static int 2258200fe25Srmesta resolv_search(void) 2268200fe25Srmesta { 2278200fe25Srmesta int len; 2288200fe25Srmesta ans_t ans = {0}; 2298200fe25Srmesta struct __res_state res; 2308200fe25Srmesta int type = T_TXT; 2318200fe25Srmesta int class = C_IN; 2328200fe25Srmesta 2338200fe25Srmesta (void) mutex_lock(&s_res_lock); 2348200fe25Srmesta res = s_res; 2358200fe25Srmesta (void) mutex_unlock(&s_res_lock); 2368200fe25Srmesta 2378200fe25Srmesta /* 2388200fe25Srmesta * Avoid holding locks across the res_nsearch() call to 2398200fe25Srmesta * prevent stalling threads during network partitions. 2408200fe25Srmesta */ 2418200fe25Srmesta len = h_errno = errno = 0; 2428200fe25Srmesta if ((len = res_nsearch(&res, NFSMAPID_DNS_RR, class, type, 2438200fe25Srmesta ans.buf, sizeof (ans))) < 0) 2448200fe25Srmesta return (resolv_error()); 2458200fe25Srmesta 2468200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 2478200fe25Srmesta s_ans = ans; 2488200fe25Srmesta s_anslen = len; 2498200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 2508200fe25Srmesta 2518200fe25Srmesta return (NETDB_SUCCESS); 2528200fe25Srmesta } 2538200fe25Srmesta 2548200fe25Srmesta /* 255bfa62c28SVallish Vaidyeshwara * Free all resolver state information stored in s_res 256bfa62c28SVallish Vaidyeshwara */ 257bfa62c28SVallish Vaidyeshwara static void 258bfa62c28SVallish Vaidyeshwara resolv_destroy(void) 259bfa62c28SVallish Vaidyeshwara { 260bfa62c28SVallish Vaidyeshwara (void) mutex_lock(&s_res_lock); 261bfa62c28SVallish Vaidyeshwara res_ndestroy(&s_res); 262bfa62c28SVallish Vaidyeshwara (void) mutex_unlock(&s_res_lock); 263bfa62c28SVallish Vaidyeshwara } 264bfa62c28SVallish Vaidyeshwara 265bfa62c28SVallish Vaidyeshwara /* 2668200fe25Srmesta * Skip one DNS record 2678200fe25Srmesta */ 2688200fe25Srmesta static uchar_t * 2698200fe25Srmesta resolv_skip_rr(uchar_t *p, uchar_t *eom) 2708200fe25Srmesta { 2718200fe25Srmesta int t; 2728200fe25Srmesta int dlen; 2738200fe25Srmesta 2748200fe25Srmesta /* 2758200fe25Srmesta * Skip compressed name 2768200fe25Srmesta */ 2778200fe25Srmesta errno = 0; 2788200fe25Srmesta if ((t = dn_skipname(p, eom)) < 0) { 2798200fe25Srmesta #ifdef DEBUG 2808200fe25Srmesta syslog(LOG_ERR, "%s", strerror(errno)); 2818200fe25Srmesta #endif 2828200fe25Srmesta return (NULL); 2838200fe25Srmesta } 2848200fe25Srmesta 2858200fe25Srmesta /* 2868200fe25Srmesta * Advance pointer and make sure 2878200fe25Srmesta * we're still within the message 2888200fe25Srmesta */ 2898200fe25Srmesta p += t; 2908200fe25Srmesta if ((p + RRFIXEDSZ) > eom) 2918200fe25Srmesta return (NULL); 2928200fe25Srmesta 2938200fe25Srmesta /* 2948200fe25Srmesta * Now, just skip over the rr fields 2958200fe25Srmesta */ 2968200fe25Srmesta p += INT16SZ; /* type */ 2978200fe25Srmesta p += INT16SZ; /* class */ 2988200fe25Srmesta p += INT32SZ; /* ttl */ 2998200fe25Srmesta dlen = ns_get16(p); 3008200fe25Srmesta p += INT16SZ; 3018200fe25Srmesta p += dlen; /* dlen */ 3028200fe25Srmesta if (p > eom) 3038200fe25Srmesta return (NULL); 3048200fe25Srmesta 3058200fe25Srmesta return (p); 3068200fe25Srmesta } 3078200fe25Srmesta 3088200fe25Srmesta /* 3098200fe25Srmesta * Process one TXT record. 3108200fe25Srmesta * 3118200fe25Srmesta * nfsmapid queries the DNS server for the specific _nfsv4idmapdomain 3128200fe25Srmesta * TXT record. Thus, if the TXT record exists, the answer section of 3138200fe25Srmesta * the DNS response carries the TXT record's value. Thus, we check that 3148200fe25Srmesta * the value is indeed a valid domain and set the modular s_txt_rr 3158200fe25Srmesta * global to the domain value. 3168200fe25Srmesta */ 3178200fe25Srmesta static void 3188200fe25Srmesta resolve_process_txt(uchar_t *p, int dlen) 3198200fe25Srmesta { 3208200fe25Srmesta char *rr_base = (char *)(p + 1); 3218200fe25Srmesta char *rr_end = (char *)(p + dlen); 3228200fe25Srmesta size_t len = rr_end - rr_base; 3238200fe25Srmesta #ifdef DEBUG 3248200fe25Srmesta static uint64_t msg_done = 0; 3258200fe25Srmesta #endif 3268200fe25Srmesta char tmp_txt_rr[DNAMEMAX]; 3278200fe25Srmesta 3288200fe25Srmesta if (len >= DNAMEMAX) 3298200fe25Srmesta return; /* process next TXT RR */ 3308200fe25Srmesta 3318200fe25Srmesta /* 3328200fe25Srmesta * make sure we have a clean buf since 3338200fe25Srmesta * we may've processed several TXT rr's 3348200fe25Srmesta */ 3358200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 3368200fe25Srmesta bzero(s_txt_rr, sizeof (s_txt_rr)); 3378200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 3388200fe25Srmesta 3398200fe25Srmesta (void) strncpy(tmp_txt_rr, rr_base, len); 3408200fe25Srmesta tmp_txt_rr[len] = '\0'; 3418200fe25Srmesta 3428200fe25Srmesta /* 3438200fe25Srmesta * If there is a record and it's a valid domain, we're done. 3448200fe25Srmesta */ 3458200fe25Srmesta if (rr_base[0] != '\0' && mapid_stdchk_domain(tmp_txt_rr) > 0) { 3468200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 3478200fe25Srmesta (void) strncpy(s_txt_rr, rr_base, len); 3488200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 3498200fe25Srmesta #ifdef DEBUG 3508200fe25Srmesta syslog(LOG_ERR, "TXT (Rec):\t%s", s_txt_rr); 3518200fe25Srmesta 3528200fe25Srmesta } else if (!(msg_done++ % NFSMAPID_SLOG_RATE)) { 3538200fe25Srmesta /* 3548200fe25Srmesta * Otherwise, log the error 3558200fe25Srmesta */ 3568200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 3578200fe25Srmesta syslog(LOG_ERR, EMSG_DNS_RR_INVAL, NFSMAPID_DNS_RR, s_dname); 3588200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 3598200fe25Srmesta #endif 3608200fe25Srmesta } 3618200fe25Srmesta } 3628200fe25Srmesta 3638200fe25Srmesta /* 3648200fe25Srmesta * Decode any answer received from the DNS server. This interface is 3658200fe25Srmesta * capable of much more than just decoding TXT records. We maintain 3668200fe25Srmesta * focus on TXT rr's for now, but this will probably change once we 3678200fe25Srmesta * get the IETF approved application specific DNS RR. 3688200fe25Srmesta * 3698200fe25Srmesta * Here's an example of the TXT record we're decoding (as would appear 3708200fe25Srmesta * in the DNS zone file): 3718200fe25Srmesta * 3728200fe25Srmesta * _nfsv4idmapdomain IN TXT "sun.com" 3738200fe25Srmesta * 3748200fe25Srmesta * Once the IETF application specific DNS RR is granted, we should only 3758200fe25Srmesta * be changing the record flavor, but all should pretty much stay the 3768200fe25Srmesta * same. 3778200fe25Srmesta */ 3788200fe25Srmesta static void 3798200fe25Srmesta resolv_decode(void) 3808200fe25Srmesta { 3818200fe25Srmesta uchar_t *buf; 3828200fe25Srmesta HEADER *hp; 3838200fe25Srmesta uchar_t name[DNAMEMAX]; 3848200fe25Srmesta uchar_t *eom; 3858200fe25Srmesta uchar_t *p; 3868200fe25Srmesta int n; 3878200fe25Srmesta uint_t qd_cnt; 3888200fe25Srmesta uint_t an_cnt; 3898200fe25Srmesta uint_t ns_cnt; 3908200fe25Srmesta uint_t ar_cnt; 3918200fe25Srmesta uint_t cnt; 3928200fe25Srmesta uint_t type; 3938200fe25Srmesta int dlen; 3948200fe25Srmesta ans_t answer = {0}; 3958200fe25Srmesta int answer_len = 0; 3968200fe25Srmesta 3978200fe25Srmesta /* 3988200fe25Srmesta * Check the HEADER for any signs of errors 3998200fe25Srmesta * and extract the answer counts for later. 4008200fe25Srmesta */ 4018200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 4028200fe25Srmesta answer = s_ans; 4038200fe25Srmesta answer_len = s_anslen; 4048200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 4058200fe25Srmesta 4068200fe25Srmesta buf = (uchar_t *)&answer.buf; 4078200fe25Srmesta hp = (HEADER *)&answer.hdr; 4088200fe25Srmesta eom = (uchar_t *)(buf + answer_len); 4098200fe25Srmesta if (hp->rcode != NOERROR) { 4108200fe25Srmesta #ifdef DEBUG 4118200fe25Srmesta syslog(LOG_ERR, "errno: %s", strerror(errno)); 4128200fe25Srmesta syslog(LOG_ERR, "h_errno: %s", hstrerror(h_errno)); 4138200fe25Srmesta #endif 4148200fe25Srmesta return; 4158200fe25Srmesta } 4168200fe25Srmesta qd_cnt = ntohs(hp->qdcount); 4178200fe25Srmesta an_cnt = ntohs(hp->ancount); 4188200fe25Srmesta ns_cnt = ntohs(hp->nscount); 4198200fe25Srmesta ar_cnt = ntohs(hp->arcount); 4208200fe25Srmesta 4218200fe25Srmesta /* 4228200fe25Srmesta * skip query entries 4238200fe25Srmesta */ 4248200fe25Srmesta p = (uchar_t *)(buf + HFIXEDSZ); 4258200fe25Srmesta errno = 0; 4268200fe25Srmesta while (qd_cnt-- > 0) { 4278200fe25Srmesta n = dn_skipname(p, eom); 4288200fe25Srmesta if (n < 0) { 4298200fe25Srmesta #ifdef DEBUG 4308200fe25Srmesta syslog(LOG_ERR, "%s", strerror(errno)); 4318200fe25Srmesta #endif 4328200fe25Srmesta return; 4338200fe25Srmesta } 4348200fe25Srmesta p += n; 4358200fe25Srmesta p += INT16SZ; /* type */ 4368200fe25Srmesta p += INT16SZ; /* class */ 4378200fe25Srmesta } 4388200fe25Srmesta 4398200fe25Srmesta #ifdef DEBUG 4408200fe25Srmesta /* 4418200fe25Srmesta * If debugging... print query only once. 4428200fe25Srmesta * NOTE: Don't advance pointer... this is done 4438200fe25Srmesta * in while() loop on a per record basis ! 4448200fe25Srmesta */ 4458200fe25Srmesta n = h_errno = errno = 0; 4468200fe25Srmesta n = dn_expand(buf, eom, p, (char *)name, sizeof (name)); 4478200fe25Srmesta if (n < 0) { 4488200fe25Srmesta (void) resolv_error(); 4498200fe25Srmesta return; 4508200fe25Srmesta } 4518200fe25Srmesta syslog(LOG_ERR, "Query:\t\t%-30s", name); 4528200fe25Srmesta #endif 4538200fe25Srmesta 4548200fe25Srmesta /* 4558200fe25Srmesta * Process actual answer(s). 4568200fe25Srmesta */ 4578200fe25Srmesta cnt = an_cnt; 4588200fe25Srmesta while (cnt-- > 0 && p < eom) { 4598200fe25Srmesta /* skip the name field */ 4608200fe25Srmesta n = dn_expand(buf, eom, p, (char *)name, sizeof (name)); 4618200fe25Srmesta if (n < 0) { 4628200fe25Srmesta (void) resolv_error(); 4638200fe25Srmesta return; 4648200fe25Srmesta } 4658200fe25Srmesta p += n; 4668200fe25Srmesta 4678200fe25Srmesta if ((p + 3 * INT16SZ + INT32SZ) > eom) 4688200fe25Srmesta return; 4698200fe25Srmesta 4708200fe25Srmesta type = ns_get16(p); 4718200fe25Srmesta p += INT16SZ; 4728200fe25Srmesta p += INT16SZ + INT32SZ; /* skip class & ttl */ 4738200fe25Srmesta dlen = ns_get16(p); 4748200fe25Srmesta p += INT16SZ; 4758200fe25Srmesta 4768200fe25Srmesta if ((p + dlen) > eom) 4778200fe25Srmesta return; 4788200fe25Srmesta 4798200fe25Srmesta switch (type) { 4808200fe25Srmesta case T_TXT: 4818200fe25Srmesta resolve_process_txt(p, dlen); 4828200fe25Srmesta break; 4838200fe25Srmesta 4848200fe25Srmesta default: 4858200fe25Srmesta /* 4868200fe25Srmesta * Advance to next answer record for any 4878200fe25Srmesta * other record types. Again, this will 4888200fe25Srmesta * probably change (see block comment). 4898200fe25Srmesta */ 4908200fe25Srmesta p += dlen; 4918200fe25Srmesta break; 4928200fe25Srmesta } 4938200fe25Srmesta } 4948200fe25Srmesta 4958200fe25Srmesta /* 4968200fe25Srmesta * Skip name server and additional records for now. 4978200fe25Srmesta */ 4988200fe25Srmesta cnt = ns_cnt + ar_cnt; 4998200fe25Srmesta if (cnt > 0) { 5008200fe25Srmesta while (--cnt != 0 && p < eom) { 5018200fe25Srmesta p = resolv_skip_rr(p, eom); 5028200fe25Srmesta if (p == NULL) 5038200fe25Srmesta return; 5048200fe25Srmesta } 5058200fe25Srmesta } 5068200fe25Srmesta } 5078200fe25Srmesta 5088200fe25Srmesta /* 5098200fe25Srmesta * If a valid TXT record entry exists, s_txt_rr contains the domain 5108200fe25Srmesta * value (as set in resolv_process_txt) and we extract the value into 5118200fe25Srmesta * dns_txt_domain (the exported global). If there was _no_ valid TXT 5128200fe25Srmesta * entry, we simply return and check_domain() will default to the 5138200fe25Srmesta * DNS domain since we did resolv_txt_reset() first. 5148200fe25Srmesta */ 5158200fe25Srmesta static void 5168200fe25Srmesta resolv_get_txt_data() 5178200fe25Srmesta { 5188200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 5198200fe25Srmesta if (s_txt_rr[0] != '\0') { 5208200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 5218200fe25Srmesta (void) snprintf(dns_txt_domain, strlen(s_txt_rr) + 1, "%s", 5228200fe25Srmesta s_txt_rr); 5238200fe25Srmesta dns_txt_domain_len = strlen(dns_txt_domain); 5248200fe25Srmesta dns_txt_cached = 1; 5258200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 5268200fe25Srmesta } 5278200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 5288200fe25Srmesta } 5298200fe25Srmesta 5308200fe25Srmesta static void 5318200fe25Srmesta domain_sync(cb_t *argp, char *dname) 5328200fe25Srmesta { 5338200fe25Srmesta int dlen = 0; 5348200fe25Srmesta void *(*fcn)(void *) = NULL; 5358200fe25Srmesta int sighup = 0; 5368200fe25Srmesta int domchg = 0; 5378200fe25Srmesta 5388200fe25Srmesta /* 5398200fe25Srmesta * Make sure values passed are sane and initialize accordingly. 5408200fe25Srmesta */ 5418200fe25Srmesta if (dname != NULL) 5428200fe25Srmesta dlen = strlen(dname); 5438200fe25Srmesta if (argp) { 5448200fe25Srmesta if (argp->fcn) 5458200fe25Srmesta fcn = argp->fcn; 5468200fe25Srmesta if (argp->signal) 5478200fe25Srmesta sighup = argp->signal; 5488200fe25Srmesta } 5498200fe25Srmesta 5508200fe25Srmesta /* 5518200fe25Srmesta * Update the library's mapid_domain variable if 'dname' is different. 5528200fe25Srmesta */ 5538200fe25Srmesta if (dlen != 0 && strncasecmp(dname, mapid_domain, NS_MAXCDNAME)) { 5548200fe25Srmesta (void) rw_wrlock(&mapid_domain_lock); 5558200fe25Srmesta (void) strncpy(mapid_domain, dname, NS_MAXCDNAME); 5568200fe25Srmesta mapid_domain_len = dlen; 5578200fe25Srmesta (void) rw_unlock(&mapid_domain_lock); 5588200fe25Srmesta domchg++; 5598200fe25Srmesta } 5608200fe25Srmesta 5618200fe25Srmesta /* 5628200fe25Srmesta * If the caller gave us a valid callback routine, we 5638200fe25Srmesta * instantiate it to announce the domain change, but 5648200fe25Srmesta * only if either the domain changed _or_ the caller 5658200fe25Srmesta * was issued a SIGHUP. 5668200fe25Srmesta */ 5678200fe25Srmesta if (fcn != NULL && (sighup || domchg)) 5688200fe25Srmesta (void) fcn((void *)mapid_domain); 5698200fe25Srmesta } 5708200fe25Srmesta 5718200fe25Srmesta /* 5728200fe25Srmesta * Thread to keep pinging DNS server for TXT record if nfsmapid's 5738200fe25Srmesta * initial attempt at contact with server failed. We could potentially 5748200fe25Srmesta * have a substantial number of NFSv4 clients and having all of them 5758200fe25Srmesta * hammering on an already unresponsive DNS server would not help 5768200fe25Srmesta * things. So, we limit the number of live query threads to at most 5778200fe25Srmesta * 1 at any one time to keep things from getting out of hand. 5788200fe25Srmesta */ 5798200fe25Srmesta /* ARGSUSED */ 5808200fe25Srmesta static void * 5818200fe25Srmesta resolv_query_thread(void *arg) 5828200fe25Srmesta { 5838200fe25Srmesta unsigned int nap_time; 5848200fe25Srmesta 5858200fe25Srmesta #ifdef DEBUG 5868200fe25Srmesta char *whoami = "query_thread"; 5878200fe25Srmesta 5888200fe25Srmesta syslog(LOG_ERR, "%s active !", whoami); 5898200fe25Srmesta #endif 5908200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 5918200fe25Srmesta nap_time = s_dns_tout; 5928200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 5938200fe25Srmesta 5948200fe25Srmesta for (;;) { 5958200fe25Srmesta (void) sleep(nap_time); 5968200fe25Srmesta 5978200fe25Srmesta resolv_txt_reset(); 5986d9307f9SVallish Vaidyeshwara if (resolv_init() < 0) { 5996d9307f9SVallish Vaidyeshwara /* 6006d9307f9SVallish Vaidyeshwara * Failed to initialize resolver. Do not 6016d9307f9SVallish Vaidyeshwara * query DNS server. 6026d9307f9SVallish Vaidyeshwara */ 6036d9307f9SVallish Vaidyeshwara goto thr_reset; 6046d9307f9SVallish Vaidyeshwara } 6058200fe25Srmesta switch (resolv_search()) { 6068200fe25Srmesta case NETDB_SUCCESS: 6078200fe25Srmesta resolv_decode(); 6088200fe25Srmesta resolv_get_txt_data(); 6098200fe25Srmesta 6108200fe25Srmesta /* 6118200fe25Srmesta * This is a bit different than what we 6128200fe25Srmesta * do in get_dns_txt_domain(), where we 6138200fe25Srmesta * simply return and let the caller 6148200fe25Srmesta * access dns_txt_domain directly. 6158200fe25Srmesta * 6168200fe25Srmesta * Here we invoke the callback routine 6178200fe25Srmesta * provided by the caller to the 6188200fe25Srmesta * mapid_reeval_domain() interface via 6198200fe25Srmesta * the cb_t's fcn param. 6208200fe25Srmesta */ 6218200fe25Srmesta domain_sync((cb_t *)arg, dns_txt_domain); 6228200fe25Srmesta goto thr_okay; 6238200fe25Srmesta 6248200fe25Srmesta case NO_DATA: 6258200fe25Srmesta /* 6268200fe25Srmesta * DNS is up now, but does not have 6278200fe25Srmesta * the NFSV4IDMAPDOMAIN TXT record. 6288200fe25Srmesta */ 6298200fe25Srmesta #ifdef DEBUG 6308200fe25Srmesta syslog(LOG_ERR, "%s: DNS has no TXT Record", whoami); 6318200fe25Srmesta #endif 6328200fe25Srmesta goto thr_reset; 6338200fe25Srmesta 6348200fe25Srmesta case NO_RECOVERY: 6358200fe25Srmesta /* 6368200fe25Srmesta * Non-Recoverable error occurred. No sense 6378200fe25Srmesta * in keep pinging the DNS server at this 6388200fe25Srmesta * point, so we disable any further contact. 6398200fe25Srmesta */ 6408200fe25Srmesta #ifdef DEBUG 6418200fe25Srmesta syslog(LOG_ERR, EMSG_DNS_DISABLE, whoami); 6428200fe25Srmesta #endif 6438200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 6448200fe25Srmesta s_dns_disabled = TRUE; 6458200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 6468200fe25Srmesta goto thr_reset; 6478200fe25Srmesta 6488200fe25Srmesta case HOST_NOT_FOUND: 6498200fe25Srmesta /* 6508200fe25Srmesta * Authoritative NS not responding... 6518200fe25Srmesta * keep trying for non-authoritative reply 6528200fe25Srmesta */ 6538200fe25Srmesta /*FALLTHROUGH*/ 6548200fe25Srmesta 6558200fe25Srmesta case TRY_AGAIN: 6568200fe25Srmesta /* keep trying */ 6578200fe25Srmesta #ifdef DEBUG 6588200fe25Srmesta syslog(LOG_ERR, "%s: retrying...", whoami); 6598200fe25Srmesta #endif 6608200fe25Srmesta break; 6618200fe25Srmesta 6628200fe25Srmesta case NETDB_INTERNAL: 6638200fe25Srmesta default: 6648200fe25Srmesta #ifdef DEBUG 6658200fe25Srmesta syslog(LOG_ERR, "%s: Internal resolver error: %s", 6668200fe25Srmesta whoami, strerror(errno)); 6678200fe25Srmesta #endif 6688200fe25Srmesta goto thr_reset; 6698200fe25Srmesta } 670bfa62c28SVallish Vaidyeshwara 671bfa62c28SVallish Vaidyeshwara resolv_destroy(); 6728200fe25Srmesta } 6738200fe25Srmesta thr_reset: 6748200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 6758200fe25Srmesta dns_txt_cached = 0; 6768200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 6778200fe25Srmesta resolv_txt_reset(); 6788200fe25Srmesta 6798200fe25Srmesta thr_okay: 680bfa62c28SVallish Vaidyeshwara resolv_destroy(); 6818200fe25Srmesta /* mark thread as done */ 6828200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 6838200fe25Srmesta s_dns_qthr_created = FALSE; 6848200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 6858200fe25Srmesta 6868200fe25Srmesta (void) thr_exit(NULL); 6878200fe25Srmesta /*NOTREACHED*/ 6888200fe25Srmesta return (NULL); 6898200fe25Srmesta } 6908200fe25Srmesta 6918200fe25Srmesta /* 6928200fe25Srmesta * nfsmapid's interface into the resolver for getting the TXT record. 6938200fe25Srmesta * 6948200fe25Srmesta * Key concepts: 6958200fe25Srmesta * 6968200fe25Srmesta * o If the DNS server is available and the TXT record is found, we 6978200fe25Srmesta * simply decode the output and fill the exported dns_txt_domain 6988200fe25Srmesta * global, so our caller can configure the daemon appropriately. 6998200fe25Srmesta * 7008200fe25Srmesta * o If the TXT record is not found, then having done resolv_txt_reset() 7018200fe25Srmesta * first will allow our caller to recognize that the exported globals 7028200fe25Srmesta * are empty and thus configure nfsmapid to use the default DNS domain. 7038200fe25Srmesta * 7048200fe25Srmesta * o Having no /etc/resolv.conf file is pretty much a show stopper, since 7058200fe25Srmesta * there is no name server address information. We return since we've 7068200fe25Srmesta * already have reset the TXT global state. 7078200fe25Srmesta * 7088200fe25Srmesta * o If a previous call to the DNS server resulted in an unrecoverable 7098200fe25Srmesta * error, then we disable further contact to the DNS server and return. 7108200fe25Srmesta * Having the TXT global state already reset guarantees that our caller 7118200fe25Srmesta * will fall back to the right configuration. 7128200fe25Srmesta * 7138200fe25Srmesta * o Query thread creation is throttled by s_dns_qthr_created. We mitigate 7148200fe25Srmesta * the problem of an already unresponsive DNS server by allowing at most 7158200fe25Srmesta * 1 outstanding query thread since we could potentially have a substantial 7168200fe25Srmesta * amount of clients hammering on the same DNS server attempting to get 7178200fe25Srmesta * the TXT record. 7188200fe25Srmesta */ 7198200fe25Srmesta static void 7208200fe25Srmesta get_dns_txt_domain(cb_t *argp) 7218200fe25Srmesta { 7228200fe25Srmesta int err; 7238200fe25Srmesta #ifdef DEBUG 7248200fe25Srmesta static uint64_t msg_done = 0; 7258200fe25Srmesta char *whoami = "get_dns_txt_domain"; 7268200fe25Srmesta #endif 7278200fe25Srmesta long thr_flags = THR_DETACHED; 7288200fe25Srmesta struct stat st; 7298200fe25Srmesta 7308200fe25Srmesta /* 7318200fe25Srmesta * We reset TXT variables first in case /etc/resolv.conf 7328200fe25Srmesta * is missing or we've had unrecoverable resolver errors, 7338200fe25Srmesta * we'll default to get_dns_domain(). If a previous DNS 7348200fe25Srmesta * TXT RR was found, don't clear it until we're certain 7358200fe25Srmesta * that contact can be made to the DNS server (see block 7368200fe25Srmesta * comment atop resolv_txt_reset). If we're responding to 7378200fe25Srmesta * a SIGHUP signal, force a reset of the cached copy. 7388200fe25Srmesta */ 7398200fe25Srmesta if (argp && argp->signal) { 7408200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 7418200fe25Srmesta dns_txt_cached = 0; 7428200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 7438200fe25Srmesta } 7448200fe25Srmesta resolv_txt_reset(); 7458200fe25Srmesta 7468200fe25Srmesta errno = 0; 7478200fe25Srmesta if (stat(_PATH_RESCONF, &st) < 0 && errno == ENOENT) { 7488200fe25Srmesta /* 7498200fe25Srmesta * If /etc/resolv.conf is not there, then we'll 7508200fe25Srmesta * get the domain from domainname(1M). No real 7518200fe25Srmesta * reason to query DNS or fire a thread since we 7528200fe25Srmesta * have no nameserver addresses. 7538200fe25Srmesta */ 754bfa62c28SVallish Vaidyeshwara (void) rw_wrlock(&s_dns_data_lock); 755bfa62c28SVallish Vaidyeshwara dns_txt_cached = 0; 756bfa62c28SVallish Vaidyeshwara (void) rw_unlock(&s_dns_data_lock); 757bfa62c28SVallish Vaidyeshwara resolv_txt_reset(); 758bfa62c28SVallish Vaidyeshwara return; 7598200fe25Srmesta } 7608200fe25Srmesta 7618200fe25Srmesta (void) rw_rdlock(&s_dns_impl_lock); 7628200fe25Srmesta if (s_dns_disabled) { 7638200fe25Srmesta /* 7648200fe25Srmesta * If there were non-recoverable problems with DNS, 7658200fe25Srmesta * we have stopped querying DNS entirely. See 7668200fe25Srmesta * NO_RECOVERY clause below. 7678200fe25Srmesta */ 7688200fe25Srmesta #ifdef DEBUG 7698200fe25Srmesta syslog(LOG_ERR, "%s: DNS queries disabled", whoami); 7708200fe25Srmesta #endif 7718200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 7728200fe25Srmesta return; 7738200fe25Srmesta } 7748200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 7758200fe25Srmesta 7766d9307f9SVallish Vaidyeshwara if (resolv_init() < 0) { 7776d9307f9SVallish Vaidyeshwara /* 7786d9307f9SVallish Vaidyeshwara * Failed to initialize resolver. Do not 7796d9307f9SVallish Vaidyeshwara * query DNS server. 7806d9307f9SVallish Vaidyeshwara */ 7816d9307f9SVallish Vaidyeshwara (void) rw_wrlock(&s_dns_data_lock); 7826d9307f9SVallish Vaidyeshwara dns_txt_cached = 0; 7836d9307f9SVallish Vaidyeshwara (void) rw_unlock(&s_dns_data_lock); 7846d9307f9SVallish Vaidyeshwara resolv_txt_reset(); 7856d9307f9SVallish Vaidyeshwara return; 7866d9307f9SVallish Vaidyeshwara } 7878200fe25Srmesta switch (resolv_search()) { 7888200fe25Srmesta case NETDB_SUCCESS: 7898200fe25Srmesta /* 7908200fe25Srmesta * If there _is_ a TXT record, we let 7918200fe25Srmesta * our caller set the global state. 7928200fe25Srmesta */ 7938200fe25Srmesta resolv_decode(); 7948200fe25Srmesta resolv_get_txt_data(); 795bfa62c28SVallish Vaidyeshwara break; 7968200fe25Srmesta 7978200fe25Srmesta case TRY_AGAIN: 7988200fe25Srmesta if (argp == NULL || argp->fcn == NULL) 7998200fe25Srmesta /* 8008200fe25Srmesta * If no valid argument was passed or 8018200fe25Srmesta * callback defined, don't fire thread 8028200fe25Srmesta */ 803bfa62c28SVallish Vaidyeshwara break; 8048200fe25Srmesta 8058200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 8068200fe25Srmesta if (s_dns_qthr_created) { 8078200fe25Srmesta /* 8088200fe25Srmesta * We may have lots of clients, so we don't 8098200fe25Srmesta * want to bog down the DNS server with tons 8108200fe25Srmesta * of requests... lest it becomes even more 8118200fe25Srmesta * unresponsive, so limit 1 thread to query 8128200fe25Srmesta * DNS at a time. 8138200fe25Srmesta */ 8148200fe25Srmesta #ifdef DEBUG 8158200fe25Srmesta syslog(LOG_ERR, "%s: query thread already active", 8168200fe25Srmesta whoami); 8178200fe25Srmesta #endif 8188200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 819bfa62c28SVallish Vaidyeshwara break; 8208200fe25Srmesta } 8218200fe25Srmesta 8228200fe25Srmesta /* 8238200fe25Srmesta * DNS did not respond ! Set timeout and kick off 8248200fe25Srmesta * thread to try op again after s_dns_tout seconds. 8258200fe25Srmesta * We've made sure that we don't have an already 8268200fe25Srmesta * running thread above. 8278200fe25Srmesta */ 8288200fe25Srmesta s_dns_tout = NFSMAPID_DNS_TOUT_SECS; 8298200fe25Srmesta err = thr_create(NULL, 0, resolv_query_thread, (void *)argp, 8308200fe25Srmesta thr_flags, &s_dns_qthread); 8318200fe25Srmesta if (!err) { 8328200fe25Srmesta s_dns_qthr_created = TRUE; 8338200fe25Srmesta } 8348200fe25Srmesta #ifdef DEBUG 8358200fe25Srmesta else { 8368200fe25Srmesta msg_done++; 8378200fe25Srmesta if (!(msg_done % NFSMAPID_SLOG_RATE)) 8388200fe25Srmesta syslog(LOG_ERR, EMSG_DNS_THREAD_ERROR); 8398200fe25Srmesta } 8408200fe25Srmesta #endif 8418200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 842bfa62c28SVallish Vaidyeshwara break; 8438200fe25Srmesta 8448200fe25Srmesta case NO_RECOVERY: 8458200fe25Srmesta #ifdef DEBUG 8468200fe25Srmesta syslog(LOG_ERR, EMSG_DNS_DISABLE, whoami); 8478200fe25Srmesta #endif 8488200fe25Srmesta (void) rw_wrlock(&s_dns_impl_lock); 8498200fe25Srmesta s_dns_disabled = TRUE; 8508200fe25Srmesta (void) rw_unlock(&s_dns_impl_lock); 8518200fe25Srmesta 8528200fe25Srmesta /*FALLTHROUGH*/ 8538200fe25Srmesta 8548200fe25Srmesta default: 8558200fe25Srmesta /* 8568200fe25Srmesta * For any other errors... DNS is responding, but 8578200fe25Srmesta * either it has no data, or some other problem is 8588200fe25Srmesta * occuring. At any rate, the TXT domain should not 8598200fe25Srmesta * be used, so we default to the DNS domain. 8608200fe25Srmesta */ 8618200fe25Srmesta (void) rw_wrlock(&s_dns_data_lock); 8628200fe25Srmesta dns_txt_cached = 0; 8638200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 8648200fe25Srmesta resolv_txt_reset(); 865bfa62c28SVallish Vaidyeshwara break; 866bfa62c28SVallish Vaidyeshwara } 867bfa62c28SVallish Vaidyeshwara 868bfa62c28SVallish Vaidyeshwara resolv_destroy(); 8698200fe25Srmesta } 8708200fe25Srmesta 8718200fe25Srmesta static int 8728200fe25Srmesta get_mtime(const char *fname, timestruc_t *mtim) 8738200fe25Srmesta { 8748200fe25Srmesta struct stat st; 8758200fe25Srmesta int err; 8768200fe25Srmesta 8778200fe25Srmesta if ((err = stat(fname, &st)) != 0) 8788200fe25Srmesta return (err); 8798200fe25Srmesta 8808200fe25Srmesta *mtim = st.st_mtim; 8818200fe25Srmesta return (0); 8828200fe25Srmesta } 8838200fe25Srmesta 8848200fe25Srmesta 8858200fe25Srmesta /* 8868200fe25Srmesta * trim_wspace is a destructive interface; it is up to 8878200fe25Srmesta * the caller to save off an original copy if needed. 8888200fe25Srmesta */ 8898200fe25Srmesta static char * 8908200fe25Srmesta trim_wspace(char *dp) 8918200fe25Srmesta { 8928200fe25Srmesta char *r; 8938200fe25Srmesta char *ndp; 8948200fe25Srmesta 8958200fe25Srmesta /* 8968200fe25Srmesta * Any empty domain is not valid 8978200fe25Srmesta */ 8988200fe25Srmesta if (dp == NULL) 8998200fe25Srmesta return (NULL); 9008200fe25Srmesta 9018200fe25Srmesta /* 9028200fe25Srmesta * Skip leading blanks 9038200fe25Srmesta */ 9048200fe25Srmesta for (ndp = dp; *ndp != '\0'; ndp++) { 9058200fe25Srmesta if (!isspace(*ndp)) 9068200fe25Srmesta break; 9078200fe25Srmesta } 9088200fe25Srmesta 9098200fe25Srmesta /* 9108200fe25Srmesta * If we reached the end of the string w/o 9118200fe25Srmesta * finding a non-blank char, return error 9128200fe25Srmesta */ 9138200fe25Srmesta if (*ndp == '\0') 9148200fe25Srmesta return (NULL); 9158200fe25Srmesta 9168200fe25Srmesta /* 9178200fe25Srmesta * Find next blank in string 9188200fe25Srmesta */ 9198200fe25Srmesta for (r = ndp; *r != '\0'; r++) { 9208200fe25Srmesta if (isspace(*r)) 9218200fe25Srmesta break; 9228200fe25Srmesta } 9238200fe25Srmesta 9248200fe25Srmesta /* 9258200fe25Srmesta * No more blanks found, we are done 9268200fe25Srmesta */ 9278200fe25Srmesta if (*r == '\0') 9288200fe25Srmesta return (ndp); 9298200fe25Srmesta 9308200fe25Srmesta /* 9318200fe25Srmesta * Terminate string at blank 9328200fe25Srmesta */ 9338200fe25Srmesta *r++ = '\0'; 9348200fe25Srmesta 9358200fe25Srmesta /* 9368200fe25Srmesta * Skip any trailing spaces 9378200fe25Srmesta */ 9388200fe25Srmesta while (*r != '\0') { 9398200fe25Srmesta /* 9408200fe25Srmesta * If a non-blank is found, it is an 9418200fe25Srmesta * illegal domain (embedded blanks). 9428200fe25Srmesta */ 9438200fe25Srmesta if (!isspace(*r)) 9448200fe25Srmesta return (NULL); 9458200fe25Srmesta r++; 9468200fe25Srmesta } 9478200fe25Srmesta return (ndp); 9488200fe25Srmesta } 9498200fe25Srmesta 9508200fe25Srmesta static void 9518200fe25Srmesta get_nfs_domain(void) 9528200fe25Srmesta { 953*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States char value[NS_MAXCDNAME]; 954*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States int ret, bufsz = NS_MAXCDNAME; 9558200fe25Srmesta 9568200fe25Srmesta /* 957*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Get NFSMAPID_DOMAIN property value from SMF. 9588200fe25Srmesta */ 959*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bzero(value, NS_MAXCDNAME); 960*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("nfsmapid_domain", value, DEFAULT_INSTANCE, 961*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_ASTRING, NFSMAPID, &bufsz); 962*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK && *value != NULL) { 9638200fe25Srmesta char *dp = NULL; 9648200fe25Srmesta #ifdef DEBUG 9658200fe25Srmesta char *whoami = "get_nfs_domain"; 9668200fe25Srmesta char orig[NS_MAXCDNAME] = {0}; 967*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States (void) strncpy(orig, value, NS_MAXCDNAME); 9688200fe25Srmesta #endif 9698200fe25Srmesta /* 9708200fe25Srmesta * NFSMAPID_DOMAIN was set, so it's time for validation. If 9718200fe25Srmesta * it's okay, then update NFS domain and return. If not, 9728200fe25Srmesta * bail (syslog in DEBUG). We make nfsmapid more a bit 9738200fe25Srmesta * more forgiving of trailing and leading white space. 9748200fe25Srmesta */ 975*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if ((dp = trim_wspace(value)) != NULL) { 9768200fe25Srmesta if (mapid_stdchk_domain(dp) > 0) { 9778200fe25Srmesta nfs_domain_len = strlen(dp); 9788200fe25Srmesta (void) strncpy(nfs_domain, dp, NS_MAXCDNAME); 9798200fe25Srmesta nfs_domain[NS_MAXCDNAME] = '\0'; 9808200fe25Srmesta return; 9818200fe25Srmesta } 9828200fe25Srmesta } 9838200fe25Srmesta #ifdef DEBUG 9848200fe25Srmesta if (orig[0] != '\0') { 9858200fe25Srmesta syslog(LOG_ERR, gettext("%s: Invalid domain name \"%s\"" 986*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States " found in SMF."), whoami, orig); 9878200fe25Srmesta } 9888200fe25Srmesta #endif 9898200fe25Srmesta } 9908200fe25Srmesta /* 991*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * So the NFS SMF parameter nfsmapid_domain cannot be obtained or 992*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * there is an invalid nfsmapid_domain property value. 993*dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Time to zap current NFS domain info. 9948200fe25Srmesta */ 9958200fe25Srmesta ZAP_DOMAIN(nfs); 9968200fe25Srmesta } 9978200fe25Srmesta 9988200fe25Srmesta static void 9998200fe25Srmesta get_dns_domain(void) 10008200fe25Srmesta { 10018200fe25Srmesta timestruc_t ntime = {0}; 10028200fe25Srmesta 10038200fe25Srmesta /* 10048200fe25Srmesta * If we can't get stats for the config file, then 10058200fe25Srmesta * zap the DNS domain info. If mtime hasn't changed, 10068200fe25Srmesta * then there's no work to do, so just return. 10078200fe25Srmesta */ 10088200fe25Srmesta errno = 0; 10098200fe25Srmesta if (get_mtime(_PATH_RESCONF, &ntime) != 0) { 10108200fe25Srmesta switch (errno) { 10118200fe25Srmesta case ENOENT: 10128200fe25Srmesta /* 10138200fe25Srmesta * The resolver defaults to obtaining the 10148200fe25Srmesta * domain off of the NIS domainname(1M) if 10158200fe25Srmesta * /etc/resolv.conf does not exist, so we 10168200fe25Srmesta * move forward. 10178200fe25Srmesta */ 10188200fe25Srmesta break; 10198200fe25Srmesta 10208200fe25Srmesta default: 10218200fe25Srmesta ZAP_DOMAIN(dns); 10228200fe25Srmesta return; 10238200fe25Srmesta } 10248200fe25Srmesta } else if (TIMESTRUC_EQ(ntime, dns_mtime)) 10258200fe25Srmesta return; 10268200fe25Srmesta 10278200fe25Srmesta /* 10288200fe25Srmesta * Re-initialize resolver to zap DNS domain from previous 10298200fe25Srmesta * resolv_init() calls. 10308200fe25Srmesta */ 10318200fe25Srmesta (void) resolv_init(); 10328200fe25Srmesta 10338200fe25Srmesta /* 10348200fe25Srmesta * Update cached DNS domain. No need for validation since 10358200fe25Srmesta * domain comes from resolver. If resolver doesn't return the 10368200fe25Srmesta * domain, then zap the DNS domain. This shouldn't ever happen, 10378200fe25Srmesta * and if it does, the machine has bigger problems (so no need 10388200fe25Srmesta * to generate a message that says DNS appears to be broken). 10398200fe25Srmesta */ 10408200fe25Srmesta (void) rw_rdlock(&s_dns_data_lock); 10418200fe25Srmesta if (sysdns_domain[0] != '\0') { 10428200fe25Srmesta (void) strncpy(dns_domain, sysdns_domain, NS_MAXCDNAME); 10438200fe25Srmesta dns_domain_len = strlen(sysdns_domain); 10448200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 10458200fe25Srmesta dns_mtime = ntime; 1046bfa62c28SVallish Vaidyeshwara resolv_destroy(); 10478200fe25Srmesta return; 10488200fe25Srmesta } 10498200fe25Srmesta (void) rw_unlock(&s_dns_data_lock); 10508200fe25Srmesta 10518200fe25Srmesta ZAP_DOMAIN(dns); 1052bfa62c28SVallish Vaidyeshwara 1053bfa62c28SVallish Vaidyeshwara resolv_destroy(); 1054bfa62c28SVallish Vaidyeshwara 10558200fe25Srmesta } 10568200fe25Srmesta 10578200fe25Srmesta /* 10588200fe25Srmesta * PSARC 2005/487 Contracted Sun Private Interface 10598200fe25Srmesta * mapid_stdchk_domain() 10608200fe25Srmesta * Changes must be reviewed by Solaris File Sharing 10618200fe25Srmesta * Changes must be communicated to contract-2005-487-01@sun.com 10628200fe25Srmesta * 10638200fe25Srmesta * Based on the recommendations from RFC1033 and RFC1035, check 10648200fe25Srmesta * if a given domain name string is valid. Return values are: 10658200fe25Srmesta * 10668200fe25Srmesta * 1 = valid domain name 10678200fe25Srmesta * 0 = invalid domain name (or invalid embedded character) 10688200fe25Srmesta * -1 = domain length > NS_MAXCDNAME 10698200fe25Srmesta */ 10708200fe25Srmesta int 10718200fe25Srmesta mapid_stdchk_domain(const char *ds) 10728200fe25Srmesta { 10738200fe25Srmesta int i; 10748200fe25Srmesta size_t len; 10758200fe25Srmesta 10768200fe25Srmesta if (ds[0] == '\0') 10778200fe25Srmesta return (0); 10788200fe25Srmesta else 10798200fe25Srmesta len = strlen(ds) - 1; 10808200fe25Srmesta 10818200fe25Srmesta /* 10827bcac252Sevanl * 1st _AND_ last char _must_ be alphanumeric. 10837bcac252Sevanl * We check for other valid chars below. 10848200fe25Srmesta */ 10857bcac252Sevanl if ((!isalpha(ds[0]) && !isdigit(ds[0])) || 10867bcac252Sevanl (!isalpha(ds[len]) && !isdigit(ds[len]))) 10878200fe25Srmesta return (0); 10888200fe25Srmesta 10898200fe25Srmesta for (i = 0; *ds && i <= NS_MAXCDNAME; i++, ds++) { 10908200fe25Srmesta if (!isalpha(*ds) && !isdigit(*ds) && 10918200fe25Srmesta (*ds != '.') && (*ds != '-') && (*ds != '_')) 10928200fe25Srmesta return (0); 10938200fe25Srmesta } 10948200fe25Srmesta return (i == (NS_MAXCDNAME + 1) ? -1 : 1); 10958200fe25Srmesta } 10968200fe25Srmesta 10978200fe25Srmesta /* 10988200fe25Srmesta * PSARC 2005/487 Consolidation Private 10998200fe25Srmesta * mapid_reeval_domain() 11008200fe25Srmesta * Changes must be reviewed by Solaris File Sharing 11018200fe25Srmesta */ 11028200fe25Srmesta void 11038200fe25Srmesta mapid_reeval_domain(cb_t *arg) 11048200fe25Srmesta { 11058200fe25Srmesta char *domain = NULL; 11068200fe25Srmesta 11078200fe25Srmesta get_nfs_domain(); 11088200fe25Srmesta if (nfs_domain_len != 0) { 11098200fe25Srmesta domain = nfs_domain; 11108200fe25Srmesta goto dsync; 11118200fe25Srmesta } 11128200fe25Srmesta 11138200fe25Srmesta get_dns_txt_domain(arg); 11148200fe25Srmesta if (dns_txt_domain_len != 0) 11158200fe25Srmesta domain = dns_txt_domain; 11168200fe25Srmesta else { 11178200fe25Srmesta /* 11188200fe25Srmesta * We're either here because: 11198200fe25Srmesta * 11208200fe25Srmesta * . NFSMAPID_DOMAIN was not set in /etc/default/nfs 11218200fe25Srmesta * . No suitable DNS TXT resource record exists 11228200fe25Srmesta * . DNS server is not responding to requests 11238200fe25Srmesta * 11248200fe25Srmesta * in either case, we want to default to using the 11258200fe25Srmesta * system configured DNS domain. If this fails, then 11268200fe25Srmesta * dns_domain will be empty and dns_domain_len will 11278200fe25Srmesta * be 0. 11288200fe25Srmesta */ 11298200fe25Srmesta get_dns_domain(); 11308200fe25Srmesta domain = dns_domain; 11318200fe25Srmesta } 11328200fe25Srmesta 11338200fe25Srmesta dsync: 11348200fe25Srmesta domain_sync(arg, domain); 11358200fe25Srmesta } 11368200fe25Srmesta 11378200fe25Srmesta /* 11388200fe25Srmesta * PSARC 2005/487 Consolidation Private 11398200fe25Srmesta * mapid_get_domain() 11408200fe25Srmesta * Changes must be reviewed by Solaris File Sharing 11418200fe25Srmesta * 11428200fe25Srmesta * The use of TSD in mapid_get_domain() diverges slightly from the typical 11438200fe25Srmesta * TSD use, since here, the benefit of doing TSD is mostly to allocate 11448200fe25Srmesta * a per-thread buffer that will be utilized by other up-calls to the 11458200fe25Srmesta * daemon. 11468200fe25Srmesta * 11478200fe25Srmesta * In doors, the thread used for the upcall never really exits, hence 11488200fe25Srmesta * the typical destructor function defined via thr_keycreate() will 11498200fe25Srmesta * never be called. Thus, we only use TSD to allocate the per-thread 11508200fe25Srmesta * buffer and fill it up w/the configured 'mapid_domain' on each call. 11518200fe25Srmesta * This still alleviates the problem of having the caller free any 11528200fe25Srmesta * malloc'd space. 11538200fe25Srmesta */ 11548200fe25Srmesta char * 11558200fe25Srmesta mapid_get_domain(void) 11568200fe25Srmesta { 11578200fe25Srmesta void *tsd = NULL; 11588200fe25Srmesta 11598200fe25Srmesta (void) thr_getspecific(s_thr_key, &tsd); 11608200fe25Srmesta if (tsd == NULL) { 11618200fe25Srmesta tsd = malloc(NS_MAXCDNAME+1); 11628200fe25Srmesta if (tsd != NULL) { 11638200fe25Srmesta (void) rw_rdlock(&mapid_domain_lock); 11648200fe25Srmesta (void) strncpy((char *)tsd, mapid_domain, NS_MAXCDNAME); 11658200fe25Srmesta (void) rw_unlock(&mapid_domain_lock); 11668200fe25Srmesta (void) thr_setspecific(s_thr_key, tsd); 11678200fe25Srmesta } 11688200fe25Srmesta } else { 11698200fe25Srmesta (void) rw_rdlock(&mapid_domain_lock); 11708200fe25Srmesta (void) strncpy((char *)tsd, mapid_domain, NS_MAXCDNAME); 11718200fe25Srmesta (void) rw_unlock(&mapid_domain_lock); 11728200fe25Srmesta } 11738200fe25Srmesta return ((char *)tsd); 11748200fe25Srmesta } 11758200fe25Srmesta 11768200fe25Srmesta /* 11778200fe25Srmesta * PSARC 2005/487 Contracted Sun Private Interface 11788200fe25Srmesta * mapid_derive_domain() 11798200fe25Srmesta * Changes must be reviewed by Solaris File Sharing 11808200fe25Srmesta * Changes must be communicated to contract-2005-487-01@sun.com 11818200fe25Srmesta * 11828200fe25Srmesta * This interface is called solely via sysidnfs4 iff no 11838200fe25Srmesta * NFSMAPID_DOMAIN was found. So, there is no ill effect 11848200fe25Srmesta * of having the reeval function call get_nfs_domain(). 11858200fe25Srmesta */ 11868200fe25Srmesta char * 11878200fe25Srmesta mapid_derive_domain(void) 11888200fe25Srmesta { 11898200fe25Srmesta cb_t cb = {0}; 11908200fe25Srmesta 11918200fe25Srmesta _lib_init(); 11928200fe25Srmesta mapid_reeval_domain(&cb); 11938200fe25Srmesta return (mapid_get_domain()); 11948200fe25Srmesta } 11958200fe25Srmesta 11968200fe25Srmesta void 11978200fe25Srmesta _lib_init(void) 11988200fe25Srmesta { 11996d9307f9SVallish Vaidyeshwara (void) resolv_init(); /* May fail! */ 12008200fe25Srmesta (void) rwlock_init(&mapid_domain_lock, USYNC_THREAD, NULL); 12018200fe25Srmesta (void) thr_keycreate(&s_thr_key, NULL); 12028200fe25Srmesta lib_init_done++; 1203bfa62c28SVallish Vaidyeshwara resolv_destroy(); 12048200fe25Srmesta } 12056d9307f9SVallish Vaidyeshwara 12066d9307f9SVallish Vaidyeshwara void 12076d9307f9SVallish Vaidyeshwara _lib_fini(void) 12086d9307f9SVallish Vaidyeshwara { 12096d9307f9SVallish Vaidyeshwara resolv_destroy(); 12106d9307f9SVallish Vaidyeshwara } 1211