10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52830Sdjl * Common Development and Distribution License (the "License"). 62830Sdjl * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*6666Ssm26363 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 232830Sdjl * Use is subject to license terms. 242830Sdjl */ 252830Sdjl 262830Sdjl #pragma ident "%Z%%M% %I% %E% SMI" 272830Sdjl 282830Sdjl /* 290Sstevel@tonic-gate * dns_common.c 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 322830Sdjl #include "dns_common.h" 330Sstevel@tonic-gate 342830Sdjl #pragma weak dn_expand 352830Sdjl #pragma weak res_ninit 362830Sdjl #pragma weak res_nsearch 372830Sdjl #pragma weak res_nclose 382830Sdjl #pragma weak ns_get16 392830Sdjl #pragma weak ns_get32 402830Sdjl #pragma weak __ns_get16 412830Sdjl #pragma weak __ns_get32 420Sstevel@tonic-gate 430Sstevel@tonic-gate #define DNS_ALIASES 0 440Sstevel@tonic-gate #define DNS_ADDRLIST 1 450Sstevel@tonic-gate #define DNS_MAPDLIST 2 460Sstevel@tonic-gate 47*6666Ssm26363 #ifndef tolower 48*6666Ssm26363 #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c)) 49*6666Ssm26363 #endif 50*6666Ssm26363 510Sstevel@tonic-gate static int 520Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type) 530Sstevel@tonic-gate char **from_list, **to_list, **aliaspp; 540Sstevel@tonic-gate int type, *count, af_type; 550Sstevel@tonic-gate { 560Sstevel@tonic-gate char *fstr; 570Sstevel@tonic-gate int cnt = 0; 580Sstevel@tonic-gate size_t len; 590Sstevel@tonic-gate 600Sstevel@tonic-gate *count = 0; 610Sstevel@tonic-gate if ((char *)to_list >= *aliaspp) 620Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 630Sstevel@tonic-gate 640Sstevel@tonic-gate for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) { 650Sstevel@tonic-gate if (type == DNS_ALIASES) 660Sstevel@tonic-gate len = strlen(fstr) + 1; 670Sstevel@tonic-gate else 680Sstevel@tonic-gate len = (af_type == AF_INET) ? sizeof (struct in_addr) 690Sstevel@tonic-gate : sizeof (struct in6_addr); 700Sstevel@tonic-gate *aliaspp -= len; 710Sstevel@tonic-gate to_list[cnt] = *aliaspp; 720Sstevel@tonic-gate if (*aliaspp <= (char *)&to_list[cnt+1]) 730Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 740Sstevel@tonic-gate if (type == DNS_MAPDLIST) { 752830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 762830Sdjl struct in6_addr *addr6p = (struct in6_addr *)*aliaspp; 770Sstevel@tonic-gate 780Sstevel@tonic-gate (void) memset(addr6p, '\0', sizeof (struct in6_addr)); 790Sstevel@tonic-gate (void) memcpy(&addr6p->s6_addr[12], fstr, 800Sstevel@tonic-gate sizeof (struct in_addr)); 810Sstevel@tonic-gate addr6p->s6_addr[10] = 0xffU; 820Sstevel@tonic-gate addr6p->s6_addr[11] = 0xffU; 830Sstevel@tonic-gate ++cnt; 840Sstevel@tonic-gate } else { 850Sstevel@tonic-gate (void) memcpy (*aliaspp, fstr, len); 860Sstevel@tonic-gate ++cnt; 870Sstevel@tonic-gate } 880Sstevel@tonic-gate } 890Sstevel@tonic-gate to_list[cnt] = NULL; 900Sstevel@tonic-gate 910Sstevel@tonic-gate *count = cnt; 920Sstevel@tonic-gate if (cnt == 0) 930Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 940Sstevel@tonic-gate 950Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 960Sstevel@tonic-gate } 970Sstevel@tonic-gate 980Sstevel@tonic-gate 990Sstevel@tonic-gate int 1000Sstevel@tonic-gate ent2result(he, argp, af_type) 1010Sstevel@tonic-gate struct hostent *he; 1020Sstevel@tonic-gate nss_XbyY_args_t *argp; 1030Sstevel@tonic-gate int af_type; 1040Sstevel@tonic-gate { 1050Sstevel@tonic-gate char *buffer, *limit; 1060Sstevel@tonic-gate int buflen = argp->buf.buflen; 1070Sstevel@tonic-gate int ret, count; 1080Sstevel@tonic-gate size_t len; 1090Sstevel@tonic-gate struct hostent *host; 1100Sstevel@tonic-gate struct in_addr *addrp; 1110Sstevel@tonic-gate struct in6_addr *addrp6; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate limit = argp->buf.buffer + buflen; 1142830Sdjl host = (struct hostent *)argp->buf.result; 1150Sstevel@tonic-gate buffer = argp->buf.buffer; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* h_addrtype and h_length */ 1180Sstevel@tonic-gate host->h_addrtype = af_type; 1190Sstevel@tonic-gate host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) 1200Sstevel@tonic-gate : sizeof (struct in6_addr); 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* h_name */ 1230Sstevel@tonic-gate len = strlen(he->h_name) + 1; 1240Sstevel@tonic-gate host->h_name = buffer; 1250Sstevel@tonic-gate if (host->h_name + len >= limit) 1260Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 1270Sstevel@tonic-gate (void) memcpy(host->h_name, he->h_name, len); 1280Sstevel@tonic-gate buffer += len; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* h_addr_list */ 1310Sstevel@tonic-gate if (af_type == AF_INET) { 1322830Sdjl addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp)); 1330Sstevel@tonic-gate host->h_addr_list = (char **) 1340Sstevel@tonic-gate ROUND_UP(buffer, sizeof (char **)); 1350Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list, 1360Sstevel@tonic-gate (char **)&addrp, DNS_ADDRLIST, &count, af_type); 1370Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS) 1380Sstevel@tonic-gate return (ret); 1390Sstevel@tonic-gate /* h_aliases */ 1400Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 1410Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 1420Sstevel@tonic-gate (char **)&addrp, DNS_ALIASES, &count, af_type); 1430Sstevel@tonic-gate } else { 1440Sstevel@tonic-gate addrp6 = (struct in6_addr *) 1450Sstevel@tonic-gate ROUND_DOWN(limit, sizeof (*addrp6)); 1460Sstevel@tonic-gate host->h_addr_list = (char **) 1470Sstevel@tonic-gate ROUND_UP(buffer, sizeof (char **)); 1480Sstevel@tonic-gate if (he->h_addrtype == AF_INET && af_type == AF_INET6) { 1490Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, 1500Sstevel@tonic-gate host->h_addr_list, (char **)&addrp6, 1510Sstevel@tonic-gate DNS_MAPDLIST, &count, af_type); 1520Sstevel@tonic-gate } else { 1530Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, 1540Sstevel@tonic-gate host->h_addr_list, (char **)&addrp6, 1550Sstevel@tonic-gate DNS_ADDRLIST, &count, af_type); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS) 1580Sstevel@tonic-gate return (ret); 1590Sstevel@tonic-gate /* h_aliases */ 1600Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 1610Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 1620Sstevel@tonic-gate (char **)&addrp6, DNS_ALIASES, &count, af_type); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate if (ret == NSS_STR_PARSE_PARSE) 1650Sstevel@tonic-gate ret = NSS_STR_PARSE_SUCCESS; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate return (ret); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1702830Sdjl /* 1712830Sdjl * Convert the hostent structure into string in the following 1722830Sdjl * format: 1732830Sdjl * 1742830Sdjl * IP-address official-host-name nicknames ... 1752830Sdjl * 1762830Sdjl * If more than one IP-addresses matches the official-host-name, 1772830Sdjl * the above line will be followed by: 1782830Sdjl * IP-address-1 official-host-name 1792830Sdjl * IP-address-2 official-host-name 1802830Sdjl * ... 1812830Sdjl * 1822830Sdjl * This is so that the str2hostent function in libnsl 1832830Sdjl * can convert the string back to the original hostent 1842830Sdjl * data. 1852830Sdjl */ 1862830Sdjl int 1872830Sdjl ent2str( 1882830Sdjl struct hostent *hp, 1892830Sdjl nss_XbyY_args_t *ap, 1902830Sdjl int af_type) 1912830Sdjl { 1922830Sdjl char **p; 1932830Sdjl char obuf[INET6_ADDRSTRLEN]; 1942830Sdjl void *addr; 1952830Sdjl struct in_addr in4; 1962830Sdjl int af; 1972830Sdjl int n; 1982830Sdjl const char *res; 1992830Sdjl char **q; 2002830Sdjl int l = ap->buf.buflen; 2012830Sdjl char *s = ap->buf.buffer; 2022830Sdjl 2032830Sdjl /* 2042830Sdjl * for "hosts" lookup, we only want address type of 2052830Sdjl * AF_INET. For "ipnodes", we can have both AF_INET 2062830Sdjl * and AF_INET6. 2072830Sdjl */ 2082830Sdjl if (af_type == AF_INET && hp->h_addrtype != AF_INET) 2092830Sdjl return (NSS_STR_PARSE_PARSE); 2102830Sdjl 2112830Sdjl for (p = hp->h_addr_list; *p != 0; p++) { 2122830Sdjl 2132830Sdjl if (p != hp->h_addr_list) { 2142830Sdjl *s = '\n'; 2152830Sdjl s++; 2162830Sdjl l--; 2172830Sdjl } 2182830Sdjl 2192830Sdjl if (hp->h_addrtype == AF_INET6) { 2202830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 2212830Sdjl if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) { 2222830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 2232830Sdjl IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p, 2245161Smichen &in4); 2252830Sdjl af = AF_INET; 2262830Sdjl addr = &in4; 2272830Sdjl } else { 2282830Sdjl af = AF_INET6; 2292830Sdjl addr = *p; 2302830Sdjl } 2312830Sdjl } else { 2322830Sdjl af = AF_INET; 2332830Sdjl addr = *p; 2342830Sdjl } 2352830Sdjl res = inet_ntop(af, addr, obuf, sizeof (obuf)); 2362830Sdjl if (res == NULL) 2372830Sdjl return (NSS_STR_PARSE_PARSE); 2382830Sdjl 2395161Smichen if ((n = snprintf(s, l, "%s", res)) >= l) 2402830Sdjl return (NSS_STR_PARSE_ERANGE); 2412830Sdjl l -= n; 2422830Sdjl s += n; 2435161Smichen if (hp->h_name != NULL && *hp->h_name != '\0') { 2445161Smichen if ((n = snprintf(s, l, " %s", hp->h_name)) >= l) 2455161Smichen return (NSS_STR_PARSE_ERANGE); 2465161Smichen l -= n; 2475161Smichen s += n; 2485161Smichen } 2492830Sdjl if (p == hp->h_addr_list) { 2502830Sdjl for (q = hp->h_aliases; q && *q; q++) { 2512830Sdjl if ((n = snprintf(s, l, " %s", *q)) >= l) 2522830Sdjl return (NSS_STR_PARSE_ERANGE); 2532830Sdjl l -= n; 2542830Sdjl s += n; 2552830Sdjl } 2562830Sdjl } 2572830Sdjl } 2582830Sdjl 2592830Sdjl ap->returnlen = s - ap->buf.buffer; 2602830Sdjl return (NSS_STR_PARSE_SUCCESS); 2612830Sdjl } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate nss_backend_t * 2640Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate dns_backend_ptr_t be; 2670Sstevel@tonic-gate 2682830Sdjl if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) 2690Sstevel@tonic-gate return (0); 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate be->ops = ops; 2720Sstevel@tonic-gate be->n_ops = n_ops; 2732830Sdjl return ((nss_backend_t *)be); 2742830Sdjl } 2752830Sdjl 2763176Smichen /* 2773176Smichen * __res_ndestroy is a simplified version of the non-public function 2783176Smichen * res_ndestroy in libresolv.so.2. Before res_ndestroy can be made 2793176Smichen * public, __res_ndestroy will be used to make sure the memory pointed 2803176Smichen * by statp->_u._ext.ext is freed after res_nclose() is called. 2813176Smichen */ 2823176Smichen static void 2833176Smichen __res_ndestroy(res_state statp) { 2843176Smichen res_nclose(statp); 2853176Smichen if (statp->_u._ext.ext != NULL) 2863176Smichen free(statp->_u._ext.ext); 2873176Smichen } 2882830Sdjl 2892830Sdjl /* 290*6666Ssm26363 * name_is_alias(aliases_ptr, name_ptr) 291*6666Ssm26363 * Verify name matches an alias in the provided aliases list. 292*6666Ssm26363 * 293*6666Ssm26363 * Within DNS there should be only one canonical name, aliases should 294*6666Ssm26363 * all refer to the one canonical. However alias chains do occur and 295*6666Ssm26363 * pre BIND 9 servers may also respond with multiple CNAMEs. This 296*6666Ssm26363 * routine checks if a given name has been provided as a CNAME in the 297*6666Ssm26363 * response. This assumes that the chains have been sent in-order. 298*6666Ssm26363 * 299*6666Ssm26363 * INPUT: 300*6666Ssm26363 * aliases_ptr: space separated list of alias names. 301*6666Ssm26363 * name_ptr: name to look for in aliases_ptr list. 302*6666Ssm26363 * RETURNS: NSS_SUCCESS or NSS_ERROR 303*6666Ssm26363 * NSS_SUCCESS indicates that the name is listed in the collected aliases. 304*6666Ssm26363 */ 305*6666Ssm26363 static nss_status_t 306*6666Ssm26363 name_is_alias(char *aliases_ptr, char *name_ptr) { 307*6666Ssm26363 char *host_ptr; 308*6666Ssm26363 /* Loop through alias string and compare it against host string. */ 309*6666Ssm26363 while (*aliases_ptr != '\0') { 310*6666Ssm26363 host_ptr = name_ptr; 311*6666Ssm26363 312*6666Ssm26363 /* Compare name with alias. */ 313*6666Ssm26363 while (tolower(*host_ptr) == tolower(*aliases_ptr) && 314*6666Ssm26363 *host_ptr != '\0') { 315*6666Ssm26363 host_ptr++; 316*6666Ssm26363 aliases_ptr++; 317*6666Ssm26363 } 318*6666Ssm26363 319*6666Ssm26363 /* 320*6666Ssm26363 * If name was exhausted and the next character in the 321*6666Ssm26363 * alias is either the end-of-string or space 322*6666Ssm26363 * character then we have a match. 323*6666Ssm26363 */ 324*6666Ssm26363 if (*host_ptr == '\0' && 325*6666Ssm26363 (*aliases_ptr == '\0' || *aliases_ptr == ' ')) { 326*6666Ssm26363 return (NSS_SUCCESS); 327*6666Ssm26363 } 328*6666Ssm26363 329*6666Ssm26363 /* Alias did not match, step over remainder of alias. */ 330*6666Ssm26363 while (*aliases_ptr != ' ' && *aliases_ptr != '\0') 331*6666Ssm26363 aliases_ptr++; 332*6666Ssm26363 /* Step over separator character. */ 333*6666Ssm26363 while (*aliases_ptr == ' ') aliases_ptr++; 334*6666Ssm26363 } 335*6666Ssm26363 return (NSS_ERROR); 336*6666Ssm26363 } 337*6666Ssm26363 338*6666Ssm26363 /* 3392830Sdjl * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 3402830Sdjl * nss2 get hosts/ipnodes with ttl backend DNS search engine. 3412830Sdjl * 3422830Sdjl * This API is given a pointer to a packed buffer, and the buffer size 3432830Sdjl * It's job is to perform the appropriate res_nsearch, extract the 3442830Sdjl * results and build a unmarshalled hosts/ipnodes result buffer. 3452830Sdjl * Additionally in the extended results a nssuint_t ttl is placed. 3462830Sdjl * This ttl is the lessor of the ttl's extracted from the result. 3472830Sdjl * 3482830Sdjl * ***Currently the first version of this API only performs simple 3492830Sdjl * single res_nsearch lookups for with T_A or T_AAAA results. 3502830Sdjl * Other searches are deferred to the generic API w/t ttls. 3512830Sdjl * 3522830Sdjl * This function is not a generic res_* operation. It only performs 3532830Sdjl * a single T_A or T_AAAA lookups*** 3542830Sdjl * 3552830Sdjl * RETURNS: NSS_SUCCESS or NSS_ERROR 3562830Sdjl * If an NSS_ERROR result is returned, nscd is expected 3572830Sdjl * to resubmit the gethosts request using the old style 3582830Sdjl * nsswitch lookup format. 3592830Sdjl */ 3602830Sdjl 3612830Sdjl nss_status_t 3622830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 3632830Sdjl { 3642830Sdjl /* nss buffer variables */ 3652830Sdjl nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 3662830Sdjl nss_XbyY_args_t arg; 3672830Sdjl char *dbname; 3682830Sdjl int dbop; 3692830Sdjl nss_status_t sret; 3702830Sdjl size_t bsize, blen; 3712830Sdjl char *bptr; 3722830Sdjl /* resolver query variables */ 3732924Smichen struct __res_state stat, *statp; /* dns state block */ 3742924Smichen union msg { 3752924Smichen uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ 3762924Smichen HEADER h; 3772924Smichen } resbuf; 3782924Smichen char aliases[NS_MAXMSG]; /* set of aliases */ 3792830Sdjl const char *name; 3802830Sdjl int qtype; 3812830Sdjl /* answer parsing variables */ 3822830Sdjl HEADER *hp; 3832830Sdjl uchar_t *cp; /* current location in message */ 3842830Sdjl uchar_t *bom; /* start of message */ 3852830Sdjl uchar_t *eom; /* end of message */ 3862830Sdjl uchar_t *eor; /* end of record */ 3872830Sdjl int ancount, qdcount; 3882830Sdjl int type, class; 3892830Sdjl nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ 3902830Sdjl int n, ret; 3912830Sdjl const char *np; 3922830Sdjl /* temporary buffers */ 3932830Sdjl char nbuf[INET6_ADDRSTRLEN]; /* address parser */ 3942830Sdjl char host[MAXHOSTNAMELEN]; /* result host name */ 3952830Sdjl char ans[MAXHOSTNAMELEN]; /* record name */ 3962830Sdjl char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ 3972830Sdjl /* misc variables */ 3982830Sdjl int af; 3992830Sdjl char *ap, *apc; 4005161Smichen int hlen = 0, alen, iplen, len; 4012830Sdjl 4022924Smichen statp = &stat; 4032924Smichen (void) memset(statp, '\0', sizeof (struct __res_state)); 4042924Smichen if (res_ninit(statp) == -1) 4052924Smichen return (NSS_ERROR); 4062924Smichen 4072924Smichen ap = apc = (char *)aliases; 4082830Sdjl alen = 0; 4092830Sdjl ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ 4102830Sdjl 4112830Sdjl /* save space for ttl otherwise, why bother... */ 4122830Sdjl bsize = pbuf->data_len - sizeof (nssuint_t); 4132830Sdjl bptr = (char *)buffer + pbuf->data_off; 4142830Sdjl blen = 0; 4152830Sdjl sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 4162830Sdjl if (sret != NSS_SUCCESS) { 4173176Smichen __res_ndestroy(statp); 4182830Sdjl return (NSS_ERROR); 4192830Sdjl } 4202830Sdjl 4212830Sdjl if (ipnode) { 4222830Sdjl /* initially only handle the simple cases */ 4232924Smichen if (arg.key.ipnode.flags != 0) { 4243176Smichen __res_ndestroy(statp); 4252830Sdjl return (NSS_ERROR); 4262924Smichen } 4272830Sdjl name = arg.key.ipnode.name; 4282830Sdjl if (arg.key.ipnode.af_family == AF_INET6) 4292830Sdjl qtype = T_AAAA; 4302830Sdjl else 4312830Sdjl qtype = T_A; 4322830Sdjl } else { 4332830Sdjl name = arg.key.name; 4342830Sdjl qtype = T_A; 4352830Sdjl } 4362924Smichen ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 4372830Sdjl if (ret == -1) { 4382924Smichen if (statp->res_h_errno == HOST_NOT_FOUND) { 4392830Sdjl pbuf->p_herrno = HOST_NOT_FOUND; 4402830Sdjl pbuf->p_status = NSS_NOTFOUND; 4412830Sdjl pbuf->data_len = 0; 4423176Smichen __res_ndestroy(statp); 4432830Sdjl return (NSS_NOTFOUND); 4442830Sdjl } 4452830Sdjl /* else lookup error - handle in general code */ 4463176Smichen __res_ndestroy(statp); 4472830Sdjl return (NSS_ERROR); 4482830Sdjl } 4492830Sdjl 4502924Smichen cp = resbuf.buf; 4512924Smichen hp = (HEADER *)&resbuf.h; 4522830Sdjl bom = cp; 4532830Sdjl eom = cp + ret; 4542830Sdjl 4552830Sdjl ancount = ntohs(hp->ancount); 4562830Sdjl qdcount = ntohs(hp->qdcount); 4572830Sdjl cp += HFIXEDSZ; 4582924Smichen if (qdcount != 1) { 4593176Smichen __res_ndestroy(statp); 4602830Sdjl return (NSS_ERROR); 4612924Smichen } 4622830Sdjl n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); 4632830Sdjl if (n < 0) { 4643176Smichen __res_ndestroy(statp); 4652830Sdjl return (NSS_ERROR); 4662830Sdjl } else 4672830Sdjl hlen = strlen(host); 4685161Smichen /* no host name is an error, return */ 4695161Smichen if (hlen <= 0) { 4705161Smichen __res_ndestroy(statp); 4715161Smichen return (NSS_ERROR); 4725161Smichen } 4732830Sdjl cp += n + QFIXEDSZ; 4742924Smichen if (cp > eom) { 4753176Smichen __res_ndestroy(statp); 4762830Sdjl return (NSS_ERROR); 4772924Smichen } 4782830Sdjl while (ancount-- > 0 && cp < eom && blen < bsize) { 4792830Sdjl n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); 4802830Sdjl if (n > 0) { 481*6666Ssm26363 /* 482*6666Ssm26363 * Check that the expanded name is either the 483*6666Ssm26363 * name we asked for or a learned alias. 484*6666Ssm26363 */ 485*6666Ssm26363 if (strncasecmp(host, ans, hlen) != 0 && (alen == 0 || 486*6666Ssm26363 name_is_alias(aliases, ans) == NSS_ERROR)) { 4873176Smichen __res_ndestroy(statp); 4882830Sdjl return (NSS_ERROR); /* spoof? */ 4892924Smichen } 4902830Sdjl } 4912830Sdjl cp += n; 4922830Sdjl /* bounds check */ 4932830Sdjl type = ns_get16(cp); /* type */ 4942830Sdjl cp += INT16SZ; 4952830Sdjl class = ns_get16(cp); /* class */ 4962830Sdjl cp += INT16SZ; 4972830Sdjl nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ 4982830Sdjl if (nttl < ttl) 4992830Sdjl ttl = nttl; 5002830Sdjl cp += INT32SZ; 5012830Sdjl n = ns_get16(cp); /* len */ 5022830Sdjl cp += INT16SZ; 5032830Sdjl if (class != C_IN) { 5042830Sdjl cp += n; 5052830Sdjl continue; 5062830Sdjl } 5072830Sdjl eor = cp + n; 5082830Sdjl if (type == T_CNAME) { 509*6666Ssm26363 /* 510*6666Ssm26363 * The name we looked up is really an alias 511*6666Ssm26363 * and the canonical name should be in the 512*6666Ssm26363 * RDATA. A canonical name may have several 513*6666Ssm26363 * aliases but an alias should only have one 514*6666Ssm26363 * canonical name. However multiple CNAMEs and 515*6666Ssm26363 * CNAME chains do exist! So for caching 516*6666Ssm26363 * purposes maintain the alias as the host 517*6666Ssm26363 * name, and the CNAME as an alias. 518*6666Ssm26363 */ 5192830Sdjl n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); 5202830Sdjl if (n > 0) { 5212830Sdjl len = strlen(aname); 5222830Sdjl if (len > 0) { 5232830Sdjl /* 5242830Sdjl * Just error out if there is an 5252830Sdjl * attempted buffer overflow exploit 5262830Sdjl * generic code will do a syslog 5272830Sdjl */ 5283176Smichen if (alen + len + 2 > NS_MAXMSG) { 5293176Smichen __res_ndestroy(statp); 5302830Sdjl return (NSS_ERROR); 5313176Smichen } 5322830Sdjl *apc++ = ' '; 5332830Sdjl alen++; 5342830Sdjl (void) strlcpy(apc, aname, len + 1); 5352830Sdjl alen += len; 5362830Sdjl apc += len; 5372830Sdjl } 5382830Sdjl } 5392830Sdjl cp += n; 5402830Sdjl continue; 5412830Sdjl } 5422830Sdjl if (type != qtype) { 5432830Sdjl cp += n; 5442830Sdjl continue; 5452830Sdjl } 5462830Sdjl /* check data size */ 5472830Sdjl if ((type == T_A && n != INADDRSZ) || 5482830Sdjl (type == T_AAAA && n != IN6ADDRSZ)) { 5492830Sdjl cp += n; 5502830Sdjl continue; 5512830Sdjl } 5522830Sdjl af = (type == T_A ? AF_INET : AF_INET6); 5532830Sdjl np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); 5542924Smichen if (np == NULL) { 5553176Smichen __res_ndestroy(statp); 5562830Sdjl return (NSS_ERROR); 5572924Smichen } 5582830Sdjl cp += n; 5592830Sdjl /* append IP host aliases to results */ 5602830Sdjl iplen = strlen(np); 5612830Sdjl /* ip <SP> hostname [<SP>][aliases] */ 5622830Sdjl len = iplen + 2 + hlen + alen; 5632830Sdjl if (alen > 0) 5642830Sdjl len++; 5653176Smichen if (blen + len > bsize) { 5663176Smichen __res_ndestroy(statp); 5672830Sdjl return (NSS_ERROR); 5683176Smichen } 5692830Sdjl (void) strlcpy(bptr, np, bsize - blen); 5702830Sdjl blen += iplen; 5712830Sdjl bptr += iplen; 5722830Sdjl *bptr++ = ' '; 5732830Sdjl blen++; 5742830Sdjl (void) strlcpy(bptr, host, bsize - blen); 5752830Sdjl blen += hlen; 5762830Sdjl bptr += hlen; 5772830Sdjl if (alen > 0) { 5782830Sdjl *bptr++ = ' '; 5792830Sdjl blen++; 5802830Sdjl (void) strlcpy(bptr, ap, bsize - blen); 5812830Sdjl blen += alen; 5822830Sdjl bptr += alen; 5832830Sdjl } 5842830Sdjl *bptr++ = '\n'; 5852830Sdjl blen++; 5862830Sdjl } 5872830Sdjl /* Presumably the buffer is now filled. */ 5882830Sdjl len = ROUND_UP(blen, sizeof (nssuint_t)); 5892830Sdjl /* still room? */ 5902830Sdjl if (len + sizeof (nssuint_t) > pbuf->data_len) { 5912830Sdjl /* sigh, no, what happened? */ 5923176Smichen __res_ndestroy(statp); 5932830Sdjl return (NSS_ERROR); 5942830Sdjl } 5952830Sdjl pbuf->ext_off = pbuf->data_off + len; 5962830Sdjl pbuf->ext_len = sizeof (nssuint_t); 5972830Sdjl pbuf->data_len = blen; 5982830Sdjl pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 5992830Sdjl *pttl = ttl; 6003176Smichen __res_ndestroy(statp); 6012830Sdjl return (NSS_SUCCESS); 6022830Sdjl } 603