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 #include <sys/cdefs.h> 47248aee62SJacques Vidrine 48333fc21eSDavid E. O'Brien #if 0 49248aee62SJacques Vidrine static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $"; 50333fc21eSDavid E. O'Brien #endif 51333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 52333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 53248aee62SJacques Vidrine 54248aee62SJacques Vidrine #include <sys/types.h> 55248aee62SJacques Vidrine #include <sys/param.h> 56248aee62SJacques Vidrine #include <netinet/in.h> 57248aee62SJacques Vidrine #include <arpa/nameser.h> 58248aee62SJacques Vidrine 59248aee62SJacques Vidrine #include <ctype.h> 60248aee62SJacques Vidrine #include <errno.h> 61248aee62SJacques Vidrine #include <hesiod.h> 62248aee62SJacques Vidrine #include <resolv.h> 63248aee62SJacques Vidrine #include <stdio.h> 64248aee62SJacques Vidrine #include <stdlib.h> 65248aee62SJacques Vidrine #include <string.h> 66b27eae53SJacques Vidrine #include <unistd.h> 67248aee62SJacques Vidrine 68248aee62SJacques Vidrine struct hesiod_p { 69248aee62SJacques Vidrine char *lhs; /* normally ".ns" */ 70248aee62SJacques Vidrine char *rhs; /* AKA the default hesiod domain */ 71248aee62SJacques Vidrine int classes[2]; /* The class search order. */ 72248aee62SJacques Vidrine }; 73248aee62SJacques Vidrine 74248aee62SJacques Vidrine #define MAX_HESRESP 1024 75248aee62SJacques Vidrine 76c05ac53bSDavid E. O'Brien static int read_config_file(struct hesiod_p *, const char *); 77c05ac53bSDavid E. O'Brien static char **get_txt_records(int, const char *); 78c05ac53bSDavid E. O'Brien static int init_context(void); 79c05ac53bSDavid E. O'Brien static void translate_errors(void); 80248aee62SJacques Vidrine 81248aee62SJacques Vidrine 82248aee62SJacques Vidrine /* 83248aee62SJacques Vidrine * hesiod_init -- 84248aee62SJacques Vidrine * initialize a hesiod_p. 85248aee62SJacques Vidrine */ 86248aee62SJacques Vidrine int 87248aee62SJacques Vidrine hesiod_init(context) 88248aee62SJacques Vidrine void **context; 89248aee62SJacques Vidrine { 90248aee62SJacques Vidrine struct hesiod_p *ctx; 91248aee62SJacques Vidrine const char *p, *configname; 92248aee62SJacques Vidrine 93248aee62SJacques Vidrine ctx = malloc(sizeof(struct hesiod_p)); 94248aee62SJacques Vidrine if (ctx) { 95248aee62SJacques Vidrine *context = ctx; 96534f2a9dSJacques Vidrine if (!issetugid()) 97248aee62SJacques Vidrine configname = getenv("HESIOD_CONFIG"); 98b27eae53SJacques Vidrine else 99b27eae53SJacques Vidrine configname = NULL; 100248aee62SJacques Vidrine if (!configname) 101248aee62SJacques Vidrine configname = _PATH_HESIOD_CONF; 102248aee62SJacques Vidrine if (read_config_file(ctx, configname) >= 0) { 103248aee62SJacques Vidrine /* 104248aee62SJacques Vidrine * The default rhs can be overridden by an 105248aee62SJacques Vidrine * environment variable. 106248aee62SJacques Vidrine */ 107534f2a9dSJacques Vidrine if (!issetugid()) 108248aee62SJacques Vidrine p = getenv("HES_DOMAIN"); 109b27eae53SJacques Vidrine else 110b27eae53SJacques Vidrine p = NULL; 111248aee62SJacques Vidrine if (p) { 112248aee62SJacques Vidrine if (ctx->rhs) 113248aee62SJacques Vidrine free(ctx->rhs); 114248aee62SJacques Vidrine ctx->rhs = malloc(strlen(p) + 2); 115248aee62SJacques Vidrine if (ctx->rhs) { 116248aee62SJacques Vidrine *ctx->rhs = '.'; 117248aee62SJacques Vidrine strcpy(ctx->rhs + 1, 118248aee62SJacques Vidrine (*p == '.') ? p + 1 : p); 119248aee62SJacques Vidrine return 0; 120248aee62SJacques Vidrine } else 121248aee62SJacques Vidrine errno = ENOMEM; 122248aee62SJacques Vidrine } else 123248aee62SJacques Vidrine return 0; 124248aee62SJacques Vidrine } 125248aee62SJacques Vidrine } else 126248aee62SJacques Vidrine errno = ENOMEM; 127248aee62SJacques Vidrine 128248aee62SJacques Vidrine if (ctx->lhs) 129248aee62SJacques Vidrine free(ctx->lhs); 130248aee62SJacques Vidrine if (ctx->rhs) 131248aee62SJacques Vidrine free(ctx->rhs); 132248aee62SJacques Vidrine if (ctx) 133248aee62SJacques Vidrine free(ctx); 134248aee62SJacques Vidrine return -1; 135248aee62SJacques Vidrine } 136248aee62SJacques Vidrine 137248aee62SJacques Vidrine /* 138248aee62SJacques Vidrine * hesiod_end -- 139248aee62SJacques Vidrine * Deallocates the hesiod_p. 140248aee62SJacques Vidrine */ 141248aee62SJacques Vidrine void 142248aee62SJacques Vidrine hesiod_end(context) 143248aee62SJacques Vidrine void *context; 144248aee62SJacques Vidrine { 145248aee62SJacques Vidrine struct hesiod_p *ctx = (struct hesiod_p *) context; 146248aee62SJacques Vidrine 147248aee62SJacques Vidrine free(ctx->rhs); 148248aee62SJacques Vidrine if (ctx->lhs) 149248aee62SJacques Vidrine free(ctx->lhs); 150248aee62SJacques Vidrine free(ctx); 151248aee62SJacques Vidrine } 152248aee62SJacques Vidrine 153248aee62SJacques Vidrine /* 154248aee62SJacques Vidrine * hesiod_to_bind -- 155248aee62SJacques Vidrine * takes a hesiod (name, type) and returns a DNS 156248aee62SJacques Vidrine * name which is to be resolved. 157248aee62SJacques Vidrine */ 158248aee62SJacques Vidrine char * 159248aee62SJacques Vidrine hesiod_to_bind(void *context, const char *name, const char *type) 160248aee62SJacques Vidrine { 161248aee62SJacques Vidrine struct hesiod_p *ctx = (struct hesiod_p *) context; 162248aee62SJacques Vidrine char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL; 163248aee62SJacques Vidrine const char *rhs; 164248aee62SJacques Vidrine int len; 165248aee62SJacques Vidrine 166d0509082SJacques Vidrine if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) { 167e31b3502SJacques Vidrine errno = EMSGSIZE; 168e31b3502SJacques Vidrine return NULL; 169e31b3502SJacques Vidrine } 170248aee62SJacques Vidrine 171248aee62SJacques Vidrine /* 172248aee62SJacques Vidrine * Find the right right hand side to use, possibly 173248aee62SJacques Vidrine * truncating bindname. 174248aee62SJacques Vidrine */ 175248aee62SJacques Vidrine p = strchr(bindname, '@'); 176248aee62SJacques Vidrine if (p) { 177248aee62SJacques Vidrine *p++ = 0; 178248aee62SJacques Vidrine if (strchr(p, '.')) 179248aee62SJacques Vidrine rhs = name + (p - bindname); 180248aee62SJacques Vidrine else { 181248aee62SJacques Vidrine rhs_list = hesiod_resolve(context, p, "rhs-extension"); 182248aee62SJacques Vidrine if (rhs_list) 183248aee62SJacques Vidrine rhs = *rhs_list; 184248aee62SJacques Vidrine else { 185248aee62SJacques Vidrine errno = ENOENT; 186248aee62SJacques Vidrine return NULL; 187248aee62SJacques Vidrine } 188248aee62SJacques Vidrine } 189248aee62SJacques Vidrine } else 190248aee62SJacques Vidrine rhs = ctx->rhs; 191248aee62SJacques Vidrine 192248aee62SJacques Vidrine /* See if we have enough room. */ 193248aee62SJacques Vidrine len = strlen(bindname) + 1 + strlen(type); 194248aee62SJacques Vidrine if (ctx->lhs) 195248aee62SJacques Vidrine len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0); 196248aee62SJacques Vidrine len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0); 197248aee62SJacques Vidrine if (len > sizeof(bindname) - 1) { 198248aee62SJacques Vidrine if (rhs_list) 199248aee62SJacques Vidrine hesiod_free_list(context, rhs_list); 200248aee62SJacques Vidrine errno = EMSGSIZE; 201248aee62SJacques Vidrine return NULL; 202248aee62SJacques Vidrine } 203248aee62SJacques Vidrine /* Put together the rest of the domain. */ 204248aee62SJacques Vidrine strcat(bindname, "."); 205248aee62SJacques Vidrine strcat(bindname, type); 206248aee62SJacques Vidrine /* Only append lhs if it isn't empty. */ 207248aee62SJacques Vidrine if (ctx->lhs && ctx->lhs[0] != '\0' ) { 208248aee62SJacques Vidrine if (ctx->lhs[0] != '.') 209248aee62SJacques Vidrine strcat(bindname, "."); 210248aee62SJacques Vidrine strcat(bindname, ctx->lhs); 211248aee62SJacques Vidrine } 212248aee62SJacques Vidrine if (rhs[0] != '.') 213248aee62SJacques Vidrine strcat(bindname, "."); 214248aee62SJacques Vidrine strcat(bindname, rhs); 215248aee62SJacques Vidrine 216248aee62SJacques Vidrine /* rhs_list is no longer needed, since we're done with rhs. */ 217248aee62SJacques Vidrine if (rhs_list) 218248aee62SJacques Vidrine hesiod_free_list(context, rhs_list); 219248aee62SJacques Vidrine 220248aee62SJacques Vidrine /* Make a copy of the result and return it to the caller. */ 221248aee62SJacques Vidrine ret = strdup(bindname); 222248aee62SJacques Vidrine if (!ret) 223248aee62SJacques Vidrine errno = ENOMEM; 224248aee62SJacques Vidrine return ret; 225248aee62SJacques Vidrine } 226248aee62SJacques Vidrine 227248aee62SJacques Vidrine /* 228248aee62SJacques Vidrine * hesiod_resolve -- 229248aee62SJacques Vidrine * Given a hesiod name and type, return an array of strings returned 230248aee62SJacques Vidrine * by the resolver. 231248aee62SJacques Vidrine */ 232248aee62SJacques Vidrine char ** 233248aee62SJacques Vidrine hesiod_resolve(context, name, type) 234248aee62SJacques Vidrine void *context; 235248aee62SJacques Vidrine const char *name; 236248aee62SJacques Vidrine const char *type; 237248aee62SJacques Vidrine { 238248aee62SJacques Vidrine struct hesiod_p *ctx = (struct hesiod_p *) context; 239248aee62SJacques Vidrine char *bindname, **retvec; 240248aee62SJacques Vidrine 241248aee62SJacques Vidrine bindname = hesiod_to_bind(context, name, type); 242248aee62SJacques Vidrine if (!bindname) 243248aee62SJacques Vidrine return NULL; 244248aee62SJacques Vidrine 245248aee62SJacques Vidrine retvec = get_txt_records(ctx->classes[0], bindname); 246248aee62SJacques Vidrine if (retvec == NULL && errno == ENOENT && ctx->classes[1]) 247248aee62SJacques Vidrine retvec = get_txt_records(ctx->classes[1], bindname); 248248aee62SJacques Vidrine 249248aee62SJacques Vidrine free(bindname); 250248aee62SJacques Vidrine return retvec; 251248aee62SJacques Vidrine } 252248aee62SJacques Vidrine 253248aee62SJacques Vidrine /*ARGSUSED*/ 254248aee62SJacques Vidrine void 255248aee62SJacques Vidrine hesiod_free_list(context, list) 256248aee62SJacques Vidrine void *context; 257248aee62SJacques Vidrine char **list; 258248aee62SJacques Vidrine { 259248aee62SJacques Vidrine char **p; 260248aee62SJacques Vidrine 261248aee62SJacques Vidrine if (list == NULL) 262248aee62SJacques Vidrine return; 263248aee62SJacques Vidrine for (p = list; *p; p++) 264248aee62SJacques Vidrine free(*p); 265248aee62SJacques Vidrine free(list); 266248aee62SJacques Vidrine } 267248aee62SJacques Vidrine 268248aee62SJacques Vidrine 269248aee62SJacques Vidrine /* read_config_file -- 270248aee62SJacques Vidrine * Parse the /etc/hesiod.conf file. Returns 0 on success, 271248aee62SJacques Vidrine * -1 on failure. On failure, it might leave values in ctx->lhs 272248aee62SJacques Vidrine * or ctx->rhs which need to be freed by the caller. 273248aee62SJacques Vidrine */ 274248aee62SJacques Vidrine static int 275248aee62SJacques Vidrine read_config_file(ctx, filename) 276248aee62SJacques Vidrine struct hesiod_p *ctx; 277248aee62SJacques Vidrine const char *filename; 278248aee62SJacques Vidrine { 279248aee62SJacques Vidrine char *key, *data, *p, **which; 280248aee62SJacques Vidrine char buf[MAXDNAME + 7]; 281248aee62SJacques Vidrine int n; 282248aee62SJacques Vidrine FILE *fp; 283248aee62SJacques Vidrine 284248aee62SJacques Vidrine /* Set default query classes. */ 285248aee62SJacques Vidrine ctx->classes[0] = C_IN; 286248aee62SJacques Vidrine ctx->classes[1] = C_HS; 287248aee62SJacques Vidrine 288248aee62SJacques Vidrine /* Try to open the configuration file. */ 289248aee62SJacques Vidrine fp = fopen(filename, "r"); 290248aee62SJacques Vidrine if (!fp) { 291248aee62SJacques Vidrine /* Use compiled in default domain names. */ 292248aee62SJacques Vidrine ctx->lhs = strdup(DEF_LHS); 293248aee62SJacques Vidrine ctx->rhs = strdup(DEF_RHS); 294248aee62SJacques Vidrine if (ctx->lhs && ctx->rhs) 295248aee62SJacques Vidrine return 0; 296248aee62SJacques Vidrine else { 297248aee62SJacques Vidrine errno = ENOMEM; 298248aee62SJacques Vidrine return -1; 299248aee62SJacques Vidrine } 300248aee62SJacques Vidrine } 301248aee62SJacques Vidrine ctx->lhs = NULL; 302248aee62SJacques Vidrine ctx->rhs = NULL; 303248aee62SJacques Vidrine while (fgets(buf, sizeof(buf), fp) != NULL) { 304248aee62SJacques Vidrine p = buf; 305248aee62SJacques Vidrine if (*p == '#' || *p == '\n' || *p == '\r') 306248aee62SJacques Vidrine continue; 307248aee62SJacques Vidrine while (*p == ' ' || *p == '\t') 308248aee62SJacques Vidrine p++; 309248aee62SJacques Vidrine key = p; 310248aee62SJacques Vidrine while (*p != ' ' && *p != '\t' && *p != '=') 311248aee62SJacques Vidrine p++; 312248aee62SJacques Vidrine *p++ = 0; 313248aee62SJacques Vidrine 314248aee62SJacques Vidrine while (isspace(*p) || *p == '=') 315248aee62SJacques Vidrine p++; 316248aee62SJacques Vidrine data = p; 317248aee62SJacques Vidrine while (!isspace(*p)) 318248aee62SJacques Vidrine p++; 319248aee62SJacques Vidrine *p = 0; 320248aee62SJacques Vidrine 321248aee62SJacques Vidrine if (strcasecmp(key, "lhs") == 0 || 322248aee62SJacques Vidrine strcasecmp(key, "rhs") == 0) { 323248aee62SJacques Vidrine which = (strcasecmp(key, "lhs") == 0) 324248aee62SJacques Vidrine ? &ctx->lhs : &ctx->rhs; 325248aee62SJacques Vidrine *which = strdup(data); 326248aee62SJacques Vidrine if (!*which) { 327248aee62SJacques Vidrine errno = ENOMEM; 328248aee62SJacques Vidrine return -1; 329248aee62SJacques Vidrine } 330248aee62SJacques Vidrine } else { 331248aee62SJacques Vidrine if (strcasecmp(key, "classes") == 0) { 332248aee62SJacques Vidrine n = 0; 333248aee62SJacques Vidrine while (*data && n < 2) { 334248aee62SJacques Vidrine p = data; 335248aee62SJacques Vidrine while (*p && *p != ',') 336248aee62SJacques Vidrine p++; 337248aee62SJacques Vidrine if (*p) 338248aee62SJacques Vidrine *p++ = 0; 339248aee62SJacques Vidrine if (strcasecmp(data, "IN") == 0) 340248aee62SJacques Vidrine ctx->classes[n++] = C_IN; 341248aee62SJacques Vidrine else 342248aee62SJacques Vidrine if (strcasecmp(data, "HS") == 0) 343248aee62SJacques Vidrine ctx->classes[n++] = 344248aee62SJacques Vidrine C_HS; 345248aee62SJacques Vidrine data = p; 346248aee62SJacques Vidrine } 347248aee62SJacques Vidrine while (n < 2) 348248aee62SJacques Vidrine ctx->classes[n++] = 0; 349248aee62SJacques Vidrine } 350248aee62SJacques Vidrine } 351248aee62SJacques Vidrine } 352248aee62SJacques Vidrine fclose(fp); 353248aee62SJacques Vidrine 354248aee62SJacques Vidrine if (!ctx->rhs || ctx->classes[0] == 0 || 355248aee62SJacques Vidrine ctx->classes[0] == ctx->classes[1]) { 356248aee62SJacques Vidrine errno = ENOEXEC; 357248aee62SJacques Vidrine return -1; 358248aee62SJacques Vidrine } 359248aee62SJacques Vidrine return 0; 360248aee62SJacques Vidrine } 361248aee62SJacques Vidrine 362248aee62SJacques Vidrine /* 363248aee62SJacques Vidrine * get_txt_records -- 364248aee62SJacques Vidrine * Given a DNS class and a DNS name, do a lookup for TXT records, and 365248aee62SJacques Vidrine * return a list of them. 366248aee62SJacques Vidrine */ 367248aee62SJacques Vidrine static char ** 368248aee62SJacques Vidrine get_txt_records(qclass, name) 369248aee62SJacques Vidrine int qclass; 370248aee62SJacques Vidrine const char *name; 371248aee62SJacques Vidrine { 372248aee62SJacques Vidrine HEADER *hp; 373248aee62SJacques Vidrine unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor; 374248aee62SJacques Vidrine char *dst, **list; 375248aee62SJacques Vidrine int ancount, qdcount, i, j, n, skip, type, class, len; 376248aee62SJacques Vidrine 377248aee62SJacques Vidrine /* Make sure the resolver is initialized. */ 378248aee62SJacques Vidrine if ((_res.options & RES_INIT) == 0 && res_init() == -1) 379248aee62SJacques Vidrine return NULL; 380248aee62SJacques Vidrine 381248aee62SJacques Vidrine /* Construct the query. */ 382248aee62SJacques Vidrine n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0, 383248aee62SJacques Vidrine NULL, qbuf, PACKETSZ); 384248aee62SJacques Vidrine if (n < 0) 385248aee62SJacques Vidrine return NULL; 386248aee62SJacques Vidrine 387248aee62SJacques Vidrine /* Send the query. */ 388248aee62SJacques Vidrine n = res_send(qbuf, n, abuf, MAX_HESRESP); 38954384cf3SJacques Vidrine if (n < 0 || n > MAX_HESRESP) { 39054384cf3SJacques Vidrine errno = ECONNREFUSED; /* XXX */ 391248aee62SJacques Vidrine return NULL; 392248aee62SJacques Vidrine } 393248aee62SJacques Vidrine /* Parse the header of the result. */ 394248aee62SJacques Vidrine hp = (HEADER *) (void *) abuf; 395248aee62SJacques Vidrine ancount = ntohs(hp->ancount); 396248aee62SJacques Vidrine qdcount = ntohs(hp->qdcount); 397248aee62SJacques Vidrine p = abuf + sizeof(HEADER); 398248aee62SJacques Vidrine eom = abuf + n; 399248aee62SJacques Vidrine 400248aee62SJacques Vidrine /* 401248aee62SJacques Vidrine * Skip questions, trying to get to the answer section 402248aee62SJacques Vidrine * which follows. 403248aee62SJacques Vidrine */ 404248aee62SJacques Vidrine for (i = 0; i < qdcount; i++) { 405248aee62SJacques Vidrine skip = dn_skipname(p, eom); 406248aee62SJacques Vidrine if (skip < 0 || p + skip + QFIXEDSZ > eom) { 407248aee62SJacques Vidrine errno = EMSGSIZE; 408248aee62SJacques Vidrine return NULL; 409248aee62SJacques Vidrine } 410248aee62SJacques Vidrine p += skip + QFIXEDSZ; 411248aee62SJacques Vidrine } 412248aee62SJacques Vidrine 413248aee62SJacques Vidrine /* Allocate space for the text record answers. */ 414248aee62SJacques Vidrine list = malloc((ancount + 1) * sizeof(char *)); 415248aee62SJacques Vidrine if (!list) { 416248aee62SJacques Vidrine errno = ENOMEM; 417248aee62SJacques Vidrine return NULL; 418248aee62SJacques Vidrine } 419248aee62SJacques Vidrine /* Parse the answers. */ 420248aee62SJacques Vidrine j = 0; 421248aee62SJacques Vidrine for (i = 0; i < ancount; i++) { 422248aee62SJacques Vidrine /* Parse the header of this answer. */ 423248aee62SJacques Vidrine skip = dn_skipname(p, eom); 424248aee62SJacques Vidrine if (skip < 0 || p + skip + 10 > eom) 425248aee62SJacques Vidrine break; 426248aee62SJacques Vidrine type = p[skip + 0] << 8 | p[skip + 1]; 427248aee62SJacques Vidrine class = p[skip + 2] << 8 | p[skip + 3]; 428248aee62SJacques Vidrine len = p[skip + 8] << 8 | p[skip + 9]; 429248aee62SJacques Vidrine p += skip + 10; 430248aee62SJacques Vidrine if (p + len > eom) { 431248aee62SJacques Vidrine errno = EMSGSIZE; 432248aee62SJacques Vidrine break; 433248aee62SJacques Vidrine } 434248aee62SJacques Vidrine /* Skip entries of the wrong class and type. */ 435248aee62SJacques Vidrine if (class != qclass || type != T_TXT) { 436248aee62SJacques Vidrine p += len; 437248aee62SJacques Vidrine continue; 438248aee62SJacques Vidrine } 439248aee62SJacques Vidrine /* Allocate space for this answer. */ 440248aee62SJacques Vidrine list[j] = malloc((size_t)len); 441248aee62SJacques Vidrine if (!list[j]) { 442248aee62SJacques Vidrine errno = ENOMEM; 443248aee62SJacques Vidrine break; 444248aee62SJacques Vidrine } 445248aee62SJacques Vidrine dst = list[j++]; 446248aee62SJacques Vidrine 447248aee62SJacques Vidrine /* Copy answer data into the allocated area. */ 448248aee62SJacques Vidrine eor = p + len; 449248aee62SJacques Vidrine while (p < eor) { 450248aee62SJacques Vidrine n = (unsigned char) *p++; 451248aee62SJacques Vidrine if (p + n > eor) { 452248aee62SJacques Vidrine errno = EMSGSIZE; 453248aee62SJacques Vidrine break; 454248aee62SJacques Vidrine } 455248aee62SJacques Vidrine memcpy(dst, p, (size_t)n); 456248aee62SJacques Vidrine p += n; 457248aee62SJacques Vidrine dst += n; 458248aee62SJacques Vidrine } 459248aee62SJacques Vidrine if (p < eor) { 460248aee62SJacques Vidrine errno = EMSGSIZE; 461248aee62SJacques Vidrine break; 462248aee62SJacques Vidrine } 463248aee62SJacques Vidrine *dst = 0; 464248aee62SJacques Vidrine } 465248aee62SJacques Vidrine 466248aee62SJacques Vidrine /* 467248aee62SJacques Vidrine * If we didn't terminate the loop normally, something 468248aee62SJacques Vidrine * went wrong. 469248aee62SJacques Vidrine */ 470248aee62SJacques Vidrine if (i < ancount) { 471248aee62SJacques Vidrine for (i = 0; i < j; i++) 472248aee62SJacques Vidrine free(list[i]); 473248aee62SJacques Vidrine free(list); 474248aee62SJacques Vidrine return NULL; 475248aee62SJacques Vidrine } 476248aee62SJacques Vidrine if (j == 0) { 477248aee62SJacques Vidrine errno = ENOENT; 478248aee62SJacques Vidrine free(list); 479248aee62SJacques Vidrine return NULL; 480248aee62SJacques Vidrine } 481248aee62SJacques Vidrine list[j] = NULL; 482248aee62SJacques Vidrine return list; 483248aee62SJacques Vidrine } 484248aee62SJacques Vidrine 485248aee62SJacques Vidrine /* 486248aee62SJacques Vidrine * COMPATIBILITY FUNCTIONS 487248aee62SJacques Vidrine */ 488248aee62SJacques Vidrine 489248aee62SJacques Vidrine static int inited = 0; 490248aee62SJacques Vidrine static void *context; 491248aee62SJacques Vidrine static int errval = HES_ER_UNINIT; 492248aee62SJacques Vidrine 493248aee62SJacques Vidrine int 494248aee62SJacques Vidrine hes_init() 495248aee62SJacques Vidrine { 496248aee62SJacques Vidrine init_context(); 497248aee62SJacques Vidrine return errval; 498248aee62SJacques Vidrine } 499248aee62SJacques Vidrine 500248aee62SJacques Vidrine char * 501248aee62SJacques Vidrine hes_to_bind(name, type) 502248aee62SJacques Vidrine const char *name; 503248aee62SJacques Vidrine const char *type; 504248aee62SJacques Vidrine { 505248aee62SJacques Vidrine static char *bindname; 506248aee62SJacques Vidrine if (init_context() < 0) 507248aee62SJacques Vidrine return NULL; 508248aee62SJacques Vidrine if (bindname) 509248aee62SJacques Vidrine free(bindname); 510248aee62SJacques Vidrine bindname = hesiod_to_bind(context, name, type); 511248aee62SJacques Vidrine if (!bindname) 512248aee62SJacques Vidrine translate_errors(); 513248aee62SJacques Vidrine return bindname; 514248aee62SJacques Vidrine } 515248aee62SJacques Vidrine 516248aee62SJacques Vidrine char ** 517248aee62SJacques Vidrine hes_resolve(name, type) 518248aee62SJacques Vidrine const char *name; 519248aee62SJacques Vidrine const char *type; 520248aee62SJacques Vidrine { 521248aee62SJacques Vidrine static char **list; 522248aee62SJacques Vidrine 523248aee62SJacques Vidrine if (init_context() < 0) 524248aee62SJacques Vidrine return NULL; 525248aee62SJacques Vidrine 526248aee62SJacques Vidrine /* 527248aee62SJacques Vidrine * In the old Hesiod interface, the caller was responsible for 528248aee62SJacques Vidrine * freeing the returned strings but not the vector of strings itself. 529248aee62SJacques Vidrine */ 530248aee62SJacques Vidrine if (list) 531248aee62SJacques Vidrine free(list); 532248aee62SJacques Vidrine 533248aee62SJacques Vidrine list = hesiod_resolve(context, name, type); 534248aee62SJacques Vidrine if (!list) 535248aee62SJacques Vidrine translate_errors(); 536248aee62SJacques Vidrine return list; 537248aee62SJacques Vidrine } 538248aee62SJacques Vidrine 539248aee62SJacques Vidrine int 540248aee62SJacques Vidrine hes_error() 541248aee62SJacques Vidrine { 542248aee62SJacques Vidrine return errval; 543248aee62SJacques Vidrine } 544248aee62SJacques Vidrine 545248aee62SJacques Vidrine void 546248aee62SJacques Vidrine hes_free(hp) 547248aee62SJacques Vidrine char **hp; 548248aee62SJacques Vidrine { 549248aee62SJacques Vidrine hesiod_free_list(context, hp); 550248aee62SJacques Vidrine } 551248aee62SJacques Vidrine 552248aee62SJacques Vidrine static int 553248aee62SJacques Vidrine init_context() 554248aee62SJacques Vidrine { 555248aee62SJacques Vidrine if (!inited) { 556248aee62SJacques Vidrine inited = 1; 557248aee62SJacques Vidrine if (hesiod_init(&context) < 0) { 558248aee62SJacques Vidrine errval = HES_ER_CONFIG; 559248aee62SJacques Vidrine return -1; 560248aee62SJacques Vidrine } 561248aee62SJacques Vidrine errval = HES_ER_OK; 562248aee62SJacques Vidrine } 563248aee62SJacques Vidrine return 0; 564248aee62SJacques Vidrine } 565248aee62SJacques Vidrine 566248aee62SJacques Vidrine static void 567248aee62SJacques Vidrine translate_errors() 568248aee62SJacques Vidrine { 569248aee62SJacques Vidrine switch (errno) { 570248aee62SJacques Vidrine case ENOENT: 571248aee62SJacques Vidrine errval = HES_ER_NOTFOUND; 572248aee62SJacques Vidrine break; 573248aee62SJacques Vidrine case ECONNREFUSED: 574248aee62SJacques Vidrine case EMSGSIZE: 575248aee62SJacques Vidrine errval = HES_ER_NET; 576248aee62SJacques Vidrine break; 577248aee62SJacques Vidrine case ENOMEM: 578248aee62SJacques Vidrine default: 579248aee62SJacques Vidrine /* Not a good match, but the best we can do. */ 580248aee62SJacques Vidrine errval = HES_ER_CONFIG; 581248aee62SJacques Vidrine break; 582248aee62SJacques Vidrine } 583248aee62SJacques Vidrine } 584