1 /* $NetBSD: hesiod.c,v 1.2 1999/01/15 12:53:23 lukem Exp $ */ 2 3 /* This file is part of the Hesiod library. 4 * 5 * Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology 6 * 7 * Export of software employing encryption from the United States of 8 * America is assumed to require a specific license from the United 9 * States Government. It is the responsibility of any person or 10 * organization contemplating export to obtain such a license before 11 * exporting. 12 * 13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 14 * distribute this software and its documentation for any purpose and 15 * without fee is hereby granted, provided that the above copyright 16 * notice appear in all copies and that both that copyright notice and 17 * this permission notice appear in supporting documentation, and that 18 * the name of M.I.T. not be used in advertising or publicity pertaining 19 * to distribution of the software without specific, written prior 20 * permission. M.I.T. makes no representations about the suitability of 21 * this software for any purpose. It is provided "as is" without express 22 * or implied warranty. 23 */ 24 25 #include <sys/cdefs.h> 26 27 #ifndef lint 28 __IDSTRING(rcsid_hesiod_c, "#Header: /afs/rel-eng.athena.mit.edu/project/release/current/source/athena/athena.lib/hesiod/RCS/hesiod.c,v 1.11 93/06/15 10:26:37 mar Exp #"); 29 __IDSTRING(rcsid_resolve_c, "#Header: /afs/rel-eng.athena.mit.edu/project/release/current/source/athena/athena.lib/hesiod/RCS/resolve.c,v 1.7 93/06/15 10:25:45 mar Exp #"); 30 #endif 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <netinet/in.h> 35 #include <arpa/nameser.h> 36 37 #include <errno.h> 38 #include <hesiod.h> 39 #include <resolv.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <stringlist.h> 44 #include <unistd.h> 45 46 typedef struct rr { 47 u_int16_t type; /* RR type */ 48 u_int16_t class; /* RR class */ 49 int dlen; /* len of data section */ 50 u_char *data; /* pointer to data */ 51 } rr_t, *rr_p; 52 53 typedef struct nsmsg { 54 int len; /* sizeof(msg) */ 55 int ns_off; /* offset to name server RRs */ 56 int ar_off; /* offset to additional RRs */ 57 int count; /* total number of RRs */ 58 HEADER *hd; /* message header */ 59 rr_t rr; /* vector of (stripped-down) RR descriptors */ 60 } nsmsg_t, *nsmsg_p; 61 62 static int Hes_Errno = HES_ER_UNINIT; 63 char *HesConfigFile = _PATH_HESIOD_CONF; 64 static char Hes_LHS[MAXDNAME + 1]; 65 static char Hes_RHS[MAXDNAME + 1]; 66 static u_char *Hes_eoM; 67 68 #define DEF_RETRANS 4 69 #define DEF_RETRY 3 70 71 static caddr_t _hes_rr_scan __P((u_char *, rr_t *)); 72 static nsmsg_p _hes_res_scan __P((u_char *)); 73 static nsmsg_p _hes_res __P((u_char *, int, int)); 74 int hes_init __P((void)); 75 76 static caddr_t 77 _hes_rr_scan(cp, rr) 78 u_char *cp; 79 rr_t *rr; 80 { 81 int n; 82 83 if ((n = dn_skipname(cp, Hes_eoM)) < 0) { 84 errno = EINVAL; 85 return((u_char *)NULL); 86 } 87 88 cp += n; 89 rr->type = _getshort(cp); 90 cp += sizeof(u_int16_t /*type*/); 91 92 rr->class = _getshort(cp); 93 cp += sizeof(u_int16_t /*class*/) + sizeof(u_int32_t /*ttl*/); 94 95 rr->dlen = (int)_getshort(cp); 96 rr->data = cp + sizeof(u_int16_t /*dlen*/); 97 98 return(rr->data + rr->dlen); 99 } 100 101 102 static nsmsg_p 103 _hes_res_scan(msg) 104 u_char *msg; 105 { 106 static u_char bigmess[sizeof(nsmsg_t) + sizeof(rr_t) * 107 ((PACKETSZ-sizeof(HEADER))/RRFIXEDSZ)]; 108 static u_char datmess[PACKETSZ-sizeof(HEADER)]; 109 u_char *cp; 110 rr_t *rp; 111 HEADER *hp; 112 u_char *data = datmess; 113 int n, n_an, n_ns, n_ar, nrec; 114 nsmsg_t *mess = (nsmsg_t *)bigmess; 115 116 hp = (HEADER *)msg; 117 cp = msg + sizeof(HEADER); 118 n_an = ntohs(hp->ancount); 119 n_ns = ntohs(hp->nscount); 120 n_ar = ntohs(hp->arcount); 121 nrec = n_an + n_ns + n_ar; 122 123 mess->len = 0; 124 mess->hd = hp; 125 mess->ns_off = n_an; 126 mess->ar_off = n_an + n_ns; 127 mess->count = nrec; 128 rp = &mess->rr; 129 130 /* skip over questions */ 131 if ((n = ntohs(hp->qdcount) != 0)) { 132 while (--n >= 0) { 133 int i; 134 if ((i = dn_skipname(cp, Hes_eoM)) < 0) 135 return((nsmsg_t *)NULL); 136 cp += i + (sizeof(u_int16_t /*type*/) 137 + sizeof(u_int16_t /*class*/)); 138 } 139 } 140 141 /* scan answers */ 142 if ((n = n_an) != 0) { 143 while (--n >= 0) { 144 if ((cp = _hes_rr_scan(cp, rp)) == NULL) 145 return((nsmsg_t *)NULL); 146 (void) strncpy(data, rp->data, rp->dlen); 147 rp->data = data; 148 data += rp->dlen; 149 *data++ = '\0'; 150 rp++; 151 } 152 } 153 154 /* scan name servers */ 155 if ((n = n_ns) != 0) { 156 while (--n >= 0) { 157 if ((cp = _hes_rr_scan(cp, rp)) == NULL) 158 return((nsmsg_t *)NULL); 159 (void) strncpy(data, rp->data, rp->dlen); 160 rp->data = data; 161 data += rp->dlen; 162 *data++ = '\0'; 163 rp++; 164 } 165 } 166 167 /* scan additional records */ 168 if ((n = n_ar) != 0) { 169 while (--n >= 0) { 170 if ((cp = _hes_rr_scan(cp, rp)) == NULL) 171 return((nsmsg_t *)NULL); 172 (void) strncpy(data, rp->data, rp->dlen); 173 rp->data = data; 174 data += rp->dlen; 175 *data++ = '\0'; 176 rp++; 177 } 178 } 179 180 mess->len = (int)cp - (int)msg; 181 182 return(mess); 183 } 184 185 /* 186 * Resolve name into data records 187 */ 188 189 static nsmsg_p 190 _hes_res(name, class, type) 191 u_char *name; 192 int class, type; 193 { 194 static u_char qbuf[PACKETSZ], abuf[PACKETSZ]; 195 int n; 196 u_int32_t res_options = _res.options; 197 int res_retrans = _res.retrans; 198 int res_retry = _res.retry; 199 200 #ifdef DEBUG 201 if (_res.options & RES_DEBUG) 202 printf("_hes_res: class = %d, type = %d\n", class, type); 203 #endif 204 205 if (class < 0 || type < 0) { 206 errno = EINVAL; 207 return((nsmsg_t *)NULL); 208 } 209 210 _res.options |= RES_IGNTC; 211 212 n = res_mkquery(QUERY, name, class, type, (u_char *)NULL, 0, 213 NULL, qbuf, PACKETSZ); 214 if (n < 0) { 215 errno = EMSGSIZE; 216 return((nsmsg_t *)NULL); 217 } 218 219 _res.retrans = DEF_RETRANS; 220 _res.retry = DEF_RETRY; 221 222 n = res_send(qbuf, n, abuf, PACKETSZ); 223 224 _res.options = res_options; 225 _res.retrans = res_retrans; 226 _res.retry = res_retry; 227 228 if (n < 0) { 229 errno = ECONNREFUSED; 230 return((nsmsg_t *)NULL); 231 } 232 Hes_eoM = abuf+n; 233 234 return(_hes_res_scan(abuf)); 235 } 236 237 int 238 hes_init() 239 { 240 FILE *fp; 241 char *key, *cp, *cpp; 242 char buf[MAXDNAME+7]; 243 244 Hes_Errno = HES_ER_UNINIT; 245 Hes_LHS[0] = '\0'; 246 Hes_RHS[0] = '\0'; 247 if ((fp = fopen(HesConfigFile, "r")) == NULL) { 248 /* use defaults compiled in */ 249 /* no file or no access uses defaults */ 250 /* but poorly formed file returns error */ 251 if (DEF_LHS) strncpy(Hes_LHS, DEF_LHS, MAXDNAME); 252 if (DEF_RHS) strncpy(Hes_RHS, DEF_RHS, MAXDNAME); 253 254 /* if DEF_RHS == "", use getdomainname() */ 255 if (Hes_RHS[0] == '\0') 256 (void)getdomainname(Hes_RHS, MAXDNAME); 257 } else { 258 while(fgets(buf, MAXDNAME+7, fp) != NULL) { 259 cp = buf; 260 if (*cp == '#' || *cp == '\n') 261 continue; 262 while(*cp == ' ' || *cp == '\t') 263 cp++; 264 key = cp; 265 while(*cp != ' ' && *cp != '\t' && *cp != '=') 266 cp++; 267 *cp++ = '\0'; 268 if (strcmp(key, "lhs") == 0) 269 cpp = Hes_LHS; 270 else if (strcmp(key, "rhs") == 0) 271 cpp = Hes_RHS; 272 else 273 continue; 274 while(*cp == ' ' || *cp == '\t' || *cp == '=') 275 cp++; 276 if (*cp != '.' && *cp != '\n') { 277 Hes_Errno = HES_ER_CONFIG; 278 fclose(fp); 279 return(Hes_Errno); 280 } 281 (void) strncpy(cpp, cp, strlen(cp)-1); 282 } 283 fclose(fp); 284 } 285 /* see if the RHS is overridden by environment variable */ 286 if ((cp = getenv("HES_DOMAIN")) != NULL) 287 strncpy(Hes_RHS, cp, MAXDNAME); 288 /* the LHS may be null, the RHS must not be null */ 289 if (Hes_RHS[0] == '\0') 290 Hes_Errno = HES_ER_CONFIG; 291 else 292 Hes_Errno = HES_ER_OK; 293 return(Hes_Errno); 294 } 295 296 char * 297 hes_to_bind(HesiodName, HesiodNameType) 298 char *HesiodName, *HesiodNameType; 299 { 300 static char bindname[MAXDNAME]; 301 char *cp, **cpp, *x; 302 char *RHS; 303 int bni = 0; 304 305 #define STRADDBIND(y) for (x = y; *x; x++, bni++) { \ 306 if (bni >= MAXDNAME) \ 307 return NULL; \ 308 bindname[bni] = *x; \ 309 } 310 311 if (Hes_Errno == HES_ER_UNINIT || Hes_Errno == HES_ER_CONFIG) 312 (void) hes_init(); 313 if (Hes_Errno == HES_ER_CONFIG) 314 return(NULL); 315 if ((cp = strchr(HesiodName,'@')) != NULL) { 316 if (strchr(++cp,'.')) 317 RHS = cp; 318 else 319 if ((cpp = hes_resolve(cp, "rhs-extension")) != NULL) 320 RHS = *cpp; 321 else { 322 Hes_Errno = HES_ER_NOTFOUND; 323 return(NULL); 324 } 325 STRADDBIND(HesiodName); 326 *strchr(bindname,'@') = '\0'; 327 } else { 328 RHS = Hes_RHS; 329 STRADDBIND(HesiodName); 330 } 331 STRADDBIND("."); 332 STRADDBIND(HesiodNameType); 333 if (Hes_LHS && Hes_LHS[0]) { 334 if (Hes_LHS[0] != '.') 335 STRADDBIND("."); 336 STRADDBIND(Hes_LHS); 337 } 338 if (RHS[0] != '.') 339 STRADDBIND("."); 340 STRADDBIND(RHS); 341 if (bni == MAXDNAME) 342 bni--; 343 bindname[bni] = '\0'; 344 return(bindname); 345 } 346 347 /* XXX: convert to resolv directly */ 348 char ** 349 hes_resolve(HesiodName, HesiodNameType) 350 char *HesiodName, *HesiodNameType; 351 { 352 char **retvec; 353 char *cp, *ocp, *dst; 354 int i, n; 355 struct nsmsg *ns; 356 rr_t *rp; 357 StringList *sl; 358 359 sl = sl_init(); 360 361 cp = hes_to_bind(HesiodName, HesiodNameType); 362 if (cp == NULL) 363 return(NULL); 364 errno = 0; 365 ns = _hes_res(cp, C_HS, T_TXT); 366 if (errno == ETIMEDOUT || errno == ECONNREFUSED) { 367 Hes_Errno = HES_ER_NET; 368 return(NULL); 369 } 370 if (ns == NULL || ns->ns_off <= 0) { 371 Hes_Errno = HES_ER_NOTFOUND; 372 return(NULL); 373 } 374 for(i = 0, rp = &ns->rr; i < ns->ns_off; rp++, i++) { 375 if (rp->class == C_HS && rp->type == T_TXT) { 376 dst = calloc(rp->dlen + 1, sizeof(char)); 377 if (dst == NULL) { 378 sl_free(sl, 1); 379 return NULL; 380 } 381 sl_add(sl, dst); 382 ocp = cp = rp->data; 383 while (cp < ocp + rp->dlen) { 384 n = (unsigned char) *cp++; 385 (void) memmove(dst, cp, n); 386 cp += n; 387 dst += n; 388 } 389 *dst = 0; 390 } 391 } 392 sl_add(sl, NULL); 393 retvec = sl->sl_str; /* XXX: nasty, knows stringlist internals */ 394 free(sl); 395 return(retvec); 396 } 397 398 int 399 hes_error() 400 { 401 return(Hes_Errno); 402 } 403 404 void 405 hes_free(hp) 406 char **hp; 407 { 408 int i; 409 if (!hp) 410 return; 411 for (i = 0; hp[i]; i++) 412 free(hp[i]); 413 free(hp); 414 } 415