hesiod.c revision 1.5 1 /* $NetBSD: hesiod.c,v 1.5 1999/01/21 12:40:07 mycroft 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 void *_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 void *
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 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 *)(void *)bigmess;
115
116 hp = (HEADER *)(void *)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 NULL;
136 cp += i + (sizeof(u_int16_t /*type*/)
137 + sizeof(u_int16_t /*class*/));
138 }
139 }
140 #define GRABDATA \
141 while (--n >= 0) { \
142 if ((cp = _hes_rr_scan(cp, rp)) == NULL) \
143 return NULL; \
144 (void)strncpy((char *)data, (char *)rp->data, \
145 (size_t)rp->dlen); \
146 rp->data = data; \
147 data += rp->dlen; \
148 *data++ = '\0'; \
149 rp++; \
150 }
151
152 /* scan answers */
153 if ((n = n_an) != 0)
154 GRABDATA
155
156 /* scan name servers */
157 if ((n = n_ns) != 0)
158 GRABDATA
159
160 /* scan additional records */
161 if ((n = n_ar) != 0)
162 GRABDATA
163
164 mess->len = (int)((long)cp - (long)msg);
165
166 return(mess);
167 }
168
169 /*
170 * Resolve name into data records
171 */
172
173 static nsmsg_p
174 _hes_res(name, class, type)
175 u_char *name;
176 int class, type;
177 {
178 static u_char qbuf[PACKETSZ], abuf[PACKETSZ];
179 int n;
180 u_int32_t res_options = (u_int32_t)_res.options;
181 int res_retrans = _res.retrans;
182 int res_retry = _res.retry;
183
184 #ifdef DEBUG
185 if (_res.options & RES_DEBUG)
186 printf("_hes_res: class = %d, type = %d\n", class, type);
187 #endif
188
189 if (class < 0 || type < 0) {
190 errno = EINVAL;
191 return((nsmsg_t *)NULL);
192 }
193
194 _res.options |= RES_IGNTC;
195
196 n = res_mkquery(QUERY, (char *)name, class, type, NULL, 0,
197 NULL, qbuf, PACKETSZ);
198 if (n < 0) {
199 errno = EMSGSIZE;
200 return((nsmsg_t *)NULL);
201 }
202
203 _res.retrans = DEF_RETRANS;
204 _res.retry = DEF_RETRY;
205
206 n = res_send(qbuf, n, abuf, PACKETSZ);
207
208 _res.options = res_options;
209 _res.retrans = res_retrans;
210 _res.retry = res_retry;
211
212 if (n < 0) {
213 errno = ECONNREFUSED;
214 return((nsmsg_t *)NULL);
215 }
216 Hes_eoM = abuf+n;
217
218 return(_hes_res_scan(abuf));
219 }
220
221 int
222 hes_init()
223 {
224 FILE *fp;
225 char *key, *cp, *cpp;
226 char buf[MAXDNAME+7];
227
228 Hes_Errno = HES_ER_UNINIT;
229 Hes_LHS[0] = '\0';
230 Hes_RHS[0] = '\0';
231 if ((fp = fopen(HesConfigFile, "r")) == NULL) {
232 /* use defaults compiled in */
233 /* no file or no access uses defaults */
234 /* but poorly formed file returns error */
235 if (DEF_LHS) strncpy(Hes_LHS, DEF_LHS, MAXDNAME);
236 if (DEF_RHS) strncpy(Hes_RHS, DEF_RHS, MAXDNAME);
237
238 /* if DEF_RHS == "", use getdomainname() */
239 if (Hes_RHS[0] == '\0')
240 (void)getdomainname(Hes_RHS, MAXDNAME);
241 } else {
242 while(fgets(buf, MAXDNAME+7, fp) != NULL) {
243 cp = buf;
244 if (*cp == '#' || *cp == '\n')
245 continue;
246 while(*cp == ' ' || *cp == '\t')
247 cp++;
248 key = cp;
249 while(*cp != ' ' && *cp != '\t' && *cp != '=')
250 cp++;
251 *cp++ = '\0';
252 if (strcmp(key, "lhs") == 0)
253 cpp = Hes_LHS;
254 else if (strcmp(key, "rhs") == 0)
255 cpp = Hes_RHS;
256 else
257 continue;
258 while(*cp == ' ' || *cp == '\t' || *cp == '=')
259 cp++;
260 if (*cp != '.' && *cp != '\n') {
261 Hes_Errno = HES_ER_CONFIG;
262 fclose(fp);
263 return(Hes_Errno);
264 }
265 (void) strncpy(cpp, cp, strlen(cp)-1);
266 }
267 fclose(fp);
268 }
269 /* see if the RHS is overridden by environment variable */
270 if ((cp = getenv("HES_DOMAIN")) != NULL)
271 strncpy(Hes_RHS, cp, MAXDNAME);
272 /* the LHS may be null, the RHS must not be null */
273 if (Hes_RHS[0] == '\0')
274 Hes_Errno = HES_ER_CONFIG;
275 else
276 Hes_Errno = HES_ER_OK;
277 return(Hes_Errno);
278 }
279
280 char *
281 hes_to_bind(HesiodName, HesiodNameType)
282 char *HesiodName, *HesiodNameType;
283 {
284 static char bindname[MAXDNAME];
285 char *cp, **cpp, *x;
286 char *RHS;
287 int bni = 0;
288
289 #define STRADDBIND(y) for (x = y; *x; x++, bni++) { \
290 if (bni >= MAXDNAME) \
291 return NULL; \
292 bindname[bni] = *x; \
293 }
294
295 if (Hes_Errno == HES_ER_UNINIT || Hes_Errno == HES_ER_CONFIG)
296 (void) hes_init();
297 if (Hes_Errno == HES_ER_CONFIG)
298 return(NULL);
299 if ((cp = strchr(HesiodName,'@')) != NULL) {
300 if (strchr(++cp,'.'))
301 RHS = cp;
302 else
303 if ((cpp = hes_resolve(cp, "rhs-extension")) != NULL)
304 RHS = *cpp;
305 else {
306 Hes_Errno = HES_ER_NOTFOUND;
307 return(NULL);
308 }
309 STRADDBIND(HesiodName);
310 *strchr(bindname,'@') = '\0';
311 } else {
312 RHS = Hes_RHS;
313 STRADDBIND(HesiodName);
314 }
315 STRADDBIND(".");
316 STRADDBIND(HesiodNameType);
317 if (Hes_LHS && Hes_LHS[0]) {
318 if (Hes_LHS[0] != '.')
319 STRADDBIND(".");
320 STRADDBIND(Hes_LHS);
321 }
322 if (RHS[0] != '.')
323 STRADDBIND(".");
324 STRADDBIND(RHS);
325 if (bni == MAXDNAME)
326 bni--;
327 bindname[bni] = '\0';
328 return(bindname);
329 }
330
331 /* XXX: convert to resolv directly */
332 char **
333 hes_resolve(HesiodName, HesiodNameType)
334 char *HesiodName, *HesiodNameType;
335 {
336 char **retvec;
337 char *cp, *ocp, *dst;
338 int i, n;
339 struct nsmsg *ns;
340 rr_t *rp;
341 StringList *sl;
342
343 sl = sl_init();
344
345 cp = hes_to_bind(HesiodName, HesiodNameType);
346 if (cp == NULL)
347 return(NULL);
348 errno = 0;
349 ns = _hes_res((u_char *)cp, C_IN, T_TXT);
350 if (errno == ETIMEDOUT || errno == ECONNREFUSED) {
351 Hes_Errno = HES_ER_NET;
352 return(NULL);
353 }
354 if (ns == NULL || ns->ns_off <= 0) {
355 Hes_Errno = HES_ER_NOTFOUND;
356 return(NULL);
357 }
358 for(i = 0, rp = &ns->rr; i < ns->ns_off; rp++, i++) {
359 if (rp->class == C_IN && rp->type == T_TXT) {
360 dst = calloc((size_t)(rp->dlen + 1), sizeof(char));
361 if (dst == NULL) {
362 sl_free(sl, 1);
363 return NULL;
364 }
365 sl_add(sl, dst);
366 ocp = cp = (char *)rp->data;
367 while (cp < ocp + rp->dlen) {
368 n = (unsigned char) *cp++;
369 (void) memmove(dst, cp, (size_t)n);
370 cp += n;
371 dst += n;
372 }
373 *dst = 0;
374 }
375 }
376 sl_add(sl, NULL);
377 retvec = sl->sl_str; /* XXX: nasty, knows stringlist internals */
378 free(sl);
379 return(retvec);
380 }
381
382 int
383 hes_error()
384 {
385 return(Hes_Errno);
386 }
387
388 void
389 hes_free(hp)
390 char **hp;
391 {
392 int i;
393 if (!hp)
394 return;
395 for (i = 0; hp[i]; i++)
396 free(hp[i]);
397 free(hp);
398 }
399