xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/dnsglue.c (revision 7934:6aeeafc994de)
11047Sgtb /*
26815Ssemery  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
31047Sgtb  * Use is subject to license terms.
41047Sgtb  */
51047Sgtb 
6781Sgtb /*
7781Sgtb  * lib/krb5/os/dnsglue.c
8781Sgtb  *
9781Sgtb  * Copyright 2004 by the Massachusetts Institute of Technology.
10781Sgtb  * All Rights Reserved.
11781Sgtb  *
12781Sgtb  * Export of this software from the United States of America may
13781Sgtb  *   require a specific license from the United States Government.
14781Sgtb  *   It is the responsibility of any person or organization contemplating
15781Sgtb  *   export to obtain such a license before exporting.
16781Sgtb  *
17781Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18781Sgtb  * distribute this software and its documentation for any purpose and
19781Sgtb  * without fee is hereby granted, provided that the above copyright
20781Sgtb  * notice appear in all copies and that both that copyright notice and
21781Sgtb  * this permission notice appear in supporting documentation, and that
22781Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
23781Sgtb  * to distribution of the software without specific, written prior
24781Sgtb  * permission.  Furthermore if you modify this software you must label
25781Sgtb  * your software as modified software and not distribute it in such a
26781Sgtb  * fashion that it might be confused with the original M.I.T. software.
27781Sgtb  * M.I.T. makes no representations about the suitability of
28781Sgtb  * this software for any purpose.  It is provided "as is" without express
29781Sgtb  * or implied warranty.
30781Sgtb  *
31781Sgtb  */
32*7934SMark.Phalan@Sun.COM #include "autoconf.h"
33781Sgtb #ifdef KRB5_DNS_LOOKUP
34781Sgtb 
35781Sgtb #include "dnsglue.h"
36781Sgtb 
37781Sgtb /*
38*7934SMark.Phalan@Sun.COM  * Only use res_ninit() if there's also a res_ndestroy(), to avoid
39*7934SMark.Phalan@Sun.COM  * memory leaks (Linux & Solaris) and outright corruption (AIX 4.x,
40*7934SMark.Phalan@Sun.COM  * 5.x).  While we're at it, make sure res_nsearch() is there too.
41*7934SMark.Phalan@Sun.COM  *
42*7934SMark.Phalan@Sun.COM  * In any case, it is probable that platforms having broken
43*7934SMark.Phalan@Sun.COM  * res_ninit() will have thread safety hacks for res_init() and _res.
44*7934SMark.Phalan@Sun.COM  */
45*7934SMark.Phalan@Sun.COM #if HAVE_RES_NINIT && HAVE_RES_NDESTROY && HAVE_RES_NSEARCH
46*7934SMark.Phalan@Sun.COM #define USE_RES_NINIT 1
47*7934SMark.Phalan@Sun.COM #endif
48*7934SMark.Phalan@Sun.COM 
49*7934SMark.Phalan@Sun.COM /*
50781Sgtb  * Opaque handle
51781Sgtb  */
52781Sgtb struct krb5int_dns_state {
53781Sgtb     int nclass;
54781Sgtb     int ntype;
55781Sgtb     void *ansp;
56781Sgtb     int anslen;
57781Sgtb     int ansmax;
58781Sgtb #if HAVE_NS_INITPARSE
59781Sgtb     int cur_ans;
60781Sgtb     ns_msg msg;
61781Sgtb #else
62781Sgtb     unsigned char *ptr;
63781Sgtb     unsigned short nanswers;
64781Sgtb #endif
65781Sgtb };
66781Sgtb 
67781Sgtb #if !HAVE_NS_INITPARSE
68781Sgtb static int initparse(struct krb5int_dns_state *);
69781Sgtb #endif
70781Sgtb 
71781Sgtb /*
72781Sgtb  * krb5int_dns_init()
73781Sgtb  *
74*7934SMark.Phalan@Sun.COM  * Initialize an opaque handle.  Do name lookup and initial parsing of
75781Sgtb  * reply, skipping question section.  Prepare to iterate over answer
76781Sgtb  * section.  Returns -1 on error, 0 on success.
77781Sgtb  */
78781Sgtb int
krb5int_dns_init(struct krb5int_dns_state ** dsp,char * host,int nclass,int ntype)79781Sgtb krb5int_dns_init(struct krb5int_dns_state **dsp,
80781Sgtb 		 char *host, int nclass, int ntype)
81781Sgtb {
82*7934SMark.Phalan@Sun.COM #if USE_RES_NINIT
83781Sgtb     struct __res_state statbuf;
84781Sgtb #endif
85781Sgtb     struct krb5int_dns_state *ds;
86781Sgtb     int len, ret;
87781Sgtb     size_t nextincr, maxincr;
88781Sgtb     unsigned char *p;
89781Sgtb 
90781Sgtb     *dsp = ds = malloc(sizeof(*ds));
91781Sgtb     if (ds == NULL)
92781Sgtb 	return -1;
93781Sgtb 
94781Sgtb     ret = -1;
95781Sgtb     ds->nclass = nclass;
96781Sgtb     ds->ntype = ntype;
97781Sgtb     ds->ansp = NULL;
98781Sgtb     ds->anslen = 0;
99781Sgtb     ds->ansmax = 0;
100781Sgtb     nextincr = 2048;
101781Sgtb     maxincr = INT_MAX;
102781Sgtb 
103781Sgtb #if HAVE_NS_INITPARSE
104781Sgtb     ds->cur_ans = 0;
105781Sgtb #endif
106781Sgtb 
107*7934SMark.Phalan@Sun.COM #if USE_RES_NINIT
1086815Ssemery     memset(&statbuf, 0, sizeof(statbuf));
109781Sgtb     ret = res_ninit(&statbuf);
110*7934SMark.Phalan@Sun.COM #else
111*7934SMark.Phalan@Sun.COM     ret = res_init();
112*7934SMark.Phalan@Sun.COM #endif
113781Sgtb     if (ret < 0)
114781Sgtb 	return -1;
115781Sgtb 
116781Sgtb     do {
117781Sgtb 	p = (ds->ansp == NULL)
118781Sgtb 	    ? malloc(nextincr) : realloc(ds->ansp, nextincr);
119781Sgtb 
120781Sgtb 	if (p == NULL && ds->ansp != NULL) {
121781Sgtb 	    ret = -1;
122781Sgtb 	    goto errout;
123781Sgtb 	}
124781Sgtb 	ds->ansp = p;
125781Sgtb 	ds->ansmax = nextincr;
126781Sgtb 
127*7934SMark.Phalan@Sun.COM #if USE_RES_NINIT
128781Sgtb 	len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
129781Sgtb 			  ds->ansp, ds->ansmax);
130781Sgtb #else
131781Sgtb 	len = res_search(host, ds->nclass, ds->ntype,
132781Sgtb 			 ds->ansp, ds->ansmax);
133781Sgtb #endif
134781Sgtb 	if (len > maxincr) {
135781Sgtb 	    ret = -1;
136781Sgtb 	    goto errout;
137781Sgtb 	}
138781Sgtb 	while (nextincr < len)
139781Sgtb 	    nextincr *= 2;
140781Sgtb 	if (len < 0 || nextincr > maxincr) {
141781Sgtb 	    ret = -1;
142781Sgtb 	    goto errout;
143781Sgtb 	}
144781Sgtb     } while (len > ds->ansmax);
145781Sgtb 
146781Sgtb     ds->anslen = len;
147781Sgtb #if HAVE_NS_INITPARSE
148781Sgtb     ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
149781Sgtb #else
150781Sgtb     ret = initparse(ds);
151781Sgtb #endif
152781Sgtb     if (ret < 0)
153781Sgtb 	goto errout;
154781Sgtb 
155781Sgtb     ret = 0;
156781Sgtb 
157781Sgtb errout:
158*7934SMark.Phalan@Sun.COM #if USE_RES_NINIT
159781Sgtb     res_ndestroy(&statbuf);
160781Sgtb #endif
161781Sgtb     if (ret < 0) {
162781Sgtb 	if (ds->ansp != NULL) {
163781Sgtb 	    free(ds->ansp);
164781Sgtb 	    ds->ansp = NULL;
165781Sgtb 	}
166781Sgtb     }
167781Sgtb 
168781Sgtb     return ret;
169781Sgtb }
170781Sgtb 
171781Sgtb #if HAVE_NS_INITPARSE
172781Sgtb /*
173781Sgtb  * krb5int_dns_nextans - get next matching answer record
174781Sgtb  *
175781Sgtb  * Sets pp to NULL if no more records.  Returns -1 on error, 0 on
176781Sgtb  * success.
177781Sgtb  */
178781Sgtb int
krb5int_dns_nextans(struct krb5int_dns_state * ds,const unsigned char ** pp,int * lenp)179781Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds,
180781Sgtb 		    const unsigned char **pp, int *lenp)
181781Sgtb {
182781Sgtb     int len;
183781Sgtb     ns_rr rr;
184781Sgtb 
185781Sgtb     *pp = NULL;
186781Sgtb     *lenp = 0;
187781Sgtb     while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
188781Sgtb 	len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
189781Sgtb 	if (len < 0)
190781Sgtb 	    return -1;
191781Sgtb 	ds->cur_ans++;
192781Sgtb 	if (ds->nclass == ns_rr_class(rr)
193781Sgtb 	    && ds->ntype == ns_rr_type(rr)) {
194781Sgtb 	    *pp = ns_rr_rdata(rr);
195781Sgtb 	    *lenp = ns_rr_rdlen(rr);
196781Sgtb 	    return 0;
197781Sgtb 	}
198781Sgtb     }
199781Sgtb     return 0;
200781Sgtb }
201781Sgtb #endif
202781Sgtb 
203781Sgtb /*
204781Sgtb  * krb5int_dns_expand - wrapper for dn_expand()
205781Sgtb  */
krb5int_dns_expand(struct krb5int_dns_state * ds,const unsigned char * p,char * buf,int len)206781Sgtb int krb5int_dns_expand(struct krb5int_dns_state *ds,
207781Sgtb 		       const unsigned char *p,
208781Sgtb 		       char *buf, int len)
209781Sgtb {
210781Sgtb 
211781Sgtb #if HAVE_NS_NAME_UNCOMPRESS
212781Sgtb     return ns_name_uncompress(ds->ansp,
213781Sgtb 			      (unsigned char *)ds->ansp + ds->anslen,
214781Sgtb 			      p, buf, (size_t)len);
215781Sgtb #else
216781Sgtb     return dn_expand(ds->ansp,
217781Sgtb 		     (unsigned char *)ds->ansp + ds->anslen,
218781Sgtb 		     p, buf, len);
219781Sgtb #endif
220781Sgtb }
221781Sgtb 
222781Sgtb /*
223781Sgtb  * Free stuff.
224781Sgtb  */
225781Sgtb void
krb5int_dns_fini(struct krb5int_dns_state * ds)226781Sgtb krb5int_dns_fini(struct krb5int_dns_state *ds)
227781Sgtb {
228781Sgtb     if (ds == NULL)
229781Sgtb 	return;
230781Sgtb     if (ds->ansp != NULL)
231781Sgtb 	free(ds->ansp);
232781Sgtb     free(ds);
233781Sgtb }
234781Sgtb 
235781Sgtb /*
236781Sgtb  * Compat routines for BIND 4
237781Sgtb  */
238781Sgtb #if !HAVE_NS_INITPARSE
239781Sgtb 
240781Sgtb /*
241781Sgtb  * initparse
242781Sgtb  *
243781Sgtb  * Skip header and question section of reply.  Set a pointer to the
244781Sgtb  * beginning of the answer section, and prepare to iterate over
245781Sgtb  * answer records.
246781Sgtb  */
247781Sgtb static int
initparse(struct krb5int_dns_state * ds)248781Sgtb initparse(struct krb5int_dns_state *ds)
249781Sgtb {
250781Sgtb     HEADER *hdr;
251781Sgtb     unsigned char *p;
252781Sgtb     unsigned short nqueries, nanswers;
253781Sgtb     int len;
254781Sgtb #if !HAVE_DN_SKIPNAME
255781Sgtb     char host[MAXDNAME];
256781Sgtb #endif
257781Sgtb 
258781Sgtb     if (ds->anslen < sizeof(HEADER))
259781Sgtb 	return -1;
260781Sgtb 
261781Sgtb     hdr = (HEADER *)ds->ansp;
262781Sgtb     p = ds->ansp;
263781Sgtb     nqueries = ntohs((unsigned short)hdr->qdcount);
264781Sgtb     nanswers = ntohs((unsigned short)hdr->ancount);
265781Sgtb     p += sizeof(HEADER);
266781Sgtb 
267781Sgtb     /*
268781Sgtb      * Skip query records.
269781Sgtb      */
270781Sgtb     while (nqueries--) {
271781Sgtb #if HAVE_DN_SKIPNAME
272781Sgtb 	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
273781Sgtb #else
274781Sgtb 	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
275781Sgtb 			p, host, sizeof(host));
276781Sgtb #endif
277781Sgtb 	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4))
278781Sgtb 	    return -1;
279781Sgtb 	p += len + 4;
280781Sgtb     }
281781Sgtb     ds->ptr = p;
282781Sgtb     ds->nanswers = nanswers;
283781Sgtb     return 0;
284781Sgtb }
285781Sgtb 
286781Sgtb /*
287781Sgtb  * krb5int_dns_nextans() - get next answer record
288781Sgtb  *
289781Sgtb  * Sets pp to NULL if no more records.
290781Sgtb  */
291781Sgtb int
krb5int_dns_nextans(struct krb5int_dns_state * ds,const unsigned char ** pp,int * lenp)292781Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds,
293781Sgtb 		    const unsigned char **pp, int *lenp)
294781Sgtb {
295781Sgtb     int len;
296781Sgtb     unsigned char *p;
297781Sgtb     unsigned short ntype, nclass, rdlen;
298781Sgtb #if !HAVE_DN_SKIPNAME
299781Sgtb     char host[MAXDNAME];
300781Sgtb #endif
301781Sgtb 
302781Sgtb     *pp = NULL;
303781Sgtb     *lenp = 0;
304781Sgtb     p = ds->ptr;
305781Sgtb 
306781Sgtb     while (ds->nanswers--) {
307781Sgtb #if HAVE_DN_SKIPNAME
308781Sgtb 	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
309781Sgtb #else
310781Sgtb 	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
311781Sgtb 			p, host, sizeof(host));
312781Sgtb #endif
313781Sgtb 	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
314781Sgtb 	    return -1;
315781Sgtb 	p += len;
316781Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
317781Sgtb 	/* Also skip 4 bytes of TTL */
318781Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
319781Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
320781Sgtb 
321781Sgtb 	if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
322781Sgtb 	    return -1;
323*7934SMark.Phalan@Sun.COM /* Solaris Kerberos - resync */
324*7934SMark.Phalan@Sun.COM #if 0
325*7934SMark.Phalan@Sun.COM 	if (rdlen > INT_MAX)
326*7934SMark.Phalan@Sun.COM 	    return -1;
327*7934SMark.Phalan@Sun.COM #endif
328781Sgtb 	if (nclass == ds->nclass && ntype == ds->ntype) {
329781Sgtb 	    *pp = p;
330781Sgtb 	    *lenp = rdlen;
331781Sgtb 	    ds->ptr = p + rdlen;
332781Sgtb 	    return 0;
333781Sgtb 	}
334781Sgtb 	p += rdlen;
335781Sgtb     }
336781Sgtb     return 0;
337781Sgtb out:
338781Sgtb     return -1;
339781Sgtb }
340781Sgtb 
341781Sgtb #endif
342781Sgtb 
343781Sgtb #endif /* KRB5_DNS_LOOKUP */
344