xref: /minix/lib/libc/net/hesiod.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: hesiod.c,v 1.28 2014/09/18 13:58:20 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /* Copyright (c) 1996 by Internet Software Consortium.
42fe8fb19SBen Gras  *
52fe8fb19SBen Gras  * Permission to use, copy, modify, and distribute this software for any
62fe8fb19SBen Gras  * purpose with or without fee is hereby granted, provided that the above
72fe8fb19SBen Gras  * copyright notice and this permission notice appear in all copies.
82fe8fb19SBen Gras  *
92fe8fb19SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
102fe8fb19SBen Gras  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
112fe8fb19SBen Gras  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
122fe8fb19SBen Gras  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
132fe8fb19SBen Gras  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
142fe8fb19SBen Gras  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
152fe8fb19SBen Gras  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
162fe8fb19SBen Gras  * SOFTWARE.
172fe8fb19SBen Gras  */
182fe8fb19SBen Gras 
192fe8fb19SBen Gras /* Copyright 1996 by the Massachusetts Institute of Technology.
202fe8fb19SBen Gras  *
212fe8fb19SBen Gras  * Permission to use, copy, modify, and distribute this
222fe8fb19SBen Gras  * software and its documentation for any purpose and without
232fe8fb19SBen Gras  * fee is hereby granted, provided that the above copyright
242fe8fb19SBen Gras  * notice appear in all copies and that both that copyright
252fe8fb19SBen Gras  * notice and this permission notice appear in supporting
262fe8fb19SBen Gras  * documentation, and that the name of M.I.T. not be used in
272fe8fb19SBen Gras  * advertising or publicity pertaining to distribution of the
282fe8fb19SBen Gras  * software without specific, written prior permission.
292fe8fb19SBen Gras  * M.I.T. makes no representations about the suitability of
302fe8fb19SBen Gras  * this software for any purpose.  It is provided "as is"
312fe8fb19SBen Gras  * without express or implied warranty.
322fe8fb19SBen Gras  */
332fe8fb19SBen Gras 
342fe8fb19SBen Gras /* This file is part of the hesiod library.  It implements the core
352fe8fb19SBen Gras  * portion of the hesiod resolver.
362fe8fb19SBen Gras  *
372fe8fb19SBen Gras  * This file is loosely based on an interim version of hesiod.c from
382fe8fb19SBen Gras  * the BIND IRS library, which was in turn based on an earlier version
392fe8fb19SBen Gras  * of this file.  Extensive changes have been made on each step of the
402fe8fb19SBen Gras  * path.
412fe8fb19SBen Gras  *
422fe8fb19SBen Gras  * This implementation is thread-safe because it uses res_nsend().
432fe8fb19SBen Gras  */
442fe8fb19SBen Gras 
452fe8fb19SBen Gras #include <sys/cdefs.h>
462fe8fb19SBen Gras 
472fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
482fe8fb19SBen Gras __IDSTRING(rcsid_hesiod_c,
492fe8fb19SBen Gras     "#Id: hesiod.c,v 1.18.2.1 1997/01/03 20:48:20 ghudson Exp #");
502fe8fb19SBen Gras __IDSTRING(rcsid_hesiod_p_h,
512fe8fb19SBen Gras     "#Id: hesiod_p.h,v 1.1 1996/12/08 21:39:37 ghudson Exp #");
522fe8fb19SBen Gras __IDSTRING(rcsid_hescompat_c,
532fe8fb19SBen Gras     "#Id: hescompat.c,v 1.1.2.1 1996/12/16 08:37:45 ghudson Exp #");
54*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: hesiod.c,v 1.28 2014/09/18 13:58:20 christos Exp $");
552fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
562fe8fb19SBen Gras 
572fe8fb19SBen Gras #include "namespace.h"
582fe8fb19SBen Gras 
592fe8fb19SBen Gras #include <sys/types.h>
602fe8fb19SBen Gras #include <sys/param.h>
612fe8fb19SBen Gras #include <netinet/in.h>
622fe8fb19SBen Gras #include <arpa/nameser.h>
632fe8fb19SBen Gras 
642fe8fb19SBen Gras #include <assert.h>
652fe8fb19SBen Gras #include <ctype.h>
662fe8fb19SBen Gras #include <errno.h>
672fe8fb19SBen Gras #include <hesiod.h>
682fe8fb19SBen Gras #include <resolv.h>
692fe8fb19SBen Gras #include <stdio.h>
702fe8fb19SBen Gras #include <stdlib.h>
712fe8fb19SBen Gras #include <string.h>
722fe8fb19SBen Gras #include <unistd.h>
732fe8fb19SBen Gras 
742fe8fb19SBen Gras #ifdef __weak_alias
752fe8fb19SBen Gras __weak_alias(hesiod_init,_hesiod_init)
762fe8fb19SBen Gras __weak_alias(hesiod_end,_hesiod_end)
772fe8fb19SBen Gras __weak_alias(hesiod_to_bind,_hesiod_to_bind)
782fe8fb19SBen Gras __weak_alias(hesiod_resolve,_hesiod_resolve)
792fe8fb19SBen Gras __weak_alias(hesiod_free_list,_hesiod_free_list)
802fe8fb19SBen Gras __weak_alias(hes_init,_hes_init)
812fe8fb19SBen Gras __weak_alias(hes_to_bind,_hes_to_bind)
822fe8fb19SBen Gras __weak_alias(hes_resolve,_hes_resolve)
832fe8fb19SBen Gras __weak_alias(hes_error,_hes_error)
842fe8fb19SBen Gras __weak_alias(hes_free,_hes_free)
852fe8fb19SBen Gras #endif
862fe8fb19SBen Gras 
872fe8fb19SBen Gras struct hesiod_p {
882fe8fb19SBen Gras 	char	*lhs;			/* normally ".ns" */
892fe8fb19SBen Gras 	char	*rhs;			/* AKA the default hesiod domain */
902fe8fb19SBen Gras 	int	 classes[2];		/* The class search order. */
912fe8fb19SBen Gras };
922fe8fb19SBen Gras 
932fe8fb19SBen Gras #define	MAX_HESRESP	1024
942fe8fb19SBen Gras 
95f14fb602SLionel Sambuc static int	  read_config_file(struct hesiod_p *, const char *);
96f14fb602SLionel Sambuc static char	**get_txt_records(int, const char *);
97f14fb602SLionel Sambuc static int	  init_context(void);
98f14fb602SLionel Sambuc static void	  translate_errors(void);
992fe8fb19SBen Gras 
1002fe8fb19SBen Gras 
1012fe8fb19SBen Gras /*
1022fe8fb19SBen Gras  * hesiod_init --
1032fe8fb19SBen Gras  *	initialize a hesiod_p.
1042fe8fb19SBen Gras  */
1052fe8fb19SBen Gras int
hesiod_init(void ** context)106f14fb602SLionel Sambuc hesiod_init(void **context)
1072fe8fb19SBen Gras {
1082fe8fb19SBen Gras 	struct hesiod_p	*ctx;
1092fe8fb19SBen Gras 	const char	*p, *configname;
1102fe8fb19SBen Gras 	int serrno;
1112fe8fb19SBen Gras 
1122fe8fb19SBen Gras 	_DIAGASSERT(context != NULL);
1132fe8fb19SBen Gras 
1142fe8fb19SBen Gras 	ctx = calloc(1, sizeof(struct hesiod_p));
1152fe8fb19SBen Gras 	if (ctx) {
1162fe8fb19SBen Gras 		*context = ctx;
1172fe8fb19SBen Gras 		/*
1182fe8fb19SBen Gras 		 * don't permit overrides from environment
1192fe8fb19SBen Gras 		 * for set.id programs
1202fe8fb19SBen Gras 		 */
1212fe8fb19SBen Gras 		if (issetugid())
1222fe8fb19SBen Gras 			configname = NULL;
1232fe8fb19SBen Gras 		else
1242fe8fb19SBen Gras 			configname = getenv("HESIOD_CONFIG");
1252fe8fb19SBen Gras 		if (!configname)
1262fe8fb19SBen Gras 			configname = _PATH_HESIOD_CONF;
1272fe8fb19SBen Gras 		if (read_config_file(ctx, configname) >= 0) {
1282fe8fb19SBen Gras 			/*
1292fe8fb19SBen Gras 			 * The default rhs can be overridden by an
1302fe8fb19SBen Gras 			 * environment variable, unless set.id.
1312fe8fb19SBen Gras 			 */
1322fe8fb19SBen Gras 			if (issetugid())
1332fe8fb19SBen Gras 				p = NULL;
1342fe8fb19SBen Gras 			else
1352fe8fb19SBen Gras 				p = getenv("HES_DOMAIN");
1362fe8fb19SBen Gras 			if (p) {
1372fe8fb19SBen Gras 				if (ctx->rhs)
1382fe8fb19SBen Gras 					free(ctx->rhs);
1392fe8fb19SBen Gras 				ctx->rhs = malloc(strlen(p) + 2);
1402fe8fb19SBen Gras 				if (ctx->rhs) {
1412fe8fb19SBen Gras 					*ctx->rhs = '.';
1422fe8fb19SBen Gras 					strcpy(ctx->rhs + 1,
1432fe8fb19SBen Gras 					    (*p == '.') ? p + 1 : p);
1442fe8fb19SBen Gras 					return 0;
1452fe8fb19SBen Gras 				} else
1462fe8fb19SBen Gras 					errno = ENOMEM;
1472fe8fb19SBen Gras 			} else
1482fe8fb19SBen Gras 				return 0;
1492fe8fb19SBen Gras 		}
1502fe8fb19SBen Gras 	} else
1512fe8fb19SBen Gras 		errno = ENOMEM;
1522fe8fb19SBen Gras 
1532fe8fb19SBen Gras 	serrno = errno;
1542fe8fb19SBen Gras 	if (ctx) {
1552fe8fb19SBen Gras 		if (ctx->lhs)
1562fe8fb19SBen Gras 			free(ctx->lhs);
1572fe8fb19SBen Gras 		if (ctx->rhs)
1582fe8fb19SBen Gras 			free(ctx->rhs);
1592fe8fb19SBen Gras 		free(ctx);
1602fe8fb19SBen Gras 	}
1612fe8fb19SBen Gras 	errno = serrno;
1622fe8fb19SBen Gras 	return -1;
1632fe8fb19SBen Gras }
1642fe8fb19SBen Gras 
1652fe8fb19SBen Gras /*
1662fe8fb19SBen Gras  * hesiod_end --
1672fe8fb19SBen Gras  *	Deallocates the hesiod_p.
1682fe8fb19SBen Gras  */
1692fe8fb19SBen Gras void
hesiod_end(void * context)170f14fb602SLionel Sambuc hesiod_end(void *context)
1712fe8fb19SBen Gras {
1722fe8fb19SBen Gras 	struct hesiod_p *ctx = (struct hesiod_p *) context;
1732fe8fb19SBen Gras 
1742fe8fb19SBen Gras 	_DIAGASSERT(context != NULL);
1752fe8fb19SBen Gras 
1762fe8fb19SBen Gras 	free(ctx->rhs);
1772fe8fb19SBen Gras 	if (ctx->lhs)
1782fe8fb19SBen Gras 		free(ctx->lhs);
1792fe8fb19SBen Gras 	free(ctx);
1802fe8fb19SBen Gras }
1812fe8fb19SBen Gras 
1822fe8fb19SBen Gras /*
1832fe8fb19SBen Gras  * hesiod_to_bind --
1842fe8fb19SBen Gras  * 	takes a hesiod (name, type) and returns a DNS
1852fe8fb19SBen Gras  *	name which is to be resolved.
1862fe8fb19SBen Gras  */
1872fe8fb19SBen Gras char *
hesiod_to_bind(void * context,const char * name,const char * type)1882fe8fb19SBen Gras hesiod_to_bind(void *context, const char *name, const char *type)
1892fe8fb19SBen Gras {
1902fe8fb19SBen Gras 	struct hesiod_p *ctx = (struct hesiod_p *) context;
1912fe8fb19SBen Gras 	char		 bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
1922fe8fb19SBen Gras 	const char	*rhs;
1932fe8fb19SBen Gras 	size_t		 len;
1942fe8fb19SBen Gras 
1952fe8fb19SBen Gras 	_DIAGASSERT(context != NULL);
1962fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
1972fe8fb19SBen Gras 	_DIAGASSERT(type != NULL);
1982fe8fb19SBen Gras 
1992fe8fb19SBen Gras         if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
2002fe8fb19SBen Gras                 errno = EMSGSIZE;
2012fe8fb19SBen Gras                 return NULL;
2022fe8fb19SBen Gras         }
2032fe8fb19SBen Gras 
2042fe8fb19SBen Gras 	/*
2052fe8fb19SBen Gras 	 * Find the right right hand side to use, possibly
2062fe8fb19SBen Gras 	 * truncating bindname.
2072fe8fb19SBen Gras 	 */
2082fe8fb19SBen Gras 	p = strchr(bindname, '@');
2092fe8fb19SBen Gras 	if (p) {
2102fe8fb19SBen Gras 		*p++ = 0;
2112fe8fb19SBen Gras 		if (strchr(p, '.'))
2122fe8fb19SBen Gras 			rhs = name + (p - bindname);
2132fe8fb19SBen Gras 		else {
2142fe8fb19SBen Gras 			rhs_list = hesiod_resolve(context, p, "rhs-extension");
2152fe8fb19SBen Gras 			if (rhs_list)
2162fe8fb19SBen Gras 				rhs = *rhs_list;
2172fe8fb19SBen Gras 			else {
2182fe8fb19SBen Gras 				errno = ENOENT;
2192fe8fb19SBen Gras 				return NULL;
2202fe8fb19SBen Gras 			}
2212fe8fb19SBen Gras 		}
2222fe8fb19SBen Gras 	} else
2232fe8fb19SBen Gras 		rhs = ctx->rhs;
2242fe8fb19SBen Gras 
2252fe8fb19SBen Gras 	/* See if we have enough room. */
2262fe8fb19SBen Gras 	len = strlen(bindname) + 1 + strlen(type);
2272fe8fb19SBen Gras 	if (ctx->lhs)
2282fe8fb19SBen Gras 		len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
2292fe8fb19SBen Gras 	len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
2302fe8fb19SBen Gras 	if (len > sizeof(bindname) - 1) {
2312fe8fb19SBen Gras 		if (rhs_list)
2322fe8fb19SBen Gras 			hesiod_free_list(context, rhs_list);
2332fe8fb19SBen Gras 		errno = EMSGSIZE;
2342fe8fb19SBen Gras 		return NULL;
2352fe8fb19SBen Gras 	}
2362fe8fb19SBen Gras 	/* Put together the rest of the domain. */
2372fe8fb19SBen Gras 	strlcat(bindname, ".", sizeof(bindname));
2382fe8fb19SBen Gras 	strlcat(bindname, type, sizeof(bindname));
2392fe8fb19SBen Gras 	/* Only append lhs if it isn't empty. */
2402fe8fb19SBen Gras 	if (ctx->lhs && ctx->lhs[0] != '\0' ) {
2412fe8fb19SBen Gras 		if (ctx->lhs[0] != '.')
2422fe8fb19SBen Gras 			strlcat(bindname, ".", sizeof(bindname));
2432fe8fb19SBen Gras 		strlcat(bindname, ctx->lhs, sizeof(bindname));
2442fe8fb19SBen Gras 	}
2452fe8fb19SBen Gras 	if (rhs[0] != '.')
2462fe8fb19SBen Gras 		strlcat(bindname, ".", sizeof(bindname));
2472fe8fb19SBen Gras 	strlcat(bindname, rhs, sizeof(bindname));
2482fe8fb19SBen Gras 
2492fe8fb19SBen Gras 	/* rhs_list is no longer needed, since we're done with rhs. */
2502fe8fb19SBen Gras 	if (rhs_list)
2512fe8fb19SBen Gras 		hesiod_free_list(context, rhs_list);
2522fe8fb19SBen Gras 
2532fe8fb19SBen Gras 	/* Make a copy of the result and return it to the caller. */
2542fe8fb19SBen Gras 	ret = strdup(bindname);
2552fe8fb19SBen Gras 	if (ret == NULL)
2562fe8fb19SBen Gras 		errno = ENOMEM;
2572fe8fb19SBen Gras 	return ret;
2582fe8fb19SBen Gras }
2592fe8fb19SBen Gras 
2602fe8fb19SBen Gras /*
2612fe8fb19SBen Gras  * hesiod_resolve --
2622fe8fb19SBen Gras  *	Given a hesiod name and type, return an array of strings returned
2632fe8fb19SBen Gras  *	by the resolver.
2642fe8fb19SBen Gras  */
2652fe8fb19SBen Gras char **
hesiod_resolve(void * context,const char * name,const char * type)266f14fb602SLionel Sambuc hesiod_resolve(void *context, const char *name, const char *type)
2672fe8fb19SBen Gras {
2682fe8fb19SBen Gras 	struct hesiod_p	*ctx = (struct hesiod_p *) context;
2692fe8fb19SBen Gras 	char		*bindname, **retvec;
2702fe8fb19SBen Gras 
2712fe8fb19SBen Gras 	_DIAGASSERT(context != NULL);
2722fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
2732fe8fb19SBen Gras 	_DIAGASSERT(type != NULL);
2742fe8fb19SBen Gras 
2752fe8fb19SBen Gras 	bindname = hesiod_to_bind(context, name, type);
2762fe8fb19SBen Gras 	if (!bindname)
2772fe8fb19SBen Gras 		return NULL;
2782fe8fb19SBen Gras 
2792fe8fb19SBen Gras 	retvec = get_txt_records(ctx->classes[0], bindname);
2802fe8fb19SBen Gras 	if (retvec == NULL && errno == ENOENT && ctx->classes[1])
2812fe8fb19SBen Gras 		retvec = get_txt_records(ctx->classes[1], bindname);
2822fe8fb19SBen Gras 
2832fe8fb19SBen Gras 	free(bindname);
2842fe8fb19SBen Gras 	return retvec;
2852fe8fb19SBen Gras }
2862fe8fb19SBen Gras 
2872fe8fb19SBen Gras /*ARGSUSED*/
2882fe8fb19SBen Gras void
hesiod_free_list(void * context,char ** list)289f14fb602SLionel Sambuc hesiod_free_list(void *context, char **list)
2902fe8fb19SBen Gras {
2912fe8fb19SBen Gras 	char  **p;
2922fe8fb19SBen Gras 
2932fe8fb19SBen Gras 	_DIAGASSERT(context != NULL);
2942fe8fb19SBen Gras 
2952fe8fb19SBen Gras 	if (list == NULL)
2962fe8fb19SBen Gras 		return;
2972fe8fb19SBen Gras 	for (p = list; *p; p++)
2982fe8fb19SBen Gras 		free(*p);
2992fe8fb19SBen Gras 	free(list);
3002fe8fb19SBen Gras }
3012fe8fb19SBen Gras 
3022fe8fb19SBen Gras 
3032fe8fb19SBen Gras /* read_config_file --
3042fe8fb19SBen Gras  *	Parse the /etc/hesiod.conf file.  Returns 0 on success,
3052fe8fb19SBen Gras  *	-1 on failure.  On failure, it might leave values in ctx->lhs
3062fe8fb19SBen Gras  *	or ctx->rhs which need to be freed by the caller.
3072fe8fb19SBen Gras  */
3082fe8fb19SBen Gras static int
read_config_file(struct hesiod_p * ctx,const char * filename)309f14fb602SLionel Sambuc read_config_file(struct hesiod_p *ctx, const char *filename)
3102fe8fb19SBen Gras {
311f14fb602SLionel Sambuc 	char	*buf, *key, *data, *p, **which;
3122fe8fb19SBen Gras 	int	 n;
3132fe8fb19SBen Gras 	FILE	*fp;
3142fe8fb19SBen Gras 
3152fe8fb19SBen Gras 	_DIAGASSERT(ctx != NULL);
3162fe8fb19SBen Gras 	_DIAGASSERT(filename != NULL);
3172fe8fb19SBen Gras 
3182fe8fb19SBen Gras 	/* Set default query classes. */
3192fe8fb19SBen Gras 	ctx->classes[0] = C_IN;
3202fe8fb19SBen Gras 	ctx->classes[1] = C_HS;
3212fe8fb19SBen Gras 
3222fe8fb19SBen Gras 	/* Try to open the configuration file. */
323*0a6a1f1dSLionel Sambuc 	fp = fopen(filename, "re");
3242fe8fb19SBen Gras 	if (!fp) {
3252fe8fb19SBen Gras 		/* Use compiled in default domain names. */
3262fe8fb19SBen Gras 		ctx->lhs = strdup(DEF_LHS);
3272fe8fb19SBen Gras 		ctx->rhs = strdup(DEF_RHS);
3282fe8fb19SBen Gras 		if (ctx->lhs && ctx->rhs)
3292fe8fb19SBen Gras 			return 0;
3302fe8fb19SBen Gras 		else {
3312fe8fb19SBen Gras 			errno = ENOMEM;
3322fe8fb19SBen Gras 			return -1;
3332fe8fb19SBen Gras 		}
3342fe8fb19SBen Gras 	}
3352fe8fb19SBen Gras 	ctx->lhs = NULL;
3362fe8fb19SBen Gras 	ctx->rhs = NULL;
337f14fb602SLionel Sambuc 	for (; (buf = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCALL))
338f14fb602SLionel Sambuc 	    != NULL; free(buf)) {
3392fe8fb19SBen Gras 		p = buf;
3402fe8fb19SBen Gras 		while (*p == ' ' || *p == '\t')
3412fe8fb19SBen Gras 			p++;
3422fe8fb19SBen Gras 		key = p;
3432fe8fb19SBen Gras 		while (*p != ' ' && *p != '\t' && *p != '=' && *p)
3442fe8fb19SBen Gras 			p++;
3452fe8fb19SBen Gras 
3462fe8fb19SBen Gras 		if (*p == '\0')
3472fe8fb19SBen Gras 			continue;
3482fe8fb19SBen Gras 
3492fe8fb19SBen Gras 		*p++ = 0;
3502fe8fb19SBen Gras 
3512fe8fb19SBen Gras 		while (isspace((u_char) *p) || *p == '=')
3522fe8fb19SBen Gras 			p++;
3532fe8fb19SBen Gras 
3542fe8fb19SBen Gras 		if (*p == '\0')
3552fe8fb19SBen Gras 			continue;
3562fe8fb19SBen Gras 
3572fe8fb19SBen Gras 		data = p;
3582fe8fb19SBen Gras 		while (!isspace((u_char) *p) && *p)
3592fe8fb19SBen Gras 			p++;
3602fe8fb19SBen Gras 
3612fe8fb19SBen Gras 		*p = 0;
3622fe8fb19SBen Gras 
3632fe8fb19SBen Gras 		if (strcasecmp(key, "lhs") == 0 ||
3642fe8fb19SBen Gras 		    strcasecmp(key, "rhs") == 0) {
3652fe8fb19SBen Gras 			which = (strcasecmp(key, "lhs") == 0)
3662fe8fb19SBen Gras 			    ? &ctx->lhs : &ctx->rhs;
3672fe8fb19SBen Gras 			*which = strdup(data);
3682fe8fb19SBen Gras 			if (!*which) {
3692fe8fb19SBen Gras 				errno = ENOMEM;
370f14fb602SLionel Sambuc 				free(buf);
3712fe8fb19SBen Gras 				(void)fclose(fp);
3722fe8fb19SBen Gras 				return -1;
3732fe8fb19SBen Gras 			}
3742fe8fb19SBen Gras 		} else {
3752fe8fb19SBen Gras 			if (strcasecmp(key, "classes") == 0) {
3762fe8fb19SBen Gras 				n = 0;
3772fe8fb19SBen Gras 				while (*data && n < 2) {
3782fe8fb19SBen Gras 					p = data;
3792fe8fb19SBen Gras 					while (*p && *p != ',')
3802fe8fb19SBen Gras 						p++;
3812fe8fb19SBen Gras 					if (*p)
3822fe8fb19SBen Gras 						*p++ = 0;
3832fe8fb19SBen Gras 					if (strcasecmp(data, "IN") == 0)
3842fe8fb19SBen Gras 						ctx->classes[n++] = C_IN;
3852fe8fb19SBen Gras 					else
3862fe8fb19SBen Gras 						if (strcasecmp(data, "HS") == 0)
3872fe8fb19SBen Gras 							ctx->classes[n++] =
3882fe8fb19SBen Gras 							    C_HS;
3892fe8fb19SBen Gras 					data = p;
3902fe8fb19SBen Gras 				}
3912fe8fb19SBen Gras 				while (n < 2)
3922fe8fb19SBen Gras 					ctx->classes[n++] = 0;
3932fe8fb19SBen Gras 			}
3942fe8fb19SBen Gras 		}
3952fe8fb19SBen Gras 	}
3962fe8fb19SBen Gras 	fclose(fp);
3972fe8fb19SBen Gras 
3982fe8fb19SBen Gras 	if (!ctx->rhs || ctx->classes[0] == 0 ||
3992fe8fb19SBen Gras 	    ctx->classes[0] == ctx->classes[1]) {
4002fe8fb19SBen Gras 		errno = ENOEXEC;
4012fe8fb19SBen Gras 		return -1;
4022fe8fb19SBen Gras 	}
4032fe8fb19SBen Gras 	return 0;
4042fe8fb19SBen Gras }
4052fe8fb19SBen Gras 
4062fe8fb19SBen Gras /*
4072fe8fb19SBen Gras  * get_txt_records --
4082fe8fb19SBen Gras  *	Given a DNS class and a DNS name, do a lookup for TXT records, and
4092fe8fb19SBen Gras  *	return a list of them.
4102fe8fb19SBen Gras  */
4112fe8fb19SBen Gras static char **
get_txt_records(int qclass,const char * name)412f14fb602SLionel Sambuc get_txt_records(int qclass, const char *name)
4132fe8fb19SBen Gras {
4142fe8fb19SBen Gras 	HEADER		*hp;
4152fe8fb19SBen Gras 	unsigned char	 qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
4162fe8fb19SBen Gras 	char		*dst, **list;
4172fe8fb19SBen Gras 	int		 ancount, qdcount, i, j, n, skip, type, class, len;
4182fe8fb19SBen Gras 	res_state	 res = __res_get_state();
4192fe8fb19SBen Gras 
4202fe8fb19SBen Gras 	if (res == NULL)
4212fe8fb19SBen Gras 		return NULL;
4222fe8fb19SBen Gras 
4232fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
4242fe8fb19SBen Gras 
4252fe8fb19SBen Gras 	/* Construct the query. */
4262fe8fb19SBen Gras 	n = res_nmkquery(res, QUERY, name, qclass, T_TXT, NULL, 0,
4272fe8fb19SBen Gras 	    NULL, qbuf, PACKETSZ);
4282fe8fb19SBen Gras 	if (n < 0) {
4292fe8fb19SBen Gras 		errno = EMSGSIZE;
4302fe8fb19SBen Gras 		__res_put_state(res);
4312fe8fb19SBen Gras 		return NULL;
4322fe8fb19SBen Gras 	}
4332fe8fb19SBen Gras 
4342fe8fb19SBen Gras 	/* Send the query. */
4352fe8fb19SBen Gras 	n = res_nsend(res, qbuf, n, abuf, MAX_HESRESP);
4362fe8fb19SBen Gras 	__res_put_state(res);
4372fe8fb19SBen Gras 	if (n < 0) {
4382fe8fb19SBen Gras 		errno = ECONNREFUSED;
4392fe8fb19SBen Gras 		return NULL;
4402fe8fb19SBen Gras 	}
4412fe8fb19SBen Gras 	/* Parse the header of the result. */
4422fe8fb19SBen Gras 	hp = (HEADER *) (void *) abuf;
4432fe8fb19SBen Gras 	ancount = ntohs(hp->ancount);
4442fe8fb19SBen Gras 	qdcount = ntohs(hp->qdcount);
4452fe8fb19SBen Gras 	p = abuf + sizeof(HEADER);
4462fe8fb19SBen Gras 	eom = abuf + n;
4472fe8fb19SBen Gras 
4482fe8fb19SBen Gras 	/*
4492fe8fb19SBen Gras 	 * Skip questions, trying to get to the answer section
4502fe8fb19SBen Gras 	 * which follows.
4512fe8fb19SBen Gras 	 */
4522fe8fb19SBen Gras 	for (i = 0; i < qdcount; i++) {
4532fe8fb19SBen Gras 		skip = dn_skipname(p, eom);
4542fe8fb19SBen Gras 		if (skip < 0 || p + skip + QFIXEDSZ > eom) {
4552fe8fb19SBen Gras 			errno = EMSGSIZE;
4562fe8fb19SBen Gras 			return NULL;
4572fe8fb19SBen Gras 		}
4582fe8fb19SBen Gras 		p += skip + QFIXEDSZ;
4592fe8fb19SBen Gras 	}
4602fe8fb19SBen Gras 
4612fe8fb19SBen Gras 	/* Allocate space for the text record answers. */
4622fe8fb19SBen Gras 	list = malloc((ancount + 1) * sizeof(char *));
4632fe8fb19SBen Gras 	if (!list) {
4642fe8fb19SBen Gras 		errno = ENOMEM;
4652fe8fb19SBen Gras 		return NULL;
4662fe8fb19SBen Gras 	}
4672fe8fb19SBen Gras 	/* Parse the answers. */
4682fe8fb19SBen Gras 	j = 0;
4692fe8fb19SBen Gras 	for (i = 0; i < ancount; i++) {
4702fe8fb19SBen Gras 		/* Parse the header of this answer. */
4712fe8fb19SBen Gras 		skip = dn_skipname(p, eom);
4722fe8fb19SBen Gras 		if (skip < 0 || p + skip + 10 > eom)
4732fe8fb19SBen Gras 			break;
4742fe8fb19SBen Gras 		type = p[skip + 0] << 8 | p[skip + 1];
4752fe8fb19SBen Gras 		class = p[skip + 2] << 8 | p[skip + 3];
4762fe8fb19SBen Gras 		len = p[skip + 8] << 8 | p[skip + 9];
4772fe8fb19SBen Gras 		p += skip + 10;
4782fe8fb19SBen Gras 		if (p + len > eom) {
4792fe8fb19SBen Gras 			errno = EMSGSIZE;
4802fe8fb19SBen Gras 			break;
4812fe8fb19SBen Gras 		}
4822fe8fb19SBen Gras 		/* Skip entries of the wrong class and type. */
4832fe8fb19SBen Gras 		if (class != qclass || type != T_TXT) {
4842fe8fb19SBen Gras 			p += len;
4852fe8fb19SBen Gras 			continue;
4862fe8fb19SBen Gras 		}
4872fe8fb19SBen Gras 		/* Allocate space for this answer. */
4882fe8fb19SBen Gras 		list[j] = malloc((size_t)len);
4892fe8fb19SBen Gras 		if (!list[j]) {
4902fe8fb19SBen Gras 			errno = ENOMEM;
4912fe8fb19SBen Gras 			break;
4922fe8fb19SBen Gras 		}
4932fe8fb19SBen Gras 		dst = list[j++];
4942fe8fb19SBen Gras 
4952fe8fb19SBen Gras 		/* Copy answer data into the allocated area. */
4962fe8fb19SBen Gras 		eor = p + len;
4972fe8fb19SBen Gras 		while (p < eor) {
4982fe8fb19SBen Gras 			n = (unsigned char) *p++;
4992fe8fb19SBen Gras 			if (p + n > eor) {
5002fe8fb19SBen Gras 				errno = EMSGSIZE;
5012fe8fb19SBen Gras 				break;
5022fe8fb19SBen Gras 			}
5032fe8fb19SBen Gras 			memcpy(dst, p, (size_t)n);
5042fe8fb19SBen Gras 			p += n;
5052fe8fb19SBen Gras 			dst += n;
5062fe8fb19SBen Gras 		}
5072fe8fb19SBen Gras 		if (p < eor) {
5082fe8fb19SBen Gras 			errno = EMSGSIZE;
5092fe8fb19SBen Gras 			break;
5102fe8fb19SBen Gras 		}
5112fe8fb19SBen Gras 		*dst = 0;
5122fe8fb19SBen Gras 	}
5132fe8fb19SBen Gras 
5142fe8fb19SBen Gras 	/*
5152fe8fb19SBen Gras 	 * If we didn't terminate the loop normally, something
5162fe8fb19SBen Gras 	 * went wrong.
5172fe8fb19SBen Gras 	 */
5182fe8fb19SBen Gras 	if (i < ancount) {
5192fe8fb19SBen Gras 		for (i = 0; i < j; i++)
5202fe8fb19SBen Gras 			free(list[i]);
5212fe8fb19SBen Gras 		free(list);
5222fe8fb19SBen Gras 		return NULL;
5232fe8fb19SBen Gras 	}
5242fe8fb19SBen Gras 	if (j == 0) {
5252fe8fb19SBen Gras 		errno = ENOENT;
5262fe8fb19SBen Gras 		free(list);
5272fe8fb19SBen Gras 		return NULL;
5282fe8fb19SBen Gras 	}
5292fe8fb19SBen Gras 	list[j] = NULL;
5302fe8fb19SBen Gras 	return list;
5312fe8fb19SBen Gras }
5322fe8fb19SBen Gras 
5332fe8fb19SBen Gras /*
5342fe8fb19SBen Gras  * COMPATIBILITY FUNCTIONS
5352fe8fb19SBen Gras  */
5362fe8fb19SBen Gras 
5372fe8fb19SBen Gras static int	  inited = 0;
5382fe8fb19SBen Gras static void	 *context;
5392fe8fb19SBen Gras static int	  errval = HES_ER_UNINIT;
5402fe8fb19SBen Gras 
5412fe8fb19SBen Gras int
hes_init(void)542f14fb602SLionel Sambuc hes_init(void)
5432fe8fb19SBen Gras {
5442fe8fb19SBen Gras 	init_context();
5452fe8fb19SBen Gras 	return errval;
5462fe8fb19SBen Gras }
5472fe8fb19SBen Gras 
5482fe8fb19SBen Gras char *
hes_to_bind(const char * name,const char * type)549f14fb602SLionel Sambuc hes_to_bind(const char *name, const char *type)
5502fe8fb19SBen Gras {
5512fe8fb19SBen Gras 	static	char	*bindname;
5522fe8fb19SBen Gras 
5532fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
5542fe8fb19SBen Gras 	_DIAGASSERT(type != NULL);
5552fe8fb19SBen Gras 
5562fe8fb19SBen Gras 	if (init_context() < 0)
5572fe8fb19SBen Gras 		return NULL;
5582fe8fb19SBen Gras 	if (bindname)
5592fe8fb19SBen Gras 		free(bindname);
5602fe8fb19SBen Gras 	bindname = hesiod_to_bind(context, name, type);
5612fe8fb19SBen Gras 	if (!bindname)
5622fe8fb19SBen Gras 		translate_errors();
5632fe8fb19SBen Gras 	return bindname;
5642fe8fb19SBen Gras }
5652fe8fb19SBen Gras 
5662fe8fb19SBen Gras char **
hes_resolve(const char * name,const char * type)567f14fb602SLionel Sambuc hes_resolve(const char *name, const char *type)
5682fe8fb19SBen Gras {
5692fe8fb19SBen Gras 	static char	**list;
5702fe8fb19SBen Gras 
5712fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
5722fe8fb19SBen Gras 	_DIAGASSERT(type != NULL);
5732fe8fb19SBen Gras 
5742fe8fb19SBen Gras 	if (init_context() < 0)
5752fe8fb19SBen Gras 		return NULL;
5762fe8fb19SBen Gras 
5772fe8fb19SBen Gras 	/*
5782fe8fb19SBen Gras 	 * In the old Hesiod interface, the caller was responsible for
5792fe8fb19SBen Gras 	 * freeing the returned strings but not the vector of strings itself.
5802fe8fb19SBen Gras 	 */
5812fe8fb19SBen Gras 	if (list)
5822fe8fb19SBen Gras 		free(list);
5832fe8fb19SBen Gras 
5842fe8fb19SBen Gras 	list = hesiod_resolve(context, name, type);
5852fe8fb19SBen Gras 	if (!list)
5862fe8fb19SBen Gras 		translate_errors();
5872fe8fb19SBen Gras 	return list;
5882fe8fb19SBen Gras }
5892fe8fb19SBen Gras 
5902fe8fb19SBen Gras int
hes_error(void)591f14fb602SLionel Sambuc hes_error(void)
5922fe8fb19SBen Gras {
5932fe8fb19SBen Gras 	return errval;
5942fe8fb19SBen Gras }
5952fe8fb19SBen Gras 
5962fe8fb19SBen Gras void
hes_free(char ** hp)597f14fb602SLionel Sambuc hes_free(char **hp)
5982fe8fb19SBen Gras {
5992fe8fb19SBen Gras 	hesiod_free_list(context, hp);
6002fe8fb19SBen Gras }
6012fe8fb19SBen Gras 
6022fe8fb19SBen Gras static int
init_context(void)603f14fb602SLionel Sambuc init_context(void)
6042fe8fb19SBen Gras {
6052fe8fb19SBen Gras 	if (!inited) {
6062fe8fb19SBen Gras 		inited = 1;
6072fe8fb19SBen Gras 		if (hesiod_init(&context) < 0) {
6082fe8fb19SBen Gras 			errval = HES_ER_CONFIG;
6092fe8fb19SBen Gras 			return -1;
6102fe8fb19SBen Gras 		}
6112fe8fb19SBen Gras 		errval = HES_ER_OK;
6122fe8fb19SBen Gras 	}
6132fe8fb19SBen Gras 	return 0;
6142fe8fb19SBen Gras }
6152fe8fb19SBen Gras 
6162fe8fb19SBen Gras static void
translate_errors(void)617f14fb602SLionel Sambuc translate_errors(void)
6182fe8fb19SBen Gras {
6192fe8fb19SBen Gras 	switch (errno) {
6202fe8fb19SBen Gras 	case ENOENT:
6212fe8fb19SBen Gras 		errval = HES_ER_NOTFOUND;
6222fe8fb19SBen Gras 		break;
6232fe8fb19SBen Gras 	case ECONNREFUSED:
6242fe8fb19SBen Gras 	case EMSGSIZE:
6252fe8fb19SBen Gras 		errval = HES_ER_NET;
6262fe8fb19SBen Gras 		break;
6272fe8fb19SBen Gras 	default:
6282fe8fb19SBen Gras 		/* Not a good match, but the best we can do. */
6292fe8fb19SBen Gras 		errval = HES_ER_CONFIG;
6302fe8fb19SBen Gras 		break;
6312fe8fb19SBen Gras 	}
6322fe8fb19SBen Gras }
633