1*4644559eSmaya /* $NetBSD: hesiod.c,v 1.30 2017/03/10 18:02:32 maya Exp $ */
2de3b78d7Slukem
37a51f6dfSlukem /* Copyright (c) 1996 by Internet Software Consortium.
4de3b78d7Slukem *
57a51f6dfSlukem * Permission to use, copy, modify, and distribute this software for any
67a51f6dfSlukem * purpose with or without fee is hereby granted, provided that the above
77a51f6dfSlukem * copyright notice and this permission notice appear in all copies.
8de3b78d7Slukem *
97a51f6dfSlukem * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
107a51f6dfSlukem * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
117a51f6dfSlukem * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
127a51f6dfSlukem * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
137a51f6dfSlukem * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
147a51f6dfSlukem * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
157a51f6dfSlukem * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
167a51f6dfSlukem * SOFTWARE.
177a51f6dfSlukem */
187a51f6dfSlukem
197a51f6dfSlukem /* Copyright 1996 by the Massachusetts Institute of Technology.
20de3b78d7Slukem *
217a51f6dfSlukem * Permission to use, copy, modify, and distribute this
227a51f6dfSlukem * software and its documentation for any purpose and without
237a51f6dfSlukem * fee is hereby granted, provided that the above copyright
247a51f6dfSlukem * notice appear in all copies and that both that copyright
257a51f6dfSlukem * notice and this permission notice appear in supporting
267a51f6dfSlukem * documentation, and that the name of M.I.T. not be used in
277a51f6dfSlukem * advertising or publicity pertaining to distribution of the
287a51f6dfSlukem * software without specific, written prior permission.
297a51f6dfSlukem * M.I.T. makes no representations about the suitability of
307a51f6dfSlukem * this software for any purpose. It is provided "as is"
317a51f6dfSlukem * without express or implied warranty.
327a51f6dfSlukem */
337a51f6dfSlukem
347a51f6dfSlukem /* This file is part of the hesiod library. It implements the core
357a51f6dfSlukem * portion of the hesiod resolver.
367a51f6dfSlukem *
377a51f6dfSlukem * This file is loosely based on an interim version of hesiod.c from
387a51f6dfSlukem * the BIND IRS library, which was in turn based on an earlier version
397a51f6dfSlukem * of this file. Extensive changes have been made on each step of the
407a51f6dfSlukem * path.
417a51f6dfSlukem *
42d14c1915Schristos * This implementation is thread-safe because it uses res_nsend().
43de3b78d7Slukem */
44de3b78d7Slukem
45de3b78d7Slukem #include <sys/cdefs.h>
46de3b78d7Slukem
477a51f6dfSlukem #if defined(LIBC_SCCS) && !defined(lint)
487a51f6dfSlukem __IDSTRING(rcsid_hesiod_c,
497a51f6dfSlukem "#Id: hesiod.c,v 1.18.2.1 1997/01/03 20:48:20 ghudson Exp #");
507a51f6dfSlukem __IDSTRING(rcsid_hesiod_p_h,
517a51f6dfSlukem "#Id: hesiod_p.h,v 1.1 1996/12/08 21:39:37 ghudson Exp #");
527a51f6dfSlukem __IDSTRING(rcsid_hescompat_c,
537a51f6dfSlukem "#Id: hescompat.c,v 1.1.2.1 1996/12/16 08:37:45 ghudson Exp #");
54*4644559eSmaya __RCSID("$NetBSD: hesiod.c,v 1.30 2017/03/10 18:02:32 maya Exp $");
557a51f6dfSlukem #endif /* LIBC_SCCS and not lint */
567a51f6dfSlukem
577a51f6dfSlukem #include "namespace.h"
58de3b78d7Slukem
59de3b78d7Slukem #include <sys/types.h>
60de3b78d7Slukem #include <sys/param.h>
61de3b78d7Slukem #include <netinet/in.h>
62de3b78d7Slukem #include <arpa/nameser.h>
63de3b78d7Slukem
64b48252f3Slukem #include <assert.h>
657a51f6dfSlukem #include <ctype.h>
66de3b78d7Slukem #include <errno.h>
67de3b78d7Slukem #include <hesiod.h>
68de3b78d7Slukem #include <resolv.h>
69de3b78d7Slukem #include <stdio.h>
70de3b78d7Slukem #include <stdlib.h>
71de3b78d7Slukem #include <string.h>
72afc75b9eSlukem #include <unistd.h>
73de3b78d7Slukem
747a51f6dfSlukem #ifdef __weak_alias
7560549036Smycroft __weak_alias(hesiod_init,_hesiod_init)
7660549036Smycroft __weak_alias(hesiod_end,_hesiod_end)
7760549036Smycroft __weak_alias(hesiod_to_bind,_hesiod_to_bind)
7860549036Smycroft __weak_alias(hesiod_resolve,_hesiod_resolve)
7960549036Smycroft __weak_alias(hesiod_free_list,_hesiod_free_list)
8060549036Smycroft __weak_alias(hes_init,_hes_init)
8160549036Smycroft __weak_alias(hes_to_bind,_hes_to_bind)
8260549036Smycroft __weak_alias(hes_resolve,_hes_resolve)
8360549036Smycroft __weak_alias(hes_error,_hes_error)
8460549036Smycroft __weak_alias(hes_free,_hes_free)
857a51f6dfSlukem #endif
86de3b78d7Slukem
877a51f6dfSlukem struct hesiod_p {
887a51f6dfSlukem char *lhs; /* normally ".ns" */
897a51f6dfSlukem char *rhs; /* AKA the default hesiod domain */
907a51f6dfSlukem int classes[2]; /* The class search order. */
917a51f6dfSlukem };
92de3b78d7Slukem
937a51f6dfSlukem #define MAX_HESRESP 1024
94de3b78d7Slukem
95504f8671Smatt static int read_config_file(struct hesiod_p *, const char *);
96504f8671Smatt static char **get_txt_records(int, const char *);
97504f8671Smatt static int init_context(void);
98504f8671Smatt static void translate_errors(void);
99de3b78d7Slukem
100de3b78d7Slukem
1017a51f6dfSlukem /*
1027a51f6dfSlukem * hesiod_init --
1037a51f6dfSlukem * initialize a hesiod_p.
1047a51f6dfSlukem */
1057a51f6dfSlukem int
hesiod_init(void ** context)106504f8671Smatt hesiod_init(void **context)
107de3b78d7Slukem {
1087a51f6dfSlukem struct hesiod_p *ctx;
1097a51f6dfSlukem const char *p, *configname;
110b48252f3Slukem int serrno;
111b48252f3Slukem
112b48252f3Slukem _DIAGASSERT(context != NULL);
113de3b78d7Slukem
114efd08c7bSlukem ctx = calloc(1, sizeof(struct hesiod_p));
1157a51f6dfSlukem if (ctx) {
1167a51f6dfSlukem *context = ctx;
117afc75b9eSlukem /*
118afc75b9eSlukem * don't permit overrides from environment
119afc75b9eSlukem * for set.id programs
120afc75b9eSlukem */
121afc75b9eSlukem if (issetugid())
122afc75b9eSlukem configname = NULL;
123afc75b9eSlukem else
1247a51f6dfSlukem configname = getenv("HESIOD_CONFIG");
1257a51f6dfSlukem if (!configname)
1267a51f6dfSlukem configname = _PATH_HESIOD_CONF;
1277a51f6dfSlukem if (read_config_file(ctx, configname) >= 0) {
1287a51f6dfSlukem /*
1297a51f6dfSlukem * The default rhs can be overridden by an
130afc75b9eSlukem * environment variable, unless set.id.
1317a51f6dfSlukem */
132afc75b9eSlukem if (issetugid())
133afc75b9eSlukem p = NULL;
134afc75b9eSlukem else
1357a51f6dfSlukem p = getenv("HES_DOMAIN");
1367a51f6dfSlukem if (p) {
1377a51f6dfSlukem if (ctx->rhs)
1387a51f6dfSlukem free(ctx->rhs);
1397a51f6dfSlukem ctx->rhs = malloc(strlen(p) + 2);
1407a51f6dfSlukem if (ctx->rhs) {
1417a51f6dfSlukem *ctx->rhs = '.';
1427a51f6dfSlukem strcpy(ctx->rhs + 1,
1437a51f6dfSlukem (*p == '.') ? p + 1 : p);
1447a51f6dfSlukem return 0;
1457a51f6dfSlukem } else
1467a51f6dfSlukem errno = ENOMEM;
1477a51f6dfSlukem } else
1487a51f6dfSlukem return 0;
149de3b78d7Slukem }
1507a51f6dfSlukem } else
1517a51f6dfSlukem errno = ENOMEM;
152de3b78d7Slukem
153b48252f3Slukem serrno = errno;
154efd08c7bSlukem if (ctx) {
1557a51f6dfSlukem free(ctx->lhs);
1567a51f6dfSlukem free(ctx->rhs);
1577a51f6dfSlukem free(ctx);
158efd08c7bSlukem }
159b48252f3Slukem errno = serrno;
1607a51f6dfSlukem return -1;
161de3b78d7Slukem }
162de3b78d7Slukem
163de3b78d7Slukem /*
1647a51f6dfSlukem * hesiod_end --
1657a51f6dfSlukem * Deallocates the hesiod_p.
166de3b78d7Slukem */
1677a51f6dfSlukem void
hesiod_end(void * context)168504f8671Smatt hesiod_end(void *context)
169de3b78d7Slukem {
1707a51f6dfSlukem struct hesiod_p *ctx = (struct hesiod_p *) context;
171de3b78d7Slukem
172b48252f3Slukem _DIAGASSERT(context != NULL);
173b48252f3Slukem
1747a51f6dfSlukem free(ctx->rhs);
1757a51f6dfSlukem if (ctx->lhs)
1767a51f6dfSlukem free(ctx->lhs);
1777a51f6dfSlukem free(ctx);
178de3b78d7Slukem }
179de3b78d7Slukem
1807a51f6dfSlukem /*
1817a51f6dfSlukem * hesiod_to_bind --
1827a51f6dfSlukem * takes a hesiod (name, type) and returns a DNS
1837a51f6dfSlukem * name which is to be resolved.
1847a51f6dfSlukem */
1857a51f6dfSlukem char *
hesiod_to_bind(void * context,const char * name,const char * type)1867a51f6dfSlukem hesiod_to_bind(void *context, const char *name, const char *type)
1877a51f6dfSlukem {
1887a51f6dfSlukem struct hesiod_p *ctx = (struct hesiod_p *) context;
1897a51f6dfSlukem char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
1907a51f6dfSlukem const char *rhs;
1911289029fSthorpej size_t len;
192de3b78d7Slukem
193b48252f3Slukem _DIAGASSERT(context != NULL);
194b48252f3Slukem _DIAGASSERT(name != NULL);
195b48252f3Slukem _DIAGASSERT(type != NULL);
196b48252f3Slukem
19737a3c0e7Ssommerfeld if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
19837a3c0e7Ssommerfeld errno = EMSGSIZE;
19937a3c0e7Ssommerfeld return NULL;
20037a3c0e7Ssommerfeld }
2017a51f6dfSlukem
2027a51f6dfSlukem /*
2037a51f6dfSlukem * Find the right right hand side to use, possibly
2047a51f6dfSlukem * truncating bindname.
2057a51f6dfSlukem */
2067a51f6dfSlukem p = strchr(bindname, '@');
2077a51f6dfSlukem if (p) {
2087a51f6dfSlukem *p++ = 0;
2097a51f6dfSlukem if (strchr(p, '.'))
2107a51f6dfSlukem rhs = name + (p - bindname);
2117a51f6dfSlukem else {
2127a51f6dfSlukem rhs_list = hesiod_resolve(context, p, "rhs-extension");
2137a51f6dfSlukem if (rhs_list)
2147a51f6dfSlukem rhs = *rhs_list;
2157a51f6dfSlukem else {
2167a51f6dfSlukem errno = ENOENT;
2177a51f6dfSlukem return NULL;
2187a51f6dfSlukem }
2197a51f6dfSlukem }
2207a51f6dfSlukem } else
2217a51f6dfSlukem rhs = ctx->rhs;
2227a51f6dfSlukem
2237a51f6dfSlukem /* See if we have enough room. */
2247a51f6dfSlukem len = strlen(bindname) + 1 + strlen(type);
2257a51f6dfSlukem if (ctx->lhs)
2267a51f6dfSlukem len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
2277a51f6dfSlukem len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
2287a51f6dfSlukem if (len > sizeof(bindname) - 1) {
2297a51f6dfSlukem if (rhs_list)
2307a51f6dfSlukem hesiod_free_list(context, rhs_list);
231de3b78d7Slukem errno = EMSGSIZE;
2327a51f6dfSlukem return NULL;
2337a51f6dfSlukem }
2347a51f6dfSlukem /* Put together the rest of the domain. */
23590a8853fSitojun strlcat(bindname, ".", sizeof(bindname));
23690a8853fSitojun strlcat(bindname, type, sizeof(bindname));
23736362e2aSsimonb /* Only append lhs if it isn't empty. */
23836362e2aSsimonb if (ctx->lhs && ctx->lhs[0] != '\0' ) {
2397a51f6dfSlukem if (ctx->lhs[0] != '.')
24090a8853fSitojun strlcat(bindname, ".", sizeof(bindname));
24190a8853fSitojun strlcat(bindname, ctx->lhs, sizeof(bindname));
2427a51f6dfSlukem }
2437a51f6dfSlukem if (rhs[0] != '.')
24490a8853fSitojun strlcat(bindname, ".", sizeof(bindname));
24590a8853fSitojun strlcat(bindname, rhs, sizeof(bindname));
2467a51f6dfSlukem
2477a51f6dfSlukem /* rhs_list is no longer needed, since we're done with rhs. */
2487a51f6dfSlukem if (rhs_list)
2497a51f6dfSlukem hesiod_free_list(context, rhs_list);
2507a51f6dfSlukem
2517a51f6dfSlukem /* Make a copy of the result and return it to the caller. */
2527a51f6dfSlukem ret = strdup(bindname);
2536bf409aaSgroo if (ret == NULL)
2547a51f6dfSlukem errno = ENOMEM;
2557a51f6dfSlukem return ret;
256de3b78d7Slukem }
257de3b78d7Slukem
2587a51f6dfSlukem /*
2597a51f6dfSlukem * hesiod_resolve --
2607a51f6dfSlukem * Given a hesiod name and type, return an array of strings returned
2617a51f6dfSlukem * by the resolver.
2627a51f6dfSlukem */
2637a51f6dfSlukem char **
hesiod_resolve(void * context,const char * name,const char * type)264504f8671Smatt hesiod_resolve(void *context, const char *name, const char *type)
2657a51f6dfSlukem {
2667a51f6dfSlukem struct hesiod_p *ctx = (struct hesiod_p *) context;
2677a51f6dfSlukem char *bindname, **retvec;
268de3b78d7Slukem
269b48252f3Slukem _DIAGASSERT(context != NULL);
270b48252f3Slukem _DIAGASSERT(name != NULL);
271b48252f3Slukem _DIAGASSERT(type != NULL);
272b48252f3Slukem
2737a51f6dfSlukem bindname = hesiod_to_bind(context, name, type);
2747a51f6dfSlukem if (!bindname)
2757a51f6dfSlukem return NULL;
276de3b78d7Slukem
2777a51f6dfSlukem retvec = get_txt_records(ctx->classes[0], bindname);
2787a51f6dfSlukem if (retvec == NULL && errno == ENOENT && ctx->classes[1])
2797a51f6dfSlukem retvec = get_txt_records(ctx->classes[1], bindname);
280de3b78d7Slukem
2817a51f6dfSlukem free(bindname);
2827a51f6dfSlukem return retvec;
2837a51f6dfSlukem }
2847a51f6dfSlukem
2857a51f6dfSlukem /*ARGSUSED*/
2867a51f6dfSlukem void
hesiod_free_list(void * context,char ** list)287504f8671Smatt hesiod_free_list(void *context, char **list)
2887a51f6dfSlukem {
2897a51f6dfSlukem char **p;
2907a51f6dfSlukem
291b48252f3Slukem _DIAGASSERT(context != NULL);
292b48252f3Slukem
2933ca17e24Slukem if (list == NULL)
2943ca17e24Slukem return;
2957a51f6dfSlukem for (p = list; *p; p++)
2967a51f6dfSlukem free(*p);
2977a51f6dfSlukem free(list);
2987a51f6dfSlukem }
2997a51f6dfSlukem
3007a51f6dfSlukem
3017a51f6dfSlukem /* read_config_file --
3027a51f6dfSlukem * Parse the /etc/hesiod.conf file. Returns 0 on success,
3037a51f6dfSlukem * -1 on failure. On failure, it might leave values in ctx->lhs
3047a51f6dfSlukem * or ctx->rhs which need to be freed by the caller.
3057a51f6dfSlukem */
3067a51f6dfSlukem static int
read_config_file(struct hesiod_p * ctx,const char * filename)307504f8671Smatt read_config_file(struct hesiod_p *ctx, const char *filename)
3087a51f6dfSlukem {
3092204ab6bSchristos char *buf, *key, *data, *p, **which;
3107a51f6dfSlukem int n;
3117a51f6dfSlukem FILE *fp;
3127a51f6dfSlukem
313b48252f3Slukem _DIAGASSERT(ctx != NULL);
314b48252f3Slukem _DIAGASSERT(filename != NULL);
315b48252f3Slukem
3167a51f6dfSlukem /* Set default query classes. */
317712ba4aeSlukem ctx->classes[0] = C_IN;
318712ba4aeSlukem ctx->classes[1] = C_HS;
3197a51f6dfSlukem
3207a51f6dfSlukem /* Try to open the configuration file. */
3219a513d96Schristos fp = fopen(filename, "re");
3227a51f6dfSlukem if (!fp) {
3237a51f6dfSlukem /* Use compiled in default domain names. */
3247a51f6dfSlukem ctx->lhs = strdup(DEF_LHS);
3257a51f6dfSlukem ctx->rhs = strdup(DEF_RHS);
3267a51f6dfSlukem if (ctx->lhs && ctx->rhs)
3277a51f6dfSlukem return 0;
3287a51f6dfSlukem else {
3297a51f6dfSlukem errno = ENOMEM;
3307a51f6dfSlukem return -1;
3317a51f6dfSlukem }
3327a51f6dfSlukem }
3337a51f6dfSlukem ctx->lhs = NULL;
3347a51f6dfSlukem ctx->rhs = NULL;
3352204ab6bSchristos for (; (buf = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCALL))
3362204ab6bSchristos != NULL; free(buf)) {
3377a51f6dfSlukem p = buf;
3387a51f6dfSlukem while (*p == ' ' || *p == '\t')
3397a51f6dfSlukem p++;
3407a51f6dfSlukem key = p;
3416bf409aaSgroo while (*p != ' ' && *p != '\t' && *p != '=' && *p)
3427a51f6dfSlukem p++;
3436bf409aaSgroo
3446bf409aaSgroo if (*p == '\0')
3456bf409aaSgroo continue;
3466bf409aaSgroo
3477a51f6dfSlukem *p++ = 0;
3487a51f6dfSlukem
3497daefc5aSitohy while (isspace((u_char) *p) || *p == '=')
3507a51f6dfSlukem p++;
3516bf409aaSgroo
3526bf409aaSgroo if (*p == '\0')
3536bf409aaSgroo continue;
3546bf409aaSgroo
3557a51f6dfSlukem data = p;
3566bf409aaSgroo while (!isspace((u_char) *p) && *p)
3577a51f6dfSlukem p++;
3586bf409aaSgroo
3597a51f6dfSlukem *p = 0;
3607a51f6dfSlukem
3617a51f6dfSlukem if (strcasecmp(key, "lhs") == 0 ||
3627a51f6dfSlukem strcasecmp(key, "rhs") == 0) {
3637a51f6dfSlukem which = (strcasecmp(key, "lhs") == 0)
3647a51f6dfSlukem ? &ctx->lhs : &ctx->rhs;
3657a51f6dfSlukem *which = strdup(data);
3667a51f6dfSlukem if (!*which) {
3677a51f6dfSlukem errno = ENOMEM;
3682204ab6bSchristos free(buf);
369aff1729aSwiz (void)fclose(fp);
3707a51f6dfSlukem return -1;
3717a51f6dfSlukem }
3727a51f6dfSlukem } else {
3737a51f6dfSlukem if (strcasecmp(key, "classes") == 0) {
3747a51f6dfSlukem n = 0;
3757a51f6dfSlukem while (*data && n < 2) {
3767a51f6dfSlukem p = data;
3777a51f6dfSlukem while (*p && *p != ',')
3787a51f6dfSlukem p++;
3797a51f6dfSlukem if (*p)
3807a51f6dfSlukem *p++ = 0;
3817a51f6dfSlukem if (strcasecmp(data, "IN") == 0)
3827a51f6dfSlukem ctx->classes[n++] = C_IN;
3837a51f6dfSlukem else
3847a51f6dfSlukem if (strcasecmp(data, "HS") == 0)
3857a51f6dfSlukem ctx->classes[n++] =
3867a51f6dfSlukem C_HS;
3877a51f6dfSlukem data = p;
3887a51f6dfSlukem }
3897a51f6dfSlukem while (n < 2)
3907a51f6dfSlukem ctx->classes[n++] = 0;
3917a51f6dfSlukem }
3927a51f6dfSlukem }
3937a51f6dfSlukem }
3947a51f6dfSlukem fclose(fp);
3957a51f6dfSlukem
3967a51f6dfSlukem if (!ctx->rhs || ctx->classes[0] == 0 ||
3977a51f6dfSlukem ctx->classes[0] == ctx->classes[1]) {
3987a51f6dfSlukem errno = ENOEXEC;
3997a51f6dfSlukem return -1;
4007a51f6dfSlukem }
4017a51f6dfSlukem return 0;
4027a51f6dfSlukem }
4037a51f6dfSlukem
4047a51f6dfSlukem /*
4057a51f6dfSlukem * get_txt_records --
4067a51f6dfSlukem * Given a DNS class and a DNS name, do a lookup for TXT records, and
4077a51f6dfSlukem * return a list of them.
4087a51f6dfSlukem */
4097a51f6dfSlukem static char **
get_txt_records(int qclass,const char * name)410504f8671Smatt get_txt_records(int qclass, const char *name)
4117a51f6dfSlukem {
4127a51f6dfSlukem HEADER *hp;
4137a51f6dfSlukem unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
4147a51f6dfSlukem char *dst, **list;
4157a51f6dfSlukem int ancount, qdcount, i, j, n, skip, type, class, len;
416d14c1915Schristos res_state res = __res_get_state();
4177a51f6dfSlukem
41813cc3543Schristos if (res == NULL)
4197a51f6dfSlukem return NULL;
42013cc3543Schristos
42113cc3543Schristos _DIAGASSERT(name != NULL);
4227a51f6dfSlukem
4237a51f6dfSlukem /* Construct the query. */
424d14c1915Schristos n = res_nmkquery(res, QUERY, name, qclass, T_TXT, NULL, 0,
4257a51f6dfSlukem NULL, qbuf, PACKETSZ);
426dcb9078cSghudson if (n < 0) {
427dcb9078cSghudson errno = EMSGSIZE;
428d14c1915Schristos __res_put_state(res);
4297a51f6dfSlukem return NULL;
430dcb9078cSghudson }
4317a51f6dfSlukem
4327a51f6dfSlukem /* Send the query. */
433d14c1915Schristos n = res_nsend(res, qbuf, n, abuf, MAX_HESRESP);
434d14c1915Schristos __res_put_state(res);
435de3b78d7Slukem if (n < 0) {
436de3b78d7Slukem errno = ECONNREFUSED;
4377a51f6dfSlukem return NULL;
438de3b78d7Slukem }
4397a51f6dfSlukem /* Parse the header of the result. */
4407a51f6dfSlukem hp = (HEADER *) (void *) abuf;
4417a51f6dfSlukem ancount = ntohs(hp->ancount);
4427a51f6dfSlukem qdcount = ntohs(hp->qdcount);
4437a51f6dfSlukem p = abuf + sizeof(HEADER);
4447a51f6dfSlukem eom = abuf + n;
445de3b78d7Slukem
4467a51f6dfSlukem /*
4477a51f6dfSlukem * Skip questions, trying to get to the answer section
4487a51f6dfSlukem * which follows.
4497a51f6dfSlukem */
4507a51f6dfSlukem for (i = 0; i < qdcount; i++) {
4517a51f6dfSlukem skip = dn_skipname(p, eom);
4527a51f6dfSlukem if (skip < 0 || p + skip + QFIXEDSZ > eom) {
4537a51f6dfSlukem errno = EMSGSIZE;
4547a51f6dfSlukem return NULL;
455de3b78d7Slukem }
4567a51f6dfSlukem p += skip + QFIXEDSZ;
4577a51f6dfSlukem }
4587a51f6dfSlukem
4597a51f6dfSlukem /* Allocate space for the text record answers. */
4607a51f6dfSlukem list = malloc((ancount + 1) * sizeof(char *));
4617a51f6dfSlukem if (!list) {
4627a51f6dfSlukem errno = ENOMEM;
4637a51f6dfSlukem return NULL;
4647a51f6dfSlukem }
4657a51f6dfSlukem /* Parse the answers. */
4667a51f6dfSlukem j = 0;
4677a51f6dfSlukem for (i = 0; i < ancount; i++) {
4687a51f6dfSlukem /* Parse the header of this answer. */
4697a51f6dfSlukem skip = dn_skipname(p, eom);
4707a51f6dfSlukem if (skip < 0 || p + skip + 10 > eom)
4717a51f6dfSlukem break;
4727a51f6dfSlukem type = p[skip + 0] << 8 | p[skip + 1];
4737a51f6dfSlukem class = p[skip + 2] << 8 | p[skip + 3];
4747a51f6dfSlukem len = p[skip + 8] << 8 | p[skip + 9];
4757a51f6dfSlukem p += skip + 10;
4767a51f6dfSlukem if (p + len > eom) {
4777a51f6dfSlukem errno = EMSGSIZE;
4787a51f6dfSlukem break;
4797a51f6dfSlukem }
4807a51f6dfSlukem /* Skip entries of the wrong class and type. */
4817a51f6dfSlukem if (class != qclass || type != T_TXT) {
4827a51f6dfSlukem p += len;
4837a51f6dfSlukem continue;
4847a51f6dfSlukem }
4857a51f6dfSlukem /* Allocate space for this answer. */
4867a51f6dfSlukem list[j] = malloc((size_t)len);
4877a51f6dfSlukem if (!list[j]) {
4887a51f6dfSlukem errno = ENOMEM;
4897a51f6dfSlukem break;
4907a51f6dfSlukem }
4917a51f6dfSlukem dst = list[j++];
4927a51f6dfSlukem
4937a51f6dfSlukem /* Copy answer data into the allocated area. */
4947a51f6dfSlukem eor = p + len;
4957a51f6dfSlukem while (p < eor) {
4967a51f6dfSlukem n = (unsigned char) *p++;
4977a51f6dfSlukem if (p + n > eor) {
4987a51f6dfSlukem errno = EMSGSIZE;
4997a51f6dfSlukem break;
5007a51f6dfSlukem }
5017a51f6dfSlukem memcpy(dst, p, (size_t)n);
5027a51f6dfSlukem p += n;
5037a51f6dfSlukem dst += n;
5047a51f6dfSlukem }
5057a51f6dfSlukem if (p < eor) {
5067a51f6dfSlukem errno = EMSGSIZE;
5077a51f6dfSlukem break;
5087a51f6dfSlukem }
5097a51f6dfSlukem *dst = 0;
5107a51f6dfSlukem }
5117a51f6dfSlukem
5127a51f6dfSlukem /*
5137a51f6dfSlukem * If we didn't terminate the loop normally, something
5147a51f6dfSlukem * went wrong.
5157a51f6dfSlukem */
5167a51f6dfSlukem if (i < ancount) {
5177a51f6dfSlukem for (i = 0; i < j; i++)
5187a51f6dfSlukem free(list[i]);
5197a51f6dfSlukem free(list);
5207a51f6dfSlukem return NULL;
5217a51f6dfSlukem }
5227a51f6dfSlukem if (j == 0) {
5237a51f6dfSlukem errno = ENOENT;
5247a51f6dfSlukem free(list);
5257a51f6dfSlukem return NULL;
5267a51f6dfSlukem }
5277a51f6dfSlukem list[j] = NULL;
5287a51f6dfSlukem return list;
5297a51f6dfSlukem }
5307a51f6dfSlukem
5317a51f6dfSlukem /*
5327a51f6dfSlukem * COMPATIBILITY FUNCTIONS
5337a51f6dfSlukem */
5347a51f6dfSlukem
5357a51f6dfSlukem static int inited = 0;
5367a51f6dfSlukem static void *context;
5377a51f6dfSlukem static int errval = HES_ER_UNINIT;
538de3b78d7Slukem
539de3b78d7Slukem int
hes_init(void)540504f8671Smatt hes_init(void)
541de3b78d7Slukem {
5427a51f6dfSlukem init_context();
5437a51f6dfSlukem return errval;
544de3b78d7Slukem }
545de3b78d7Slukem
546de3b78d7Slukem char *
hes_to_bind(const char * name,const char * type)547504f8671Smatt hes_to_bind(const char *name, const char *type)
548de3b78d7Slukem {
5497a51f6dfSlukem static char *bindname;
550b48252f3Slukem
551b48252f3Slukem _DIAGASSERT(name != NULL);
552b48252f3Slukem _DIAGASSERT(type != NULL);
553b48252f3Slukem
5547a51f6dfSlukem if (init_context() < 0)
555de3b78d7Slukem return NULL;
556*4644559eSmaya
5577a51f6dfSlukem bindname = hesiod_to_bind(context, name, type);
5587a51f6dfSlukem if (!bindname)
5597a51f6dfSlukem translate_errors();
5607a51f6dfSlukem return bindname;
561de3b78d7Slukem }
5627a51f6dfSlukem
5637a51f6dfSlukem char **
hes_resolve(const char * name,const char * type)564504f8671Smatt hes_resolve(const char *name, const char *type)
5657a51f6dfSlukem {
5667a51f6dfSlukem static char **list;
5677a51f6dfSlukem
568b48252f3Slukem _DIAGASSERT(name != NULL);
569b48252f3Slukem _DIAGASSERT(type != NULL);
570b48252f3Slukem
5717a51f6dfSlukem if (init_context() < 0)
5727a51f6dfSlukem return NULL;
5737a51f6dfSlukem
5747a51f6dfSlukem /*
5757a51f6dfSlukem * In the old Hesiod interface, the caller was responsible for
5767a51f6dfSlukem * freeing the returned strings but not the vector of strings itself.
5777a51f6dfSlukem */
5787a51f6dfSlukem if (list)
5797a51f6dfSlukem free(list);
5807a51f6dfSlukem
5817a51f6dfSlukem list = hesiod_resolve(context, name, type);
5827a51f6dfSlukem if (!list)
5837a51f6dfSlukem translate_errors();
5847a51f6dfSlukem return list;
585de3b78d7Slukem }
586de3b78d7Slukem
587de3b78d7Slukem int
hes_error(void)588504f8671Smatt hes_error(void)
589de3b78d7Slukem {
5907a51f6dfSlukem return errval;
591de3b78d7Slukem }
592de3b78d7Slukem
593de3b78d7Slukem void
hes_free(char ** hp)594504f8671Smatt hes_free(char **hp)
595de3b78d7Slukem {
5963ca17e24Slukem hesiod_free_list(context, hp);
597de3b78d7Slukem }
5987a51f6dfSlukem
5997a51f6dfSlukem static int
init_context(void)600504f8671Smatt init_context(void)
6017a51f6dfSlukem {
6027a51f6dfSlukem if (!inited) {
6037a51f6dfSlukem inited = 1;
6047a51f6dfSlukem if (hesiod_init(&context) < 0) {
6057a51f6dfSlukem errval = HES_ER_CONFIG;
6067a51f6dfSlukem return -1;
6077a51f6dfSlukem }
6087a51f6dfSlukem errval = HES_ER_OK;
6097a51f6dfSlukem }
6107a51f6dfSlukem return 0;
6117a51f6dfSlukem }
6127a51f6dfSlukem
6137a51f6dfSlukem static void
translate_errors(void)614504f8671Smatt translate_errors(void)
6157a51f6dfSlukem {
6167a51f6dfSlukem switch (errno) {
6177a51f6dfSlukem case ENOENT:
6187a51f6dfSlukem errval = HES_ER_NOTFOUND;
6197a51f6dfSlukem break;
6207a51f6dfSlukem case ECONNREFUSED:
6217a51f6dfSlukem case EMSGSIZE:
6227a51f6dfSlukem errval = HES_ER_NET;
6237a51f6dfSlukem break;
6247a51f6dfSlukem default:
6257a51f6dfSlukem /* Not a good match, but the best we can do. */
6267a51f6dfSlukem errval = HES_ER_CONFIG;
6277a51f6dfSlukem break;
6287a51f6dfSlukem }
6297a51f6dfSlukem }
630