dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / gss_mechs / mech_krb5 / krb5 / os / dnsglue.c
blob465d744350090d1c7d06e7cfd1086e016432fc06
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * lib/krb5/os/dnsglue.c
9 * Copyright 2004 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
32 #include "autoconf.h"
33 #ifdef KRB5_DNS_LOOKUP
35 #include "dnsglue.h"
38 * Only use res_ninit() if there's also a res_ndestroy(), to avoid
39 * memory leaks (Linux & Solaris) and outright corruption (AIX 4.x,
40 * 5.x). While we're at it, make sure res_nsearch() is there too.
42 * In any case, it is probable that platforms having broken
43 * res_ninit() will have thread safety hacks for res_init() and _res.
45 #if HAVE_RES_NINIT && HAVE_RES_NDESTROY && HAVE_RES_NSEARCH
46 #define USE_RES_NINIT 1
47 #endif
50 * Opaque handle
52 struct krb5int_dns_state {
53 int nclass;
54 int ntype;
55 void *ansp;
56 int anslen;
57 int ansmax;
58 #if HAVE_NS_INITPARSE
59 int cur_ans;
60 ns_msg msg;
61 #else
62 unsigned char *ptr;
63 unsigned short nanswers;
64 #endif
67 #if !HAVE_NS_INITPARSE
68 static int initparse(struct krb5int_dns_state *);
69 #endif
72 * krb5int_dns_init()
74 * Initialize an opaque handle. Do name lookup and initial parsing of
75 * reply, skipping question section. Prepare to iterate over answer
76 * section. Returns -1 on error, 0 on success.
78 int
79 krb5int_dns_init(struct krb5int_dns_state **dsp,
80 char *host, int nclass, int ntype)
82 #if USE_RES_NINIT
83 struct __res_state statbuf;
84 #endif
85 struct krb5int_dns_state *ds;
86 int len, ret;
87 size_t nextincr, maxincr;
88 unsigned char *p;
90 *dsp = ds = malloc(sizeof(*ds));
91 if (ds == NULL)
92 return -1;
94 ret = -1;
95 ds->nclass = nclass;
96 ds->ntype = ntype;
97 ds->ansp = NULL;
98 ds->anslen = 0;
99 ds->ansmax = 0;
100 nextincr = 2048;
101 maxincr = INT_MAX;
103 #if HAVE_NS_INITPARSE
104 ds->cur_ans = 0;
105 #endif
107 #if USE_RES_NINIT
108 memset(&statbuf, 0, sizeof(statbuf));
109 ret = res_ninit(&statbuf);
110 #else
111 ret = res_init();
112 #endif
113 if (ret < 0)
114 return -1;
116 do {
117 p = (ds->ansp == NULL)
118 ? malloc(nextincr) : realloc(ds->ansp, nextincr);
120 if (p == NULL && ds->ansp != NULL) {
121 ret = -1;
122 goto errout;
124 ds->ansp = p;
125 ds->ansmax = nextincr;
127 #if USE_RES_NINIT
128 len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
129 ds->ansp, ds->ansmax);
130 #else
131 len = res_search(host, ds->nclass, ds->ntype,
132 ds->ansp, ds->ansmax);
133 #endif
134 if (len > maxincr) {
135 ret = -1;
136 goto errout;
138 while (nextincr < len)
139 nextincr *= 2;
140 if (len < 0 || nextincr > maxincr) {
141 ret = -1;
142 goto errout;
144 } while (len > ds->ansmax);
146 ds->anslen = len;
147 #if HAVE_NS_INITPARSE
148 ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
149 #else
150 ret = initparse(ds);
151 #endif
152 if (ret < 0)
153 goto errout;
155 ret = 0;
157 errout:
158 #if USE_RES_NINIT
159 res_ndestroy(&statbuf);
160 #endif
161 if (ret < 0) {
162 if (ds->ansp != NULL) {
163 free(ds->ansp);
164 ds->ansp = NULL;
168 return ret;
171 #if HAVE_NS_INITPARSE
173 * krb5int_dns_nextans - get next matching answer record
175 * Sets pp to NULL if no more records. Returns -1 on error, 0 on
176 * success.
179 krb5int_dns_nextans(struct krb5int_dns_state *ds,
180 const unsigned char **pp, int *lenp)
182 int len;
183 ns_rr rr;
185 *pp = NULL;
186 *lenp = 0;
187 while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
188 len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
189 if (len < 0)
190 return -1;
191 ds->cur_ans++;
192 if (ds->nclass == ns_rr_class(rr)
193 && ds->ntype == ns_rr_type(rr)) {
194 *pp = ns_rr_rdata(rr);
195 *lenp = ns_rr_rdlen(rr);
196 return 0;
199 return 0;
201 #endif
204 * krb5int_dns_expand - wrapper for dn_expand()
206 int krb5int_dns_expand(struct krb5int_dns_state *ds,
207 const unsigned char *p,
208 char *buf, int len)
211 #if HAVE_NS_NAME_UNCOMPRESS
212 return ns_name_uncompress(ds->ansp,
213 (unsigned char *)ds->ansp + ds->anslen,
214 p, buf, (size_t)len);
215 #else
216 return dn_expand(ds->ansp,
217 (unsigned char *)ds->ansp + ds->anslen,
218 p, buf, len);
219 #endif
223 * Free stuff.
225 void
226 krb5int_dns_fini(struct krb5int_dns_state *ds)
228 if (ds == NULL)
229 return;
230 free(ds->ansp);
231 free(ds);
235 * Compat routines for BIND 4
237 #if !HAVE_NS_INITPARSE
240 * initparse
242 * Skip header and question section of reply. Set a pointer to the
243 * beginning of the answer section, and prepare to iterate over
244 * answer records.
246 static int
247 initparse(struct krb5int_dns_state *ds)
249 HEADER *hdr;
250 unsigned char *p;
251 unsigned short nqueries, nanswers;
252 int len;
253 #if !HAVE_DN_SKIPNAME
254 char host[MAXDNAME];
255 #endif
257 if (ds->anslen < sizeof(HEADER))
258 return -1;
260 hdr = (HEADER *)ds->ansp;
261 p = ds->ansp;
262 nqueries = ntohs((unsigned short)hdr->qdcount);
263 nanswers = ntohs((unsigned short)hdr->ancount);
264 p += sizeof(HEADER);
267 * Skip query records.
269 while (nqueries--) {
270 #if HAVE_DN_SKIPNAME
271 len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
272 #else
273 len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
274 p, host, sizeof(host));
275 #endif
276 if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4))
277 return -1;
278 p += len + 4;
280 ds->ptr = p;
281 ds->nanswers = nanswers;
282 return 0;
286 * krb5int_dns_nextans() - get next answer record
288 * Sets pp to NULL if no more records.
291 krb5int_dns_nextans(struct krb5int_dns_state *ds,
292 const unsigned char **pp, int *lenp)
294 int len;
295 unsigned char *p;
296 unsigned short ntype, nclass, rdlen;
297 #if !HAVE_DN_SKIPNAME
298 char host[MAXDNAME];
299 #endif
301 *pp = NULL;
302 *lenp = 0;
303 p = ds->ptr;
305 while (ds->nanswers--) {
306 #if HAVE_DN_SKIPNAME
307 len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
308 #else
309 len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
310 p, host, sizeof(host));
311 #endif
312 if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
313 return -1;
314 p += len;
315 SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
316 /* Also skip 4 bytes of TTL */
317 SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
318 SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
320 if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
321 return -1;
322 /* Solaris Kerberos - resync */
323 #if 0
324 if (rdlen > INT_MAX)
325 return -1;
326 #endif
327 if (nclass == ds->nclass && ntype == ds->ntype) {
328 *pp = p;
329 *lenp = rdlen;
330 ds->ptr = p + rdlen;
331 return 0;
333 p += rdlen;
335 return 0;
336 out:
337 return -1;
340 #endif
342 #endif /* KRB5_DNS_LOOKUP */