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