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 2007 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 * dns_common.c 30 */ 31 32 #include "dns_common.h" 33 34 #pragma weak dn_expand 35 #pragma weak res_ninit 36 #pragma weak res_nsearch 37 #pragma weak res_nclose 38 #pragma weak ns_get16 39 #pragma weak ns_get32 40 #pragma weak __ns_get16 41 #pragma weak __ns_get32 42 43 #define DNS_ALIASES 0 44 #define DNS_ADDRLIST 1 45 #define DNS_MAPDLIST 2 46 47 static int 48 dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type) 49 char **from_list, **to_list, **aliaspp; 50 int type, *count, af_type; 51 { 52 char *fstr; 53 int cnt = 0; 54 size_t len; 55 56 *count = 0; 57 if ((char *)to_list >= *aliaspp) 58 return (NSS_STR_PARSE_ERANGE); 59 60 for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) { 61 if (type == DNS_ALIASES) 62 len = strlen(fstr) + 1; 63 else 64 len = (af_type == AF_INET) ? sizeof (struct in_addr) 65 : sizeof (struct in6_addr); 66 *aliaspp -= len; 67 to_list[cnt] = *aliaspp; 68 if (*aliaspp <= (char *)&to_list[cnt+1]) 69 return (NSS_STR_PARSE_ERANGE); 70 if (type == DNS_MAPDLIST) { 71 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 72 struct in6_addr *addr6p = (struct in6_addr *)*aliaspp; 73 74 (void) memset(addr6p, '\0', sizeof (struct in6_addr)); 75 (void) memcpy(&addr6p->s6_addr[12], fstr, 76 sizeof (struct in_addr)); 77 addr6p->s6_addr[10] = 0xffU; 78 addr6p->s6_addr[11] = 0xffU; 79 ++cnt; 80 } else { 81 (void) memcpy (*aliaspp, fstr, len); 82 ++cnt; 83 } 84 } 85 to_list[cnt] = NULL; 86 87 *count = cnt; 88 if (cnt == 0) 89 return (NSS_STR_PARSE_PARSE); 90 91 return (NSS_STR_PARSE_SUCCESS); 92 } 93 94 95 int 96 ent2result(he, argp, af_type) 97 struct hostent *he; 98 nss_XbyY_args_t *argp; 99 int af_type; 100 { 101 char *buffer, *limit; 102 int buflen = argp->buf.buflen; 103 int ret, count; 104 size_t len; 105 struct hostent *host; 106 struct in_addr *addrp; 107 struct in6_addr *addrp6; 108 109 limit = argp->buf.buffer + buflen; 110 host = (struct hostent *)argp->buf.result; 111 buffer = argp->buf.buffer; 112 113 /* h_addrtype and h_length */ 114 host->h_addrtype = af_type; 115 host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) 116 : sizeof (struct in6_addr); 117 118 /* h_name */ 119 len = strlen(he->h_name) + 1; 120 host->h_name = buffer; 121 if (host->h_name + len >= limit) 122 return (NSS_STR_PARSE_ERANGE); 123 (void) memcpy(host->h_name, he->h_name, len); 124 buffer += len; 125 126 /* h_addr_list */ 127 if (af_type == AF_INET) { 128 addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp)); 129 host->h_addr_list = (char **) 130 ROUND_UP(buffer, sizeof (char **)); 131 ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list, 132 (char **)&addrp, DNS_ADDRLIST, &count, af_type); 133 if (ret != NSS_STR_PARSE_SUCCESS) 134 return (ret); 135 /* h_aliases */ 136 host->h_aliases = host->h_addr_list + count + 1; 137 ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 138 (char **)&addrp, DNS_ALIASES, &count, af_type); 139 } else { 140 addrp6 = (struct in6_addr *) 141 ROUND_DOWN(limit, sizeof (*addrp6)); 142 host->h_addr_list = (char **) 143 ROUND_UP(buffer, sizeof (char **)); 144 if (he->h_addrtype == AF_INET && af_type == AF_INET6) { 145 ret = dns_netdb_aliases(he->h_addr_list, 146 host->h_addr_list, (char **)&addrp6, 147 DNS_MAPDLIST, &count, af_type); 148 } else { 149 ret = dns_netdb_aliases(he->h_addr_list, 150 host->h_addr_list, (char **)&addrp6, 151 DNS_ADDRLIST, &count, af_type); 152 } 153 if (ret != NSS_STR_PARSE_SUCCESS) 154 return (ret); 155 /* h_aliases */ 156 host->h_aliases = host->h_addr_list + count + 1; 157 ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 158 (char **)&addrp6, DNS_ALIASES, &count, af_type); 159 } 160 if (ret == NSS_STR_PARSE_PARSE) 161 ret = NSS_STR_PARSE_SUCCESS; 162 163 return (ret); 164 } 165 166 /* 167 * Convert the hostent structure into string in the following 168 * format: 169 * 170 * IP-address official-host-name nicknames ... 171 * 172 * If more than one IP-addresses matches the official-host-name, 173 * the above line will be followed by: 174 * IP-address-1 official-host-name 175 * IP-address-2 official-host-name 176 * ... 177 * 178 * This is so that the str2hostent function in libnsl 179 * can convert the string back to the original hostent 180 * data. 181 */ 182 int 183 ent2str( 184 struct hostent *hp, 185 nss_XbyY_args_t *ap, 186 int af_type) 187 { 188 char **p; 189 char obuf[INET6_ADDRSTRLEN]; 190 void *addr; 191 struct in_addr in4; 192 int af; 193 int n; 194 const char *res; 195 char **q; 196 int l = ap->buf.buflen; 197 char *s = ap->buf.buffer; 198 199 /* 200 * for "hosts" lookup, we only want address type of 201 * AF_INET. For "ipnodes", we can have both AF_INET 202 * and AF_INET6. 203 */ 204 if (af_type == AF_INET && hp->h_addrtype != AF_INET) 205 return (NSS_STR_PARSE_PARSE); 206 207 for (p = hp->h_addr_list; *p != 0; p++) { 208 209 if (p != hp->h_addr_list) { 210 *s = '\n'; 211 s++; 212 l--; 213 } 214 215 if (hp->h_addrtype == AF_INET6) { 216 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 217 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) { 218 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 219 IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p, 220 &in4); 221 af = AF_INET; 222 addr = &in4; 223 } else { 224 af = AF_INET6; 225 addr = *p; 226 } 227 } else { 228 af = AF_INET; 229 addr = *p; 230 } 231 res = inet_ntop(af, addr, obuf, sizeof (obuf)); 232 if (res == NULL) 233 return (NSS_STR_PARSE_PARSE); 234 235 if ((n = snprintf(s, l, "%s", res)) >= l) 236 return (NSS_STR_PARSE_ERANGE); 237 l -= n; 238 s += n; 239 if (hp->h_name != NULL && *hp->h_name != '\0') { 240 if ((n = snprintf(s, l, " %s", hp->h_name)) >= l) 241 return (NSS_STR_PARSE_ERANGE); 242 l -= n; 243 s += n; 244 } 245 if (p == hp->h_addr_list) { 246 for (q = hp->h_aliases; q && *q; q++) { 247 if ((n = snprintf(s, l, " %s", *q)) >= l) 248 return (NSS_STR_PARSE_ERANGE); 249 l -= n; 250 s += n; 251 } 252 } 253 } 254 255 ap->returnlen = s - ap->buf.buffer; 256 return (NSS_STR_PARSE_SUCCESS); 257 } 258 259 nss_backend_t * 260 _nss_dns_constr(dns_backend_op_t ops[], int n_ops) 261 { 262 dns_backend_ptr_t be; 263 264 if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) 265 return (0); 266 267 be->ops = ops; 268 be->n_ops = n_ops; 269 return ((nss_backend_t *)be); 270 } 271 272 /* 273 * __res_ndestroy is a simplified version of the non-public function 274 * res_ndestroy in libresolv.so.2. Before res_ndestroy can be made 275 * public, __res_ndestroy will be used to make sure the memory pointed 276 * by statp->_u._ext.ext is freed after res_nclose() is called. 277 */ 278 static void 279 __res_ndestroy(res_state statp) { 280 res_nclose(statp); 281 if (statp->_u._ext.ext != NULL) 282 free(statp->_u._ext.ext); 283 } 284 285 /* 286 * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 287 * nss2 get hosts/ipnodes with ttl backend DNS search engine. 288 * 289 * This API is given a pointer to a packed buffer, and the buffer size 290 * It's job is to perform the appropriate res_nsearch, extract the 291 * results and build a unmarshalled hosts/ipnodes result buffer. 292 * Additionally in the extended results a nssuint_t ttl is placed. 293 * This ttl is the lessor of the ttl's extracted from the result. 294 * 295 * ***Currently the first version of this API only performs simple 296 * single res_nsearch lookups for with T_A or T_AAAA results. 297 * Other searches are deferred to the generic API w/t ttls. 298 * 299 * This function is not a generic res_* operation. It only performs 300 * a single T_A or T_AAAA lookups*** 301 * 302 * RETURNS: NSS_SUCCESS or NSS_ERROR 303 * If an NSS_ERROR result is returned, nscd is expected 304 * to resubmit the gethosts request using the old style 305 * nsswitch lookup format. 306 */ 307 308 nss_status_t 309 _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 310 { 311 /* nss buffer variables */ 312 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 313 nss_XbyY_args_t arg; 314 char *dbname; 315 int dbop; 316 nss_status_t sret; 317 size_t bsize, blen; 318 char *bptr; 319 /* resolver query variables */ 320 struct __res_state stat, *statp; /* dns state block */ 321 union msg { 322 uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ 323 HEADER h; 324 } resbuf; 325 char aliases[NS_MAXMSG]; /* set of aliases */ 326 const char *name; 327 int qtype; 328 /* answer parsing variables */ 329 HEADER *hp; 330 uchar_t *cp; /* current location in message */ 331 uchar_t *bom; /* start of message */ 332 uchar_t *eom; /* end of message */ 333 uchar_t *eor; /* end of record */ 334 int ancount, qdcount; 335 int type, class; 336 nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ 337 int n, ret; 338 const char *np; 339 /* temporary buffers */ 340 char nbuf[INET6_ADDRSTRLEN]; /* address parser */ 341 char host[MAXHOSTNAMELEN]; /* result host name */ 342 char ans[MAXHOSTNAMELEN]; /* record name */ 343 char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ 344 /* misc variables */ 345 int af; 346 char *ap, *apc; 347 int hlen = 0, alen, iplen, len; 348 349 statp = &stat; 350 (void) memset(statp, '\0', sizeof (struct __res_state)); 351 if (res_ninit(statp) == -1) 352 return (NSS_ERROR); 353 354 ap = apc = (char *)aliases; 355 alen = 0; 356 ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ 357 358 /* save space for ttl otherwise, why bother... */ 359 bsize = pbuf->data_len - sizeof (nssuint_t); 360 bptr = (char *)buffer + pbuf->data_off; 361 blen = 0; 362 sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 363 if (sret != NSS_SUCCESS) { 364 __res_ndestroy(statp); 365 return (NSS_ERROR); 366 } 367 368 if (ipnode) { 369 /* initially only handle the simple cases */ 370 if (arg.key.ipnode.flags != 0) { 371 __res_ndestroy(statp); 372 return (NSS_ERROR); 373 } 374 name = arg.key.ipnode.name; 375 if (arg.key.ipnode.af_family == AF_INET6) 376 qtype = T_AAAA; 377 else 378 qtype = T_A; 379 } else { 380 name = arg.key.name; 381 qtype = T_A; 382 } 383 ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 384 if (ret == -1) { 385 if (statp->res_h_errno == HOST_NOT_FOUND) { 386 pbuf->p_herrno = HOST_NOT_FOUND; 387 pbuf->p_status = NSS_NOTFOUND; 388 pbuf->data_len = 0; 389 __res_ndestroy(statp); 390 return (NSS_NOTFOUND); 391 } 392 /* else lookup error - handle in general code */ 393 __res_ndestroy(statp); 394 return (NSS_ERROR); 395 } 396 397 cp = resbuf.buf; 398 hp = (HEADER *)&resbuf.h; 399 bom = cp; 400 eom = cp + ret; 401 402 ancount = ntohs(hp->ancount); 403 qdcount = ntohs(hp->qdcount); 404 cp += HFIXEDSZ; 405 if (qdcount != 1) { 406 __res_ndestroy(statp); 407 return (NSS_ERROR); 408 } 409 n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); 410 if (n < 0) { 411 __res_ndestroy(statp); 412 return (NSS_ERROR); 413 } else 414 hlen = strlen(host); 415 /* no host name is an error, return */ 416 if (hlen <= 0) { 417 __res_ndestroy(statp); 418 return (NSS_ERROR); 419 } 420 cp += n + QFIXEDSZ; 421 if (cp > eom) { 422 __res_ndestroy(statp); 423 return (NSS_ERROR); 424 } 425 while (ancount-- > 0 && cp < eom && blen < bsize) { 426 n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); 427 if (n > 0) { 428 if (strncasecmp(host, ans, hlen) != 0) { 429 __res_ndestroy(statp); 430 return (NSS_ERROR); /* spoof? */ 431 } 432 } 433 cp += n; 434 /* bounds check */ 435 type = ns_get16(cp); /* type */ 436 cp += INT16SZ; 437 class = ns_get16(cp); /* class */ 438 cp += INT16SZ; 439 nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ 440 if (nttl < ttl) 441 ttl = nttl; 442 cp += INT32SZ; 443 n = ns_get16(cp); /* len */ 444 cp += INT16SZ; 445 if (class != C_IN) { 446 cp += n; 447 continue; 448 } 449 eor = cp + n; 450 if (type == T_CNAME) { 451 /* add an alias to the alias list */ 452 n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); 453 if (n > 0) { 454 len = strlen(aname); 455 if (len > 0) { 456 /* 457 * Just error out if there is an 458 * attempted buffer overflow exploit 459 * generic code will do a syslog 460 */ 461 if (alen + len + 2 > NS_MAXMSG) { 462 __res_ndestroy(statp); 463 return (NSS_ERROR); 464 } 465 *apc++ = ' '; 466 alen++; 467 (void) strlcpy(apc, aname, len + 1); 468 alen += len; 469 apc += len; 470 } 471 } 472 cp += n; 473 continue; 474 } 475 if (type != qtype) { 476 cp += n; 477 continue; 478 } 479 /* check data size */ 480 if ((type == T_A && n != INADDRSZ) || 481 (type == T_AAAA && n != IN6ADDRSZ)) { 482 cp += n; 483 continue; 484 } 485 af = (type == T_A ? AF_INET : AF_INET6); 486 np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); 487 if (np == NULL) { 488 __res_ndestroy(statp); 489 return (NSS_ERROR); 490 } 491 cp += n; 492 /* append IP host aliases to results */ 493 iplen = strlen(np); 494 /* ip <SP> hostname [<SP>][aliases] */ 495 len = iplen + 2 + hlen + alen; 496 if (alen > 0) 497 len++; 498 if (blen + len > bsize) { 499 __res_ndestroy(statp); 500 return (NSS_ERROR); 501 } 502 (void) strlcpy(bptr, np, bsize - blen); 503 blen += iplen; 504 bptr += iplen; 505 *bptr++ = ' '; 506 blen++; 507 (void) strlcpy(bptr, host, bsize - blen); 508 blen += hlen; 509 bptr += hlen; 510 if (alen > 0) { 511 *bptr++ = ' '; 512 blen++; 513 (void) strlcpy(bptr, ap, bsize - blen); 514 blen += alen; 515 bptr += alen; 516 } 517 *bptr++ = '\n'; 518 blen++; 519 } 520 /* Presumably the buffer is now filled. */ 521 len = ROUND_UP(blen, sizeof (nssuint_t)); 522 /* still room? */ 523 if (len + sizeof (nssuint_t) > pbuf->data_len) { 524 /* sigh, no, what happened? */ 525 __res_ndestroy(statp); 526 return (NSS_ERROR); 527 } 528 pbuf->ext_off = pbuf->data_off + len; 529 pbuf->ext_len = sizeof (nssuint_t); 530 pbuf->data_len = blen; 531 pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 532 *pttl = ttl; 533 __res_ndestroy(statp); 534 return (NSS_SUCCESS); 535 } 536