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