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