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