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
dns_netdb_aliases(from_list,to_list,aliaspp,type,count,af_type)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
ent2result(he,argp,af_type)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
ent2str(struct hostent * hp,nss_XbyY_args_t * ap,int af_type)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 *
_nss_dns_constr(dns_backend_op_t ops[],int n_ops)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
name_is_alias(char * aliases_ptr,char * name_ptr)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
_nss_dns_gethost_withttl(void * buffer,size_t bufsize,int ipnode)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