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