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 (c) 1993, 1998-2000 by Sun Microsystems, Inc. 24 * All rights reserved. 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 ret = ent2result(he, a, AF_INET); 148 if (ret == NSS_STR_PARSE_SUCCESS) { 149 argp->returnval = argp->buf.result; 150 } else { 151 argp->h_errno = HOST_NOT_FOUND; 152 if (ret == NSS_STR_PARSE_ERANGE) { 153 argp->erange = 1; 154 } 155 } 156 } 157 158 switch_resolver_reset(mt_disabled, oldmask, old_retry); 159 160 return (_herrno2nss(argp->h_errno)); 161 } 162 163 164 165 /*ARGSUSED*/ 166 static nss_status_t 167 getbyaddr(be, a) 168 dns_backend_ptr_t be; 169 void *a; 170 { 171 return (__nss_dns_getbyaddr(be, a)); 172 } 173 174 175 /* 176 * Exposing a DNS backend specific interface so that it doesn't conflict 177 * with other getbyaddr() routines from other switch backends. 178 */ 179 nss_status_t 180 __nss_dns_getbyaddr(be, a) 181 dns_backend_ptr_t be; 182 void *a; 183 { 184 size_t n; 185 struct hostent *he, *he2; 186 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 187 int ret, save_h_errno, mt_disabled; 188 char **ans, hbuf[MAXHOSTNAMELEN]; 189 char dst[INET6_ADDRSTRLEN]; 190 struct in_addr unmapv4; 191 sigset_t oldmask; 192 int af, addrlen; 193 void *addrp; 194 int old_retry; 195 196 switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); 197 198 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)argp->key.hostaddr.addr)) { 199 addrp = &unmapv4; 200 addrlen = sizeof (unmapv4); 201 af = AF_INET; 202 memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen); 203 } else { 204 addrp = (void *)argp->key.hostaddr.addr; 205 addrlen = argp->key.hostaddr.len; 206 af = argp->key.hostaddr.type; 207 } 208 he = _gethostbyaddr(&argp->h_errno, addrp, addrlen, af); 209 210 if (he != NULL) { 211 if (strlen(he->h_name) >= MAXHOSTNAMELEN) 212 ret = NSS_STR_PARSE_ERANGE; 213 else { 214 /* save a copy of the (alleged) hostname */ 215 (void) strcpy(hbuf, he->h_name); 216 n = strlen(hbuf); 217 if (n < MAXHOSTNAMELEN-1 && hbuf[n-1] != '.') { 218 (void) strcat(hbuf, "."); 219 } 220 ret = ent2result(he, a, argp->key.hostaddr.type); 221 save_h_errno = argp->h_errno; 222 } 223 if (ret == NSS_STR_PARSE_SUCCESS) { 224 /* 225 * check to make sure by doing a forward query 226 * We use _gethostbyname() to avoid the stack, and 227 * then we throw the result from argp->h_errno away, 228 * becase we don't care. And besides you want the 229 * return code from _gethostbyaddr() anyway. 230 */ 231 232 if (af == AF_INET) 233 he2 = _gethostbyname(&argp->h_errno, hbuf); 234 else 235 he2 = _nss_dns_gethostbyname2(&argp->h_errno, 236 hbuf); 237 if (he2 != (struct hostent *)NULL) { 238 239 /* until we prove name and addr match */ 240 argp->h_errno = HOST_NOT_FOUND; 241 for (ans = he2->h_addr_list; *ans; ans++) 242 if (memcmp(*ans, addrp, addrlen) == 243 0) { 244 argp->h_errno = save_h_errno; 245 argp->returnval = argp->buf.result; 246 break; 247 } 248 } else { 249 250 /* 251 * What to do if _gethostbyname() fails ??? 252 * We assume they are doing something stupid 253 * like registering addresses but not names 254 * (some people actually think that provides 255 * some "security", through obscurity). So for 256 * these poor lost souls, because we can't 257 * PROVE spoofing and because we did try (and 258 * we don't want a bug filed on this), we let 259 * this go. And return the name from byaddr. 260 */ 261 argp->h_errno = save_h_errno; 262 argp->returnval = argp->buf.result; 263 } 264 /* we've been spoofed, make sure to log it. */ 265 if (argp->h_errno == HOST_NOT_FOUND) { 266 if (argp->key.hostaddr.type == AF_INET) 267 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", 268 hbuf, inet_ntoa(*(struct in_addr *)argp->key.hostaddr.addr)); 269 else 270 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", 271 hbuf, inet_ntop(AF_INET6, (void *) argp->key.hostaddr.addr, 272 dst, sizeof (dst))); 273 } 274 } else { 275 argp->h_errno = HOST_NOT_FOUND; 276 if (ret == NSS_STR_PARSE_ERANGE) { 277 argp->erange = 1; 278 } 279 } 280 } 281 282 switch_resolver_reset(mt_disabled, oldmask, old_retry); 283 284 return (_herrno2nss(argp->h_errno)); 285 } 286 287 288 /*ARGSUSED*/ 289 static nss_status_t 290 _nss_dns_getent(be, args) 291 dns_backend_ptr_t be; 292 void *args; 293 { 294 return (NSS_UNAVAIL); 295 } 296 297 298 /*ARGSUSED*/ 299 static nss_status_t 300 _nss_dns_setent(be, dummy) 301 dns_backend_ptr_t be; 302 void *dummy; 303 { 304 nss_status_t errp; 305 306 sigset_t oldmask, newmask; 307 int mt_disabled = 1; 308 309 /* 310 * Try to enable MT; if not, we have to single-thread libresolv 311 * access 312 */ 313 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 314 (void) sigfillset(&newmask); 315 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 316 _mutex_lock(&one_lane); 317 } 318 319 _sethostent(&errp, 1); 320 321 if (mt_disabled) { 322 _mutex_unlock(&one_lane); 323 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 324 } else { 325 (void) (*disable_mt)(); 326 } 327 328 return (errp); 329 } 330 331 332 /*ARGSUSED*/ 333 static nss_status_t 334 _nss_dns_endent(be, dummy) 335 dns_backend_ptr_t be; 336 void *dummy; 337 { 338 nss_status_t errp; 339 340 sigset_t oldmask, newmask; 341 int mt_disabled = 1; 342 343 /* 344 * Try to enable MT; if not, we have to single-thread libresolv 345 * access 346 */ 347 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 348 (void) sigfillset(&newmask); 349 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 350 _mutex_lock(&one_lane); 351 } 352 353 _endhostent(&errp); 354 355 if (mt_disabled) { 356 _mutex_unlock(&one_lane); 357 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 358 } else { 359 (void) (*disable_mt)(); 360 } 361 362 return (errp); 363 } 364 365 366 /*ARGSUSED*/ 367 static nss_status_t 368 _nss_dns_destr(be, dummy) 369 dns_backend_ptr_t be; 370 void *dummy; 371 { 372 nss_status_t errp; 373 374 if (be != 0) { 375 /* === Should change to invoke ops[ENDENT] ? */ 376 sigset_t oldmask, newmask; 377 int mt_disabled = 1; 378 379 if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) { 380 (void) sigfillset(&newmask); 381 _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); 382 _mutex_lock(&one_lane); 383 } 384 385 _endhostent(&errp); 386 387 if (mt_disabled) { 388 _mutex_unlock(&one_lane); 389 _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL); 390 } else { 391 (void) (*disable_mt)(); 392 } 393 394 free(be); 395 } 396 return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ 397 } 398 399 400 static dns_backend_op_t host_ops[] = { 401 _nss_dns_destr, 402 _nss_dns_endent, 403 _nss_dns_setent, 404 _nss_dns_getent, 405 getbyname, 406 getbyaddr, 407 }; 408 409 /*ARGSUSED*/ 410 nss_backend_t * 411 _nss_dns_hosts_constr(dummy1, dummy2, dummy3) 412 const char *dummy1, *dummy2, *dummy3; 413 { 414 return (_nss_dns_constr(host_ops, 415 sizeof (host_ops) / sizeof (host_ops[0]))); 416 } 417