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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * gethostent.c 30 * 31 * In order to avoid duplicating libresolv code here, and since libresolv.so.2 32 * provides res_-equivalents of the getXbyY and {set,get}Xent, lets call 33 * re_gethostbyaddr() and so on from this file. Among other things, this 34 * should help us avoid problems like the one described in bug 1264386, 35 * where the internal getanswer() acquired new functionality in BIND 4.9.3, 36 * but the local copy of getanswer() in this file wasn't updated, so that new 37 * functionality wasn't available to the name service switch. 38 */ 39 40 #define gethostbyaddr res_gethostbyaddr 41 #define gethostbyname res_gethostbyname 42 #define gethostbyname2 res_gethostbyname2 43 #define sethostent res_sethostent 44 #define endhostent res_endhostent 45 46 #include "dns_common.h" 47 48 extern char *inet_ntoa(struct in_addr in); 49 50 struct hostent *_gethostbyname(int *h_errnop, const char *name); 51 static struct hostent *_gethostbyaddr(int *h_errnop, const char *addr, 52 int len, int type); 53 struct hostent *_nss_dns_gethostbyname2(int *h_errnop, const char *name); 54 55 #pragma weak res_gethostbyname 56 #pragma weak res_gethostbyname2 57 #pragma weak res_gethostbyaddr 58 #pragma weak res_sethostent 59 #pragma weak res_endhostent 60 61 nss_backend_t *_nss_dns_constr(dns_backend_op_t ops[], int n_ops); 62 nss_status_t __nss_dns_getbyaddr(dns_backend_ptr_t, void *); 63 64 typedef union { 65 long al; 66 char ac; 67 } align; 68 69 /* 70 * Internet Name Domain Server (DNS) only implementation. 71 */ 72 static struct hostent * 73 _gethostbyaddr(int *h_errnop, const char *addr, int len, int type) 74 { 75 struct hostent *hp; 76 77 hp = gethostbyaddr(addr, len, type); 78 *h_errnop = *get_h_errno(); 79 return (hp); 80 } 81 82 struct hostent * 83 _nss_dns_gethostbyname2(int *h_errnop, const char *name) 84 { 85 struct hostent *hp; 86 87 hp = gethostbyname2(name, AF_INET6); 88 *h_errnop = *get_h_errno(); 89 return (hp); 90 } 91 92 struct hostent * 93 _gethostbyname(int *h_errnop, const char *name) 94 { 95 struct hostent *hp; 96 97 hp = gethostbyname(name); 98 *h_errnop = *get_h_errno(); 99 return (hp); 100 } 101 102 static void 103 _sethostent(errp, stayopen) 104 nss_status_t *errp; 105 int stayopen; 106 { 107 int ret; 108 109 ret = sethostent(stayopen); 110 if (ret == 0) 111 *errp = NSS_SUCCESS; 112 else 113 *errp = NSS_UNAVAIL; 114 } 115 116 static void 117 _endhostent(errp) 118 nss_status_t *errp; 119 { 120 int ret; 121 122 ret = endhostent(); 123 if (ret == 0) 124 *errp = NSS_SUCCESS; 125 else 126 *errp = NSS_UNAVAIL; 127 } 128 129 130 /*ARGSUSED*/ 131 static nss_status_t 132 getbyname(be, a) 133 dns_backend_ptr_t be; 134 void *a; 135 { 136 struct hostent *he; 137 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 138 int ret, mt_disabled; 139 int old_retry; 140 sigset_t oldmask; 141 142 switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); 143 144 he = _gethostbyname(&argp->h_errno, argp->key.name); 145 if (he != NULL) { 146 if (argp->buf.result == NULL) { 147 /* 148 * if asked to return data in string, 149 * convert the hostent structure into 150 * string data 151 */ 152 ret = ent2str(he, a, AF_INET); 153 if (ret == NSS_STR_PARSE_SUCCESS) 154 argp->returnval = argp->buf.buffer; 155 } else { 156 ret = ent2result(he, a, AF_INET); 157 if (ret == NSS_STR_PARSE_SUCCESS) 158 argp->returnval = argp->buf.result; 159 } 160 161 if (ret != NSS_STR_PARSE_SUCCESS) { 162 argp->h_errno = HOST_NOT_FOUND; 163 if (ret == NSS_STR_PARSE_ERANGE) { 164 argp->erange = 1; 165 } 166 } 167 } 168 169 switch_resolver_reset(mt_disabled, oldmask, old_retry); 170 171 return (_herrno2nss(argp->h_errno)); 172 } 173 174 175 176 /*ARGSUSED*/ 177 static nss_status_t 178 getbyaddr(be, a) 179 dns_backend_ptr_t be; 180 void *a; 181 { 182 return (__nss_dns_getbyaddr(be, a)); 183 } 184 185 186 /* 187 * Exposing a DNS backend specific interface so that it doesn't conflict 188 * with other getbyaddr() routines from other switch backends. 189 */ 190 /*ARGSUSED*/ 191 nss_status_t 192 __nss_dns_getbyaddr(be, a) 193 dns_backend_ptr_t be; 194 void *a; 195 { 196 size_t n; 197 struct hostent *he, *he2; 198 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 199 int ret, save_h_errno, mt_disabled; 200 char **ans, hbuf[MAXHOSTNAMELEN]; 201 char dst[INET6_ADDRSTRLEN]; 202 struct in_addr unmapv4; 203 sigset_t oldmask; 204 int af, addrlen; 205 void *addrp; 206 int old_retry; 207 208 switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); 209 210 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 211 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)argp->key.hostaddr.addr)) { 212 addrp = &unmapv4; 213 addrlen = sizeof (unmapv4); 214 af = AF_INET; 215 (void) memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen); 216 } else { 217 addrp = (void *)argp->key.hostaddr.addr; 218 addrlen = argp->key.hostaddr.len; 219 af = argp->key.hostaddr.type; 220 } 221 he = _gethostbyaddr(&argp->h_errno, addrp, addrlen, af); 222 223 if (he != NULL) { 224 if (strlen(he->h_name) >= MAXHOSTNAMELEN) 225 ret = NSS_STR_PARSE_ERANGE; 226 else { 227 /* save a copy of the (alleged) hostname */ 228 (void) strcpy(hbuf, he->h_name); 229 n = strlen(hbuf); 230 if (n < MAXHOSTNAMELEN-1 && hbuf[n-1] != '.') { 231 (void) strcat(hbuf, "."); 232 } 233 234 /* 235 * if asked to return data in string, 236 * convert the hostent structure into 237 * string data 238 */ 239 if (argp->buf.result == NULL) 240 ret = ent2str(he, a, argp->key.hostaddr.type); 241 else 242 ret = ent2result(he, a, 243 argp->key.hostaddr.type); 244 245 save_h_errno = argp->h_errno; 246 } 247 if (ret == NSS_STR_PARSE_SUCCESS) { 248 /* 249 * check to make sure by doing a forward query 250 * We use _gethostbyname() to avoid the stack, and 251 * then we throw the result from argp->h_errno away, 252 * becase we don't care. And besides you want the 253 * return code from _gethostbyaddr() anyway. 254 */ 255 256 if (af == AF_INET) 257 he2 = _gethostbyname(&argp->h_errno, hbuf); 258 else 259 he2 = _nss_dns_gethostbyname2(&argp->h_errno, 260 hbuf); 261 if (he2 != (struct hostent *)NULL) { 262 263 /* until we prove name and addr match */ 264 argp->h_errno = HOST_NOT_FOUND; 265 for (ans = he2->h_addr_list; *ans; ans++) 266 if (memcmp(*ans, addrp, addrlen) == 267 0) { 268 argp->h_errno = save_h_errno; 269 if (argp->buf.result == NULL) 270 argp->returnval = 271 argp->buf.buffer; 272 else 273 argp->returnval = 274 argp->buf.result; 275 break; 276 } 277 } else { 278 279 /* 280 * What to do if _gethostbyname() fails ??? 281 * We assume they are doing something stupid 282 * like registering addresses but not names 283 * (some people actually think that provides 284 * some "security", through obscurity). So for 285 * these poor lost souls, because we can't 286 * PROVE spoofing and because we did try (and 287 * we don't want a bug filed on this), we let 288 * this go. And return the name from byaddr. 289 */ 290 argp->h_errno = save_h_errno; 291 if (argp->buf.result == NULL) 292 argp->returnval = argp->buf.buffer; 293 else 294 argp->returnval = argp->buf.result; 295 } 296 /* we've been spoofed, make sure to log it. */ 297 if (argp->h_errno == HOST_NOT_FOUND) { 298 if (argp->key.hostaddr.type == AF_INET) 299 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", 300 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 301 hbuf, inet_ntoa(*(struct in_addr *)argp->key.hostaddr.addr)); 302 else 303 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", 304 hbuf, inet_ntop(AF_INET6, (void *) argp->key.hostaddr.addr, 305 dst, sizeof (dst))); 306 } 307 } else { 308 argp->h_errno = HOST_NOT_FOUND; 309 if (ret == NSS_STR_PARSE_ERANGE) { 310 argp->erange = 1; 311 } 312 } 313 } 314 315 switch_resolver_reset(mt_disabled, oldmask, old_retry); 316 317 return (_herrno2nss(argp->h_errno)); 318 } 319 320 321 /*ARGSUSED*/ 322 static nss_status_t 323 _nss_dns_getent(be, args) 324 dns_backend_ptr_t be; 325 void *args; 326 { 327 return (NSS_UNAVAIL); 328 } 329 330 331 /*ARGSUSED*/ 332 static nss_status_t 333 _nss_dns_setent(be, dummy) 334 dns_backend_ptr_t be; 335 void *dummy; 336 { 337 nss_status_t errp; 338 339 sigset_t oldmask, newmask; 340 int mt_disabled = 1; 341 342 /* 343 * Try to enable MT; if not, we have to single-thread libresolv 344 * access 345 */ 346 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 347 (void) sigfillset(&newmask); 348 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 349 _mutex_lock(&one_lane); 350 } 351 352 _sethostent(&errp, 1); 353 354 if (mt_disabled) { 355 _mutex_unlock(&one_lane); 356 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 357 } else { 358 (void) (*disable_mt)(); 359 } 360 361 return (errp); 362 } 363 364 365 /*ARGSUSED*/ 366 static nss_status_t 367 _nss_dns_endent(be, dummy) 368 dns_backend_ptr_t be; 369 void *dummy; 370 { 371 nss_status_t errp; 372 373 sigset_t oldmask, newmask; 374 int mt_disabled = 1; 375 376 /* 377 * Try to enable MT; if not, we have to single-thread libresolv 378 * access 379 */ 380 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 381 (void) sigfillset(&newmask); 382 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 383 _mutex_lock(&one_lane); 384 } 385 386 _endhostent(&errp); 387 388 if (mt_disabled) { 389 _mutex_unlock(&one_lane); 390 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 391 } else { 392 (void) (*disable_mt)(); 393 } 394 395 return (errp); 396 } 397 398 399 /*ARGSUSED*/ 400 static nss_status_t 401 _nss_dns_destr(be, dummy) 402 dns_backend_ptr_t be; 403 void *dummy; 404 { 405 nss_status_t errp; 406 407 if (be != 0) { 408 /* === Should change to invoke ops[ENDENT] ? */ 409 sigset_t oldmask, newmask; 410 int mt_disabled = 1; 411 412 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 413 (void) sigfillset(&newmask); 414 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 415 _mutex_lock(&one_lane); 416 } 417 418 _endhostent(&errp); 419 420 if (mt_disabled) { 421 _mutex_unlock(&one_lane); 422 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 423 } else { 424 (void) (*disable_mt)(); 425 } 426 427 free(be); 428 } 429 return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ 430 } 431 432 433 static dns_backend_op_t host_ops[] = { 434 _nss_dns_destr, 435 _nss_dns_endent, 436 _nss_dns_setent, 437 _nss_dns_getent, 438 getbyname, 439 getbyaddr, 440 }; 441 442 /*ARGSUSED*/ 443 nss_backend_t * 444 _nss_dns_hosts_constr(dummy1, dummy2, dummy3) 445 const char *dummy1, *dummy2, *dummy3; 446 { 447 return (_nss_dns_constr(host_ops, 448 sizeof (host_ops) / sizeof (host_ops[0]))); 449 } 450 451 /* 452 * optional NSS2 packed backend gethostsbyname with ttl 453 * entry point. 454 * 455 * Returns: 456 * NSS_SUCCESS - successful 457 * NSS_NOTFOUND - successful but nothing found 458 * NSS_ERROR - fallback to NSS backend lookup mode 459 * If successful, buffer will be filled with valid data 460 * 461 */ 462 463 /*ARGSUSED*/ 464 nss_status_t 465 _nss_get_dns_hosts_name(dns_backend_ptr_t *be, void **bufp, size_t *sizep) 466 { 467 return (_nss_dns_gethost_withttl(*bufp, *sizep, 0)); 468 } 469