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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * gethostent.c 29 * 30 * In order to avoid duplicating libresolv code here, and since libresolv.so.2 31 * provides res_-equivalents of the getXbyY and {set,get}Xent, lets call 32 * re_gethostbyaddr() and so on from this file. Among other things, this 33 * should help us avoid problems like the one described in bug 1264386, 34 * where the internal getanswer() acquired new functionality in BIND 4.9.3, 35 * but the local copy of getanswer() in this file wasn't updated, so that new 36 * functionality wasn't available to the name service switch. 37 */ 38 39 #define gethostbyaddr res_gethostbyaddr 40 #define gethostbyname res_gethostbyname 41 #define gethostbyname2 res_gethostbyname2 42 #define sethostent res_sethostent 43 #define endhostent res_endhostent 44 45 #include "dns_common.h" 46 47 extern char *inet_ntoa(struct in_addr in); 48 49 struct hostent *_gethostbyname(int *h_errnop, const char *name); 50 static struct hostent *_gethostbyaddr(int *h_errnop, const char *addr, 51 int len, int type); 52 struct hostent *_nss_dns_gethostbyname2(int *h_errnop, const char *name); 53 54 #pragma weak res_gethostbyname 55 #pragma weak res_gethostbyname2 56 #pragma weak res_gethostbyaddr 57 #pragma weak res_sethostent 58 #pragma weak res_endhostent 59 60 nss_backend_t *_nss_dns_constr(dns_backend_op_t ops[], int n_ops); 61 nss_status_t __nss_dns_getbyaddr(dns_backend_ptr_t, void *); 62 63 typedef union { 64 long al; 65 char ac; 66 } align; 67 68 /* 69 * Internet Name Domain Server (DNS) only implementation. 70 */ 71 static struct hostent * 72 _gethostbyaddr(int *h_errnop, const char *addr, int len, int type) 73 { 74 struct hostent *hp; 75 76 hp = gethostbyaddr(addr, len, type); 77 *h_errnop = *get_h_errno(); 78 return (hp); 79 } 80 81 struct hostent * 82 _nss_dns_gethostbyname2(int *h_errnop, const char *name) 83 { 84 struct hostent *hp; 85 86 hp = gethostbyname2(name, AF_INET6); 87 *h_errnop = *get_h_errno(); 88 return (hp); 89 } 90 91 struct hostent * 92 _gethostbyname(int *h_errnop, const char *name) 93 { 94 struct hostent *hp; 95 96 hp = gethostbyname(name); 97 *h_errnop = *get_h_errno(); 98 return (hp); 99 } 100 101 static void 102 _sethostent(errp, stayopen) 103 nss_status_t *errp; 104 int stayopen; 105 { 106 int ret; 107 108 ret = sethostent(stayopen); 109 if (ret == 0) 110 *errp = NSS_SUCCESS; 111 else 112 *errp = NSS_UNAVAIL; 113 } 114 115 static void 116 _endhostent(errp) 117 nss_status_t *errp; 118 { 119 int ret; 120 121 ret = endhostent(); 122 if (ret == 0) 123 *errp = NSS_SUCCESS; 124 else 125 *errp = NSS_UNAVAIL; 126 } 127 128 129 /*ARGSUSED*/ 130 static nss_status_t 131 getbyname(be, a) 132 dns_backend_ptr_t be; 133 void *a; 134 { 135 struct hostent *he; 136 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 137 int ret, mt_disabled; 138 int old_retry; 139 sigset_t oldmask; 140 141 switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); 142 143 he = _gethostbyname(&argp->h_errno, argp->key.name); 144 if (he != NULL) { 145 if (argp->buf.result == NULL) { 146 /* 147 * if asked to return data in string, 148 * convert the hostent structure into 149 * string data 150 */ 151 ret = ent2str(he, a, AF_INET); 152 if (ret == NSS_STR_PARSE_SUCCESS) 153 argp->returnval = argp->buf.buffer; 154 } else { 155 ret = ent2result(he, a, AF_INET); 156 if (ret == NSS_STR_PARSE_SUCCESS) 157 argp->returnval = argp->buf.result; 158 } 159 160 if (ret != NSS_STR_PARSE_SUCCESS) { 161 argp->h_errno = HOST_NOT_FOUND; 162 if (ret == NSS_STR_PARSE_ERANGE) { 163 argp->erange = 1; 164 } 165 } 166 } 167 168 switch_resolver_reset(mt_disabled, oldmask, old_retry); 169 170 return (_herrno2nss(argp->h_errno)); 171 } 172 173 174 175 /*ARGSUSED*/ 176 static nss_status_t 177 getbyaddr(be, a) 178 dns_backend_ptr_t be; 179 void *a; 180 { 181 return (__nss_dns_getbyaddr(be, a)); 182 } 183 184 185 /* 186 * Exposing a DNS backend specific interface so that it doesn't conflict 187 * with other getbyaddr() routines from other switch backends. 188 */ 189 /*ARGSUSED*/ 190 nss_status_t 191 __nss_dns_getbyaddr(be, a) 192 dns_backend_ptr_t be; 193 void *a; 194 { 195 struct hostent *he; 196 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 197 int ret, mt_disabled; 198 struct in_addr unmapv4; 199 sigset_t oldmask; 200 int af, addrlen; 201 void *addrp; 202 int old_retry; 203 204 switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); 205 206 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 207 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)argp->key.hostaddr.addr)) { 208 addrp = &unmapv4; 209 addrlen = sizeof (unmapv4); 210 af = AF_INET; 211 (void) memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen); 212 } else { 213 addrp = (void *)argp->key.hostaddr.addr; 214 addrlen = argp->key.hostaddr.len; 215 af = argp->key.hostaddr.type; 216 } 217 he = _gethostbyaddr(&argp->h_errno, addrp, addrlen, af); 218 219 if (he != NULL) { 220 /* 221 * if asked to return data in string, convert 222 * the hostent structure into string data 223 */ 224 if (argp->buf.result == NULL) 225 ret = ent2str(he, a, argp->key.hostaddr.type); 226 else 227 ret = ent2result(he, a, argp->key.hostaddr.type); 228 229 if (ret == NSS_STR_PARSE_SUCCESS) { 230 if (argp->buf.result == NULL) 231 argp->returnval = argp->buf.buffer; 232 else 233 argp->returnval = argp->buf.result; 234 } else { 235 argp->h_errno = HOST_NOT_FOUND; 236 if (ret == NSS_STR_PARSE_ERANGE) 237 argp->erange = 1; 238 } 239 } 240 241 switch_resolver_reset(mt_disabled, oldmask, old_retry); 242 243 return (_herrno2nss(argp->h_errno)); 244 } 245 246 247 /*ARGSUSED*/ 248 static nss_status_t 249 _nss_dns_getent(be, args) 250 dns_backend_ptr_t be; 251 void *args; 252 { 253 return (NSS_UNAVAIL); 254 } 255 256 257 /*ARGSUSED*/ 258 static nss_status_t 259 _nss_dns_setent(be, dummy) 260 dns_backend_ptr_t be; 261 void *dummy; 262 { 263 nss_status_t errp; 264 265 sigset_t oldmask, newmask; 266 int mt_disabled = 1; 267 268 /* 269 * Try to enable MT; if not, we have to single-thread libresolv 270 * access 271 */ 272 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 273 (void) sigfillset(&newmask); 274 (void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 275 (void) mutex_lock(&one_lane); 276 } 277 278 _sethostent(&errp, 1); 279 280 if (mt_disabled) { 281 (void) mutex_unlock(&one_lane); 282 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 283 } else { 284 (void) (*disable_mt)(); 285 } 286 287 return (errp); 288 } 289 290 291 /*ARGSUSED*/ 292 static nss_status_t 293 _nss_dns_endent(be, dummy) 294 dns_backend_ptr_t be; 295 void *dummy; 296 { 297 nss_status_t errp; 298 299 sigset_t oldmask, newmask; 300 int mt_disabled = 1; 301 302 /* 303 * Try to enable MT; if not, we have to single-thread libresolv 304 * access 305 */ 306 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 307 (void) sigfillset(&newmask); 308 (void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 309 (void) mutex_lock(&one_lane); 310 } 311 312 _endhostent(&errp); 313 314 if (mt_disabled) { 315 (void) mutex_unlock(&one_lane); 316 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 317 } else { 318 (void) (*disable_mt)(); 319 } 320 321 return (errp); 322 } 323 324 325 /*ARGSUSED*/ 326 static nss_status_t 327 _nss_dns_destr(be, dummy) 328 dns_backend_ptr_t be; 329 void *dummy; 330 { 331 nss_status_t errp; 332 333 if (be != 0) { 334 /* === Should change to invoke ops[ENDENT] ? */ 335 sigset_t oldmask, newmask; 336 int mt_disabled = 1; 337 338 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 339 (void) sigfillset(&newmask); 340 (void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 341 (void) mutex_lock(&one_lane); 342 } 343 344 _endhostent(&errp); 345 346 if (mt_disabled) { 347 (void) mutex_unlock(&one_lane); 348 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 349 } else { 350 (void) (*disable_mt)(); 351 } 352 353 free(be); 354 } 355 return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ 356 } 357 358 359 static dns_backend_op_t host_ops[] = { 360 _nss_dns_destr, 361 _nss_dns_endent, 362 _nss_dns_setent, 363 _nss_dns_getent, 364 getbyname, 365 getbyaddr, 366 }; 367 368 /*ARGSUSED*/ 369 nss_backend_t * 370 _nss_dns_hosts_constr(dummy1, dummy2, dummy3) 371 const char *dummy1, *dummy2, *dummy3; 372 { 373 return (_nss_dns_constr(host_ops, 374 sizeof (host_ops) / sizeof (host_ops[0]))); 375 } 376 377 /* 378 * optional NSS2 packed backend gethostsbyname with ttl 379 * entry point. 380 * 381 * Returns: 382 * NSS_SUCCESS - successful 383 * NSS_NOTFOUND - successful but nothing found 384 * NSS_ERROR - fallback to NSS backend lookup mode 385 * If successful, buffer will be filled with valid data 386 * 387 */ 388 389 /*ARGSUSED*/ 390 nss_status_t 391 _nss_get_dns_hosts_name(dns_backend_ptr_t *be, void **bufp, size_t *sizep) 392 { 393 return (_nss_dns_gethost_withttl(*bufp, *sizep, 0)); 394 } 395