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