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