1: #if defined(LIBC_SCCS) && !defined(lint)
2: static const char rcsid[] = "$BINDId: hesiod.c,v 1.21 2000/02/28 14:51:08 vixie Exp $";
3: #endif
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36: #include <sys/types.h>
37: #include <netinet/in.h>
38: #include <arpa/nameser.h>
39:
40: #include <errno.h>
41: #include <netdb.h>
42: #include <resolv.h>
43: #include <stdio.h>
44: #include <stdlib.h>
45: #include <string.h>
46:
47: #include "hesiod.h"
48: #include "hesiod_p.h"
49: #undef DEF_RHS
50:
51: #define _PATH_HESIOD_CONF "/etc/hesiod.conf"
52:
53:
54:
55: int hesiod_init(void **context);
56: void hesiod_end(void *context);
57: char * hesiod_to_bind(void *context, const char *name,
58: const char *type);
59: char ** hesiod_resolve(void *context, const char *name,
60: const char *type);
61: void hesiod_free_list(void *context, char **list);
62:
63: static int parse_config_file(struct hesiod_p *ctx, const char *filename);
64: static char ** get_txt_records(struct hesiod_p *ctx, int class,
65: const char *name);
66: static int init(struct hesiod_p *ctx);
67:
68:
69:
70:
71:
72:
73: int
74: hesiod_init(void **context) {
75: struct hesiod_p *ctx;
76: const char *configname;
77: char *cp;
78:
79: ctx = malloc(sizeof(struct hesiod_p));
80: if (ctx == 0)
81: return (-1);
82:
83: ctx->LHS = NULL;
84: ctx->RHS = NULL;
85: ctx->res = NULL;
86:
87: ctx->classes[0] = C_IN;
88: ctx->classes[1] = C_HS;
89:
90: configname = __secure_getenv("HESIOD_CONFIG");
91: if (!configname)
92: configname = _PATH_HESIOD_CONF;
93: if (parse_config_file(ctx, configname) < 0) {
94: #ifdef DEF_RHS
95:
96:
97:
98: ctx->LHS = malloc(strlen(DEF_LHS)+1);
99: ctx->RHS = malloc(strlen(DEF_RHS)+1);
100: if (ctx->LHS == 0 || ctx->RHS == 0)
101: goto cleanup;
102: strcpy(ctx->LHS, DEF_LHS);
103: strcpy(ctx->RHS, DEF_RHS);
104: #else
105: goto cleanup;
106: #endif
107: }
108:
109:
110:
111:
112: if ((cp = __secure_getenv("HES_DOMAIN")) != NULL) {
113: free(ctx->RHS);
114: ctx->RHS = malloc(strlen(cp)+2);
115: if (!ctx->RHS)
116: goto cleanup;
117: if (cp[0] == '.')
118: strcpy(ctx->RHS, cp);
119: else {
120: ctx->RHS[0] = '.';
121: strcpy(ctx->RHS + 1, cp);
122: }
123: }
124:
125:
126:
127:
128:
129: if (!ctx->RHS) {
130: __set_errno(ENOEXEC);
131: goto cleanup;
132: }
133:
134: #if 0
135: if (res_ninit(ctx->res) < 0)
136: goto cleanup;
137: #endif
138:
139: *context = ctx;
140: return (0);
141:
142: cleanup:
143: hesiod_end(ctx);
144: return (-1);
145: }
146:
147:
148:
149:
150: void
151: hesiod_end(void *context) {
152: struct hesiod_p *ctx = (struct hesiod_p *) context;
153: int save_errno = errno;
154:
155: if (ctx->res)
156: res_nclose(ctx->res);
157: free(ctx->RHS);
158: free(ctx->LHS);
159: if (ctx->res && ctx->free_res)
160: (*ctx->free_res)(ctx->res);
161: free(ctx);
162: __set_errno(save_errno);
163: }
164:
165:
166:
167:
168:
169: char *
170: hesiod_to_bind(void *context, const char *name, const char *type) {
171: struct hesiod_p *ctx = (struct hesiod_p *) context;
172: char *bindname;
173: char **rhs_list = NULL;
174: const char *RHS, *cp;
175: char *endp;
176:
177:
178: if ((cp = strchr(name, '@')) != NULL) {
179: if (strchr(cp + 1, '.'))
180: RHS = cp + 1;
181: else if ((rhs_list = hesiod_resolve(context, cp + 1,
182: "rhs-extension")) != NULL)
183: RHS = *rhs_list;
184: else {
185: __set_errno(ENOENT);
186: return (NULL);
187: }
188: } else {
189: RHS = ctx->RHS;
190: cp = name + strlen(name);
191: }
192:
193:
194:
195:
196:
197: if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
198: (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
199: if (rhs_list)
200: hesiod_free_list(context, rhs_list);
201: return NULL;
202: }
203:
204:
205: endp = (char *) __mempcpy (bindname, name, cp - name);
206: *endp++ = '.';
207: endp = (char *) __stpcpy (endp, type);
208: if (ctx->LHS) {
209: if (ctx->LHS[0] != '.')
210: *endp++ = '.';
211: endp = __stpcpy (endp, ctx->LHS);
212: }
213: if (RHS[0] != '.')
214: *endp++ = '.';
215: strcpy (endp, RHS);
216:
217: if (rhs_list)
218: hesiod_free_list(context, rhs_list);
219:
220: return (bindname);
221: }
222:
223:
224:
225:
226:
227: char **
228: hesiod_resolve(void *context, const char *name, const char *type) {
229: struct hesiod_p *ctx = (struct hesiod_p *) context;
230: char *bindname = hesiod_to_bind(context, name, type);
231: char **retvec;
232:
233: if (bindname == NULL)
234: return (NULL);
235: if (init(ctx) == -1) {
236: free(bindname);
237: return (NULL);
238: }
239:
240: retvec = get_txt_records(ctx, ctx->classes[0], bindname);
241:
242: if (retvec == NULL && (errno == ENOENT || errno == ECONNREFUSED) && ctx->classes[1])
243: retvec = get_txt_records(ctx, ctx->classes[1], bindname);
244:
245:
246: free(bindname);
247: return (retvec);
248: }
249:
250: void
251: hesiod_free_list(void *context, char **list) {
252: char **p;
253:
254: for (p = list; *p; p++)
255: free(*p);
256: free(list);
257: }
258:
259:
260:
261:
262: static int
263: parse_config_file(struct hesiod_p *ctx, const char *filename) {
264: char buf[MAXDNAME+7];
265: FILE *fp;
266:
267:
268:
269:
270:
271: free(ctx->RHS);
272: free(ctx->LHS);
273: ctx->RHS = ctx->LHS = 0;
274:
275: ctx->classes[0] = C_IN;
276: ctx->classes[1] = C_HS;
277:
278:
279:
280:
281: if (!(fp = fopen(filename, "r")))
282: return (-1);
283:
284: while (fgets(buf, sizeof(buf), fp) != NULL) {
285: char *key, *data, *cp, **cpp;
286:
287: cp = buf;
288: if (*cp == '#' || *cp == '\n' || *cp == '\r')
289: continue;
290: while(*cp == ' ' || *cp == '\t')
291: cp++;
292: key = cp;
293: while(*cp != ' ' && *cp != '\t' && *cp != '=')
294: cp++;
295: *cp++ = '\0';
296:
297: while(*cp == ' ' || *cp == '\t' || *cp == '=')
298: cp++;
299: data = cp;
300: while(*cp != ' ' && *cp != '\n' && *cp != '\r')
301: cp++;
302: *cp++ = '\0';
303:
304: cpp = NULL;
305: if (strcasecmp(key, "lhs") == 0)
306: cpp = &ctx->LHS;
307: else if (strcasecmp(key, "rhs") == 0)
308: cpp = &ctx->RHS;
309: if (cpp) {
310: *cpp = strdup(data);
311: if (!*cpp)
312: goto cleanup;
313: } else if (strcasecmp(key, "classes") == 0) {
314: int n = 0;
315: while (*data && n < 2) {
316: cp = strchrnul(data, ',');
317: if (*cp != '\0')
318: *cp++ = '\0';
319: if (strcasecmp(data, "IN") == 0)
320: ctx->classes[n++] = C_IN;
321: else if (strcasecmp(data, "HS") == 0)
322: ctx->classes[n++] = C_HS;
323: data = cp;
324: }
325: if (n == 0) {
326:
327:
328: ctx->classes[0] = C_IN;
329: ctx->classes[1] = C_HS;
330: } else if (n == 1
331: || ctx->classes[0] == ctx->classes[1])
332: ctx->classes[1] = 0;
333: }
334: }
335: fclose(fp);
336: return (0);
337:
338: cleanup:
339: fclose(fp);
340: free(ctx->RHS);
341: free(ctx->LHS);
342: ctx->RHS = ctx->LHS = 0;
343: return (-1);
344: }
345:
346:
347:
348:
349:
350: static char **
351: get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
352: struct {
353: int type;
354: int class;
355: int dlen;
356: u_char *data;
357: } rr;
358: HEADER *hp;
359: u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
360: u_char *cp, *erdata, *eom;
361: char *dst, *edst, **list;
362: int ancount, qdcount;
363: int i, j, n, skip;
364:
365:
366:
367:
368: n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
369: NULL, qbuf, MAX_HESRESP);
370: if (n < 0) {
371: __set_errno(EMSGSIZE);
372: return (NULL);
373: }
374: n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
375: if (n < 0) {
376: __set_errno(ECONNREFUSED);
377: return (NULL);
378: }
379: if (n < HFIXEDSZ) {
380: __set_errno(EMSGSIZE);
381: return (NULL);
382: }
383:
384:
385:
386:
387: hp = (HEADER *) abuf;
388: ancount = ntohs(hp->ancount);
389: qdcount = ntohs(hp->qdcount);
390: cp = abuf + sizeof(HEADER);
391: eom = abuf + n;
392:
393:
394: for (i = 0; i < qdcount; i++) {
395: skip = dn_skipname(cp, eom);
396: if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
397: __set_errno(EMSGSIZE);
398: return (NULL);
399: }
400: cp += skip + QFIXEDSZ;
401: }
402:
403: list = malloc((ancount + 1) * sizeof(char *));
404: if (!list)
405: return (NULL);
406: j = 0;
407: for (i = 0; i < ancount; i++) {
408: skip = dn_skipname(cp, eom);
409: if (skip < 0) {
410: __set_errno(EMSGSIZE);
411: goto cleanup;
412: }
413: cp += skip;
414: if (cp + 3 * INT16SZ + INT32SZ > eom) {
415: __set_errno(EMSGSIZE);
416: goto cleanup;
417: }
418: rr.type = ns_get16(cp);
419: cp += INT16SZ;
420: rr.class = ns_get16(cp);
421: cp += INT16SZ + INT32SZ;
422: rr.dlen = ns_get16(cp);
423: cp += INT16SZ;
424: if (cp + rr.dlen > eom) {
425: __set_errno(EMSGSIZE);
426: goto cleanup;
427: }
428: rr.data = cp;
429: cp += rr.dlen;
430: if (rr.class != class || rr.type != T_TXT)
431: continue;
432: if (!(list[j] = malloc(rr.dlen)))
433: goto cleanup;
434: dst = list[j++];
435: edst = dst + rr.dlen;
436: erdata = rr.data + rr.dlen;
437: cp = rr.data;
438: while (cp < erdata) {
439: n = (unsigned char) *cp++;
440: if (cp + n > eom || dst + n > edst) {
441: __set_errno(EMSGSIZE);
442: goto cleanup;
443: }
444: memcpy(dst, cp, n);
445: cp += n;
446: dst += n;
447: }
448: if (cp != erdata) {
449: __set_errno(EMSGSIZE);
450: goto cleanup;
451: }
452: *dst = '\0';
453: }
454: list[j] = NULL;
455: if (j == 0) {
456: __set_errno(ENOENT);
457: goto cleanup;
458: }
459: return (list);
460:
461: cleanup:
462: for (i = 0; i < j; i++)
463: free(list[i]);
464: free(list);
465: return (NULL);
466: }
467:
468: struct __res_state *
469: __hesiod_res_get(void *context) {
470: struct hesiod_p *ctx = context;
471:
472: if (!ctx->res) {
473: struct __res_state *res;
474: res = (struct __res_state *)calloc(1, sizeof *res);
475: if (res == NULL)
476: return (NULL);
477: __hesiod_res_set(ctx, res, free);
478: }
479:
480: return (ctx->res);
481: }
482:
483: void
484: __hesiod_res_set(void *context, struct __res_state *res,
485: void (*free_res)(void *)) {
486: struct hesiod_p *ctx = context;
487:
488: if (ctx->res && ctx->free_res) {
489: res_nclose(ctx->res);
490: (*ctx->free_res)(ctx->res);
491: }
492:
493: ctx->res = res;
494: ctx->free_res = free_res;
495: }
496:
497: static int
498: init(struct hesiod_p *ctx) {
499:
500: if (!ctx->res && !__hesiod_res_get(ctx))
501: return (-1);
502:
503: if (__res_maybe_init (ctx->res, 0) == -1)
504: return (-1);
505:
506: return (0);
507: }