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 /* 2210544SStacey.Marshall@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232830Sdjl * Use is subject to license terms. 242830Sdjl */ 252830Sdjl 262830Sdjl /* 270Sstevel@tonic-gate * dns_common.c 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 302830Sdjl #include "dns_common.h" 310Sstevel@tonic-gate 322830Sdjl #pragma weak dn_expand 332830Sdjl #pragma weak res_ninit 34*10545SStacey.Marshall@Sun.COM #pragma weak res_ndestroy 352830Sdjl #pragma weak res_nsearch 362830Sdjl #pragma weak res_nclose 372830Sdjl #pragma weak ns_get16 382830Sdjl #pragma weak ns_get32 392830Sdjl #pragma weak __ns_get16 402830Sdjl #pragma weak __ns_get32 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define DNS_ALIASES 0 430Sstevel@tonic-gate #define DNS_ADDRLIST 1 440Sstevel@tonic-gate #define DNS_MAPDLIST 2 450Sstevel@tonic-gate 466666Ssm26363 #ifndef tolower 476666Ssm26363 #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) | 0x20 : (c)) 486666Ssm26363 #endif 496666Ssm26363 500Sstevel@tonic-gate static int 510Sstevel@tonic-gate dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type) 520Sstevel@tonic-gate char **from_list, **to_list, **aliaspp; 530Sstevel@tonic-gate int type, *count, af_type; 540Sstevel@tonic-gate { 550Sstevel@tonic-gate char *fstr; 560Sstevel@tonic-gate int cnt = 0; 570Sstevel@tonic-gate size_t len; 580Sstevel@tonic-gate 590Sstevel@tonic-gate *count = 0; 600Sstevel@tonic-gate if ((char *)to_list >= *aliaspp) 610Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 620Sstevel@tonic-gate 630Sstevel@tonic-gate for (fstr = from_list[cnt]; fstr != NULL; fstr = from_list[cnt]) { 640Sstevel@tonic-gate if (type == DNS_ALIASES) 650Sstevel@tonic-gate len = strlen(fstr) + 1; 660Sstevel@tonic-gate else 670Sstevel@tonic-gate len = (af_type == AF_INET) ? sizeof (struct in_addr) 680Sstevel@tonic-gate : sizeof (struct in6_addr); 690Sstevel@tonic-gate *aliaspp -= len; 700Sstevel@tonic-gate to_list[cnt] = *aliaspp; 710Sstevel@tonic-gate if (*aliaspp <= (char *)&to_list[cnt+1]) 720Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 730Sstevel@tonic-gate if (type == DNS_MAPDLIST) { 742830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 752830Sdjl struct in6_addr *addr6p = (struct in6_addr *)*aliaspp; 760Sstevel@tonic-gate 770Sstevel@tonic-gate (void) memset(addr6p, '\0', sizeof (struct in6_addr)); 780Sstevel@tonic-gate (void) memcpy(&addr6p->s6_addr[12], fstr, 790Sstevel@tonic-gate sizeof (struct in_addr)); 800Sstevel@tonic-gate addr6p->s6_addr[10] = 0xffU; 810Sstevel@tonic-gate addr6p->s6_addr[11] = 0xffU; 820Sstevel@tonic-gate ++cnt; 830Sstevel@tonic-gate } else { 840Sstevel@tonic-gate (void) memcpy (*aliaspp, fstr, len); 850Sstevel@tonic-gate ++cnt; 860Sstevel@tonic-gate } 870Sstevel@tonic-gate } 880Sstevel@tonic-gate to_list[cnt] = NULL; 890Sstevel@tonic-gate 900Sstevel@tonic-gate *count = cnt; 910Sstevel@tonic-gate if (cnt == 0) 920Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 930Sstevel@tonic-gate 940Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate 980Sstevel@tonic-gate int 990Sstevel@tonic-gate ent2result(he, argp, af_type) 1000Sstevel@tonic-gate struct hostent *he; 1010Sstevel@tonic-gate nss_XbyY_args_t *argp; 1020Sstevel@tonic-gate int af_type; 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate char *buffer, *limit; 1050Sstevel@tonic-gate int buflen = argp->buf.buflen; 1060Sstevel@tonic-gate int ret, count; 1070Sstevel@tonic-gate size_t len; 1080Sstevel@tonic-gate struct hostent *host; 1090Sstevel@tonic-gate struct in_addr *addrp; 1100Sstevel@tonic-gate struct in6_addr *addrp6; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate limit = argp->buf.buffer + buflen; 1132830Sdjl host = (struct hostent *)argp->buf.result; 1140Sstevel@tonic-gate buffer = argp->buf.buffer; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* h_addrtype and h_length */ 1170Sstevel@tonic-gate host->h_addrtype = af_type; 1180Sstevel@tonic-gate host->h_length = (af_type == AF_INET) ? sizeof (struct in_addr) 1190Sstevel@tonic-gate : sizeof (struct in6_addr); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* h_name */ 1220Sstevel@tonic-gate len = strlen(he->h_name) + 1; 1230Sstevel@tonic-gate host->h_name = buffer; 1240Sstevel@tonic-gate if (host->h_name + len >= limit) 1250Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 1260Sstevel@tonic-gate (void) memcpy(host->h_name, he->h_name, len); 1270Sstevel@tonic-gate buffer += len; 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* h_addr_list */ 1300Sstevel@tonic-gate if (af_type == AF_INET) { 1312830Sdjl addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp)); 1320Sstevel@tonic-gate host->h_addr_list = (char **) 1330Sstevel@tonic-gate ROUND_UP(buffer, sizeof (char **)); 1340Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list, 1350Sstevel@tonic-gate (char **)&addrp, DNS_ADDRLIST, &count, af_type); 1360Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS) 1370Sstevel@tonic-gate return (ret); 1380Sstevel@tonic-gate /* h_aliases */ 1390Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 1400Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 1410Sstevel@tonic-gate (char **)&addrp, DNS_ALIASES, &count, af_type); 1420Sstevel@tonic-gate } else { 1430Sstevel@tonic-gate addrp6 = (struct in6_addr *) 1440Sstevel@tonic-gate ROUND_DOWN(limit, sizeof (*addrp6)); 1450Sstevel@tonic-gate host->h_addr_list = (char **) 1460Sstevel@tonic-gate ROUND_UP(buffer, sizeof (char **)); 1470Sstevel@tonic-gate if (he->h_addrtype == AF_INET && af_type == AF_INET6) { 1480Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, 1490Sstevel@tonic-gate host->h_addr_list, (char **)&addrp6, 1500Sstevel@tonic-gate DNS_MAPDLIST, &count, af_type); 1510Sstevel@tonic-gate } else { 1520Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_addr_list, 1530Sstevel@tonic-gate host->h_addr_list, (char **)&addrp6, 1540Sstevel@tonic-gate DNS_ADDRLIST, &count, af_type); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate if (ret != NSS_STR_PARSE_SUCCESS) 1570Sstevel@tonic-gate return (ret); 1580Sstevel@tonic-gate /* h_aliases */ 1590Sstevel@tonic-gate host->h_aliases = host->h_addr_list + count + 1; 1600Sstevel@tonic-gate ret = dns_netdb_aliases(he->h_aliases, host->h_aliases, 1610Sstevel@tonic-gate (char **)&addrp6, DNS_ALIASES, &count, af_type); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate if (ret == NSS_STR_PARSE_PARSE) 1640Sstevel@tonic-gate ret = NSS_STR_PARSE_SUCCESS; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate return (ret); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1692830Sdjl /* 1702830Sdjl * Convert the hostent structure into string in the following 1712830Sdjl * format: 1722830Sdjl * 1732830Sdjl * IP-address official-host-name nicknames ... 1742830Sdjl * 1752830Sdjl * If more than one IP-addresses matches the official-host-name, 1762830Sdjl * the above line will be followed by: 1772830Sdjl * IP-address-1 official-host-name 1782830Sdjl * IP-address-2 official-host-name 1792830Sdjl * ... 1802830Sdjl * 1812830Sdjl * This is so that the str2hostent function in libnsl 1822830Sdjl * can convert the string back to the original hostent 1832830Sdjl * data. 1842830Sdjl */ 1852830Sdjl int 1862830Sdjl ent2str( 1872830Sdjl struct hostent *hp, 1882830Sdjl nss_XbyY_args_t *ap, 1892830Sdjl int af_type) 1902830Sdjl { 1912830Sdjl char **p; 1922830Sdjl char obuf[INET6_ADDRSTRLEN]; 1932830Sdjl void *addr; 1942830Sdjl struct in_addr in4; 1952830Sdjl int af; 1962830Sdjl int n; 1972830Sdjl const char *res; 1982830Sdjl char **q; 1992830Sdjl int l = ap->buf.buflen; 2002830Sdjl char *s = ap->buf.buffer; 2012830Sdjl 2022830Sdjl /* 2032830Sdjl * for "hosts" lookup, we only want address type of 2042830Sdjl * AF_INET. For "ipnodes", we can have both AF_INET 2052830Sdjl * and AF_INET6. 2062830Sdjl */ 2072830Sdjl if (af_type == AF_INET && hp->h_addrtype != AF_INET) 2082830Sdjl return (NSS_STR_PARSE_PARSE); 2092830Sdjl 2102830Sdjl for (p = hp->h_addr_list; *p != 0; p++) { 2112830Sdjl 2122830Sdjl if (p != hp->h_addr_list) { 2132830Sdjl *s = '\n'; 2142830Sdjl s++; 2152830Sdjl l--; 2162830Sdjl } 2172830Sdjl 2182830Sdjl if (hp->h_addrtype == AF_INET6) { 2192830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 2202830Sdjl if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) { 2212830Sdjl /* LINTED: E_BAD_PTR_CAST_ALIGN */ 2222830Sdjl IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p, 2235161Smichen &in4); 2242830Sdjl af = AF_INET; 2252830Sdjl addr = &in4; 2262830Sdjl } else { 2272830Sdjl af = AF_INET6; 2282830Sdjl addr = *p; 2292830Sdjl } 2302830Sdjl } else { 2312830Sdjl af = AF_INET; 2322830Sdjl addr = *p; 2332830Sdjl } 2342830Sdjl res = inet_ntop(af, addr, obuf, sizeof (obuf)); 2352830Sdjl if (res == NULL) 2362830Sdjl return (NSS_STR_PARSE_PARSE); 2372830Sdjl 2385161Smichen if ((n = snprintf(s, l, "%s", res)) >= l) 2392830Sdjl return (NSS_STR_PARSE_ERANGE); 2402830Sdjl l -= n; 2412830Sdjl s += n; 2425161Smichen if (hp->h_name != NULL && *hp->h_name != '\0') { 2435161Smichen if ((n = snprintf(s, l, " %s", hp->h_name)) >= l) 2445161Smichen return (NSS_STR_PARSE_ERANGE); 2455161Smichen l -= n; 2465161Smichen s += n; 2475161Smichen } 2482830Sdjl if (p == hp->h_addr_list) { 2492830Sdjl for (q = hp->h_aliases; q && *q; q++) { 2502830Sdjl if ((n = snprintf(s, l, " %s", *q)) >= l) 2512830Sdjl return (NSS_STR_PARSE_ERANGE); 2522830Sdjl l -= n; 2532830Sdjl s += n; 2542830Sdjl } 2552830Sdjl } 2562830Sdjl } 2572830Sdjl 2582830Sdjl ap->returnlen = s - ap->buf.buffer; 2592830Sdjl return (NSS_STR_PARSE_SUCCESS); 2602830Sdjl } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate nss_backend_t * 2630Sstevel@tonic-gate _nss_dns_constr(dns_backend_op_t ops[], int n_ops) 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate dns_backend_ptr_t be; 2660Sstevel@tonic-gate 2672830Sdjl if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) 2680Sstevel@tonic-gate return (0); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate be->ops = ops; 2710Sstevel@tonic-gate be->n_ops = n_ops; 2722830Sdjl return ((nss_backend_t *)be); 2732830Sdjl } 2742830Sdjl 2753176Smichen /* 2766666Ssm26363 * name_is_alias(aliases_ptr, name_ptr) 2776666Ssm26363 * Verify name matches an alias in the provided aliases list. 2786666Ssm26363 * 2796666Ssm26363 * Within DNS there should be only one canonical name, aliases should 2806666Ssm26363 * all refer to the one canonical. However alias chains do occur and 2816666Ssm26363 * pre BIND 9 servers may also respond with multiple CNAMEs. This 2826666Ssm26363 * routine checks if a given name has been provided as a CNAME in the 2836666Ssm26363 * response. This assumes that the chains have been sent in-order. 2846666Ssm26363 * 2856666Ssm26363 * INPUT: 2866666Ssm26363 * aliases_ptr: space separated list of alias names. 2876666Ssm26363 * name_ptr: name to look for in aliases_ptr list. 28810544SStacey.Marshall@Sun.COM * RETURNS: NSS_SUCCESS or NSS_NOTFOUND 2896666Ssm26363 * NSS_SUCCESS indicates that the name is listed in the collected aliases. 2906666Ssm26363 */ 2916666Ssm26363 static nss_status_t 2926666Ssm26363 name_is_alias(char *aliases_ptr, char *name_ptr) { 2936666Ssm26363 char *host_ptr; 2946666Ssm26363 /* Loop through alias string and compare it against host string. */ 2956666Ssm26363 while (*aliases_ptr != '\0') { 2966666Ssm26363 host_ptr = name_ptr; 2976666Ssm26363 2986666Ssm26363 /* Compare name with alias. */ 2996666Ssm26363 while (tolower(*host_ptr) == tolower(*aliases_ptr) && 3006666Ssm26363 *host_ptr != '\0') { 3016666Ssm26363 host_ptr++; 3026666Ssm26363 aliases_ptr++; 3036666Ssm26363 } 3046666Ssm26363 3056666Ssm26363 /* 3066666Ssm26363 * If name was exhausted and the next character in the 3076666Ssm26363 * alias is either the end-of-string or space 3086666Ssm26363 * character then we have a match. 3096666Ssm26363 */ 3106666Ssm26363 if (*host_ptr == '\0' && 3116666Ssm26363 (*aliases_ptr == '\0' || *aliases_ptr == ' ')) { 3126666Ssm26363 return (NSS_SUCCESS); 3136666Ssm26363 } 3146666Ssm26363 3156666Ssm26363 /* Alias did not match, step over remainder of alias. */ 3166666Ssm26363 while (*aliases_ptr != ' ' && *aliases_ptr != '\0') 3176666Ssm26363 aliases_ptr++; 3186666Ssm26363 /* Step over separator character. */ 3196666Ssm26363 while (*aliases_ptr == ' ') aliases_ptr++; 3206666Ssm26363 } 32110544SStacey.Marshall@Sun.COM return (NSS_NOTFOUND); 3226666Ssm26363 } 3236666Ssm26363 3246666Ssm26363 /* 3252830Sdjl * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 3262830Sdjl * nss2 get hosts/ipnodes with ttl backend DNS search engine. 3272830Sdjl * 3282830Sdjl * This API is given a pointer to a packed buffer, and the buffer size 3292830Sdjl * It's job is to perform the appropriate res_nsearch, extract the 3302830Sdjl * results and build a unmarshalled hosts/ipnodes result buffer. 3312830Sdjl * Additionally in the extended results a nssuint_t ttl is placed. 3322830Sdjl * This ttl is the lessor of the ttl's extracted from the result. 3332830Sdjl * 3342830Sdjl * ***Currently the first version of this API only performs simple 3352830Sdjl * single res_nsearch lookups for with T_A or T_AAAA results. 3362830Sdjl * Other searches are deferred to the generic API w/t ttls. 3372830Sdjl * 3382830Sdjl * This function is not a generic res_* operation. It only performs 3392830Sdjl * a single T_A or T_AAAA lookups*** 3402830Sdjl * 3412830Sdjl * RETURNS: NSS_SUCCESS or NSS_ERROR 3422830Sdjl * If an NSS_ERROR result is returned, nscd is expected 3432830Sdjl * to resubmit the gethosts request using the old style 3442830Sdjl * nsswitch lookup format. 3452830Sdjl */ 3462830Sdjl 3472830Sdjl nss_status_t 3482830Sdjl _nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) 3492830Sdjl { 3502830Sdjl /* nss buffer variables */ 3512830Sdjl nss_pheader_t *pbuf = (nss_pheader_t *)buffer; 3522830Sdjl nss_XbyY_args_t arg; 3532830Sdjl char *dbname; 3542830Sdjl int dbop; 3552830Sdjl nss_status_t sret; 3562830Sdjl size_t bsize, blen; 3572830Sdjl char *bptr; 3582830Sdjl /* resolver query variables */ 3592924Smichen struct __res_state stat, *statp; /* dns state block */ 3602924Smichen union msg { 3612924Smichen uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ 3622924Smichen HEADER h; 3632924Smichen } resbuf; 3642924Smichen char aliases[NS_MAXMSG]; /* set of aliases */ 3652830Sdjl const char *name; 3662830Sdjl int qtype; 3672830Sdjl /* answer parsing variables */ 3682830Sdjl HEADER *hp; 3692830Sdjl uchar_t *cp; /* current location in message */ 3702830Sdjl uchar_t *bom; /* start of message */ 3712830Sdjl uchar_t *eom; /* end of message */ 3722830Sdjl uchar_t *eor; /* end of record */ 3732830Sdjl int ancount, qdcount; 3742830Sdjl int type, class; 3752830Sdjl nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ 3762830Sdjl int n, ret; 3772830Sdjl const char *np; 3782830Sdjl /* temporary buffers */ 3792830Sdjl char nbuf[INET6_ADDRSTRLEN]; /* address parser */ 3802830Sdjl char host[MAXHOSTNAMELEN]; /* result host name */ 3812830Sdjl char ans[MAXHOSTNAMELEN]; /* record name */ 3822830Sdjl char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ 3832830Sdjl /* misc variables */ 3842830Sdjl int af; 3852830Sdjl char *ap, *apc; 38610544SStacey.Marshall@Sun.COM int hlen = 0, alen, iplen, len, isans; 3872830Sdjl 3882924Smichen statp = &stat; 3892924Smichen (void) memset(statp, '\0', sizeof (struct __res_state)); 3902924Smichen if (res_ninit(statp) == -1) 3912924Smichen return (NSS_ERROR); 3922924Smichen 3932924Smichen ap = apc = (char *)aliases; 3942830Sdjl alen = 0; 3952830Sdjl ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ 3962830Sdjl 3972830Sdjl /* save space for ttl otherwise, why bother... */ 3982830Sdjl bsize = pbuf->data_len - sizeof (nssuint_t); 3992830Sdjl bptr = (char *)buffer + pbuf->data_off; 4002830Sdjl blen = 0; 4012830Sdjl sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); 4022830Sdjl if (sret != NSS_SUCCESS) { 403*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4042830Sdjl return (NSS_ERROR); 4052830Sdjl } 4062830Sdjl 4072830Sdjl if (ipnode) { 4082830Sdjl /* initially only handle the simple cases */ 4092924Smichen if (arg.key.ipnode.flags != 0) { 410*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4112830Sdjl return (NSS_ERROR); 4122924Smichen } 4132830Sdjl name = arg.key.ipnode.name; 4142830Sdjl if (arg.key.ipnode.af_family == AF_INET6) 4152830Sdjl qtype = T_AAAA; 4162830Sdjl else 4172830Sdjl qtype = T_A; 4182830Sdjl } else { 4192830Sdjl name = arg.key.name; 4202830Sdjl qtype = T_A; 4212830Sdjl } 4222924Smichen ret = res_nsearch(statp, name, C_IN, qtype, resbuf.buf, NS_MAXMSG); 4232830Sdjl if (ret == -1) { 4242924Smichen if (statp->res_h_errno == HOST_NOT_FOUND) { 4252830Sdjl pbuf->p_herrno = HOST_NOT_FOUND; 4262830Sdjl pbuf->p_status = NSS_NOTFOUND; 4272830Sdjl pbuf->data_len = 0; 428*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4292830Sdjl return (NSS_NOTFOUND); 4302830Sdjl } 4312830Sdjl /* else lookup error - handle in general code */ 432*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4332830Sdjl return (NSS_ERROR); 4342830Sdjl } 4352830Sdjl 4362924Smichen cp = resbuf.buf; 4372924Smichen hp = (HEADER *)&resbuf.h; 4382830Sdjl bom = cp; 4392830Sdjl eom = cp + ret; 4402830Sdjl 4412830Sdjl ancount = ntohs(hp->ancount); 4422830Sdjl qdcount = ntohs(hp->qdcount); 4432830Sdjl cp += HFIXEDSZ; 4442924Smichen if (qdcount != 1) { 445*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4462830Sdjl return (NSS_ERROR); 4472924Smichen } 4482830Sdjl n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); 4492830Sdjl if (n < 0) { 450*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4512830Sdjl return (NSS_ERROR); 4522830Sdjl } else 4532830Sdjl hlen = strlen(host); 4545161Smichen /* no host name is an error, return */ 4555161Smichen if (hlen <= 0) { 456*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4575161Smichen return (NSS_ERROR); 4585161Smichen } 4592830Sdjl cp += n + QFIXEDSZ; 4602924Smichen if (cp > eom) { 461*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4622830Sdjl return (NSS_ERROR); 4632924Smichen } 4642830Sdjl while (ancount-- > 0 && cp < eom && blen < bsize) { 4652830Sdjl n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); 4662830Sdjl if (n > 0) { 4676666Ssm26363 /* 4686666Ssm26363 * Check that the expanded name is either the 4696666Ssm26363 * name we asked for or a learned alias. 4706666Ssm26363 */ 47110544SStacey.Marshall@Sun.COM if ((isans = strncasecmp(host, ans, hlen)) != 0 && 47210544SStacey.Marshall@Sun.COM (alen == 0 || name_is_alias(aliases, ans) 47310544SStacey.Marshall@Sun.COM == NSS_NOTFOUND)) { 474*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 4752830Sdjl return (NSS_ERROR); /* spoof? */ 4762924Smichen } 4772830Sdjl } 4782830Sdjl cp += n; 4792830Sdjl /* bounds check */ 4802830Sdjl type = ns_get16(cp); /* type */ 4812830Sdjl cp += INT16SZ; 4822830Sdjl class = ns_get16(cp); /* class */ 4832830Sdjl cp += INT16SZ; 48410544SStacey.Marshall@Sun.COM nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ 4852830Sdjl if (nttl < ttl) 4862830Sdjl ttl = nttl; 4872830Sdjl cp += INT32SZ; 4882830Sdjl n = ns_get16(cp); /* len */ 4892830Sdjl cp += INT16SZ; 4902830Sdjl if (class != C_IN) { 4912830Sdjl cp += n; 4922830Sdjl continue; 4932830Sdjl } 4942830Sdjl eor = cp + n; 4952830Sdjl if (type == T_CNAME) { 4966666Ssm26363 /* 49710544SStacey.Marshall@Sun.COM * The name looked up is really an alias and the 49810544SStacey.Marshall@Sun.COM * canonical name should be in the RDATA. 49910544SStacey.Marshall@Sun.COM * A canonical name may have several aliases but an 50010544SStacey.Marshall@Sun.COM * alias should only have one canonical name. 50110544SStacey.Marshall@Sun.COM * However multiple CNAMEs and CNAME chains do exist! 50210544SStacey.Marshall@Sun.COM * 50310544SStacey.Marshall@Sun.COM * Just error out on attempted buffer overflow exploit, 50410544SStacey.Marshall@Sun.COM * generic code will syslog. 50510544SStacey.Marshall@Sun.COM * 5066666Ssm26363 */ 5072830Sdjl n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); 50810544SStacey.Marshall@Sun.COM if (n > 0 && (len = strlen(aname)) > 0) { 50910544SStacey.Marshall@Sun.COM if (isans == 0) { /* host matched ans. */ 5102830Sdjl /* 51110544SStacey.Marshall@Sun.COM * Append host to alias list. 5122830Sdjl */ 51310544SStacey.Marshall@Sun.COM if (alen + hlen + 2 > NS_MAXMSG) { 514*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 5152830Sdjl return (NSS_ERROR); 5163176Smichen } 5172830Sdjl *apc++ = ' '; 5182830Sdjl alen++; 51910544SStacey.Marshall@Sun.COM (void) strlcpy(apc, host, 52010544SStacey.Marshall@Sun.COM NS_MAXMSG - alen); 52110544SStacey.Marshall@Sun.COM alen += hlen; 52210544SStacey.Marshall@Sun.COM apc += hlen; 5232830Sdjl } 52410544SStacey.Marshall@Sun.COM /* 52510544SStacey.Marshall@Sun.COM * Overwrite host with canonical name. 52610544SStacey.Marshall@Sun.COM */ 52710544SStacey.Marshall@Sun.COM if (strlcpy(host, aname, MAXHOSTNAMELEN) >= 52810544SStacey.Marshall@Sun.COM MAXHOSTNAMELEN) { 529*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 53010544SStacey.Marshall@Sun.COM return (NSS_ERROR); 53110544SStacey.Marshall@Sun.COM } 53210544SStacey.Marshall@Sun.COM hlen = len; 5332830Sdjl } 5342830Sdjl cp += n; 5352830Sdjl continue; 5362830Sdjl } 5372830Sdjl if (type != qtype) { 5382830Sdjl cp += n; 5392830Sdjl continue; 5402830Sdjl } 5412830Sdjl /* check data size */ 5422830Sdjl if ((type == T_A && n != INADDRSZ) || 5432830Sdjl (type == T_AAAA && n != IN6ADDRSZ)) { 5442830Sdjl cp += n; 5452830Sdjl continue; 5462830Sdjl } 5472830Sdjl af = (type == T_A ? AF_INET : AF_INET6); 5482830Sdjl np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); 5492924Smichen if (np == NULL) { 550*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 5512830Sdjl return (NSS_ERROR); 5522924Smichen } 5532830Sdjl cp += n; 5542830Sdjl /* append IP host aliases to results */ 5552830Sdjl iplen = strlen(np); 5562830Sdjl /* ip <SP> hostname [<SP>][aliases] */ 5572830Sdjl len = iplen + 2 + hlen + alen; 5582830Sdjl if (alen > 0) 5592830Sdjl len++; 5603176Smichen if (blen + len > bsize) { 561*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 5622830Sdjl return (NSS_ERROR); 5633176Smichen } 5642830Sdjl (void) strlcpy(bptr, np, bsize - blen); 5652830Sdjl blen += iplen; 5662830Sdjl bptr += iplen; 5672830Sdjl *bptr++ = ' '; 5682830Sdjl blen++; 5692830Sdjl (void) strlcpy(bptr, host, bsize - blen); 5702830Sdjl blen += hlen; 5712830Sdjl bptr += hlen; 5722830Sdjl if (alen > 0) { 5732830Sdjl *bptr++ = ' '; 5742830Sdjl blen++; 5752830Sdjl (void) strlcpy(bptr, ap, bsize - blen); 5762830Sdjl blen += alen; 5772830Sdjl bptr += alen; 5782830Sdjl } 5792830Sdjl *bptr++ = '\n'; 5802830Sdjl blen++; 5812830Sdjl } 5822830Sdjl /* Presumably the buffer is now filled. */ 5832830Sdjl len = ROUND_UP(blen, sizeof (nssuint_t)); 5842830Sdjl /* still room? */ 5852830Sdjl if (len + sizeof (nssuint_t) > pbuf->data_len) { 5862830Sdjl /* sigh, no, what happened? */ 587*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 5882830Sdjl return (NSS_ERROR); 5892830Sdjl } 5902830Sdjl pbuf->ext_off = pbuf->data_off + len; 5912830Sdjl pbuf->ext_len = sizeof (nssuint_t); 5922830Sdjl pbuf->data_len = blen; 5932830Sdjl pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); 5942830Sdjl *pttl = ttl; 595*10545SStacey.Marshall@Sun.COM res_ndestroy(statp); 5962830Sdjl return (NSS_SUCCESS); 5972830Sdjl } 598