xref: /dflybsd-src/lib/libc/net/hesiod.c (revision 5dcdf7782ae85aaffb8ec8b15dfa4516b05cad6b)
1ed5d5720SPeter Avalos /* Copyright (c) 1996 by Internet Software Consortium.
2ed5d5720SPeter Avalos  *
3ed5d5720SPeter Avalos  * Permission to use, copy, modify, and distribute this software for any
4ed5d5720SPeter Avalos  * purpose with or without fee is hereby granted, provided that the above
5ed5d5720SPeter Avalos  * copyright notice and this permission notice appear in all copies.
6ed5d5720SPeter Avalos  *
7ed5d5720SPeter Avalos  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
8ed5d5720SPeter Avalos  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
9ed5d5720SPeter Avalos  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
10ed5d5720SPeter Avalos  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
11ed5d5720SPeter Avalos  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
12ed5d5720SPeter Avalos  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
13ed5d5720SPeter Avalos  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
14ed5d5720SPeter Avalos  * SOFTWARE.
15ed5d5720SPeter Avalos  */
16ed5d5720SPeter Avalos 
17ed5d5720SPeter Avalos /* Copyright 1996 by the Massachusetts Institute of Technology.
18ed5d5720SPeter Avalos  *
19ed5d5720SPeter Avalos  * Permission to use, copy, modify, and distribute this
20ed5d5720SPeter Avalos  * software and its documentation for any purpose and without
21ed5d5720SPeter Avalos  * fee is hereby granted, provided that the above copyright
22ed5d5720SPeter Avalos  * notice appear in all copies and that both that copyright
23ed5d5720SPeter Avalos  * notice and this permission notice appear in supporting
24ed5d5720SPeter Avalos  * documentation, and that the name of M.I.T. not be used in
25ed5d5720SPeter Avalos  * advertising or publicity pertaining to distribution of the
26ed5d5720SPeter Avalos  * software without specific, written prior permission.
27ed5d5720SPeter Avalos  * M.I.T. makes no representations about the suitability of
28ed5d5720SPeter Avalos  * this software for any purpose.  It is provided "as is"
29ed5d5720SPeter Avalos  * without express or implied warranty.
30ed5d5720SPeter Avalos  */
31ed5d5720SPeter Avalos 
32ed5d5720SPeter Avalos /* This file is part of the hesiod library.  It implements the core
33ed5d5720SPeter Avalos  * portion of the hesiod resolver.
34ed5d5720SPeter Avalos  *
35ed5d5720SPeter Avalos  * This file is loosely based on an interim version of hesiod.c from
36ed5d5720SPeter Avalos  * the BIND IRS library, which was in turn based on an earlier version
37ed5d5720SPeter Avalos  * of this file.  Extensive changes have been made on each step of the
38ed5d5720SPeter Avalos  * path.
39ed5d5720SPeter Avalos  *
40ed5d5720SPeter Avalos  * This implementation is not truly thread-safe at the moment because
41ed5d5720SPeter Avalos  * it uses res_send() and accesses _res.
42ed5d5720SPeter Avalos  *
43ed5d5720SPeter Avalos  * $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $
44ed5d5720SPeter Avalos  * $FreeBSD: src/lib/libc/net/hesiod.c,v 1.9 2003/05/01 19:03:14 nectar Exp $
45ed5d5720SPeter Avalos  */
46ed5d5720SPeter Avalos 
47ed5d5720SPeter Avalos #include <sys/types.h>
48ed5d5720SPeter Avalos #include <sys/param.h>
49ed5d5720SPeter Avalos #include <netinet/in.h>
50ed5d5720SPeter Avalos #include <arpa/nameser.h>
51ed5d5720SPeter Avalos 
52ed5d5720SPeter Avalos #include <ctype.h>
53ed5d5720SPeter Avalos #include <errno.h>
54ed5d5720SPeter Avalos #include <hesiod.h>
55ed5d5720SPeter Avalos #include <resolv.h>
56ed5d5720SPeter Avalos #include <stdio.h>
57ed5d5720SPeter Avalos #include <stdlib.h>
58ed5d5720SPeter Avalos #include <string.h>
59ed5d5720SPeter Avalos #include <unistd.h>
60ed5d5720SPeter Avalos 
61ed5d5720SPeter Avalos struct hesiod_p {
62ed5d5720SPeter Avalos 	char	*lhs;			/* normally ".ns" */
63ed5d5720SPeter Avalos 	char	*rhs;			/* AKA the default hesiod domain */
64ed5d5720SPeter Avalos 	int	 classes[2];		/* The class search order. */
65ed5d5720SPeter Avalos };
66ed5d5720SPeter Avalos 
67ed5d5720SPeter Avalos #define	MAX_HESRESP	1024
68ed5d5720SPeter Avalos 
69ed5d5720SPeter Avalos static int	  read_config_file(struct hesiod_p *, const char *);
70ed5d5720SPeter Avalos static char	**get_txt_records(int, const char *);
71ed5d5720SPeter Avalos static int	  init_context(void);
72ed5d5720SPeter Avalos static void	  translate_errors(void);
73ed5d5720SPeter Avalos 
74ed5d5720SPeter Avalos 
75ed5d5720SPeter Avalos /*
76ed5d5720SPeter Avalos  * hesiod_init --
77ed5d5720SPeter Avalos  *	initialize a hesiod_p.
78ed5d5720SPeter Avalos  */
79ed5d5720SPeter Avalos int
hesiod_init(void ** context)80ed5d5720SPeter Avalos hesiod_init(void **context)
81ed5d5720SPeter Avalos {
82ed5d5720SPeter Avalos 	struct hesiod_p	*ctx;
83ed5d5720SPeter Avalos 	const char	*p, *configname;
84ed5d5720SPeter Avalos 
85ed5d5720SPeter Avalos 	ctx = malloc(sizeof(struct hesiod_p));
86ed5d5720SPeter Avalos 	if (ctx) {
87ed5d5720SPeter Avalos 		*context = ctx;
88ed5d5720SPeter Avalos 		if (!issetugid())
89ed5d5720SPeter Avalos 			configname = getenv("HESIOD_CONFIG");
90ed5d5720SPeter Avalos 		else
91ed5d5720SPeter Avalos 			configname = NULL;
92ed5d5720SPeter Avalos 		if (!configname)
93ed5d5720SPeter Avalos 			configname = _PATH_HESIOD_CONF;
94ed5d5720SPeter Avalos 		if (read_config_file(ctx, configname) >= 0) {
95ed5d5720SPeter Avalos 			/*
96ed5d5720SPeter Avalos 			 * The default rhs can be overridden by an
97ed5d5720SPeter Avalos 			 * environment variable.
98ed5d5720SPeter Avalos 			 */
99ed5d5720SPeter Avalos 			if (!issetugid())
100ed5d5720SPeter Avalos 				p = getenv("HES_DOMAIN");
101ed5d5720SPeter Avalos 			else
102ed5d5720SPeter Avalos 				p = NULL;
103ed5d5720SPeter Avalos 			if (p) {
104ed5d5720SPeter Avalos 				if (ctx->rhs)
105ed5d5720SPeter Avalos 					free(ctx->rhs);
106ed5d5720SPeter Avalos 				ctx->rhs = malloc(strlen(p) + 2);
107ed5d5720SPeter Avalos 				if (ctx->rhs) {
108ed5d5720SPeter Avalos 					*ctx->rhs = '.';
109ed5d5720SPeter Avalos 					strcpy(ctx->rhs + 1,
110ed5d5720SPeter Avalos 					    (*p == '.') ? p + 1 : p);
111ed5d5720SPeter Avalos 					return 0;
112ed5d5720SPeter Avalos 				} else
113ed5d5720SPeter Avalos 					errno = ENOMEM;
114ed5d5720SPeter Avalos 			} else
115ed5d5720SPeter Avalos 				return 0;
116ed5d5720SPeter Avalos 		}
117ed5d5720SPeter Avalos 	} else
118ed5d5720SPeter Avalos 		errno = ENOMEM;
119ed5d5720SPeter Avalos 
120ed5d5720SPeter Avalos 	if (ctx->lhs)
121ed5d5720SPeter Avalos 		free(ctx->lhs);
122ed5d5720SPeter Avalos 	if (ctx->rhs)
123ed5d5720SPeter Avalos 		free(ctx->rhs);
124ed5d5720SPeter Avalos 	if (ctx)
125ed5d5720SPeter Avalos 		free(ctx);
126ed5d5720SPeter Avalos 	return -1;
127ed5d5720SPeter Avalos }
128ed5d5720SPeter Avalos 
129ed5d5720SPeter Avalos /*
130ed5d5720SPeter Avalos  * hesiod_end --
131ed5d5720SPeter Avalos  *	Deallocates the hesiod_p.
132ed5d5720SPeter Avalos  */
133ed5d5720SPeter Avalos void
hesiod_end(void * context)134ed5d5720SPeter Avalos hesiod_end(void *context)
135ed5d5720SPeter Avalos {
136ed5d5720SPeter Avalos 	struct hesiod_p *ctx = (struct hesiod_p *) context;
137ed5d5720SPeter Avalos 
138ed5d5720SPeter Avalos 	free(ctx->rhs);
139ed5d5720SPeter Avalos 	if (ctx->lhs)
140ed5d5720SPeter Avalos 		free(ctx->lhs);
141ed5d5720SPeter Avalos 	free(ctx);
142ed5d5720SPeter Avalos }
143ed5d5720SPeter Avalos 
144ed5d5720SPeter Avalos /*
145ed5d5720SPeter Avalos  * hesiod_to_bind --
146ed5d5720SPeter Avalos  * 	takes a hesiod (name, type) and returns a DNS
147ed5d5720SPeter Avalos  *	name which is to be resolved.
148ed5d5720SPeter Avalos  */
149ed5d5720SPeter Avalos char *
hesiod_to_bind(void * context,const char * name,const char * type)150ed5d5720SPeter Avalos hesiod_to_bind(void *context, const char *name, const char *type)
151ed5d5720SPeter Avalos {
152ed5d5720SPeter Avalos 	struct hesiod_p *ctx = (struct hesiod_p *) context;
153ed5d5720SPeter Avalos 	char		 bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
154ed5d5720SPeter Avalos 	const char	*rhs;
155ed5d5720SPeter Avalos 	int		 len;
156ed5d5720SPeter Avalos 
157ed5d5720SPeter Avalos 	if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
158ed5d5720SPeter Avalos 		errno = EMSGSIZE;
159ed5d5720SPeter Avalos 		return NULL;
160ed5d5720SPeter Avalos 	}
161ed5d5720SPeter Avalos 
162ed5d5720SPeter Avalos 		/*
163ed5d5720SPeter Avalos 		 * Find the right right hand side to use, possibly
164ed5d5720SPeter Avalos 		 * truncating bindname.
165ed5d5720SPeter Avalos 		 */
166ed5d5720SPeter Avalos 	p = strchr(bindname, '@');
167ed5d5720SPeter Avalos 	if (p) {
168ed5d5720SPeter Avalos 		*p++ = 0;
169ed5d5720SPeter Avalos 		if (strchr(p, '.'))
170ed5d5720SPeter Avalos 			rhs = name + (p - bindname);
171ed5d5720SPeter Avalos 		else {
172ed5d5720SPeter Avalos 			rhs_list = hesiod_resolve(context, p, "rhs-extension");
173ed5d5720SPeter Avalos 			if (rhs_list)
174ed5d5720SPeter Avalos 				rhs = *rhs_list;
175ed5d5720SPeter Avalos 			else {
176ed5d5720SPeter Avalos 				errno = ENOENT;
177ed5d5720SPeter Avalos 				return NULL;
178ed5d5720SPeter Avalos 			}
179ed5d5720SPeter Avalos 		}
180ed5d5720SPeter Avalos 	} else
181ed5d5720SPeter Avalos 		rhs = ctx->rhs;
182ed5d5720SPeter Avalos 
183ed5d5720SPeter Avalos 		/* See if we have enough room. */
184ed5d5720SPeter Avalos 	len = strlen(bindname) + 1 + strlen(type);
185ed5d5720SPeter Avalos 	if (ctx->lhs)
186ed5d5720SPeter Avalos 		len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
187ed5d5720SPeter Avalos 	len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
188ed5d5720SPeter Avalos 	if (len > sizeof(bindname) - 1) {
189ed5d5720SPeter Avalos 		if (rhs_list)
190ed5d5720SPeter Avalos 			hesiod_free_list(context, rhs_list);
191ed5d5720SPeter Avalos 		errno = EMSGSIZE;
192ed5d5720SPeter Avalos 		return NULL;
193ed5d5720SPeter Avalos 	}
194ed5d5720SPeter Avalos 		/* Put together the rest of the domain. */
195ed5d5720SPeter Avalos 	strcat(bindname, ".");
196ed5d5720SPeter Avalos 	strcat(bindname, type);
197ed5d5720SPeter Avalos 		/* Only append lhs if it isn't empty. */
198ed5d5720SPeter Avalos 	if (ctx->lhs && ctx->lhs[0] != '\0' ) {
199ed5d5720SPeter Avalos 		if (ctx->lhs[0] != '.')
200ed5d5720SPeter Avalos 			strcat(bindname, ".");
201ed5d5720SPeter Avalos 		strcat(bindname, ctx->lhs);
202ed5d5720SPeter Avalos 	}
203ed5d5720SPeter Avalos 	if (rhs[0] != '.')
204ed5d5720SPeter Avalos 		strcat(bindname, ".");
205ed5d5720SPeter Avalos 	strcat(bindname, rhs);
206ed5d5720SPeter Avalos 
207ed5d5720SPeter Avalos 		/* rhs_list is no longer needed, since we're done with rhs. */
208ed5d5720SPeter Avalos 	if (rhs_list)
209ed5d5720SPeter Avalos 		hesiod_free_list(context, rhs_list);
210ed5d5720SPeter Avalos 
211ed5d5720SPeter Avalos 		/* Make a copy of the result and return it to the caller. */
212ed5d5720SPeter Avalos 	ret = strdup(bindname);
213ed5d5720SPeter Avalos 	if (!ret)
214ed5d5720SPeter Avalos 		errno = ENOMEM;
215ed5d5720SPeter Avalos 	return ret;
216ed5d5720SPeter Avalos }
217ed5d5720SPeter Avalos 
218ed5d5720SPeter Avalos /*
219ed5d5720SPeter Avalos  * hesiod_resolve --
220ed5d5720SPeter Avalos  *	Given a hesiod name and type, return an array of strings returned
221ed5d5720SPeter Avalos  *	by the resolver.
222ed5d5720SPeter Avalos  */
223ed5d5720SPeter Avalos char **
hesiod_resolve(void * context,const char * name,const char * type)224ed5d5720SPeter Avalos hesiod_resolve(void *context, const char *name, const char *type)
225ed5d5720SPeter Avalos {
226ed5d5720SPeter Avalos 	struct hesiod_p	*ctx = (struct hesiod_p *) context;
227ed5d5720SPeter Avalos 	char		*bindname, **retvec;
228ed5d5720SPeter Avalos 
229ed5d5720SPeter Avalos 	bindname = hesiod_to_bind(context, name, type);
230ed5d5720SPeter Avalos 	if (!bindname)
231ed5d5720SPeter Avalos 		return NULL;
232ed5d5720SPeter Avalos 
233ed5d5720SPeter Avalos 	retvec = get_txt_records(ctx->classes[0], bindname);
234ed5d5720SPeter Avalos 	if (retvec == NULL && errno == ENOENT && ctx->classes[1])
235ed5d5720SPeter Avalos 		retvec = get_txt_records(ctx->classes[1], bindname);
236ed5d5720SPeter Avalos 
237ed5d5720SPeter Avalos 	free(bindname);
238ed5d5720SPeter Avalos 	return retvec;
239ed5d5720SPeter Avalos }
240ed5d5720SPeter Avalos 
241ed5d5720SPeter Avalos /*ARGSUSED*/
242ed5d5720SPeter Avalos void
hesiod_free_list(void * context __unused,char ** list)243*5dcdf778SSascha Wildner hesiod_free_list(void *context __unused, char **list)
244ed5d5720SPeter Avalos {
245ed5d5720SPeter Avalos 	char  **p;
246ed5d5720SPeter Avalos 
247ed5d5720SPeter Avalos 	if (list == NULL)
248ed5d5720SPeter Avalos 		return;
249ed5d5720SPeter Avalos 	for (p = list; *p; p++)
250ed5d5720SPeter Avalos 		free(*p);
251ed5d5720SPeter Avalos 	free(list);
252ed5d5720SPeter Avalos }
253ed5d5720SPeter Avalos 
254ed5d5720SPeter Avalos 
255ed5d5720SPeter Avalos /* read_config_file --
256ed5d5720SPeter Avalos  *	Parse the /etc/hesiod.conf file.  Returns 0 on success,
257ed5d5720SPeter Avalos  *	-1 on failure.  On failure, it might leave values in ctx->lhs
258ed5d5720SPeter Avalos  *	or ctx->rhs which need to be freed by the caller.
259ed5d5720SPeter Avalos  */
260ed5d5720SPeter Avalos static int
read_config_file(struct hesiod_p * ctx,const char * filename)261ed5d5720SPeter Avalos read_config_file(struct hesiod_p *ctx, const char *filename)
262ed5d5720SPeter Avalos {
263ed5d5720SPeter Avalos 	char	*key, *data, *p, **which;
264ed5d5720SPeter Avalos 	char	 buf[MAXDNAME + 7];
265ed5d5720SPeter Avalos 	int	 n;
266ed5d5720SPeter Avalos 	FILE	*fp;
267ed5d5720SPeter Avalos 
268ed5d5720SPeter Avalos 		/* Set default query classes. */
269ed5d5720SPeter Avalos 	ctx->classes[0] = C_IN;
270ed5d5720SPeter Avalos 	ctx->classes[1] = C_HS;
271ed5d5720SPeter Avalos 
272ed5d5720SPeter Avalos 		/* Try to open the configuration file. */
273ed5d5720SPeter Avalos 	fp = fopen(filename, "r");
274ed5d5720SPeter Avalos 	if (!fp) {
275ed5d5720SPeter Avalos 		/* Use compiled in default domain names. */
276ed5d5720SPeter Avalos 		ctx->lhs = strdup(DEF_LHS);
277ed5d5720SPeter Avalos 		ctx->rhs = strdup(DEF_RHS);
278ed5d5720SPeter Avalos 		if (ctx->lhs && ctx->rhs)
279ed5d5720SPeter Avalos 			return 0;
280ed5d5720SPeter Avalos 		else {
281ed5d5720SPeter Avalos 			errno = ENOMEM;
282ed5d5720SPeter Avalos 			return -1;
283ed5d5720SPeter Avalos 		}
284ed5d5720SPeter Avalos 	}
285ed5d5720SPeter Avalos 	ctx->lhs = NULL;
286ed5d5720SPeter Avalos 	ctx->rhs = NULL;
287ed5d5720SPeter Avalos 	while (fgets(buf, sizeof(buf), fp) != NULL) {
288ed5d5720SPeter Avalos 		p = buf;
289ed5d5720SPeter Avalos 		if (*p == '#' || *p == '\n' || *p == '\r')
290ed5d5720SPeter Avalos 			continue;
291ed5d5720SPeter Avalos 		while (*p == ' ' || *p == '\t')
292ed5d5720SPeter Avalos 			p++;
293ed5d5720SPeter Avalos 		key = p;
294ed5d5720SPeter Avalos 		while (*p != ' ' && *p != '\t' && *p != '=')
295ed5d5720SPeter Avalos 			p++;
296ed5d5720SPeter Avalos 		*p++ = 0;
297ed5d5720SPeter Avalos 
298ed5d5720SPeter Avalos 		while (isspace(*p) || *p == '=')
299ed5d5720SPeter Avalos 			p++;
300ed5d5720SPeter Avalos 		data = p;
301ed5d5720SPeter Avalos 		while (!isspace(*p))
302ed5d5720SPeter Avalos 			p++;
303ed5d5720SPeter Avalos 		*p = 0;
304ed5d5720SPeter Avalos 
305ed5d5720SPeter Avalos 		if (strcasecmp(key, "lhs") == 0 ||
306ed5d5720SPeter Avalos 		    strcasecmp(key, "rhs") == 0) {
307ed5d5720SPeter Avalos 			which = (strcasecmp(key, "lhs") == 0)
308ed5d5720SPeter Avalos 			    ? &ctx->lhs : &ctx->rhs;
309ed5d5720SPeter Avalos 			*which = strdup(data);
310ed5d5720SPeter Avalos 			if (!*which) {
311ed5d5720SPeter Avalos 				errno = ENOMEM;
312ed5d5720SPeter Avalos 				return -1;
313ed5d5720SPeter Avalos 			}
314ed5d5720SPeter Avalos 		} else {
315ed5d5720SPeter Avalos 			if (strcasecmp(key, "classes") == 0) {
316ed5d5720SPeter Avalos 				n = 0;
317ed5d5720SPeter Avalos 				while (*data && n < 2) {
318ed5d5720SPeter Avalos 					p = data;
319ed5d5720SPeter Avalos 					while (*p && *p != ',')
320ed5d5720SPeter Avalos 						p++;
321ed5d5720SPeter Avalos 					if (*p)
322ed5d5720SPeter Avalos 						*p++ = 0;
323ed5d5720SPeter Avalos 					if (strcasecmp(data, "IN") == 0)
324ed5d5720SPeter Avalos 						ctx->classes[n++] = C_IN;
325ed5d5720SPeter Avalos 					else
326ed5d5720SPeter Avalos 						if (strcasecmp(data, "HS") == 0)
327ed5d5720SPeter Avalos 							ctx->classes[n++] =
328ed5d5720SPeter Avalos 							    C_HS;
329ed5d5720SPeter Avalos 					data = p;
330ed5d5720SPeter Avalos 				}
331ed5d5720SPeter Avalos 				while (n < 2)
332ed5d5720SPeter Avalos 					ctx->classes[n++] = 0;
333ed5d5720SPeter Avalos 			}
334ed5d5720SPeter Avalos 		}
335ed5d5720SPeter Avalos 	}
336ed5d5720SPeter Avalos 	fclose(fp);
337ed5d5720SPeter Avalos 
338ed5d5720SPeter Avalos 	if (!ctx->rhs || ctx->classes[0] == 0 ||
339ed5d5720SPeter Avalos 	    ctx->classes[0] == ctx->classes[1]) {
340ed5d5720SPeter Avalos 		errno = ENOEXEC;
341ed5d5720SPeter Avalos 		return -1;
342ed5d5720SPeter Avalos 	}
343ed5d5720SPeter Avalos 	return 0;
344ed5d5720SPeter Avalos }
345ed5d5720SPeter Avalos 
346ed5d5720SPeter Avalos /*
347ed5d5720SPeter Avalos  * get_txt_records --
348ed5d5720SPeter Avalos  *	Given a DNS class and a DNS name, do a lookup for TXT records, and
349ed5d5720SPeter Avalos  *	return a list of them.
350ed5d5720SPeter Avalos  */
351ed5d5720SPeter Avalos static char **
get_txt_records(int qclass,const char * name)352ed5d5720SPeter Avalos get_txt_records(int qclass, const char *name)
353ed5d5720SPeter Avalos {
354ed5d5720SPeter Avalos 	HEADER		*hp;
355ed5d5720SPeter Avalos 	unsigned char	 qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
356ed5d5720SPeter Avalos 	char		*dst, **list;
357ed5d5720SPeter Avalos 	int		 ancount, qdcount, i, j, n, skip, type, class, len;
358ed5d5720SPeter Avalos 
359ed5d5720SPeter Avalos 		/* Make sure the resolver is initialized. */
360ed5d5720SPeter Avalos 	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
361ed5d5720SPeter Avalos 		return NULL;
362ed5d5720SPeter Avalos 
363ed5d5720SPeter Avalos 		/* Construct the query. */
364ed5d5720SPeter Avalos 	n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
365ed5d5720SPeter Avalos 	    NULL, qbuf, PACKETSZ);
366ed5d5720SPeter Avalos 	if (n < 0)
367ed5d5720SPeter Avalos 		return NULL;
368ed5d5720SPeter Avalos 
369ed5d5720SPeter Avalos 		/* Send the query. */
370ed5d5720SPeter Avalos 	n = res_send(qbuf, n, abuf, MAX_HESRESP);
371ed5d5720SPeter Avalos 	if (n < 0 || n > MAX_HESRESP) {
372ed5d5720SPeter Avalos 		errno = ECONNREFUSED; /* XXX */
373ed5d5720SPeter Avalos 		return NULL;
374ed5d5720SPeter Avalos 	}
375ed5d5720SPeter Avalos 		/* Parse the header of the result. */
376ed5d5720SPeter Avalos 	hp = (HEADER *) (void *) abuf;
377ed5d5720SPeter Avalos 	ancount = ntohs(hp->ancount);
378ed5d5720SPeter Avalos 	qdcount = ntohs(hp->qdcount);
379ed5d5720SPeter Avalos 	p = abuf + sizeof(HEADER);
380ed5d5720SPeter Avalos 	eom = abuf + n;
381ed5d5720SPeter Avalos 
382ed5d5720SPeter Avalos 		/*
383ed5d5720SPeter Avalos 		 * Skip questions, trying to get to the answer section
384ed5d5720SPeter Avalos 		 * which follows.
385ed5d5720SPeter Avalos 		 */
386ed5d5720SPeter Avalos 	for (i = 0; i < qdcount; i++) {
387ed5d5720SPeter Avalos 		skip = dn_skipname(p, eom);
388ed5d5720SPeter Avalos 		if (skip < 0 || p + skip + QFIXEDSZ > eom) {
389ed5d5720SPeter Avalos 			errno = EMSGSIZE;
390ed5d5720SPeter Avalos 			return NULL;
391ed5d5720SPeter Avalos 		}
392ed5d5720SPeter Avalos 		p += skip + QFIXEDSZ;
393ed5d5720SPeter Avalos 	}
394ed5d5720SPeter Avalos 
395ed5d5720SPeter Avalos 		/* Allocate space for the text record answers. */
396ed5d5720SPeter Avalos 	list = malloc((ancount + 1) * sizeof(char *));
397ed5d5720SPeter Avalos 	if (!list) {
398ed5d5720SPeter Avalos 		errno = ENOMEM;
399ed5d5720SPeter Avalos 		return NULL;
400ed5d5720SPeter Avalos 	}
401ed5d5720SPeter Avalos 		/* Parse the answers. */
402ed5d5720SPeter Avalos 	j = 0;
403ed5d5720SPeter Avalos 	for (i = 0; i < ancount; i++) {
404ed5d5720SPeter Avalos 		/* Parse the header of this answer. */
405ed5d5720SPeter Avalos 		skip = dn_skipname(p, eom);
406ed5d5720SPeter Avalos 		if (skip < 0 || p + skip + 10 > eom)
407ed5d5720SPeter Avalos 			break;
408ed5d5720SPeter Avalos 		type = p[skip + 0] << 8 | p[skip + 1];
409ed5d5720SPeter Avalos 		class = p[skip + 2] << 8 | p[skip + 3];
410ed5d5720SPeter Avalos 		len = p[skip + 8] << 8 | p[skip + 9];
411ed5d5720SPeter Avalos 		p += skip + 10;
412ed5d5720SPeter Avalos 		if (p + len > eom) {
413ed5d5720SPeter Avalos 			errno = EMSGSIZE;
414ed5d5720SPeter Avalos 			break;
415ed5d5720SPeter Avalos 		}
416ed5d5720SPeter Avalos 		/* Skip entries of the wrong class and type. */
417ed5d5720SPeter Avalos 		if (class != qclass || type != T_TXT) {
418ed5d5720SPeter Avalos 			p += len;
419ed5d5720SPeter Avalos 			continue;
420ed5d5720SPeter Avalos 		}
421ed5d5720SPeter Avalos 		/* Allocate space for this answer. */
422ed5d5720SPeter Avalos 		list[j] = malloc((size_t)len);
423ed5d5720SPeter Avalos 		if (!list[j]) {
424ed5d5720SPeter Avalos 			errno = ENOMEM;
425ed5d5720SPeter Avalos 			break;
426ed5d5720SPeter Avalos 		}
427ed5d5720SPeter Avalos 		dst = list[j++];
428ed5d5720SPeter Avalos 
429ed5d5720SPeter Avalos 		/* Copy answer data into the allocated area. */
430ed5d5720SPeter Avalos 		eor = p + len;
431ed5d5720SPeter Avalos 		while (p < eor) {
432ed5d5720SPeter Avalos 			n = (unsigned char) *p++;
433ed5d5720SPeter Avalos 			if (p + n > eor) {
434ed5d5720SPeter Avalos 				errno = EMSGSIZE;
435ed5d5720SPeter Avalos 				break;
436ed5d5720SPeter Avalos 			}
437ed5d5720SPeter Avalos 			memcpy(dst, p, (size_t)n);
438ed5d5720SPeter Avalos 			p += n;
439ed5d5720SPeter Avalos 			dst += n;
440ed5d5720SPeter Avalos 		}
441ed5d5720SPeter Avalos 		if (p < eor) {
442ed5d5720SPeter Avalos 			errno = EMSGSIZE;
443ed5d5720SPeter Avalos 			break;
444ed5d5720SPeter Avalos 		}
445ed5d5720SPeter Avalos 		*dst = 0;
446ed5d5720SPeter Avalos 	}
447ed5d5720SPeter Avalos 
448ed5d5720SPeter Avalos 		/*
449ed5d5720SPeter Avalos 		 * If we didn't terminate the loop normally, something
450ed5d5720SPeter Avalos 		 * went wrong.
451ed5d5720SPeter Avalos 		 */
452ed5d5720SPeter Avalos 	if (i < ancount) {
453ed5d5720SPeter Avalos 		for (i = 0; i < j; i++)
454ed5d5720SPeter Avalos 			free(list[i]);
455ed5d5720SPeter Avalos 		free(list);
456ed5d5720SPeter Avalos 		return NULL;
457ed5d5720SPeter Avalos 	}
458ed5d5720SPeter Avalos 	if (j == 0) {
459ed5d5720SPeter Avalos 		errno = ENOENT;
460ed5d5720SPeter Avalos 		free(list);
461ed5d5720SPeter Avalos 		return NULL;
462ed5d5720SPeter Avalos 	}
463ed5d5720SPeter Avalos 	list[j] = NULL;
464ed5d5720SPeter Avalos 	return list;
465ed5d5720SPeter Avalos }
466ed5d5720SPeter Avalos 
467ed5d5720SPeter Avalos 		/*
468ed5d5720SPeter Avalos 		 *	COMPATIBILITY FUNCTIONS
469ed5d5720SPeter Avalos 		 */
470ed5d5720SPeter Avalos 
471ed5d5720SPeter Avalos static int	  inited = 0;
472ed5d5720SPeter Avalos static void	 *context;
473ed5d5720SPeter Avalos static int	  errval = HES_ER_UNINIT;
474ed5d5720SPeter Avalos 
475ed5d5720SPeter Avalos int
hes_init(void)476ed5d5720SPeter Avalos hes_init(void)
477ed5d5720SPeter Avalos {
478ed5d5720SPeter Avalos 	init_context();
479ed5d5720SPeter Avalos 	return errval;
480ed5d5720SPeter Avalos }
481ed5d5720SPeter Avalos 
482ed5d5720SPeter Avalos char *
hes_to_bind(const char * name,const char * type)483ed5d5720SPeter Avalos hes_to_bind(const char *name, const char *type)
484ed5d5720SPeter Avalos {
485ed5d5720SPeter Avalos 	static	char	*bindname;
486ed5d5720SPeter Avalos 	if (init_context() < 0)
487ed5d5720SPeter Avalos 		return NULL;
488ed5d5720SPeter Avalos 	if (bindname)
489ed5d5720SPeter Avalos 		free(bindname);
490ed5d5720SPeter Avalos 	bindname = hesiod_to_bind(context, name, type);
491ed5d5720SPeter Avalos 	if (!bindname)
492ed5d5720SPeter Avalos 		translate_errors();
493ed5d5720SPeter Avalos 	return bindname;
494ed5d5720SPeter Avalos }
495ed5d5720SPeter Avalos 
496ed5d5720SPeter Avalos char **
hes_resolve(const char * name,const char * type)497ed5d5720SPeter Avalos hes_resolve(const char *name, const char *type)
498ed5d5720SPeter Avalos {
499ed5d5720SPeter Avalos 	static char	**list;
500ed5d5720SPeter Avalos 
501ed5d5720SPeter Avalos 	if (init_context() < 0)
502ed5d5720SPeter Avalos 		return NULL;
503ed5d5720SPeter Avalos 
504ed5d5720SPeter Avalos 	/*
505ed5d5720SPeter Avalos 	 * In the old Hesiod interface, the caller was responsible for
506ed5d5720SPeter Avalos 	 * freeing the returned strings but not the vector of strings itself.
507ed5d5720SPeter Avalos 	 */
508ed5d5720SPeter Avalos 	if (list)
509ed5d5720SPeter Avalos 		free(list);
510ed5d5720SPeter Avalos 
511ed5d5720SPeter Avalos 	list = hesiod_resolve(context, name, type);
512ed5d5720SPeter Avalos 	if (!list)
513ed5d5720SPeter Avalos 		translate_errors();
514ed5d5720SPeter Avalos 	return list;
515ed5d5720SPeter Avalos }
516ed5d5720SPeter Avalos 
517ed5d5720SPeter Avalos int
hes_error(void)518ed5d5720SPeter Avalos hes_error(void)
519ed5d5720SPeter Avalos {
520ed5d5720SPeter Avalos 	return errval;
521ed5d5720SPeter Avalos }
522ed5d5720SPeter Avalos 
523ed5d5720SPeter Avalos void
hes_free(char ** hp)524ed5d5720SPeter Avalos hes_free(char **hp)
525ed5d5720SPeter Avalos {
526ed5d5720SPeter Avalos 	hesiod_free_list(context, hp);
527ed5d5720SPeter Avalos }
528ed5d5720SPeter Avalos 
529ed5d5720SPeter Avalos static int
init_context(void)530ed5d5720SPeter Avalos init_context(void)
531ed5d5720SPeter Avalos {
532ed5d5720SPeter Avalos 	if (!inited) {
533ed5d5720SPeter Avalos 		inited = 1;
534ed5d5720SPeter Avalos 		if (hesiod_init(&context) < 0) {
535ed5d5720SPeter Avalos 			errval = HES_ER_CONFIG;
536ed5d5720SPeter Avalos 			return -1;
537ed5d5720SPeter Avalos 		}
538ed5d5720SPeter Avalos 		errval = HES_ER_OK;
539ed5d5720SPeter Avalos 	}
540ed5d5720SPeter Avalos 	return 0;
541ed5d5720SPeter Avalos }
542ed5d5720SPeter Avalos 
543ed5d5720SPeter Avalos static void
translate_errors(void)544ed5d5720SPeter Avalos translate_errors(void)
545ed5d5720SPeter Avalos {
546ed5d5720SPeter Avalos 	switch (errno) {
547ed5d5720SPeter Avalos 	case ENOENT:
548ed5d5720SPeter Avalos 		errval = HES_ER_NOTFOUND;
549ed5d5720SPeter Avalos 		break;
550ed5d5720SPeter Avalos 	case ECONNREFUSED:
551ed5d5720SPeter Avalos 	case EMSGSIZE:
552ed5d5720SPeter Avalos 		errval = HES_ER_NET;
553ed5d5720SPeter Avalos 		break;
554ed5d5720SPeter Avalos 	case ENOMEM:
555ed5d5720SPeter Avalos 	default:
556ed5d5720SPeter Avalos 		/* Not a good match, but the best we can do. */
557ed5d5720SPeter Avalos 		errval = HES_ER_CONFIG;
558ed5d5720SPeter Avalos 		break;
559ed5d5720SPeter Avalos 	}
560ed5d5720SPeter Avalos }
561