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