1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint) 7*0Sstevel@tonic-gate static const char rcsid[] = "$Id: hesiod.c,v 1.23 2002/07/18 02:07:45 marka Exp $"; 8*0Sstevel@tonic-gate #endif 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate /* 11*0Sstevel@tonic-gate * Copyright (c) 1996,1999 by Internet Software Consortium. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 14*0Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 15*0Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 16*0Sstevel@tonic-gate * 17*0Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 18*0Sstevel@tonic-gate * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 19*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 20*0Sstevel@tonic-gate * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 21*0Sstevel@tonic-gate * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 22*0Sstevel@tonic-gate * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 23*0Sstevel@tonic-gate * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 24*0Sstevel@tonic-gate * SOFTWARE. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate /* 34*0Sstevel@tonic-gate * hesiod.c --- the core portion of the hesiod resolver. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * This file is derived from the hesiod library from Project Athena; 37*0Sstevel@tonic-gate * It has been extensively rewritten by Theodore Ts'o to have a more 38*0Sstevel@tonic-gate * thread-safe interface. 39*0Sstevel@tonic-gate */ 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate /* Imports */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include "port_before.h" 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <sys/types.h> 46*0Sstevel@tonic-gate #include <netinet/in.h> 47*0Sstevel@tonic-gate #include <arpa/nameser.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #include <errno.h> 50*0Sstevel@tonic-gate #include <netdb.h> 51*0Sstevel@tonic-gate #include <resolv.h> 52*0Sstevel@tonic-gate #include <stdio.h> 53*0Sstevel@tonic-gate #include <stdlib.h> 54*0Sstevel@tonic-gate #include <string.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #include "port_after.h" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #include "pathnames.h" 59*0Sstevel@tonic-gate #include "hesiod.h" 60*0Sstevel@tonic-gate #include "hesiod_p.h" 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* Forward */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate int hesiod_init(void **context); 65*0Sstevel@tonic-gate void hesiod_end(void *context); 66*0Sstevel@tonic-gate char * hesiod_to_bind(void *context, const char *name, 67*0Sstevel@tonic-gate const char *type); 68*0Sstevel@tonic-gate char ** hesiod_resolve(void *context, const char *name, 69*0Sstevel@tonic-gate const char *type); 70*0Sstevel@tonic-gate void hesiod_free_list(void *context, char **list); 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate static int parse_config_file(struct hesiod_p *ctx, const char *filename); 73*0Sstevel@tonic-gate static char ** get_txt_records(struct hesiod_p *ctx, int class, 74*0Sstevel@tonic-gate const char *name); 75*0Sstevel@tonic-gate static int init(struct hesiod_p *ctx); 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* Public */ 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* 80*0Sstevel@tonic-gate * This function is called to initialize a hesiod_p. 81*0Sstevel@tonic-gate */ 82*0Sstevel@tonic-gate int 83*0Sstevel@tonic-gate hesiod_init(void **context) { 84*0Sstevel@tonic-gate struct hesiod_p *ctx; 85*0Sstevel@tonic-gate char *cp; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate ctx = malloc(sizeof(struct hesiod_p)); 88*0Sstevel@tonic-gate if (ctx == 0) { 89*0Sstevel@tonic-gate errno = ENOMEM; 90*0Sstevel@tonic-gate return (-1); 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate #ifdef ORIGINAL_ISC_CODE 94*0Sstevel@tonic-gate ctx->LHS = NULL; 95*0Sstevel@tonic-gate ctx->RHS = NULL; 96*0Sstevel@tonic-gate ctx->res = NULL; 97*0Sstevel@tonic-gate #else 98*0Sstevel@tonic-gate memset(ctx, 0, sizeof (*ctx)); 99*0Sstevel@tonic-gate #endif /* ORIGINAL_ISC_CODE */ 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) { 102*0Sstevel@tonic-gate #ifdef DEF_RHS 103*0Sstevel@tonic-gate /* 104*0Sstevel@tonic-gate * Use compiled in defaults. 105*0Sstevel@tonic-gate */ 106*0Sstevel@tonic-gate ctx->LHS = malloc(strlen(DEF_LHS)+1); 107*0Sstevel@tonic-gate ctx->RHS = malloc(strlen(DEF_RHS)+1); 108*0Sstevel@tonic-gate if (ctx->LHS == 0 || ctx->RHS == 0) { 109*0Sstevel@tonic-gate errno = ENOMEM; 110*0Sstevel@tonic-gate goto cleanup; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY 113*0Sstevel@tonic-gate strlcpy(ctx->LHS, DEF_LHS, strlen(DEF_LHS) + 1); 114*0Sstevel@tonic-gate strlcpy(ctx->RHS, DEF_RHS, strlen(DEF_RHS) + 1); 115*0Sstevel@tonic-gate #else 116*0Sstevel@tonic-gate strcpy(ctx->LHS, DEF_LHS); 117*0Sstevel@tonic-gate strcpy(ctx->RHS, DEF_RHS); 118*0Sstevel@tonic-gate #endif 119*0Sstevel@tonic-gate #else 120*0Sstevel@tonic-gate goto cleanup; 121*0Sstevel@tonic-gate #endif 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate * The default RHS can be overridden by an environment 125*0Sstevel@tonic-gate * variable. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate if ((cp = getenv("HES_DOMAIN")) != NULL) { 128*0Sstevel@tonic-gate size_t RHSlen = strlen(cp) + 2; 129*0Sstevel@tonic-gate if (ctx->RHS) 130*0Sstevel@tonic-gate free(ctx->RHS); 131*0Sstevel@tonic-gate ctx->RHS = malloc(RHSlen); 132*0Sstevel@tonic-gate if (!ctx->RHS) { 133*0Sstevel@tonic-gate errno = ENOMEM; 134*0Sstevel@tonic-gate goto cleanup; 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate if (cp[0] == '.') { 137*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY 138*0Sstevel@tonic-gate strlcpy(ctx->RHS, cp, RHSlen); 139*0Sstevel@tonic-gate #else 140*0Sstevel@tonic-gate strcpy(ctx->RHS, cp); 141*0Sstevel@tonic-gate #endif 142*0Sstevel@tonic-gate } else { 143*0Sstevel@tonic-gate #ifdef HAVE_STRLCPY 144*0Sstevel@tonic-gate strlcpy(ctx->RHS, ".", RHSlen); 145*0Sstevel@tonic-gate #else 146*0Sstevel@tonic-gate strcpy(ctx->RHS, "."); 147*0Sstevel@tonic-gate #endif 148*0Sstevel@tonic-gate #ifdef HAVE_STRLCAT 149*0Sstevel@tonic-gate strlcat(ctx->RHS, cp, RHSlen); 150*0Sstevel@tonic-gate #else 151*0Sstevel@tonic-gate strcat(ctx->RHS, cp); 152*0Sstevel@tonic-gate #endif 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate /* 157*0Sstevel@tonic-gate * If there is no default hesiod realm set, we return an 158*0Sstevel@tonic-gate * error. 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate if (!ctx->RHS) { 161*0Sstevel@tonic-gate errno = ENOEXEC; 162*0Sstevel@tonic-gate goto cleanup; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate #if 0 166*0Sstevel@tonic-gate if (res_ninit(ctx->res) < 0) 167*0Sstevel@tonic-gate goto cleanup; 168*0Sstevel@tonic-gate #endif 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate *context = ctx; 171*0Sstevel@tonic-gate return (0); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate cleanup: 174*0Sstevel@tonic-gate hesiod_end(ctx); 175*0Sstevel@tonic-gate return (-1); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * This function deallocates the hesiod_p 180*0Sstevel@tonic-gate */ 181*0Sstevel@tonic-gate void 182*0Sstevel@tonic-gate hesiod_end(void *context) { 183*0Sstevel@tonic-gate struct hesiod_p *ctx = (struct hesiod_p *) context; 184*0Sstevel@tonic-gate int save_errno = errno; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate if (ctx->res) 187*0Sstevel@tonic-gate res_nclose(ctx->res); 188*0Sstevel@tonic-gate if (ctx->RHS) 189*0Sstevel@tonic-gate free(ctx->RHS); 190*0Sstevel@tonic-gate if (ctx->LHS) 191*0Sstevel@tonic-gate free(ctx->LHS); 192*0Sstevel@tonic-gate if (ctx->res && ctx->free_res) 193*0Sstevel@tonic-gate (*ctx->free_res)(ctx->res); 194*0Sstevel@tonic-gate free(ctx); 195*0Sstevel@tonic-gate errno = save_errno; 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * This function takes a hesiod (name, type) and returns a DNS 200*0Sstevel@tonic-gate * name which is to be resolved. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate char * 203*0Sstevel@tonic-gate hesiod_to_bind(void *context, const char *name, const char *type) { 204*0Sstevel@tonic-gate struct hesiod_p *ctx = (struct hesiod_p *) context; 205*0Sstevel@tonic-gate char *bindname; 206*0Sstevel@tonic-gate char **rhs_list = NULL; 207*0Sstevel@tonic-gate const char *RHS, *cp; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* Decide what our RHS is, and set cp to the end of the actual name. */ 210*0Sstevel@tonic-gate if ((cp = strchr(name, '@')) != NULL) { 211*0Sstevel@tonic-gate if (strchr(cp + 1, '.')) 212*0Sstevel@tonic-gate RHS = cp + 1; 213*0Sstevel@tonic-gate else if ((rhs_list = hesiod_resolve(context, cp + 1, 214*0Sstevel@tonic-gate "rhs-extension")) != NULL) 215*0Sstevel@tonic-gate RHS = *rhs_list; 216*0Sstevel@tonic-gate else { 217*0Sstevel@tonic-gate errno = ENOENT; 218*0Sstevel@tonic-gate return (NULL); 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate } else { 221*0Sstevel@tonic-gate RHS = ctx->RHS; 222*0Sstevel@tonic-gate cp = name + strlen(name); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate /* 226*0Sstevel@tonic-gate * Allocate the space we need, including up to three periods and 227*0Sstevel@tonic-gate * the terminating NUL. 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) + 230*0Sstevel@tonic-gate (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) { 231*0Sstevel@tonic-gate errno = ENOMEM; 232*0Sstevel@tonic-gate if (rhs_list) 233*0Sstevel@tonic-gate hesiod_free_list(context, rhs_list); 234*0Sstevel@tonic-gate return NULL; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* Now put together the DNS name. */ 238*0Sstevel@tonic-gate memcpy(bindname, name, cp - name); 239*0Sstevel@tonic-gate bindname[cp - name] = '\0'; 240*0Sstevel@tonic-gate strcat(bindname, "."); 241*0Sstevel@tonic-gate strcat(bindname, type); 242*0Sstevel@tonic-gate if (ctx->LHS) { 243*0Sstevel@tonic-gate if (ctx->LHS[0] != '.') 244*0Sstevel@tonic-gate strcat(bindname, "."); 245*0Sstevel@tonic-gate strcat(bindname, ctx->LHS); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate if (RHS[0] != '.') 248*0Sstevel@tonic-gate strcat(bindname, "."); 249*0Sstevel@tonic-gate strcat(bindname, RHS); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate if (rhs_list) 252*0Sstevel@tonic-gate hesiod_free_list(context, rhs_list); 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate return (bindname); 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * This is the core function. Given a hesiod (name, type), it 259*0Sstevel@tonic-gate * returns an array of strings returned by the resolver. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate char ** 262*0Sstevel@tonic-gate hesiod_resolve(void *context, const char *name, const char *type) { 263*0Sstevel@tonic-gate struct hesiod_p *ctx = (struct hesiod_p *) context; 264*0Sstevel@tonic-gate char *bindname = hesiod_to_bind(context, name, type); 265*0Sstevel@tonic-gate char **retvec; 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate if (bindname == NULL) 268*0Sstevel@tonic-gate return (NULL); 269*0Sstevel@tonic-gate if (init(ctx) == -1) { 270*0Sstevel@tonic-gate free(bindname); 271*0Sstevel@tonic-gate return (NULL); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate if ((retvec = get_txt_records(ctx, C_IN, bindname))) { 275*0Sstevel@tonic-gate free(bindname); 276*0Sstevel@tonic-gate return (retvec); 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (errno != ENOENT) 280*0Sstevel@tonic-gate return (NULL); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate retvec = get_txt_records(ctx, C_HS, bindname); 283*0Sstevel@tonic-gate free(bindname); 284*0Sstevel@tonic-gate return (retvec); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate void 288*0Sstevel@tonic-gate hesiod_free_list(void *context, char **list) { 289*0Sstevel@tonic-gate char **p; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate UNUSED(context); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate for (p = list; *p; p++) 294*0Sstevel@tonic-gate free(*p); 295*0Sstevel@tonic-gate free(list); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * This function parses the /etc/hesiod.conf file 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate static int 302*0Sstevel@tonic-gate parse_config_file(struct hesiod_p *ctx, const char *filename) { 303*0Sstevel@tonic-gate char *key, *data, *cp, **cpp; 304*0Sstevel@tonic-gate char buf[MAXDNAME+7]; 305*0Sstevel@tonic-gate FILE *fp; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * Clear the existing configuration variable, just in case 309*0Sstevel@tonic-gate * they're set. 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate if (ctx->RHS) 312*0Sstevel@tonic-gate free(ctx->RHS); 313*0Sstevel@tonic-gate if (ctx->LHS) 314*0Sstevel@tonic-gate free(ctx->LHS); 315*0Sstevel@tonic-gate ctx->RHS = ctx->LHS = 0; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate /* 318*0Sstevel@tonic-gate * Now open and parse the file... 319*0Sstevel@tonic-gate */ 320*0Sstevel@tonic-gate if (!(fp = fopen(filename, "r"))) 321*0Sstevel@tonic-gate return (-1); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate while (fgets(buf, sizeof(buf), fp) != NULL) { 324*0Sstevel@tonic-gate cp = buf; 325*0Sstevel@tonic-gate if (*cp == '#' || *cp == '\n' || *cp == '\r') 326*0Sstevel@tonic-gate continue; 327*0Sstevel@tonic-gate while(*cp == ' ' || *cp == '\t') 328*0Sstevel@tonic-gate cp++; 329*0Sstevel@tonic-gate key = cp; 330*0Sstevel@tonic-gate while(*cp != ' ' && *cp != '\t' && *cp != '=') 331*0Sstevel@tonic-gate cp++; 332*0Sstevel@tonic-gate *cp++ = '\0'; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate while(*cp == ' ' || *cp == '\t' || *cp == '=') 335*0Sstevel@tonic-gate cp++; 336*0Sstevel@tonic-gate data = cp; 337*0Sstevel@tonic-gate while(*cp != ' ' && *cp != '\n' && *cp != '\r') 338*0Sstevel@tonic-gate cp++; 339*0Sstevel@tonic-gate *cp++ = '\0'; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (strcmp(key, "lhs") == 0) 342*0Sstevel@tonic-gate cpp = &ctx->LHS; 343*0Sstevel@tonic-gate else if (strcmp(key, "rhs") == 0) 344*0Sstevel@tonic-gate cpp = &ctx->RHS; 345*0Sstevel@tonic-gate else 346*0Sstevel@tonic-gate continue; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate *cpp = malloc(strlen(data) + 1); 349*0Sstevel@tonic-gate if (!*cpp) { 350*0Sstevel@tonic-gate errno = ENOMEM; 351*0Sstevel@tonic-gate goto cleanup; 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate strcpy(*cpp, data); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate fclose(fp); 356*0Sstevel@tonic-gate return (0); 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate cleanup: 359*0Sstevel@tonic-gate fclose(fp); 360*0Sstevel@tonic-gate if (ctx->RHS) 361*0Sstevel@tonic-gate free(ctx->RHS); 362*0Sstevel@tonic-gate if (ctx->LHS) 363*0Sstevel@tonic-gate free(ctx->LHS); 364*0Sstevel@tonic-gate ctx->RHS = ctx->LHS = 0; 365*0Sstevel@tonic-gate return (-1); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * Given a DNS class and a DNS name, do a lookup for TXT records, and 370*0Sstevel@tonic-gate * return a list of them. 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate static char ** 373*0Sstevel@tonic-gate get_txt_records(struct hesiod_p *ctx, int class, const char *name) { 374*0Sstevel@tonic-gate struct { 375*0Sstevel@tonic-gate int type; /* RR type */ 376*0Sstevel@tonic-gate int class; /* RR class */ 377*0Sstevel@tonic-gate int dlen; /* len of data section */ 378*0Sstevel@tonic-gate u_char *data; /* pointer to data */ 379*0Sstevel@tonic-gate } rr; 380*0Sstevel@tonic-gate HEADER *hp; 381*0Sstevel@tonic-gate u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP]; 382*0Sstevel@tonic-gate u_char *cp, *erdata, *eom; 383*0Sstevel@tonic-gate char *dst, *edst, **list; 384*0Sstevel@tonic-gate int ancount, qdcount; 385*0Sstevel@tonic-gate int i, j, n, skip; 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate * Construct the query and send it. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0, 391*0Sstevel@tonic-gate NULL, qbuf, MAX_HESRESP); 392*0Sstevel@tonic-gate if (n < 0) { 393*0Sstevel@tonic-gate errno = EMSGSIZE; 394*0Sstevel@tonic-gate return (NULL); 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP); 397*0Sstevel@tonic-gate if (n < 0) { 398*0Sstevel@tonic-gate errno = ECONNREFUSED; 399*0Sstevel@tonic-gate return (NULL); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate if (n < HFIXEDSZ) { 402*0Sstevel@tonic-gate errno = EMSGSIZE; 403*0Sstevel@tonic-gate return (NULL); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* 407*0Sstevel@tonic-gate * OK, parse the result. 408*0Sstevel@tonic-gate */ 409*0Sstevel@tonic-gate hp = (HEADER *) abuf; 410*0Sstevel@tonic-gate ancount = ntohs(hp->ancount); 411*0Sstevel@tonic-gate qdcount = ntohs(hp->qdcount); 412*0Sstevel@tonic-gate cp = abuf + sizeof(HEADER); 413*0Sstevel@tonic-gate eom = abuf + n; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* Skip query, trying to get to the answer section which follows. */ 416*0Sstevel@tonic-gate for (i = 0; i < qdcount; i++) { 417*0Sstevel@tonic-gate skip = dn_skipname(cp, eom); 418*0Sstevel@tonic-gate if (skip < 0 || cp + skip + QFIXEDSZ > eom) { 419*0Sstevel@tonic-gate errno = EMSGSIZE; 420*0Sstevel@tonic-gate return (NULL); 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate cp += skip + QFIXEDSZ; 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate list = malloc((ancount + 1) * sizeof(char *)); 426*0Sstevel@tonic-gate if (!list) { 427*0Sstevel@tonic-gate errno = ENOMEM; 428*0Sstevel@tonic-gate return (NULL); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate j = 0; 431*0Sstevel@tonic-gate for (i = 0; i < ancount; i++) { 432*0Sstevel@tonic-gate skip = dn_skipname(cp, eom); 433*0Sstevel@tonic-gate if (skip < 0) { 434*0Sstevel@tonic-gate errno = EMSGSIZE; 435*0Sstevel@tonic-gate goto cleanup; 436*0Sstevel@tonic-gate } 437*0Sstevel@tonic-gate cp += skip; 438*0Sstevel@tonic-gate if (cp + 3 * INT16SZ + INT32SZ > eom) { 439*0Sstevel@tonic-gate errno = EMSGSIZE; 440*0Sstevel@tonic-gate goto cleanup; 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate rr.type = ns_get16(cp); 443*0Sstevel@tonic-gate cp += INT16SZ; 444*0Sstevel@tonic-gate rr.class = ns_get16(cp); 445*0Sstevel@tonic-gate cp += INT16SZ + INT32SZ; /* skip the ttl, too */ 446*0Sstevel@tonic-gate rr.dlen = ns_get16(cp); 447*0Sstevel@tonic-gate cp += INT16SZ; 448*0Sstevel@tonic-gate if (cp + rr.dlen > eom) { 449*0Sstevel@tonic-gate errno = EMSGSIZE; 450*0Sstevel@tonic-gate goto cleanup; 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate rr.data = cp; 453*0Sstevel@tonic-gate cp += rr.dlen; 454*0Sstevel@tonic-gate if (rr.class != class || rr.type != T_TXT) 455*0Sstevel@tonic-gate continue; 456*0Sstevel@tonic-gate if (!(list[j] = malloc(rr.dlen))) 457*0Sstevel@tonic-gate goto cleanup; 458*0Sstevel@tonic-gate dst = list[j++]; 459*0Sstevel@tonic-gate edst = dst + rr.dlen; 460*0Sstevel@tonic-gate erdata = rr.data + rr.dlen; 461*0Sstevel@tonic-gate cp = rr.data; 462*0Sstevel@tonic-gate while (cp < erdata) { 463*0Sstevel@tonic-gate n = (unsigned char) *cp++; 464*0Sstevel@tonic-gate if (cp + n > eom || dst + n > edst) { 465*0Sstevel@tonic-gate errno = EMSGSIZE; 466*0Sstevel@tonic-gate goto cleanup; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate memcpy(dst, cp, n); 469*0Sstevel@tonic-gate cp += n; 470*0Sstevel@tonic-gate dst += n; 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate if (cp != erdata) { 473*0Sstevel@tonic-gate errno = EMSGSIZE; 474*0Sstevel@tonic-gate goto cleanup; 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate *dst = '\0'; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate list[j] = NULL; 479*0Sstevel@tonic-gate if (j == 0) { 480*0Sstevel@tonic-gate errno = ENOENT; 481*0Sstevel@tonic-gate goto cleanup; 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate return (list); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate cleanup: 486*0Sstevel@tonic-gate for (i = 0; i < j; i++) 487*0Sstevel@tonic-gate free(list[i]); 488*0Sstevel@tonic-gate free(list); 489*0Sstevel@tonic-gate return (NULL); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate struct __res_state * 493*0Sstevel@tonic-gate __hesiod_res_get(void *context) { 494*0Sstevel@tonic-gate struct hesiod_p *ctx = context; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate if (!ctx->res) { 497*0Sstevel@tonic-gate struct __res_state *res; 498*0Sstevel@tonic-gate res = (struct __res_state *)malloc(sizeof *res); 499*0Sstevel@tonic-gate if (res == NULL) { 500*0Sstevel@tonic-gate errno = ENOMEM; 501*0Sstevel@tonic-gate return (NULL); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate memset(res, 0, sizeof *res); 504*0Sstevel@tonic-gate __hesiod_res_set(ctx, res, free); 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate return (ctx->res); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate void 511*0Sstevel@tonic-gate __hesiod_res_set(void *context, struct __res_state *res, 512*0Sstevel@tonic-gate void (*free_res)(void *)) { 513*0Sstevel@tonic-gate struct hesiod_p *ctx = context; 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate if (ctx->res && ctx->free_res) { 516*0Sstevel@tonic-gate res_nclose(ctx->res); 517*0Sstevel@tonic-gate (*ctx->free_res)(ctx->res); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate ctx->res = res; 521*0Sstevel@tonic-gate ctx->free_res = free_res; 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate static int 525*0Sstevel@tonic-gate init(struct hesiod_p *ctx) { 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate if (!ctx->res && !__hesiod_res_get(ctx)) 528*0Sstevel@tonic-gate return (-1); 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate if (((ctx->res->options & RES_INIT) == 0) && 531*0Sstevel@tonic-gate (res_ninit(ctx->res) == -1)) 532*0Sstevel@tonic-gate return (-1); 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate return (0); 535*0Sstevel@tonic-gate } 536