Home | History | Annotate | Line # | Download | only in net
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