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