hesiod.c revision 1.1.4.3 1 /* $NetBSD: hesiod.c,v 1.1.4.3 1998/11/02 03:29:36 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