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