xref: /freebsd/lib/libc/net/hesiod.c (revision d05090827f0e5b95cc7d2bcdde8b3b4e0f986241)
1248aee62SJacques Vidrine /*	$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $	*/
2248aee62SJacques Vidrine 
3248aee62SJacques Vidrine /* Copyright (c) 1996 by Internet Software Consortium.
4248aee62SJacques Vidrine  *
5248aee62SJacques Vidrine  * Permission to use, copy, modify, and distribute this software for any
6248aee62SJacques Vidrine  * purpose with or without fee is hereby granted, provided that the above
7248aee62SJacques Vidrine  * copyright notice and this permission notice appear in all copies.
8248aee62SJacques Vidrine  *
9248aee62SJacques Vidrine  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
10248aee62SJacques Vidrine  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11248aee62SJacques Vidrine  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
12248aee62SJacques Vidrine  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13248aee62SJacques Vidrine  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14248aee62SJacques Vidrine  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
15248aee62SJacques Vidrine  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
16248aee62SJacques Vidrine  * SOFTWARE.
17248aee62SJacques Vidrine  */
18248aee62SJacques Vidrine 
19248aee62SJacques Vidrine /* Copyright 1996 by the Massachusetts Institute of Technology.
20248aee62SJacques Vidrine  *
21248aee62SJacques Vidrine  * Permission to use, copy, modify, and distribute this
22248aee62SJacques Vidrine  * software and its documentation for any purpose and without
23248aee62SJacques Vidrine  * fee is hereby granted, provided that the above copyright
24248aee62SJacques Vidrine  * notice appear in all copies and that both that copyright
25248aee62SJacques Vidrine  * notice and this permission notice appear in supporting
26248aee62SJacques Vidrine  * documentation, and that the name of M.I.T. not be used in
27248aee62SJacques Vidrine  * advertising or publicity pertaining to distribution of the
28248aee62SJacques Vidrine  * software without specific, written prior permission.
29248aee62SJacques Vidrine  * M.I.T. makes no representations about the suitability of
30248aee62SJacques Vidrine  * this software for any purpose.  It is provided "as is"
31248aee62SJacques Vidrine  * without express or implied warranty.
32248aee62SJacques Vidrine  */
33248aee62SJacques Vidrine 
34248aee62SJacques Vidrine /* This file is part of the hesiod library.  It implements the core
35248aee62SJacques Vidrine  * portion of the hesiod resolver.
36248aee62SJacques Vidrine  *
37248aee62SJacques Vidrine  * This file is loosely based on an interim version of hesiod.c from
38248aee62SJacques Vidrine  * the BIND IRS library, which was in turn based on an earlier version
39248aee62SJacques Vidrine  * of this file.  Extensive changes have been made on each step of the
40248aee62SJacques Vidrine  * path.
41248aee62SJacques Vidrine  *
42248aee62SJacques Vidrine  * This implementation is not truly thread-safe at the moment because
43248aee62SJacques Vidrine  * it uses res_send() and accesses _res.
44248aee62SJacques Vidrine  */
45248aee62SJacques Vidrine 
46248aee62SJacques Vidrine #include <sys/cdefs.h>
47248aee62SJacques Vidrine 
48333fc21eSDavid E. O'Brien #if 0
49248aee62SJacques Vidrine static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
50333fc21eSDavid E. O'Brien #endif
51333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
52333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
53248aee62SJacques Vidrine 
54248aee62SJacques Vidrine #include <sys/types.h>
55248aee62SJacques Vidrine #include <sys/param.h>
56248aee62SJacques Vidrine #include <netinet/in.h>
57248aee62SJacques Vidrine #include <arpa/nameser.h>
58248aee62SJacques Vidrine 
59248aee62SJacques Vidrine #include <ctype.h>
60248aee62SJacques Vidrine #include <errno.h>
61248aee62SJacques Vidrine #include <hesiod.h>
62248aee62SJacques Vidrine #include <resolv.h>
63248aee62SJacques Vidrine #include <stdio.h>
64248aee62SJacques Vidrine #include <stdlib.h>
65248aee62SJacques Vidrine #include <string.h>
66b27eae53SJacques Vidrine #include <unistd.h>
67248aee62SJacques Vidrine 
68248aee62SJacques Vidrine struct hesiod_p {
69248aee62SJacques Vidrine 	char	*lhs;			/* normally ".ns" */
70248aee62SJacques Vidrine 	char	*rhs;			/* AKA the default hesiod domain */
71248aee62SJacques Vidrine 	int	 classes[2];		/* The class search order. */
72248aee62SJacques Vidrine };
73248aee62SJacques Vidrine 
74248aee62SJacques Vidrine #define	MAX_HESRESP	1024
75248aee62SJacques Vidrine 
76c05ac53bSDavid E. O'Brien static int	  read_config_file(struct hesiod_p *, const char *);
77c05ac53bSDavid E. O'Brien static char	**get_txt_records(int, const char *);
78c05ac53bSDavid E. O'Brien static int	  init_context(void);
79c05ac53bSDavid E. O'Brien static void	  translate_errors(void);
80248aee62SJacques Vidrine 
81248aee62SJacques Vidrine 
82248aee62SJacques Vidrine /*
83248aee62SJacques Vidrine  * hesiod_init --
84248aee62SJacques Vidrine  *	initialize a hesiod_p.
85248aee62SJacques Vidrine  */
86248aee62SJacques Vidrine int
87248aee62SJacques Vidrine hesiod_init(context)
88248aee62SJacques Vidrine 	void	**context;
89248aee62SJacques Vidrine {
90248aee62SJacques Vidrine 	struct hesiod_p	*ctx;
91248aee62SJacques Vidrine 	const char	*p, *configname;
92248aee62SJacques Vidrine 
93248aee62SJacques Vidrine 	ctx = malloc(sizeof(struct hesiod_p));
94248aee62SJacques Vidrine 	if (ctx) {
95248aee62SJacques Vidrine 		*context = ctx;
96534f2a9dSJacques Vidrine 		if (!issetugid())
97248aee62SJacques Vidrine 			configname = getenv("HESIOD_CONFIG");
98b27eae53SJacques Vidrine 		else
99b27eae53SJacques Vidrine 			configname = NULL;
100248aee62SJacques Vidrine 		if (!configname)
101248aee62SJacques Vidrine 			configname = _PATH_HESIOD_CONF;
102248aee62SJacques Vidrine 		if (read_config_file(ctx, configname) >= 0) {
103248aee62SJacques Vidrine 			/*
104248aee62SJacques Vidrine 			 * The default rhs can be overridden by an
105248aee62SJacques Vidrine 			 * environment variable.
106248aee62SJacques Vidrine 			 */
107534f2a9dSJacques Vidrine 			if (!issetugid())
108248aee62SJacques Vidrine 				p = getenv("HES_DOMAIN");
109b27eae53SJacques Vidrine 			else
110b27eae53SJacques Vidrine 				p = NULL;
111248aee62SJacques Vidrine 			if (p) {
112248aee62SJacques Vidrine 				if (ctx->rhs)
113248aee62SJacques Vidrine 					free(ctx->rhs);
114248aee62SJacques Vidrine 				ctx->rhs = malloc(strlen(p) + 2);
115248aee62SJacques Vidrine 				if (ctx->rhs) {
116248aee62SJacques Vidrine 					*ctx->rhs = '.';
117248aee62SJacques Vidrine 					strcpy(ctx->rhs + 1,
118248aee62SJacques Vidrine 					    (*p == '.') ? p + 1 : p);
119248aee62SJacques Vidrine 					return 0;
120248aee62SJacques Vidrine 				} else
121248aee62SJacques Vidrine 					errno = ENOMEM;
122248aee62SJacques Vidrine 			} else
123248aee62SJacques Vidrine 				return 0;
124248aee62SJacques Vidrine 		}
125248aee62SJacques Vidrine 	} else
126248aee62SJacques Vidrine 		errno = ENOMEM;
127248aee62SJacques Vidrine 
128248aee62SJacques Vidrine 	if (ctx->lhs)
129248aee62SJacques Vidrine 		free(ctx->lhs);
130248aee62SJacques Vidrine 	if (ctx->rhs)
131248aee62SJacques Vidrine 		free(ctx->rhs);
132248aee62SJacques Vidrine 	if (ctx)
133248aee62SJacques Vidrine 		free(ctx);
134248aee62SJacques Vidrine 	return -1;
135248aee62SJacques Vidrine }
136248aee62SJacques Vidrine 
137248aee62SJacques Vidrine /*
138248aee62SJacques Vidrine  * hesiod_end --
139248aee62SJacques Vidrine  *	Deallocates the hesiod_p.
140248aee62SJacques Vidrine  */
141248aee62SJacques Vidrine void
142248aee62SJacques Vidrine hesiod_end(context)
143248aee62SJacques Vidrine 	void	*context;
144248aee62SJacques Vidrine {
145248aee62SJacques Vidrine 	struct hesiod_p *ctx = (struct hesiod_p *) context;
146248aee62SJacques Vidrine 
147248aee62SJacques Vidrine 	free(ctx->rhs);
148248aee62SJacques Vidrine 	if (ctx->lhs)
149248aee62SJacques Vidrine 		free(ctx->lhs);
150248aee62SJacques Vidrine 	free(ctx);
151248aee62SJacques Vidrine }
152248aee62SJacques Vidrine 
153248aee62SJacques Vidrine /*
154248aee62SJacques Vidrine  * hesiod_to_bind --
155248aee62SJacques Vidrine  * 	takes a hesiod (name, type) and returns a DNS
156248aee62SJacques Vidrine  *	name which is to be resolved.
157248aee62SJacques Vidrine  */
158248aee62SJacques Vidrine char *
159248aee62SJacques Vidrine hesiod_to_bind(void *context, const char *name, const char *type)
160248aee62SJacques Vidrine {
161248aee62SJacques Vidrine 	struct hesiod_p *ctx = (struct hesiod_p *) context;
162248aee62SJacques Vidrine 	char		 bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
163248aee62SJacques Vidrine 	const char	*rhs;
164248aee62SJacques Vidrine 	int		 len;
165248aee62SJacques Vidrine 
166d0509082SJacques Vidrine 	if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
167e31b3502SJacques Vidrine 		errno = EMSGSIZE;
168e31b3502SJacques Vidrine 		return NULL;
169e31b3502SJacques Vidrine 	}
170248aee62SJacques Vidrine 
171248aee62SJacques Vidrine 		/*
172248aee62SJacques Vidrine 		 * Find the right right hand side to use, possibly
173248aee62SJacques Vidrine 		 * truncating bindname.
174248aee62SJacques Vidrine 		 */
175248aee62SJacques Vidrine 	p = strchr(bindname, '@');
176248aee62SJacques Vidrine 	if (p) {
177248aee62SJacques Vidrine 		*p++ = 0;
178248aee62SJacques Vidrine 		if (strchr(p, '.'))
179248aee62SJacques Vidrine 			rhs = name + (p - bindname);
180248aee62SJacques Vidrine 		else {
181248aee62SJacques Vidrine 			rhs_list = hesiod_resolve(context, p, "rhs-extension");
182248aee62SJacques Vidrine 			if (rhs_list)
183248aee62SJacques Vidrine 				rhs = *rhs_list;
184248aee62SJacques Vidrine 			else {
185248aee62SJacques Vidrine 				errno = ENOENT;
186248aee62SJacques Vidrine 				return NULL;
187248aee62SJacques Vidrine 			}
188248aee62SJacques Vidrine 		}
189248aee62SJacques Vidrine 	} else
190248aee62SJacques Vidrine 		rhs = ctx->rhs;
191248aee62SJacques Vidrine 
192248aee62SJacques Vidrine 		/* See if we have enough room. */
193248aee62SJacques Vidrine 	len = strlen(bindname) + 1 + strlen(type);
194248aee62SJacques Vidrine 	if (ctx->lhs)
195248aee62SJacques Vidrine 		len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
196248aee62SJacques Vidrine 	len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
197248aee62SJacques Vidrine 	if (len > sizeof(bindname) - 1) {
198248aee62SJacques Vidrine 		if (rhs_list)
199248aee62SJacques Vidrine 			hesiod_free_list(context, rhs_list);
200248aee62SJacques Vidrine 		errno = EMSGSIZE;
201248aee62SJacques Vidrine 		return NULL;
202248aee62SJacques Vidrine 	}
203248aee62SJacques Vidrine 		/* Put together the rest of the domain. */
204248aee62SJacques Vidrine 	strcat(bindname, ".");
205248aee62SJacques Vidrine 	strcat(bindname, type);
206248aee62SJacques Vidrine 		/* Only append lhs if it isn't empty. */
207248aee62SJacques Vidrine 	if (ctx->lhs && ctx->lhs[0] != '\0' ) {
208248aee62SJacques Vidrine 		if (ctx->lhs[0] != '.')
209248aee62SJacques Vidrine 			strcat(bindname, ".");
210248aee62SJacques Vidrine 		strcat(bindname, ctx->lhs);
211248aee62SJacques Vidrine 	}
212248aee62SJacques Vidrine 	if (rhs[0] != '.')
213248aee62SJacques Vidrine 		strcat(bindname, ".");
214248aee62SJacques Vidrine 	strcat(bindname, rhs);
215248aee62SJacques Vidrine 
216248aee62SJacques Vidrine 		/* rhs_list is no longer needed, since we're done with rhs. */
217248aee62SJacques Vidrine 	if (rhs_list)
218248aee62SJacques Vidrine 		hesiod_free_list(context, rhs_list);
219248aee62SJacques Vidrine 
220248aee62SJacques Vidrine 		/* Make a copy of the result and return it to the caller. */
221248aee62SJacques Vidrine 	ret = strdup(bindname);
222248aee62SJacques Vidrine 	if (!ret)
223248aee62SJacques Vidrine 		errno = ENOMEM;
224248aee62SJacques Vidrine 	return ret;
225248aee62SJacques Vidrine }
226248aee62SJacques Vidrine 
227248aee62SJacques Vidrine /*
228248aee62SJacques Vidrine  * hesiod_resolve --
229248aee62SJacques Vidrine  *	Given a hesiod name and type, return an array of strings returned
230248aee62SJacques Vidrine  *	by the resolver.
231248aee62SJacques Vidrine  */
232248aee62SJacques Vidrine char **
233248aee62SJacques Vidrine hesiod_resolve(context, name, type)
234248aee62SJacques Vidrine 	void		*context;
235248aee62SJacques Vidrine 	const char	*name;
236248aee62SJacques Vidrine 	const char	*type;
237248aee62SJacques Vidrine {
238248aee62SJacques Vidrine 	struct hesiod_p	*ctx = (struct hesiod_p *) context;
239248aee62SJacques Vidrine 	char		*bindname, **retvec;
240248aee62SJacques Vidrine 
241248aee62SJacques Vidrine 	bindname = hesiod_to_bind(context, name, type);
242248aee62SJacques Vidrine 	if (!bindname)
243248aee62SJacques Vidrine 		return NULL;
244248aee62SJacques Vidrine 
245248aee62SJacques Vidrine 	retvec = get_txt_records(ctx->classes[0], bindname);
246248aee62SJacques Vidrine 	if (retvec == NULL && errno == ENOENT && ctx->classes[1])
247248aee62SJacques Vidrine 		retvec = get_txt_records(ctx->classes[1], bindname);
248248aee62SJacques Vidrine 
249248aee62SJacques Vidrine 	free(bindname);
250248aee62SJacques Vidrine 	return retvec;
251248aee62SJacques Vidrine }
252248aee62SJacques Vidrine 
253248aee62SJacques Vidrine /*ARGSUSED*/
254248aee62SJacques Vidrine void
255248aee62SJacques Vidrine hesiod_free_list(context, list)
256248aee62SJacques Vidrine 	void	 *context;
257248aee62SJacques Vidrine 	char	**list;
258248aee62SJacques Vidrine {
259248aee62SJacques Vidrine 	char  **p;
260248aee62SJacques Vidrine 
261248aee62SJacques Vidrine 	if (list == NULL)
262248aee62SJacques Vidrine 		return;
263248aee62SJacques Vidrine 	for (p = list; *p; p++)
264248aee62SJacques Vidrine 		free(*p);
265248aee62SJacques Vidrine 	free(list);
266248aee62SJacques Vidrine }
267248aee62SJacques Vidrine 
268248aee62SJacques Vidrine 
269248aee62SJacques Vidrine /* read_config_file --
270248aee62SJacques Vidrine  *	Parse the /etc/hesiod.conf file.  Returns 0 on success,
271248aee62SJacques Vidrine  *	-1 on failure.  On failure, it might leave values in ctx->lhs
272248aee62SJacques Vidrine  *	or ctx->rhs which need to be freed by the caller.
273248aee62SJacques Vidrine  */
274248aee62SJacques Vidrine static int
275248aee62SJacques Vidrine read_config_file(ctx, filename)
276248aee62SJacques Vidrine 	struct hesiod_p	*ctx;
277248aee62SJacques Vidrine 	const char	*filename;
278248aee62SJacques Vidrine {
279248aee62SJacques Vidrine 	char	*key, *data, *p, **which;
280248aee62SJacques Vidrine 	char	 buf[MAXDNAME + 7];
281248aee62SJacques Vidrine 	int	 n;
282248aee62SJacques Vidrine 	FILE	*fp;
283248aee62SJacques Vidrine 
284248aee62SJacques Vidrine 		/* Set default query classes. */
285248aee62SJacques Vidrine 	ctx->classes[0] = C_IN;
286248aee62SJacques Vidrine 	ctx->classes[1] = C_HS;
287248aee62SJacques Vidrine 
288248aee62SJacques Vidrine 		/* Try to open the configuration file. */
289248aee62SJacques Vidrine 	fp = fopen(filename, "r");
290248aee62SJacques Vidrine 	if (!fp) {
291248aee62SJacques Vidrine 		/* Use compiled in default domain names. */
292248aee62SJacques Vidrine 		ctx->lhs = strdup(DEF_LHS);
293248aee62SJacques Vidrine 		ctx->rhs = strdup(DEF_RHS);
294248aee62SJacques Vidrine 		if (ctx->lhs && ctx->rhs)
295248aee62SJacques Vidrine 			return 0;
296248aee62SJacques Vidrine 		else {
297248aee62SJacques Vidrine 			errno = ENOMEM;
298248aee62SJacques Vidrine 			return -1;
299248aee62SJacques Vidrine 		}
300248aee62SJacques Vidrine 	}
301248aee62SJacques Vidrine 	ctx->lhs = NULL;
302248aee62SJacques Vidrine 	ctx->rhs = NULL;
303248aee62SJacques Vidrine 	while (fgets(buf, sizeof(buf), fp) != NULL) {
304248aee62SJacques Vidrine 		p = buf;
305248aee62SJacques Vidrine 		if (*p == '#' || *p == '\n' || *p == '\r')
306248aee62SJacques Vidrine 			continue;
307248aee62SJacques Vidrine 		while (*p == ' ' || *p == '\t')
308248aee62SJacques Vidrine 			p++;
309248aee62SJacques Vidrine 		key = p;
310248aee62SJacques Vidrine 		while (*p != ' ' && *p != '\t' && *p != '=')
311248aee62SJacques Vidrine 			p++;
312248aee62SJacques Vidrine 		*p++ = 0;
313248aee62SJacques Vidrine 
314248aee62SJacques Vidrine 		while (isspace(*p) || *p == '=')
315248aee62SJacques Vidrine 			p++;
316248aee62SJacques Vidrine 		data = p;
317248aee62SJacques Vidrine 		while (!isspace(*p))
318248aee62SJacques Vidrine 			p++;
319248aee62SJacques Vidrine 		*p = 0;
320248aee62SJacques Vidrine 
321248aee62SJacques Vidrine 		if (strcasecmp(key, "lhs") == 0 ||
322248aee62SJacques Vidrine 		    strcasecmp(key, "rhs") == 0) {
323248aee62SJacques Vidrine 			which = (strcasecmp(key, "lhs") == 0)
324248aee62SJacques Vidrine 			    ? &ctx->lhs : &ctx->rhs;
325248aee62SJacques Vidrine 			*which = strdup(data);
326248aee62SJacques Vidrine 			if (!*which) {
327248aee62SJacques Vidrine 				errno = ENOMEM;
328248aee62SJacques Vidrine 				return -1;
329248aee62SJacques Vidrine 			}
330248aee62SJacques Vidrine 		} else {
331248aee62SJacques Vidrine 			if (strcasecmp(key, "classes") == 0) {
332248aee62SJacques Vidrine 				n = 0;
333248aee62SJacques Vidrine 				while (*data && n < 2) {
334248aee62SJacques Vidrine 					p = data;
335248aee62SJacques Vidrine 					while (*p && *p != ',')
336248aee62SJacques Vidrine 						p++;
337248aee62SJacques Vidrine 					if (*p)
338248aee62SJacques Vidrine 						*p++ = 0;
339248aee62SJacques Vidrine 					if (strcasecmp(data, "IN") == 0)
340248aee62SJacques Vidrine 						ctx->classes[n++] = C_IN;
341248aee62SJacques Vidrine 					else
342248aee62SJacques Vidrine 						if (strcasecmp(data, "HS") == 0)
343248aee62SJacques Vidrine 							ctx->classes[n++] =
344248aee62SJacques Vidrine 							    C_HS;
345248aee62SJacques Vidrine 					data = p;
346248aee62SJacques Vidrine 				}
347248aee62SJacques Vidrine 				while (n < 2)
348248aee62SJacques Vidrine 					ctx->classes[n++] = 0;
349248aee62SJacques Vidrine 			}
350248aee62SJacques Vidrine 		}
351248aee62SJacques Vidrine 	}
352248aee62SJacques Vidrine 	fclose(fp);
353248aee62SJacques Vidrine 
354248aee62SJacques Vidrine 	if (!ctx->rhs || ctx->classes[0] == 0 ||
355248aee62SJacques Vidrine 	    ctx->classes[0] == ctx->classes[1]) {
356248aee62SJacques Vidrine 		errno = ENOEXEC;
357248aee62SJacques Vidrine 		return -1;
358248aee62SJacques Vidrine 	}
359248aee62SJacques Vidrine 	return 0;
360248aee62SJacques Vidrine }
361248aee62SJacques Vidrine 
362248aee62SJacques Vidrine /*
363248aee62SJacques Vidrine  * get_txt_records --
364248aee62SJacques Vidrine  *	Given a DNS class and a DNS name, do a lookup for TXT records, and
365248aee62SJacques Vidrine  *	return a list of them.
366248aee62SJacques Vidrine  */
367248aee62SJacques Vidrine static char **
368248aee62SJacques Vidrine get_txt_records(qclass, name)
369248aee62SJacques Vidrine 	int		 qclass;
370248aee62SJacques Vidrine 	const char	*name;
371248aee62SJacques Vidrine {
372248aee62SJacques Vidrine 	HEADER		*hp;
373248aee62SJacques Vidrine 	unsigned char	 qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
374248aee62SJacques Vidrine 	char		*dst, **list;
375248aee62SJacques Vidrine 	int		 ancount, qdcount, i, j, n, skip, type, class, len;
376248aee62SJacques Vidrine 
377248aee62SJacques Vidrine 		/* Make sure the resolver is initialized. */
378248aee62SJacques Vidrine 	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
379248aee62SJacques Vidrine 		return NULL;
380248aee62SJacques Vidrine 
381248aee62SJacques Vidrine 		/* Construct the query. */
382248aee62SJacques Vidrine 	n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
383248aee62SJacques Vidrine 	    NULL, qbuf, PACKETSZ);
384248aee62SJacques Vidrine 	if (n < 0)
385248aee62SJacques Vidrine 		return NULL;
386248aee62SJacques Vidrine 
387248aee62SJacques Vidrine 		/* Send the query. */
388248aee62SJacques Vidrine 	n = res_send(qbuf, n, abuf, MAX_HESRESP);
38954384cf3SJacques Vidrine 	if (n < 0 || n > MAX_HESRESP) {
39054384cf3SJacques Vidrine 		errno = ECONNREFUSED; /* XXX */
391248aee62SJacques Vidrine 		return NULL;
392248aee62SJacques Vidrine 	}
393248aee62SJacques Vidrine 		/* Parse the header of the result. */
394248aee62SJacques Vidrine 	hp = (HEADER *) (void *) abuf;
395248aee62SJacques Vidrine 	ancount = ntohs(hp->ancount);
396248aee62SJacques Vidrine 	qdcount = ntohs(hp->qdcount);
397248aee62SJacques Vidrine 	p = abuf + sizeof(HEADER);
398248aee62SJacques Vidrine 	eom = abuf + n;
399248aee62SJacques Vidrine 
400248aee62SJacques Vidrine 		/*
401248aee62SJacques Vidrine 		 * Skip questions, trying to get to the answer section
402248aee62SJacques Vidrine 		 * which follows.
403248aee62SJacques Vidrine 		 */
404248aee62SJacques Vidrine 	for (i = 0; i < qdcount; i++) {
405248aee62SJacques Vidrine 		skip = dn_skipname(p, eom);
406248aee62SJacques Vidrine 		if (skip < 0 || p + skip + QFIXEDSZ > eom) {
407248aee62SJacques Vidrine 			errno = EMSGSIZE;
408248aee62SJacques Vidrine 			return NULL;
409248aee62SJacques Vidrine 		}
410248aee62SJacques Vidrine 		p += skip + QFIXEDSZ;
411248aee62SJacques Vidrine 	}
412248aee62SJacques Vidrine 
413248aee62SJacques Vidrine 		/* Allocate space for the text record answers. */
414248aee62SJacques Vidrine 	list = malloc((ancount + 1) * sizeof(char *));
415248aee62SJacques Vidrine 	if (!list) {
416248aee62SJacques Vidrine 		errno = ENOMEM;
417248aee62SJacques Vidrine 		return NULL;
418248aee62SJacques Vidrine 	}
419248aee62SJacques Vidrine 		/* Parse the answers. */
420248aee62SJacques Vidrine 	j = 0;
421248aee62SJacques Vidrine 	for (i = 0; i < ancount; i++) {
422248aee62SJacques Vidrine 		/* Parse the header of this answer. */
423248aee62SJacques Vidrine 		skip = dn_skipname(p, eom);
424248aee62SJacques Vidrine 		if (skip < 0 || p + skip + 10 > eom)
425248aee62SJacques Vidrine 			break;
426248aee62SJacques Vidrine 		type = p[skip + 0] << 8 | p[skip + 1];
427248aee62SJacques Vidrine 		class = p[skip + 2] << 8 | p[skip + 3];
428248aee62SJacques Vidrine 		len = p[skip + 8] << 8 | p[skip + 9];
429248aee62SJacques Vidrine 		p += skip + 10;
430248aee62SJacques Vidrine 		if (p + len > eom) {
431248aee62SJacques Vidrine 			errno = EMSGSIZE;
432248aee62SJacques Vidrine 			break;
433248aee62SJacques Vidrine 		}
434248aee62SJacques Vidrine 		/* Skip entries of the wrong class and type. */
435248aee62SJacques Vidrine 		if (class != qclass || type != T_TXT) {
436248aee62SJacques Vidrine 			p += len;
437248aee62SJacques Vidrine 			continue;
438248aee62SJacques Vidrine 		}
439248aee62SJacques Vidrine 		/* Allocate space for this answer. */
440248aee62SJacques Vidrine 		list[j] = malloc((size_t)len);
441248aee62SJacques Vidrine 		if (!list[j]) {
442248aee62SJacques Vidrine 			errno = ENOMEM;
443248aee62SJacques Vidrine 			break;
444248aee62SJacques Vidrine 		}
445248aee62SJacques Vidrine 		dst = list[j++];
446248aee62SJacques Vidrine 
447248aee62SJacques Vidrine 		/* Copy answer data into the allocated area. */
448248aee62SJacques Vidrine 		eor = p + len;
449248aee62SJacques Vidrine 		while (p < eor) {
450248aee62SJacques Vidrine 			n = (unsigned char) *p++;
451248aee62SJacques Vidrine 			if (p + n > eor) {
452248aee62SJacques Vidrine 				errno = EMSGSIZE;
453248aee62SJacques Vidrine 				break;
454248aee62SJacques Vidrine 			}
455248aee62SJacques Vidrine 			memcpy(dst, p, (size_t)n);
456248aee62SJacques Vidrine 			p += n;
457248aee62SJacques Vidrine 			dst += n;
458248aee62SJacques Vidrine 		}
459248aee62SJacques Vidrine 		if (p < eor) {
460248aee62SJacques Vidrine 			errno = EMSGSIZE;
461248aee62SJacques Vidrine 			break;
462248aee62SJacques Vidrine 		}
463248aee62SJacques Vidrine 		*dst = 0;
464248aee62SJacques Vidrine 	}
465248aee62SJacques Vidrine 
466248aee62SJacques Vidrine 		/*
467248aee62SJacques Vidrine 		 * If we didn't terminate the loop normally, something
468248aee62SJacques Vidrine 		 * went wrong.
469248aee62SJacques Vidrine 		 */
470248aee62SJacques Vidrine 	if (i < ancount) {
471248aee62SJacques Vidrine 		for (i = 0; i < j; i++)
472248aee62SJacques Vidrine 			free(list[i]);
473248aee62SJacques Vidrine 		free(list);
474248aee62SJacques Vidrine 		return NULL;
475248aee62SJacques Vidrine 	}
476248aee62SJacques Vidrine 	if (j == 0) {
477248aee62SJacques Vidrine 		errno = ENOENT;
478248aee62SJacques Vidrine 		free(list);
479248aee62SJacques Vidrine 		return NULL;
480248aee62SJacques Vidrine 	}
481248aee62SJacques Vidrine 	list[j] = NULL;
482248aee62SJacques Vidrine 	return list;
483248aee62SJacques Vidrine }
484248aee62SJacques Vidrine 
485248aee62SJacques Vidrine 		/*
486248aee62SJacques Vidrine 		 *	COMPATIBILITY FUNCTIONS
487248aee62SJacques Vidrine 		 */
488248aee62SJacques Vidrine 
489248aee62SJacques Vidrine static int	  inited = 0;
490248aee62SJacques Vidrine static void	 *context;
491248aee62SJacques Vidrine static int	  errval = HES_ER_UNINIT;
492248aee62SJacques Vidrine 
493248aee62SJacques Vidrine int
494248aee62SJacques Vidrine hes_init()
495248aee62SJacques Vidrine {
496248aee62SJacques Vidrine 	init_context();
497248aee62SJacques Vidrine 	return errval;
498248aee62SJacques Vidrine }
499248aee62SJacques Vidrine 
500248aee62SJacques Vidrine char *
501248aee62SJacques Vidrine hes_to_bind(name, type)
502248aee62SJacques Vidrine 	const char	*name;
503248aee62SJacques Vidrine 	const char	*type;
504248aee62SJacques Vidrine {
505248aee62SJacques Vidrine 	static	char	*bindname;
506248aee62SJacques Vidrine 	if (init_context() < 0)
507248aee62SJacques Vidrine 		return NULL;
508248aee62SJacques Vidrine 	if (bindname)
509248aee62SJacques Vidrine 		free(bindname);
510248aee62SJacques Vidrine 	bindname = hesiod_to_bind(context, name, type);
511248aee62SJacques Vidrine 	if (!bindname)
512248aee62SJacques Vidrine 		translate_errors();
513248aee62SJacques Vidrine 	return bindname;
514248aee62SJacques Vidrine }
515248aee62SJacques Vidrine 
516248aee62SJacques Vidrine char **
517248aee62SJacques Vidrine hes_resolve(name, type)
518248aee62SJacques Vidrine 	const char	*name;
519248aee62SJacques Vidrine 	const char	*type;
520248aee62SJacques Vidrine {
521248aee62SJacques Vidrine 	static char	**list;
522248aee62SJacques Vidrine 
523248aee62SJacques Vidrine 	if (init_context() < 0)
524248aee62SJacques Vidrine 		return NULL;
525248aee62SJacques Vidrine 
526248aee62SJacques Vidrine 	/*
527248aee62SJacques Vidrine 	 * In the old Hesiod interface, the caller was responsible for
528248aee62SJacques Vidrine 	 * freeing the returned strings but not the vector of strings itself.
529248aee62SJacques Vidrine 	 */
530248aee62SJacques Vidrine 	if (list)
531248aee62SJacques Vidrine 		free(list);
532248aee62SJacques Vidrine 
533248aee62SJacques Vidrine 	list = hesiod_resolve(context, name, type);
534248aee62SJacques Vidrine 	if (!list)
535248aee62SJacques Vidrine 		translate_errors();
536248aee62SJacques Vidrine 	return list;
537248aee62SJacques Vidrine }
538248aee62SJacques Vidrine 
539248aee62SJacques Vidrine int
540248aee62SJacques Vidrine hes_error()
541248aee62SJacques Vidrine {
542248aee62SJacques Vidrine 	return errval;
543248aee62SJacques Vidrine }
544248aee62SJacques Vidrine 
545248aee62SJacques Vidrine void
546248aee62SJacques Vidrine hes_free(hp)
547248aee62SJacques Vidrine 	char **hp;
548248aee62SJacques Vidrine {
549248aee62SJacques Vidrine 	hesiod_free_list(context, hp);
550248aee62SJacques Vidrine }
551248aee62SJacques Vidrine 
552248aee62SJacques Vidrine static int
553248aee62SJacques Vidrine init_context()
554248aee62SJacques Vidrine {
555248aee62SJacques Vidrine 	if (!inited) {
556248aee62SJacques Vidrine 		inited = 1;
557248aee62SJacques Vidrine 		if (hesiod_init(&context) < 0) {
558248aee62SJacques Vidrine 			errval = HES_ER_CONFIG;
559248aee62SJacques Vidrine 			return -1;
560248aee62SJacques Vidrine 		}
561248aee62SJacques Vidrine 		errval = HES_ER_OK;
562248aee62SJacques Vidrine 	}
563248aee62SJacques Vidrine 	return 0;
564248aee62SJacques Vidrine }
565248aee62SJacques Vidrine 
566248aee62SJacques Vidrine static void
567248aee62SJacques Vidrine translate_errors()
568248aee62SJacques Vidrine {
569248aee62SJacques Vidrine 	switch (errno) {
570248aee62SJacques Vidrine 	case ENOENT:
571248aee62SJacques Vidrine 		errval = HES_ER_NOTFOUND;
572248aee62SJacques Vidrine 		break;
573248aee62SJacques Vidrine 	case ECONNREFUSED:
574248aee62SJacques Vidrine 	case EMSGSIZE:
575248aee62SJacques Vidrine 		errval = HES_ER_NET;
576248aee62SJacques Vidrine 		break;
577248aee62SJacques Vidrine 	case ENOMEM:
578248aee62SJacques Vidrine 	default:
579248aee62SJacques Vidrine 		/* Not a good match, but the best we can do. */
580248aee62SJacques Vidrine 		errval = HES_ER_CONFIG;
581248aee62SJacques Vidrine 		break;
582248aee62SJacques Vidrine 	}
583248aee62SJacques Vidrine }
584