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