1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint)
7*0Sstevel@tonic-gate static const char rcsid[] = "$Id: hesiod.c,v 1.23 2002/07/18 02:07:45 marka Exp $";
8*0Sstevel@tonic-gate #endif
9*0Sstevel@tonic-gate 
10*0Sstevel@tonic-gate /*
11*0Sstevel@tonic-gate  * Copyright (c) 1996,1999 by Internet Software Consortium.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
14*0Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
15*0Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
18*0Sstevel@tonic-gate  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
19*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
20*0Sstevel@tonic-gate  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
21*0Sstevel@tonic-gate  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
22*0Sstevel@tonic-gate  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
23*0Sstevel@tonic-gate  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24*0Sstevel@tonic-gate  * SOFTWARE.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * hesiod.c --- the core portion of the hesiod resolver.
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * This file is derived from the hesiod library from Project Athena;
37*0Sstevel@tonic-gate  * It has been extensively rewritten by Theodore Ts'o to have a more
38*0Sstevel@tonic-gate  * thread-safe interface.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /* Imports */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include "port_before.h"
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <sys/types.h>
46*0Sstevel@tonic-gate #include <netinet/in.h>
47*0Sstevel@tonic-gate #include <arpa/nameser.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <errno.h>
50*0Sstevel@tonic-gate #include <netdb.h>
51*0Sstevel@tonic-gate #include <resolv.h>
52*0Sstevel@tonic-gate #include <stdio.h>
53*0Sstevel@tonic-gate #include <stdlib.h>
54*0Sstevel@tonic-gate #include <string.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include "port_after.h"
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #include "pathnames.h"
59*0Sstevel@tonic-gate #include "hesiod.h"
60*0Sstevel@tonic-gate #include "hesiod_p.h"
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /* Forward */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate int		hesiod_init(void **context);
65*0Sstevel@tonic-gate void		hesiod_end(void *context);
66*0Sstevel@tonic-gate char *		hesiod_to_bind(void *context, const char *name,
67*0Sstevel@tonic-gate 			       const char *type);
68*0Sstevel@tonic-gate char **		hesiod_resolve(void *context, const char *name,
69*0Sstevel@tonic-gate 			       const char *type);
70*0Sstevel@tonic-gate void		hesiod_free_list(void *context, char **list);
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate static int	parse_config_file(struct hesiod_p *ctx, const char *filename);
73*0Sstevel@tonic-gate static char **	get_txt_records(struct hesiod_p *ctx, int class,
74*0Sstevel@tonic-gate 				const char *name);
75*0Sstevel@tonic-gate static int	init(struct hesiod_p *ctx);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate /* Public */
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate /*
80*0Sstevel@tonic-gate  * This function is called to initialize a hesiod_p.
81*0Sstevel@tonic-gate  */
82*0Sstevel@tonic-gate int
83*0Sstevel@tonic-gate hesiod_init(void **context) {
84*0Sstevel@tonic-gate 	struct hesiod_p *ctx;
85*0Sstevel@tonic-gate 	char *cp;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	ctx = malloc(sizeof(struct hesiod_p));
88*0Sstevel@tonic-gate 	if (ctx == 0) {
89*0Sstevel@tonic-gate 		errno = ENOMEM;
90*0Sstevel@tonic-gate 		return (-1);
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate #ifdef	ORIGINAL_ISC_CODE
94*0Sstevel@tonic-gate 	ctx->LHS = NULL;
95*0Sstevel@tonic-gate 	ctx->RHS = NULL;
96*0Sstevel@tonic-gate 	ctx->res = NULL;
97*0Sstevel@tonic-gate #else
98*0Sstevel@tonic-gate 	memset(ctx, 0, sizeof (*ctx));
99*0Sstevel@tonic-gate #endif	/* ORIGINAL_ISC_CODE */
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) {
102*0Sstevel@tonic-gate #ifdef DEF_RHS
103*0Sstevel@tonic-gate 		/*
104*0Sstevel@tonic-gate 		 * Use compiled in defaults.
105*0Sstevel@tonic-gate 		 */
106*0Sstevel@tonic-gate 		ctx->LHS = malloc(strlen(DEF_LHS)+1);
107*0Sstevel@tonic-gate 		ctx->RHS = malloc(strlen(DEF_RHS)+1);
108*0Sstevel@tonic-gate 		if (ctx->LHS == 0 || ctx->RHS == 0) {
109*0Sstevel@tonic-gate 			errno = ENOMEM;
110*0Sstevel@tonic-gate 			goto cleanup;
111*0Sstevel@tonic-gate 		}
112*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY
113*0Sstevel@tonic-gate 		strlcpy(ctx->LHS, DEF_LHS, strlen(DEF_LHS) + 1);
114*0Sstevel@tonic-gate 		strlcpy(ctx->RHS, DEF_RHS, strlen(DEF_RHS) + 1);
115*0Sstevel@tonic-gate #else
116*0Sstevel@tonic-gate 		strcpy(ctx->LHS, DEF_LHS);
117*0Sstevel@tonic-gate 		strcpy(ctx->RHS, DEF_RHS);
118*0Sstevel@tonic-gate #endif
119*0Sstevel@tonic-gate #else
120*0Sstevel@tonic-gate 		goto cleanup;
121*0Sstevel@tonic-gate #endif
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 	/*
124*0Sstevel@tonic-gate 	 * The default RHS can be overridden by an environment
125*0Sstevel@tonic-gate 	 * variable.
126*0Sstevel@tonic-gate 	 */
127*0Sstevel@tonic-gate 	if ((cp = getenv("HES_DOMAIN")) != NULL) {
128*0Sstevel@tonic-gate 		size_t RHSlen = strlen(cp) + 2;
129*0Sstevel@tonic-gate 		if (ctx->RHS)
130*0Sstevel@tonic-gate 			free(ctx->RHS);
131*0Sstevel@tonic-gate 		ctx->RHS = malloc(RHSlen);
132*0Sstevel@tonic-gate 		if (!ctx->RHS) {
133*0Sstevel@tonic-gate 			errno = ENOMEM;
134*0Sstevel@tonic-gate 			goto cleanup;
135*0Sstevel@tonic-gate 		}
136*0Sstevel@tonic-gate 		if (cp[0] == '.') {
137*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY
138*0Sstevel@tonic-gate 			strlcpy(ctx->RHS, cp, RHSlen);
139*0Sstevel@tonic-gate #else
140*0Sstevel@tonic-gate 			strcpy(ctx->RHS, cp);
141*0Sstevel@tonic-gate #endif
142*0Sstevel@tonic-gate 		} else {
143*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY
144*0Sstevel@tonic-gate 			strlcpy(ctx->RHS, ".", RHSlen);
145*0Sstevel@tonic-gate #else
146*0Sstevel@tonic-gate 			strcpy(ctx->RHS, ".");
147*0Sstevel@tonic-gate #endif
148*0Sstevel@tonic-gate #ifdef HAVE_STRLCAT
149*0Sstevel@tonic-gate 			strlcat(ctx->RHS, cp, RHSlen);
150*0Sstevel@tonic-gate #else
151*0Sstevel@tonic-gate 			strcat(ctx->RHS, cp);
152*0Sstevel@tonic-gate #endif
153*0Sstevel@tonic-gate 		}
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	/*
157*0Sstevel@tonic-gate 	 * If there is no default hesiod realm set, we return an
158*0Sstevel@tonic-gate 	 * error.
159*0Sstevel@tonic-gate 	 */
160*0Sstevel@tonic-gate 	if (!ctx->RHS) {
161*0Sstevel@tonic-gate 		errno = ENOEXEC;
162*0Sstevel@tonic-gate 		goto cleanup;
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate #if 0
166*0Sstevel@tonic-gate 	if (res_ninit(ctx->res) < 0)
167*0Sstevel@tonic-gate 		goto cleanup;
168*0Sstevel@tonic-gate #endif
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	*context = ctx;
171*0Sstevel@tonic-gate 	return (0);
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate  cleanup:
174*0Sstevel@tonic-gate 	hesiod_end(ctx);
175*0Sstevel@tonic-gate 	return (-1);
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate /*
179*0Sstevel@tonic-gate  * This function deallocates the hesiod_p
180*0Sstevel@tonic-gate  */
181*0Sstevel@tonic-gate void
182*0Sstevel@tonic-gate hesiod_end(void *context) {
183*0Sstevel@tonic-gate 	struct hesiod_p *ctx = (struct hesiod_p *) context;
184*0Sstevel@tonic-gate 	int save_errno = errno;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	if (ctx->res)
187*0Sstevel@tonic-gate 		res_nclose(ctx->res);
188*0Sstevel@tonic-gate 	if (ctx->RHS)
189*0Sstevel@tonic-gate 		free(ctx->RHS);
190*0Sstevel@tonic-gate 	if (ctx->LHS)
191*0Sstevel@tonic-gate 		free(ctx->LHS);
192*0Sstevel@tonic-gate 	if (ctx->res && ctx->free_res)
193*0Sstevel@tonic-gate 		(*ctx->free_res)(ctx->res);
194*0Sstevel@tonic-gate 	free(ctx);
195*0Sstevel@tonic-gate 	errno = save_errno;
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /*
199*0Sstevel@tonic-gate  * This function takes a hesiod (name, type) and returns a DNS
200*0Sstevel@tonic-gate  * name which is to be resolved.
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate char *
203*0Sstevel@tonic-gate hesiod_to_bind(void *context, const char *name, const char *type) {
204*0Sstevel@tonic-gate 	struct hesiod_p *ctx = (struct hesiod_p *) context;
205*0Sstevel@tonic-gate 	char *bindname;
206*0Sstevel@tonic-gate 	char **rhs_list = NULL;
207*0Sstevel@tonic-gate 	const char *RHS, *cp;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	/* Decide what our RHS is, and set cp to the end of the actual name. */
210*0Sstevel@tonic-gate 	if ((cp = strchr(name, '@')) != NULL) {
211*0Sstevel@tonic-gate 		if (strchr(cp + 1, '.'))
212*0Sstevel@tonic-gate 			RHS = cp + 1;
213*0Sstevel@tonic-gate 		else if ((rhs_list = hesiod_resolve(context, cp + 1,
214*0Sstevel@tonic-gate 		    "rhs-extension")) != NULL)
215*0Sstevel@tonic-gate 			RHS = *rhs_list;
216*0Sstevel@tonic-gate 		else {
217*0Sstevel@tonic-gate 			errno = ENOENT;
218*0Sstevel@tonic-gate 			return (NULL);
219*0Sstevel@tonic-gate 		}
220*0Sstevel@tonic-gate 	} else {
221*0Sstevel@tonic-gate 		RHS = ctx->RHS;
222*0Sstevel@tonic-gate 		cp = name + strlen(name);
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/*
226*0Sstevel@tonic-gate 	 * Allocate the space we need, including up to three periods and
227*0Sstevel@tonic-gate 	 * the terminating NUL.
228*0Sstevel@tonic-gate 	 */
229*0Sstevel@tonic-gate 	if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
230*0Sstevel@tonic-gate 	    (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
231*0Sstevel@tonic-gate 		errno = ENOMEM;
232*0Sstevel@tonic-gate 		if (rhs_list)
233*0Sstevel@tonic-gate 			hesiod_free_list(context, rhs_list);
234*0Sstevel@tonic-gate 		return NULL;
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	/* Now put together the DNS name. */
238*0Sstevel@tonic-gate 	memcpy(bindname, name, cp - name);
239*0Sstevel@tonic-gate 	bindname[cp - name] = '\0';
240*0Sstevel@tonic-gate 	strcat(bindname, ".");
241*0Sstevel@tonic-gate 	strcat(bindname, type);
242*0Sstevel@tonic-gate 	if (ctx->LHS) {
243*0Sstevel@tonic-gate 		if (ctx->LHS[0] != '.')
244*0Sstevel@tonic-gate 			strcat(bindname, ".");
245*0Sstevel@tonic-gate 		strcat(bindname, ctx->LHS);
246*0Sstevel@tonic-gate 	}
247*0Sstevel@tonic-gate 	if (RHS[0] != '.')
248*0Sstevel@tonic-gate 		strcat(bindname, ".");
249*0Sstevel@tonic-gate 	strcat(bindname, RHS);
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if (rhs_list)
252*0Sstevel@tonic-gate 		hesiod_free_list(context, rhs_list);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	return (bindname);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * This is the core function.  Given a hesiod (name, type), it
259*0Sstevel@tonic-gate  * returns an array of strings returned by the resolver.
260*0Sstevel@tonic-gate  */
261*0Sstevel@tonic-gate char **
262*0Sstevel@tonic-gate hesiod_resolve(void *context, const char *name, const char *type) {
263*0Sstevel@tonic-gate 	struct hesiod_p *ctx = (struct hesiod_p *) context;
264*0Sstevel@tonic-gate 	char *bindname = hesiod_to_bind(context, name, type);
265*0Sstevel@tonic-gate 	char **retvec;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	if (bindname == NULL)
268*0Sstevel@tonic-gate 		return (NULL);
269*0Sstevel@tonic-gate 	if (init(ctx) == -1) {
270*0Sstevel@tonic-gate 		free(bindname);
271*0Sstevel@tonic-gate 		return (NULL);
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	if ((retvec = get_txt_records(ctx, C_IN, bindname))) {
275*0Sstevel@tonic-gate 		free(bindname);
276*0Sstevel@tonic-gate 		return (retvec);
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (errno != ENOENT)
280*0Sstevel@tonic-gate 		return (NULL);
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	retvec = get_txt_records(ctx, C_HS, bindname);
283*0Sstevel@tonic-gate 	free(bindname);
284*0Sstevel@tonic-gate 	return (retvec);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate void
288*0Sstevel@tonic-gate hesiod_free_list(void *context, char **list) {
289*0Sstevel@tonic-gate 	char **p;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	UNUSED(context);
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	for (p = list; *p; p++)
294*0Sstevel@tonic-gate 		free(*p);
295*0Sstevel@tonic-gate 	free(list);
296*0Sstevel@tonic-gate }
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate /*
299*0Sstevel@tonic-gate  * This function parses the /etc/hesiod.conf file
300*0Sstevel@tonic-gate  */
301*0Sstevel@tonic-gate static int
302*0Sstevel@tonic-gate parse_config_file(struct hesiod_p *ctx, const char *filename) {
303*0Sstevel@tonic-gate 	char *key, *data, *cp, **cpp;
304*0Sstevel@tonic-gate 	char buf[MAXDNAME+7];
305*0Sstevel@tonic-gate 	FILE *fp;
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	/*
308*0Sstevel@tonic-gate 	 * Clear the existing configuration variable, just in case
309*0Sstevel@tonic-gate 	 * they're set.
310*0Sstevel@tonic-gate 	 */
311*0Sstevel@tonic-gate 	if (ctx->RHS)
312*0Sstevel@tonic-gate 		free(ctx->RHS);
313*0Sstevel@tonic-gate 	if (ctx->LHS)
314*0Sstevel@tonic-gate 		free(ctx->LHS);
315*0Sstevel@tonic-gate 	ctx->RHS = ctx->LHS = 0;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	/*
318*0Sstevel@tonic-gate 	 * Now open and parse the file...
319*0Sstevel@tonic-gate 	 */
320*0Sstevel@tonic-gate 	if (!(fp = fopen(filename, "r")))
321*0Sstevel@tonic-gate 		return (-1);
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	while (fgets(buf, sizeof(buf), fp) != NULL) {
324*0Sstevel@tonic-gate 		cp = buf;
325*0Sstevel@tonic-gate 		if (*cp == '#' || *cp == '\n' || *cp == '\r')
326*0Sstevel@tonic-gate 			continue;
327*0Sstevel@tonic-gate 		while(*cp == ' ' || *cp == '\t')
328*0Sstevel@tonic-gate 			cp++;
329*0Sstevel@tonic-gate 		key = cp;
330*0Sstevel@tonic-gate 		while(*cp != ' ' && *cp != '\t' && *cp != '=')
331*0Sstevel@tonic-gate 			cp++;
332*0Sstevel@tonic-gate 		*cp++ = '\0';
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 		while(*cp == ' ' || *cp == '\t' || *cp == '=')
335*0Sstevel@tonic-gate 			cp++;
336*0Sstevel@tonic-gate 		data = cp;
337*0Sstevel@tonic-gate 		while(*cp != ' ' && *cp != '\n' && *cp != '\r')
338*0Sstevel@tonic-gate 			cp++;
339*0Sstevel@tonic-gate 		*cp++ = '\0';
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 		if (strcmp(key, "lhs") == 0)
342*0Sstevel@tonic-gate 			cpp = &ctx->LHS;
343*0Sstevel@tonic-gate 		else if (strcmp(key, "rhs") == 0)
344*0Sstevel@tonic-gate 			cpp = &ctx->RHS;
345*0Sstevel@tonic-gate 		else
346*0Sstevel@tonic-gate 			continue;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 		*cpp = malloc(strlen(data) + 1);
349*0Sstevel@tonic-gate 		if (!*cpp) {
350*0Sstevel@tonic-gate 			errno = ENOMEM;
351*0Sstevel@tonic-gate 			goto cleanup;
352*0Sstevel@tonic-gate 		}
353*0Sstevel@tonic-gate 		strcpy(*cpp, data);
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 	fclose(fp);
356*0Sstevel@tonic-gate 	return (0);
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate  cleanup:
359*0Sstevel@tonic-gate 	fclose(fp);
360*0Sstevel@tonic-gate 	if (ctx->RHS)
361*0Sstevel@tonic-gate 		free(ctx->RHS);
362*0Sstevel@tonic-gate 	if (ctx->LHS)
363*0Sstevel@tonic-gate 		free(ctx->LHS);
364*0Sstevel@tonic-gate 	ctx->RHS = ctx->LHS = 0;
365*0Sstevel@tonic-gate 	return (-1);
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate /*
369*0Sstevel@tonic-gate  * Given a DNS class and a DNS name, do a lookup for TXT records, and
370*0Sstevel@tonic-gate  * return a list of them.
371*0Sstevel@tonic-gate  */
372*0Sstevel@tonic-gate static char **
373*0Sstevel@tonic-gate get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
374*0Sstevel@tonic-gate 	struct {
375*0Sstevel@tonic-gate 		int type;		/* RR type */
376*0Sstevel@tonic-gate 		int class;		/* RR class */
377*0Sstevel@tonic-gate 		int dlen;		/* len of data section */
378*0Sstevel@tonic-gate 		u_char *data;		/* pointer to data */
379*0Sstevel@tonic-gate 	} rr;
380*0Sstevel@tonic-gate 	HEADER *hp;
381*0Sstevel@tonic-gate 	u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
382*0Sstevel@tonic-gate 	u_char *cp, *erdata, *eom;
383*0Sstevel@tonic-gate 	char *dst, *edst, **list;
384*0Sstevel@tonic-gate 	int ancount, qdcount;
385*0Sstevel@tonic-gate 	int i, j, n, skip;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	/*
388*0Sstevel@tonic-gate 	 * Construct the query and send it.
389*0Sstevel@tonic-gate 	 */
390*0Sstevel@tonic-gate 	n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
391*0Sstevel@tonic-gate 			 NULL, qbuf, MAX_HESRESP);
392*0Sstevel@tonic-gate 	if (n < 0) {
393*0Sstevel@tonic-gate 		errno = EMSGSIZE;
394*0Sstevel@tonic-gate 		return (NULL);
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 	n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
397*0Sstevel@tonic-gate 	if (n < 0) {
398*0Sstevel@tonic-gate 		errno = ECONNREFUSED;
399*0Sstevel@tonic-gate 		return (NULL);
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 	if (n < HFIXEDSZ) {
402*0Sstevel@tonic-gate 		errno = EMSGSIZE;
403*0Sstevel@tonic-gate 		return (NULL);
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	/*
407*0Sstevel@tonic-gate 	 * OK, parse the result.
408*0Sstevel@tonic-gate 	 */
409*0Sstevel@tonic-gate 	hp = (HEADER *) abuf;
410*0Sstevel@tonic-gate 	ancount = ntohs(hp->ancount);
411*0Sstevel@tonic-gate 	qdcount = ntohs(hp->qdcount);
412*0Sstevel@tonic-gate 	cp = abuf + sizeof(HEADER);
413*0Sstevel@tonic-gate 	eom = abuf + n;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	/* Skip query, trying to get to the answer section which follows. */
416*0Sstevel@tonic-gate 	for (i = 0; i < qdcount; i++) {
417*0Sstevel@tonic-gate 		skip = dn_skipname(cp, eom);
418*0Sstevel@tonic-gate 		if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
419*0Sstevel@tonic-gate 			errno = EMSGSIZE;
420*0Sstevel@tonic-gate 			return (NULL);
421*0Sstevel@tonic-gate 		}
422*0Sstevel@tonic-gate 		cp += skip + QFIXEDSZ;
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	list = malloc((ancount + 1) * sizeof(char *));
426*0Sstevel@tonic-gate 	if (!list) {
427*0Sstevel@tonic-gate 		errno = ENOMEM;
428*0Sstevel@tonic-gate 		return (NULL);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 	j = 0;
431*0Sstevel@tonic-gate 	for (i = 0; i < ancount; i++) {
432*0Sstevel@tonic-gate 		skip = dn_skipname(cp, eom);
433*0Sstevel@tonic-gate 		if (skip < 0) {
434*0Sstevel@tonic-gate 			errno = EMSGSIZE;
435*0Sstevel@tonic-gate 			goto cleanup;
436*0Sstevel@tonic-gate 		}
437*0Sstevel@tonic-gate 		cp += skip;
438*0Sstevel@tonic-gate 		if (cp + 3 * INT16SZ + INT32SZ > eom) {
439*0Sstevel@tonic-gate 			errno = EMSGSIZE;
440*0Sstevel@tonic-gate 			goto cleanup;
441*0Sstevel@tonic-gate 		}
442*0Sstevel@tonic-gate 		rr.type = ns_get16(cp);
443*0Sstevel@tonic-gate 		cp += INT16SZ;
444*0Sstevel@tonic-gate 		rr.class = ns_get16(cp);
445*0Sstevel@tonic-gate 		cp += INT16SZ + INT32SZ;	/* skip the ttl, too */
446*0Sstevel@tonic-gate 		rr.dlen = ns_get16(cp);
447*0Sstevel@tonic-gate 		cp += INT16SZ;
448*0Sstevel@tonic-gate 		if (cp + rr.dlen > eom) {
449*0Sstevel@tonic-gate 			errno = EMSGSIZE;
450*0Sstevel@tonic-gate 			goto cleanup;
451*0Sstevel@tonic-gate 		}
452*0Sstevel@tonic-gate 		rr.data = cp;
453*0Sstevel@tonic-gate 		cp += rr.dlen;
454*0Sstevel@tonic-gate 		if (rr.class != class || rr.type != T_TXT)
455*0Sstevel@tonic-gate 			continue;
456*0Sstevel@tonic-gate 		if (!(list[j] = malloc(rr.dlen)))
457*0Sstevel@tonic-gate 			goto cleanup;
458*0Sstevel@tonic-gate 		dst = list[j++];
459*0Sstevel@tonic-gate 		edst = dst + rr.dlen;
460*0Sstevel@tonic-gate 		erdata = rr.data + rr.dlen;
461*0Sstevel@tonic-gate 		cp = rr.data;
462*0Sstevel@tonic-gate 		while (cp < erdata) {
463*0Sstevel@tonic-gate 			n = (unsigned char) *cp++;
464*0Sstevel@tonic-gate 			if (cp + n > eom || dst + n > edst) {
465*0Sstevel@tonic-gate 				errno = EMSGSIZE;
466*0Sstevel@tonic-gate 				goto cleanup;
467*0Sstevel@tonic-gate 			}
468*0Sstevel@tonic-gate 			memcpy(dst, cp, n);
469*0Sstevel@tonic-gate 			cp += n;
470*0Sstevel@tonic-gate 			dst += n;
471*0Sstevel@tonic-gate 		}
472*0Sstevel@tonic-gate 		if (cp != erdata) {
473*0Sstevel@tonic-gate 			errno = EMSGSIZE;
474*0Sstevel@tonic-gate 			goto cleanup;
475*0Sstevel@tonic-gate 		}
476*0Sstevel@tonic-gate 		*dst = '\0';
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 	list[j] = NULL;
479*0Sstevel@tonic-gate 	if (j == 0) {
480*0Sstevel@tonic-gate 		errno = ENOENT;
481*0Sstevel@tonic-gate 		goto cleanup;
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate 	return (list);
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate  cleanup:
486*0Sstevel@tonic-gate 	for (i = 0; i < j; i++)
487*0Sstevel@tonic-gate 		free(list[i]);
488*0Sstevel@tonic-gate 	free(list);
489*0Sstevel@tonic-gate 	return (NULL);
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate struct __res_state *
493*0Sstevel@tonic-gate __hesiod_res_get(void *context) {
494*0Sstevel@tonic-gate 	struct hesiod_p *ctx = context;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	if (!ctx->res) {
497*0Sstevel@tonic-gate 		struct __res_state *res;
498*0Sstevel@tonic-gate 		res = (struct __res_state *)malloc(sizeof *res);
499*0Sstevel@tonic-gate 		if (res == NULL) {
500*0Sstevel@tonic-gate 			errno = ENOMEM;
501*0Sstevel@tonic-gate 			return (NULL);
502*0Sstevel@tonic-gate 		}
503*0Sstevel@tonic-gate 		memset(res, 0, sizeof *res);
504*0Sstevel@tonic-gate 		__hesiod_res_set(ctx, res, free);
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	return (ctx->res);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate void
511*0Sstevel@tonic-gate __hesiod_res_set(void *context, struct __res_state *res,
512*0Sstevel@tonic-gate 	         void (*free_res)(void *)) {
513*0Sstevel@tonic-gate 	struct hesiod_p *ctx = context;
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	if (ctx->res && ctx->free_res) {
516*0Sstevel@tonic-gate 		res_nclose(ctx->res);
517*0Sstevel@tonic-gate 		(*ctx->free_res)(ctx->res);
518*0Sstevel@tonic-gate 	}
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	ctx->res = res;
521*0Sstevel@tonic-gate 	ctx->free_res = free_res;
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate static int
525*0Sstevel@tonic-gate init(struct hesiod_p *ctx) {
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	if (!ctx->res && !__hesiod_res_get(ctx))
528*0Sstevel@tonic-gate 		return (-1);
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	if (((ctx->res->options & RES_INIT) == 0) &&
531*0Sstevel@tonic-gate 	    (res_ninit(ctx->res) == -1))
532*0Sstevel@tonic-gate 		return (-1);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	return (0);
535*0Sstevel@tonic-gate }
536