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 * 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 %s", res, hp->h_name)) >= l) 236 return (NSS_STR_PARSE_ERANGE); 237 l -= n; 238 s += n; 239 if (p == hp->h_addr_list) { 240 for (q = hp->h_aliases; q && *q; q++) { 241 if ((n = snprintf(s, l, " %s", *q)) >= l) 242 return (NSS_STR_PARSE_ERANGE); 243 l -= n; 244 s += n; 245 } 246 } 247 } 248 249 ap->returnlen = s - ap->buf.buffer; 250 return (NSS_STR_PARSE_SUCCESS); 251 } 252 253 nss_backend_t * 254 _nss_dns_constr(dns_backend_op_t ops[], int n_ops) 255 { 256 dns_backend_ptr_t be; 257 258 if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) 259 return (0); 260 261 be->ops = ops; 262 be->n_ops = n_ops; 263 return ((nss_backend_t *)be); 264 } 265 266 /* 267 * __res_ndestroy is a simplified version of the non-public function 268 * res_ndestroy in libresolv.so.2. Before res_ndestroy can be made 269 * public, __res_ndestroy will be used to make sure the memory pointed 270 * by statp->_u._ext.ext is freed after res_nclose() is called. 271 */ 272 static void 273 __res_ndestroy(res_state statp) { 274 res_nclose(statp); 275 if (statp->_u._ext.ext != NULL) 276 free(statp->_u._ext.ext); 277 } 278 279 /* 280 * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 281 * nss2 get hosts/ipnodes with ttl backend DNS search engine. 282 * 283 * This API is given a pointer to a packed buffer, and the buffer size 284 * It's job is to perform the appropriate res_nsearch, extract the 285 * results and build a unmarshalled hosts/ipnodes result buffer. 286 * Additionally in the extended results a nssuint_t ttl is placed. 287 * This ttl is the lessor of the ttl's extracted from the result. 288 * 289 * ***Currently the first version of this API only performs simple 290 * single res_nsearch lookups for with T_A or T_AAAA results. 291 * Other searches are deferred to the generic API w/t ttls. 292 * 293 * This function is not a generic res_* operation. It only performs 294 * a single T_A or T_AAAA lookups*** 295 * 296 * RETURNS: NSS_SUCCESS or NSS_ERROR 297 * If an NSS_ERROR result is returned, nscd is expected 298 * to resubmit the gethosts request using the old style 299 * nsswitch lookup format. 300 */ 301 302 nss_status_t 303 _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 304 { 305 /* nss buffer variables */ 306 nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 307 nss_XbyY_args_t arg; 308 char *dbname; 309 int dbop; 310 nss_status_t sret; 311 size_t bsize, blen; 312 char *bptr; 313 /* resolver query variables */ 314 struct __res_state stat, *statp; /* dns state block */ 315 union msg { 316 uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ 317 HEADER h; 318 } resbuf; 319 char aliases[NS_MAXMSG]; /* set of aliases */ 320 const char *name; 321 int qtype; 322 /* answer parsing variables */ 323 HEADER *hp; 324 uchar_t *cp; /* current location in message */ 325 uchar_t *bom; /* start of message */ 326 uchar_t *eom; /* end of message */ 327 uchar_t *eor; /* end of record */ 328 int ancount, qdcount; 329 int type, class; 330 nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ 331 int n, ret; 332 const char *np; 333 /* temporary buffers */ 334 char nbuf[INET6_ADDRSTRLEN]; /* address parser */ 335 char host[MAXHOSTNAMELEN]; /* result host name */ 336 char ans[MAXHOSTNAMELEN]; /* record name */ 337 char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ 338 /* misc variables */ 339 int af; 340 char *ap, *apc; 341 int hlen, alen, iplen, len; 342 343 statp = &stat; 344 (void) memset(statp, '\0', sizeof (struct __res_state)); 345 if (res_ninit(statp) == -1) 346 return (NSS_ERROR); 347 348 ap = apc = (char *)aliases; 349 alen = 0; 350 ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ 351 352 /* save space for ttl otherwise, why bother... */ 353 bsize = pbuf->data_len - sizeof (nssuint_t); 354 bptr = (char *)buffer + pbuf->data_off; 355 blen = 0; 356 sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 357 if (sret != NSS_SUCCESS) { 358 __res_ndestroy(statp); 359 return (NSS_ERROR); 360 } 361 362 if (ipnode) { 363 /* initially only handle the simple cases */ 364 if (arg.key.ipnode.flags != 0) { 365 __res_ndestroy(statp); 366 return (NSS_ERROR); 367 } 368 name = arg.key.ipnode.name; 369 if (arg.key.ipnode.af_family == AF_INET6) 370 qtype = T_AAAA; 371 else 372 qtype = T_A; 373 } else { 374 name = arg.key.name; 375 qtype = T_A; 376 } 377 ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 378 if (ret == -1) { 379 if (statp->res_h_errno == HOST_NOT_FOUND) { 380 pbuf->p_herrno = HOST_NOT_FOUND; 381 pbuf->p_status = NSS_NOTFOUND; 382 pbuf->data_len = 0; 383 __res_ndestroy(statp); 384 return (NSS_NOTFOUND); 385 } 386 /* else lookup error - handle in general code */ 387 __res_ndestroy(statp); 388 return (NSS_ERROR); 389 } 390 391 cp = resbuf.buf; 392 hp = (HEADER *)&resbuf.h; 393 bom = cp; 394 eom = cp + ret; 395 396 ancount = ntohs(hp->ancount); 397 qdcount = ntohs(hp->qdcount); 398 cp += HFIXEDSZ; 399 if (qdcount != 1) { 400 __res_ndestroy(statp); 401 return (NSS_ERROR); 402 } 403 n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); 404 if (n < 0) { 405 __res_ndestroy(statp); 406 return (NSS_ERROR); 407 } else 408 hlen = strlen(host); 409 cp += n + QFIXEDSZ; 410 if (cp > eom) { 411 __res_ndestroy(statp); 412 return (NSS_ERROR); 413 } 414 while (ancount-- > 0 && cp < eom && blen < bsize) { 415 n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); 416 if (n > 0) { 417 if (strncasecmp(host, ans, hlen) != 0) { 418 __res_ndestroy(statp); 419 return (NSS_ERROR); /* spoof? */ 420 } 421 } 422 cp += n; 423 /* bounds check */ 424 type = ns_get16(cp); /* type */ 425 cp += INT16SZ; 426 class = ns_get16(cp); /* class */ 427 cp += INT16SZ; 428 nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ 429 if (nttl < ttl) 430 ttl = nttl; 431 cp += INT32SZ; 432 n = ns_get16(cp); /* len */ 433 cp += INT16SZ; 434 if (class != C_IN) { 435 cp += n; 436 continue; 437 } 438 eor = cp + n; 439 if (type == T_CNAME) { 440 /* add an alias to the alias list */ 441 n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); 442 if (n > 0) { 443 len = strlen(aname); 444 if (len > 0) { 445 /* 446 * Just error out if there is an 447 * attempted buffer overflow exploit 448 * generic code will do a syslog 449 */ 450 if (alen + len + 2 > NS_MAXMSG) { 451 __res_ndestroy(statp); 452 return (NSS_ERROR); 453 } 454 *apc++ = ' '; 455 alen++; 456 (void) strlcpy(apc, aname, len + 1); 457 alen += len; 458 apc += len; 459 } 460 } 461 cp += n; 462 continue; 463 } 464 if (type != qtype) { 465 cp += n; 466 continue; 467 } 468 /* check data size */ 469 if ((type == T_A && n != INADDRSZ) || 470 (type == T_AAAA && n != IN6ADDRSZ)) { 471 cp += n; 472 continue; 473 } 474 af = (type == T_A ? AF_INET : AF_INET6); 475 np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); 476 if (np == NULL) { 477 __res_ndestroy(statp); 478 return (NSS_ERROR); 479 } 480 cp += n; 481 /* append IP host aliases to results */ 482 iplen = strlen(np); 483 /* ip <SP> hostname [<SP>][aliases] */ 484 len = iplen + 2 + hlen + alen; 485 if (alen > 0) 486 len++; 487 if (blen + len > bsize) { 488 __res_ndestroy(statp); 489 return (NSS_ERROR); 490 } 491 (void) strlcpy(bptr, np, bsize - blen); 492 blen += iplen; 493 bptr += iplen; 494 *bptr++ = ' '; 495 blen++; 496 (void) strlcpy(bptr, host, bsize - blen); 497 blen += hlen; 498 bptr += hlen; 499 if (alen > 0) { 500 *bptr++ = ' '; 501 blen++; 502 (void) strlcpy(bptr, ap, bsize - blen); 503 blen += alen; 504 bptr += alen; 505 } 506 *bptr++ = '\n'; 507 blen++; 508 } 509 /* Presumably the buffer is now filled. */ 510 len = ROUND_UP(blen, sizeof (nssuint_t)); 511 /* still room? */ 512 if (len + sizeof (nssuint_t) > pbuf->data_len) { 513 /* sigh, no, what happened? */ 514 __res_ndestroy(statp); 515 return (NSS_ERROR); 516 } 517 pbuf->ext_off = pbuf->data_off + len; 518 pbuf->ext_len = sizeof (nssuint_t); 519 pbuf->data_len = blen; 520 pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 521 *pttl = ttl; 522 __res_ndestroy(statp); 523 return (NSS_SUCCESS); 524 } 525