1*505d05c7Sgtb #pragma ident	"%Z%%M%	%I%	%E% SMI"
2*505d05c7Sgtb /*
3*505d05c7Sgtb  * lib/krb5/os/dnsglue.c
4*505d05c7Sgtb  *
5*505d05c7Sgtb  * Copyright 2004 by the Massachusetts Institute of Technology.
6*505d05c7Sgtb  * All Rights Reserved.
7*505d05c7Sgtb  *
8*505d05c7Sgtb  * Export of this software from the United States of America may
9*505d05c7Sgtb  *   require a specific license from the United States Government.
10*505d05c7Sgtb  *   It is the responsibility of any person or organization contemplating
11*505d05c7Sgtb  *   export to obtain such a license before exporting.
12*505d05c7Sgtb  *
13*505d05c7Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14*505d05c7Sgtb  * distribute this software and its documentation for any purpose and
15*505d05c7Sgtb  * without fee is hereby granted, provided that the above copyright
16*505d05c7Sgtb  * notice appear in all copies and that both that copyright notice and
17*505d05c7Sgtb  * this permission notice appear in supporting documentation, and that
18*505d05c7Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
19*505d05c7Sgtb  * to distribution of the software without specific, written prior
20*505d05c7Sgtb  * permission.  Furthermore if you modify this software you must label
21*505d05c7Sgtb  * your software as modified software and not distribute it in such a
22*505d05c7Sgtb  * fashion that it might be confused with the original M.I.T. software.
23*505d05c7Sgtb  * M.I.T. makes no representations about the suitability of
24*505d05c7Sgtb  * this software for any purpose.  It is provided "as is" without express
25*505d05c7Sgtb  * or implied warranty.
26*505d05c7Sgtb  *
27*505d05c7Sgtb  */
28*505d05c7Sgtb #ifdef KRB5_DNS_LOOKUP
29*505d05c7Sgtb 
30*505d05c7Sgtb #include "dnsglue.h"
31*505d05c7Sgtb 
32*505d05c7Sgtb /*
33*505d05c7Sgtb  * Opaque handle
34*505d05c7Sgtb  */
35*505d05c7Sgtb struct krb5int_dns_state {
36*505d05c7Sgtb     int nclass;
37*505d05c7Sgtb     int ntype;
38*505d05c7Sgtb     void *ansp;
39*505d05c7Sgtb     int anslen;
40*505d05c7Sgtb     int ansmax;
41*505d05c7Sgtb #if HAVE_NS_INITPARSE
42*505d05c7Sgtb     int cur_ans;
43*505d05c7Sgtb     ns_msg msg;
44*505d05c7Sgtb #else
45*505d05c7Sgtb     unsigned char *ptr;
46*505d05c7Sgtb     unsigned short nanswers;
47*505d05c7Sgtb #endif
48*505d05c7Sgtb };
49*505d05c7Sgtb 
50*505d05c7Sgtb #if !HAVE_NS_INITPARSE
51*505d05c7Sgtb static int initparse(struct krb5int_dns_state *);
52*505d05c7Sgtb #endif
53*505d05c7Sgtb 
54*505d05c7Sgtb /*
55*505d05c7Sgtb  * krb5int_dns_init()
56*505d05c7Sgtb  *
57*505d05c7Sgtb  * Initialize an opaue handl.  Do name lookup and initial parsing of
58*505d05c7Sgtb  * reply, skipping question section.  Prepare to iterate over answer
59*505d05c7Sgtb  * section.  Returns -1 on error, 0 on success.
60*505d05c7Sgtb  */
61*505d05c7Sgtb int
62*505d05c7Sgtb krb5int_dns_init(struct krb5int_dns_state **dsp,
63*505d05c7Sgtb 		 char *host, int nclass, int ntype)
64*505d05c7Sgtb {
65*505d05c7Sgtb #if HAVE_RES_NSEARCH
66*505d05c7Sgtb     struct __res_state statbuf;
67*505d05c7Sgtb #endif
68*505d05c7Sgtb     struct krb5int_dns_state *ds;
69*505d05c7Sgtb     int len, ret;
70*505d05c7Sgtb     size_t nextincr, maxincr;
71*505d05c7Sgtb     unsigned char *p;
72*505d05c7Sgtb 
73*505d05c7Sgtb     *dsp = ds = malloc(sizeof(*ds));
74*505d05c7Sgtb     if (ds == NULL)
75*505d05c7Sgtb 	return -1;
76*505d05c7Sgtb 
77*505d05c7Sgtb     ret = -1;
78*505d05c7Sgtb     ds->nclass = nclass;
79*505d05c7Sgtb     ds->ntype = ntype;
80*505d05c7Sgtb     ds->ansp = NULL;
81*505d05c7Sgtb     ds->anslen = 0;
82*505d05c7Sgtb     ds->ansmax = 0;
83*505d05c7Sgtb     nextincr = 2048;
84*505d05c7Sgtb     maxincr = INT_MAX;
85*505d05c7Sgtb 
86*505d05c7Sgtb #if HAVE_NS_INITPARSE
87*505d05c7Sgtb     ds->cur_ans = 0;
88*505d05c7Sgtb #endif
89*505d05c7Sgtb 
90*505d05c7Sgtb #if HAVE_RES_NSEARCH
91*505d05c7Sgtb     ret = res_ninit(&statbuf);
92*505d05c7Sgtb     if (ret < 0)
93*505d05c7Sgtb 	return -1;
94*505d05c7Sgtb #endif
95*505d05c7Sgtb 
96*505d05c7Sgtb     do {
97*505d05c7Sgtb 	p = (ds->ansp == NULL)
98*505d05c7Sgtb 	    ? malloc(nextincr) : realloc(ds->ansp, nextincr);
99*505d05c7Sgtb 
100*505d05c7Sgtb 	if (p == NULL && ds->ansp != NULL) {
101*505d05c7Sgtb 	    ret = -1;
102*505d05c7Sgtb 	    goto errout;
103*505d05c7Sgtb 	}
104*505d05c7Sgtb 	ds->ansp = p;
105*505d05c7Sgtb 	ds->ansmax = nextincr;
106*505d05c7Sgtb 
107*505d05c7Sgtb #if HAVE_RES_NSEARCH
108*505d05c7Sgtb 	len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
109*505d05c7Sgtb 			  ds->ansp, ds->ansmax);
110*505d05c7Sgtb #else
111*505d05c7Sgtb 	len = res_search(host, ds->nclass, ds->ntype,
112*505d05c7Sgtb 			 ds->ansp, ds->ansmax);
113*505d05c7Sgtb #endif
114*505d05c7Sgtb 	if (len > maxincr) {
115*505d05c7Sgtb 	    ret = -1;
116*505d05c7Sgtb 	    goto errout;
117*505d05c7Sgtb 	}
118*505d05c7Sgtb 	while (nextincr < len)
119*505d05c7Sgtb 	    nextincr *= 2;
120*505d05c7Sgtb 	if (len < 0 || nextincr > maxincr) {
121*505d05c7Sgtb 	    ret = -1;
122*505d05c7Sgtb 	    goto errout;
123*505d05c7Sgtb 	}
124*505d05c7Sgtb     } while (len > ds->ansmax);
125*505d05c7Sgtb 
126*505d05c7Sgtb     ds->anslen = len;
127*505d05c7Sgtb #if HAVE_NS_INITPARSE
128*505d05c7Sgtb     ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
129*505d05c7Sgtb #else
130*505d05c7Sgtb     ret = initparse(ds);
131*505d05c7Sgtb #endif
132*505d05c7Sgtb     if (ret < 0)
133*505d05c7Sgtb 	goto errout;
134*505d05c7Sgtb 
135*505d05c7Sgtb     ret = 0;
136*505d05c7Sgtb 
137*505d05c7Sgtb errout:
138*505d05c7Sgtb #if HAVE_RES_NSEARCH
139*505d05c7Sgtb #if HAVE_RES_NDESTROY
140*505d05c7Sgtb     res_ndestroy(&statbuf);
141*505d05c7Sgtb #else
142*505d05c7Sgtb     res_nclose(&statbuf);
143*505d05c7Sgtb #endif
144*505d05c7Sgtb #endif
145*505d05c7Sgtb     if (ret < 0) {
146*505d05c7Sgtb 	if (ds->ansp != NULL) {
147*505d05c7Sgtb 	    free(ds->ansp);
148*505d05c7Sgtb 	    ds->ansp = NULL;
149*505d05c7Sgtb 	}
150*505d05c7Sgtb     }
151*505d05c7Sgtb 
152*505d05c7Sgtb     return ret;
153*505d05c7Sgtb }
154*505d05c7Sgtb 
155*505d05c7Sgtb #if HAVE_NS_INITPARSE
156*505d05c7Sgtb /*
157*505d05c7Sgtb  * krb5int_dns_nextans - get next matching answer record
158*505d05c7Sgtb  *
159*505d05c7Sgtb  * Sets pp to NULL if no more records.  Returns -1 on error, 0 on
160*505d05c7Sgtb  * success.
161*505d05c7Sgtb  */
162*505d05c7Sgtb int
163*505d05c7Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds,
164*505d05c7Sgtb 		    const unsigned char **pp, int *lenp)
165*505d05c7Sgtb {
166*505d05c7Sgtb     int len;
167*505d05c7Sgtb     ns_rr rr;
168*505d05c7Sgtb 
169*505d05c7Sgtb     *pp = NULL;
170*505d05c7Sgtb     *lenp = 0;
171*505d05c7Sgtb     while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
172*505d05c7Sgtb 	len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
173*505d05c7Sgtb 	if (len < 0)
174*505d05c7Sgtb 	    return -1;
175*505d05c7Sgtb 	ds->cur_ans++;
176*505d05c7Sgtb 	if (ds->nclass == ns_rr_class(rr)
177*505d05c7Sgtb 	    && ds->ntype == ns_rr_type(rr)) {
178*505d05c7Sgtb 	    *pp = ns_rr_rdata(rr);
179*505d05c7Sgtb 	    *lenp = ns_rr_rdlen(rr);
180*505d05c7Sgtb 	    return 0;
181*505d05c7Sgtb 	}
182*505d05c7Sgtb     }
183*505d05c7Sgtb     return 0;
184*505d05c7Sgtb }
185*505d05c7Sgtb #endif
186*505d05c7Sgtb 
187*505d05c7Sgtb /*
188*505d05c7Sgtb  * krb5int_dns_expand - wrapper for dn_expand()
189*505d05c7Sgtb  */
190*505d05c7Sgtb int krb5int_dns_expand(struct krb5int_dns_state *ds,
191*505d05c7Sgtb 		       const unsigned char *p,
192*505d05c7Sgtb 		       char *buf, int len)
193*505d05c7Sgtb {
194*505d05c7Sgtb 
195*505d05c7Sgtb #if HAVE_NS_NAME_UNCOMPRESS
196*505d05c7Sgtb     return ns_name_uncompress(ds->ansp,
197*505d05c7Sgtb 			      (unsigned char *)ds->ansp + ds->anslen,
198*505d05c7Sgtb 			      p, buf, (size_t)len);
199*505d05c7Sgtb #else
200*505d05c7Sgtb     return dn_expand(ds->ansp,
201*505d05c7Sgtb 		     (unsigned char *)ds->ansp + ds->anslen,
202*505d05c7Sgtb 		     p, buf, len);
203*505d05c7Sgtb #endif
204*505d05c7Sgtb }
205*505d05c7Sgtb 
206*505d05c7Sgtb /*
207*505d05c7Sgtb  * Free stuff.
208*505d05c7Sgtb  */
209*505d05c7Sgtb void
210*505d05c7Sgtb krb5int_dns_fini(struct krb5int_dns_state *ds)
211*505d05c7Sgtb {
212*505d05c7Sgtb     if (ds == NULL)
213*505d05c7Sgtb 	return;
214*505d05c7Sgtb     if (ds->ansp != NULL)
215*505d05c7Sgtb 	free(ds->ansp);
216*505d05c7Sgtb     free(ds);
217*505d05c7Sgtb }
218*505d05c7Sgtb 
219*505d05c7Sgtb /*
220*505d05c7Sgtb  * Compat routines for BIND 4
221*505d05c7Sgtb  */
222*505d05c7Sgtb #if !HAVE_NS_INITPARSE
223*505d05c7Sgtb 
224*505d05c7Sgtb /*
225*505d05c7Sgtb  * initparse
226*505d05c7Sgtb  *
227*505d05c7Sgtb  * Skip header and question section of reply.  Set a pointer to the
228*505d05c7Sgtb  * beginning of the answer section, and prepare to iterate over
229*505d05c7Sgtb  * answer records.
230*505d05c7Sgtb  */
231*505d05c7Sgtb static int
232*505d05c7Sgtb initparse(struct krb5int_dns_state *ds)
233*505d05c7Sgtb {
234*505d05c7Sgtb     HEADER *hdr;
235*505d05c7Sgtb     unsigned char *p;
236*505d05c7Sgtb     unsigned short nqueries, nanswers;
237*505d05c7Sgtb     int len;
238*505d05c7Sgtb #if !HAVE_DN_SKIPNAME
239*505d05c7Sgtb     char host[MAXDNAME];
240*505d05c7Sgtb #endif
241*505d05c7Sgtb 
242*505d05c7Sgtb     if (ds->anslen < sizeof(HEADER))
243*505d05c7Sgtb 	return -1;
244*505d05c7Sgtb 
245*505d05c7Sgtb     hdr = (HEADER *)ds->ansp;
246*505d05c7Sgtb     p = ds->ansp;
247*505d05c7Sgtb     nqueries = ntohs((unsigned short)hdr->qdcount);
248*505d05c7Sgtb     nanswers = ntohs((unsigned short)hdr->ancount);
249*505d05c7Sgtb     p += sizeof(HEADER);
250*505d05c7Sgtb 
251*505d05c7Sgtb     /*
252*505d05c7Sgtb      * Skip query records.
253*505d05c7Sgtb      */
254*505d05c7Sgtb     while (nqueries--) {
255*505d05c7Sgtb #if HAVE_DN_SKIPNAME
256*505d05c7Sgtb 	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
257*505d05c7Sgtb #else
258*505d05c7Sgtb 	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
259*505d05c7Sgtb 			p, host, sizeof(host));
260*505d05c7Sgtb #endif
261*505d05c7Sgtb 	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4))
262*505d05c7Sgtb 	    return -1;
263*505d05c7Sgtb 	p += len + 4;
264*505d05c7Sgtb     }
265*505d05c7Sgtb     ds->ptr = p;
266*505d05c7Sgtb     ds->nanswers = nanswers;
267*505d05c7Sgtb     return 0;
268*505d05c7Sgtb }
269*505d05c7Sgtb 
270*505d05c7Sgtb /*
271*505d05c7Sgtb  * krb5int_dns_nextans() - get next answer record
272*505d05c7Sgtb  *
273*505d05c7Sgtb  * Sets pp to NULL if no more records.
274*505d05c7Sgtb  */
275*505d05c7Sgtb int
276*505d05c7Sgtb krb5int_dns_nextans(struct krb5int_dns_state *ds,
277*505d05c7Sgtb 		    const unsigned char **pp, int *lenp)
278*505d05c7Sgtb {
279*505d05c7Sgtb     int len;
280*505d05c7Sgtb     unsigned char *p;
281*505d05c7Sgtb     unsigned short ntype, nclass, rdlen;
282*505d05c7Sgtb #if !HAVE_DN_SKIPNAME
283*505d05c7Sgtb     char host[MAXDNAME];
284*505d05c7Sgtb #endif
285*505d05c7Sgtb 
286*505d05c7Sgtb     *pp = NULL;
287*505d05c7Sgtb     *lenp = 0;
288*505d05c7Sgtb     p = ds->ptr;
289*505d05c7Sgtb 
290*505d05c7Sgtb     while (ds->nanswers--) {
291*505d05c7Sgtb #if HAVE_DN_SKIPNAME
292*505d05c7Sgtb 	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
293*505d05c7Sgtb #else
294*505d05c7Sgtb 	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
295*505d05c7Sgtb 			p, host, sizeof(host));
296*505d05c7Sgtb #endif
297*505d05c7Sgtb 	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
298*505d05c7Sgtb 	    return -1;
299*505d05c7Sgtb 	p += len;
300*505d05c7Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
301*505d05c7Sgtb 	/* Also skip 4 bytes of TTL */
302*505d05c7Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
303*505d05c7Sgtb 	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
304*505d05c7Sgtb 
305*505d05c7Sgtb 	if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
306*505d05c7Sgtb 	    return -1;
307*505d05c7Sgtb 	if (rdlen > INT_MAX)
308*505d05c7Sgtb 	    return -1;
309*505d05c7Sgtb 	if (nclass == ds->nclass && ntype == ds->ntype) {
310*505d05c7Sgtb 	    *pp = p;
311*505d05c7Sgtb 	    *lenp = rdlen;
312*505d05c7Sgtb 	    ds->ptr = p + rdlen;
313*505d05c7Sgtb 	    return 0;
314*505d05c7Sgtb 	}
315*505d05c7Sgtb 	p += rdlen;
316*505d05c7Sgtb     }
317*505d05c7Sgtb     return 0;
318*505d05c7Sgtb out:
319*505d05c7Sgtb     return -1;
320*505d05c7Sgtb }
321*505d05c7Sgtb 
322*505d05c7Sgtb #endif
323*505d05c7Sgtb 
324*505d05c7Sgtb #endif /* KRB5_DNS_LOOKUP */
325