Date: Thu, 29 Jun 2006 17:20:29 GMT From: Michael Bushkov <bushman@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 100298 for review Message-ID: <200606291720.k5THKT31096956@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=100298 Change 100298 by bushman@bushman_nss_ldap_cached on 2006/06/29 17:19:49 "shells" nsswitch database reworked to be supported by the caching daemon Affected files ... .. //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/gen/getusershell.c#2 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/Makefile#8 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/dns_shells.c#1 add .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/dns_shells.h#1 add .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/nss_dns.c#8 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/Makefile#7 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/files_shells.c#4 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/files_shells.h#3 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/nss_files.c#10 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/Makefile#8 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/nis_shells.c#1 add .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/nis_shells.h#1 add .. //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/nss_nis.c#7 edit .. //depot/projects/soc2006/nss_ldap_cached/tests/getusershell_test/Makefile#3 edit .. //depot/projects/soc2006/nss_ldap_cached/tests/getusershell_test/getusershell_test.c#3 edit Differences ... ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/gen/getusershell.c#2 (text+ko) ==== @@ -39,236 +39,128 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/getusershell.c,v 1.9 2003/04/24 20:16:21 nectar Exp $"); #include "namespace.h" -#include <sys/param.h> -#include <sys/file.h> - #include <ctype.h> #include <errno.h> #include <nsswitch.h> #include <paths.h> +#include <pthread.h> +#include <pthread_np.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stringlist.h> #include <unistd.h> +#include "un-namespace.h" -#ifdef HESIOD -#include <hesiod.h> -#endif -#ifdef YP -#include <rpc/rpc.h> -#include <rpcsvc/ypclnt.h> -#include <rpcsvc/yp_prot.h> -#endif -#include "un-namespace.h" +static const ns_src defaultsrc[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NULL, 0} +}; + +enum constants +{ + USERSHELL_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ + USERSHELL_STORAGE_MAX = 1 << 20, /* 1 MByte */ +}; /* * Local shells should NOT be added here. They should be added in * /etc/shells. */ - static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL }; -static const char *const *curshell; -static StringList *sl; -static const char *const *initshells(void); +struct usershell_state { + char *buffer; + size_t bufsize; +}; +static void usershell_endstate(void *); +NSS_TLS_HANDLING(usershell); -/* - * Get a list of shells from "shells" nsswitch database - */ -char * -getusershell(void) +static void usershell_endstate(void *st) { - char *ret; - - if (curshell == NULL) - curshell = initshells(); - /*LINTED*/ - ret = (char *)*curshell; - if (ret != NULL) - curshell++; - return (ret); + if (st == NULL) + return; + + free(((struct usershell_state *)st)->buffer); + free(st); } -void -endusershell(void) +static int +getusershell_r(char **retval, char *buffer, size_t bufsize) { - if (sl) { - sl_free(sl, 1); - sl = NULL; - } - curshell = NULL; -} + static const ns_dtab dtab[] = { + { NULL, NULL, NULL } + }; + int rv, ret_errno; -void -setusershell(void) -{ + ret_errno = 0; + *retval = NULL; + rv = nsdispatch(retval, dtab, NSDB_SHELLS, "getusershell_r", + defaultsrc, buffer, bufsize, &ret_errno); - curshell = initshells(); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); + } - -static int _local_initshells(void *, void *, va_list); - -/*ARGSUSED*/ -static int -_local_initshells(rv, cb_data, ap) - void *rv; - void *cb_data; - va_list ap; +char * +getusershell(void) { - char *sp, *cp; - FILE *fp; - char line[MAXPATHLEN + 2]; + int rv; + char *res; + struct usershell_state *st; - if (sl) - sl_free(sl, 1); - sl = sl_init(); + rv = usershell_getstate(&st); + if (rv != 0) { + errno = rv; + return NULL; + } - if ((fp = fopen(_PATH_SHELLS, "r")) == NULL) - return NS_UNAVAIL; - - sp = cp = line; - while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) { - while (*cp != '#' && *cp != '/' && *cp != '\0') - cp++; - if (*cp == '#' || *cp == '\0') - continue; - sp = cp; - while (!isspace(*cp) && *cp != '#' && *cp != '\0') - cp++; - *cp++ = '\0'; - sl_add(sl, strdup(sp)); + if (st->buffer == NULL) { + st->buffer = malloc(USERSHELL_STORAGE_INITIAL); + if (st->buffer == NULL) + return (NULL); + st->bufsize = USERSHELL_STORAGE_INITIAL; } - (void)fclose(fp); - return NS_SUCCESS; -} - -#ifdef HESIOD -static int _dns_initshells(void *, void *, va_list); - -/*ARGSUSED*/ -static int -_dns_initshells(rv, cb_data, ap) - void *rv; - void *cb_data; - va_list ap; -{ - char shellname[] = "shells-XXXXX"; - int hsindex, hpi, r; - char **hp; - void *context; - - if (sl) - sl_free(sl, 1); - sl = sl_init(); - r = NS_UNAVAIL; - if (hesiod_init(&context) == -1) - return (r); - - for (hsindex = 0; ; hsindex++) { - snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex); - hp = hesiod_resolve(context, shellname, "shells"); - if (hp == NULL) { - if (errno == ENOENT) { - if (hsindex == 0) - r = NS_NOTFOUND; - else - r = NS_SUCCESS; + do { + rv = getusershell_r(&res, st->buffer, st->bufsize); + if (res == NULL && rv == ERANGE) { + free(st->buffer); + if ((st->bufsize << 1) > USERSHELL_STORAGE_MAX) { + st->buffer = NULL; + errno = ERANGE; + return (NULL); } - break; - } else { - for (hpi = 0; hp[hpi]; hpi++) - sl_add(sl, hp[hpi]); - free(hp); + st->bufsize <<= 1; + st->buffer = malloc(st->bufsize); + if (st->buffer == NULL) + return (NULL); } - } - hesiod_end(context); - return (r); + } while (res == NULL && rv == ERANGE); + if (rv != 0) + errno = rv; + + return (res); } -#endif /* HESIOD */ -#ifdef YP -static int _nis_initshells(void *, void *, va_list); -/*ARGSUSED*/ -static int -_nis_initshells(rv, cb_data, ap) - void *rv; - void *cb_data; - va_list ap; +void +endusershell(void) { - static char *ypdomain; - char *key, *data; - char *lastkey; - int keylen, datalen; - int r; + static const ns_dtab dtab[] = { + { NULL, NULL, NULL } + }; - if (sl) - sl_free(sl, 1); - sl = sl_init(); - - if (ypdomain == NULL) { - switch (yp_get_default_domain(&ypdomain)) { - case 0: - break; - case YPERR_RESRC: - return NS_TRYAGAIN; - default: - return NS_UNAVAIL; - } - } - - /* - * `key' and `data' point to strings dynamically allocated by - * the yp_... functions. - * `data' is directly put into the stringlist of shells. - */ - key = data = NULL; - if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen)) - return NS_UNAVAIL; - do { - data[datalen] = '\0'; /* clear trailing \n */ - sl_add(sl, data); - - lastkey = key; - r = yp_next(ypdomain, "shells", lastkey, keylen, - &key, &keylen, &data, &datalen); - free(lastkey); - } while (r == 0); - - if (r == YPERR_NOMORE) { - /* - * `data' and `key' ought to be NULL - do not try to free them. - */ - return NS_SUCCESS; - } - - return NS_UNAVAIL; + nsdispatch(NULL, dtab, NSDB_SHELLS, "setusershell"); } -#endif /* YP */ -static const char *const * -initshells() +void +setusershell(void) { static const ns_dtab dtab[] = { - NS_FILES_CB(_local_initshells, NULL) - NS_DNS_CB(_dns_initshells, NULL) - NS_NIS_CB(_nis_initshells, NULL) - { 0 } + { NULL, NULL, NULL } }; - if (sl) - sl_free(sl, 1); - sl = sl_init(); - if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc) - != NS_SUCCESS) { - if (sl) - sl_free(sl, 1); - sl = NULL; - return (okshells); - } - sl_add(sl, NULL); - - return (const char *const *)(sl->sl_str); + nsdispatch(NULL, dtab, NSDB_SHELLS, "setusershell"); } ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/Makefile#8 (text+ko) ==== @@ -8,7 +8,7 @@ SHLIBDIR?= /lib SRCS= nss_dns.c dns_hosts_namadr.c dns_hosts_addrinfo.c dns_passwd.c\ - dns_group.c dns_net.c + dns_group.c dns_net.c dns_shells.c CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../libc/gen -I${.CURDIR}/../libc/include\ -I${.CURDIR}/../libc/net -I${.CURDIR}/../libnssutil CFLAGS+=-DINET6 ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_dns/nss_dns.c#8 (text+ko) ==== @@ -36,6 +36,7 @@ #include "dns_net.h" #include "dns_passwd.h" #include "dns_group.h" +#include "dns_shells.h" #include "netdb_private.h" static ns_mtab methods[] = { @@ -64,6 +65,10 @@ {NSDB_NETWORKS_INTERNAL, "setnetent", __dns_setnetent, NULL}, {NSDB_NETWORKS_INTERNAL, "endnetent", __dns_endnetent, NULL}, + {NSDB_SHELLS, "getusershell_r", __dns_getusershell_r, NULL}, + {NSDB_SHELLS, "setusershell", __dns_setusershell, NULL}, + {NSDB_SHELLS, "endusershell", __dns_setusershell, NULL}, + {NSDB_GROUP_COMPAT, "getgrnam_r", __dns_group, (void *)nss_lt_name}, {NSDB_GROUP_COMPAT, "getgrgid_r", __dns_group, (void *)nss_lt_id}, {NSDB_GROUP_COMPAT, "getgrent_r", __dns_group, (void *)nss_lt_all}, ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/Makefile#7 (text+ko) ==== @@ -9,7 +9,7 @@ SRCS= nss_files.c files_passwd.c files_group.c files_hosts_namadr.c\ files_hosts_addrinfo.c files_serv.c files_proto.c\ - files_net.c files_rpc.c + files_net.c files_rpc.c files_shells.c CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../libc/gen -I${.CURDIR}/../libc/include\ -I${.CURDIR}/../libc/net -I${.CURDIR}/../libnssutil CFLAGS+=-DINET6 ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/files_shells.c#4 (text+ko) ==== @@ -30,3 +30,117 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/file.h> + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <nsswitch.h> +#include <paths.h> +#include "namespace.h" +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "reentrant.h" +#include "nss_tls.h" + +struct files_usershell_state { + FILE *fp; +}; +static void files_usershell_endstate(void *); +NSS_TLS_HANDLING(files_usershell); + +static void +files_usershell_endstate(void *st) +{ + struct files_usershell_state *state; + + if (st == NULL) + return; + + state = (struct files_usershell_state *)st; + if (state->fp != NULL) { + fclose(state->fp); + state->fp = NULL; + } + + free(state); +} + +int +__files_getusershell_r(void *rv, void *cb_data, va_list ap) +{ + struct files_usershell_state *st; + char *buffer; + size_t buflen; + int *errnop; + char **retval; + + char *cp, *sp; + + buffer = va_arg(ap, char *); + buflen = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + retval = (char **)rv; + + assert(buffer != NULL); + assert(buflen != 0); + assert(rv != NULL); + + *errnop = files_usershell_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + + if ((st->fp == NULL) && ((st->fp = fopen(_PATH_SHELLS, "r")) == NULL)) + return NS_UNAVAIL; + + cp = buffer; + while (fgets(cp, buflen - 1, st->fp) != NULL) { + while (*cp != '#' && *cp != '/' && *cp != '\0') + cp++; + if (*cp == '#' || *cp == '\0') + continue; + sp = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') + cp++; + *cp++ = '\0'; + + *retval = sp; + return (NS_SUCCESS); + } + + (void)fclose(st->fp); + st->fp = NULL; + + return (NS_UNAVAIL); +} + +int +__files_setusershell(void *rv, void *cb_data, va_list ap) +{ + struct files_usershell_state *st; + int error; + + error = files_usershell_getstate(&st); + if (error != 0) { + errno = error; + return (NS_UNAVAIL); + } + + if (st->fp != NULL) { + fclose(st->fp); + st->fp = NULL; + } + + return (NS_UNAVAIL); + +} ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/files_shells.h#3 (text+ko) ==== @@ -26,4 +26,5 @@ * $FreeBSD$ */ -extern int __files_initshells(void *, void *, va_list); +int __files_getusershell_r(void *, void *, va_list); +int __files_setusershell(void *, void *, va_list); ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_files/nss_files.c#10 (text+ko) ==== @@ -41,6 +41,7 @@ #include "files_proto.h" #include "files_rpc.h" #include "files_serv.h" +#include "files_shells.h" #include "netdb_private.h" #include "nss_files.h" @@ -94,6 +95,10 @@ {NSDB_RPC, "getrpcent_r", __files_rpcent, (void *)nss_lt_all}, {NSDB_RPC, "setrpcent", __files_setrpcent, (void *)nss_set_ent}, {NSDB_RPC, "endrpcent", __files_setrpcent, (void *)nss_end_ent}, + + {NSDB_SHELLS, "getusershell_r", __files_getusershell_r, NULL}, + {NSDB_SHELLS, "setusershell", __files_setusershell, NULL}, + {NSDB_SHELLS, "endusershell", __files_setusershell, NULL}, {NSDB_GROUP_COMPAT, "getgrnam_r", __files_group, (void *)nss_lt_name}, {NSDB_GROUP_COMPAT, "getgrgid_r", __files_group, (void *)nss_lt_id}, ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/Makefile#8 (text+ko) ==== @@ -8,7 +8,7 @@ SHLIBDIR?= /lib SRCS= nss_nis.c nis_hosts_namadr.c nis_hosts_addrinfo.c nis_passwd.c\ - nis_group.c nis_net.c nis_rpc.c nis_serv.c + nis_group.c nis_net.c nis_rpc.c nis_serv.c nis_shells.c CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../libc/gen -I${.CURDIR}/../libc/include\ -I${.CURDIR}/../libc/net -I${.CURDIR}/../libnssutil CFLAGS+=-DINET6 ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/nss_nis/nss_nis.c#7 (text+ko) ==== @@ -37,6 +37,7 @@ #include "nis_group.h" #include "nis_rpc.h" #include "nis_serv.h" +#include "nis_shells.h" static ns_mtab methods[] = { {NSDB_GROUP, "getgrnam_r", __nis_group, (void *)nss_lt_name}, @@ -65,7 +66,11 @@ {NSDB_RPC, "getrpcbyport_r", __nis_rpcent, (void *)nss_lt_id}, {NSDB_RPC, "getrpcent_r", __nis_rpcent, (void *)nss_lt_all}, {NSDB_RPC, "setrpcent", __nis_setrpcent, NULL}, - {NSDB_RPC, "endrpcent", __nis_setrpcent, NULL}, + {NSDB_RPC, "endrpcent", __nis_setrpcent, NULL}, + + {NSDB_SHELLS, "getusershell_r", __nis_getusershell_r, NULL}, + {NSDB_SHELLS, "setusershell", __nis_setusershell, NULL}, + {NSDB_SHELLS, "endusershell", __nis_setusershell, NULL}, {NSDB_GROUP_COMPAT, "getgrnam_r", __nis_group, (void *)nss_lt_name}, {NSDB_GROUP_COMPAT, "getgrgid_r", __nis_group, (void *)nss_lt_id}, ==== //depot/projects/soc2006/nss_ldap_cached/tests/getusershell_test/Makefile#3 (text+ko) ==== @@ -4,7 +4,8 @@ SRCS= getusershell_test.c CFLAGS+= -g -I${.CURDIR} -I${.CURDIR}/../../src/lib/libc/gen -I${.CURDIR}/../../src/lib/libc/include\ -I${.CURDIR}/../../src/lib/libc/net - +LDFLAGS+= -L/usr/local/lib +#LDADD+= -lhesiod MAN= .include <bsd.prog.mk> ==== //depot/projects/soc2006/nss_ldap_cached/tests/getusershell_test/getusershell_test.c#3 (text+ko) ==== @@ -1,3 +1,544 @@ +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/nameser.h> + +#include <ctype.h> +#include <errno.h> +#include <hesiod.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct hesiod_p { + char *lhs; /* normally ".ns" */ + char *rhs; /* AKA the default hesiod domain */ + int classes[2]; /* The class search order. */ +}; + +#define MAX_HESRESP 1024 + +static int read_config_file(struct hesiod_p *, const char *); +static char **get_txt_records(int, const char *); +static int init_context(void); +static void translate_errors(void); + + +/* + * hesiod_init -- + * initialize a hesiod_p. + */ +int +hesiod_init(context) + void **context; +{ + struct hesiod_p *ctx; + const char *p, *configname; + + ctx = malloc(sizeof(struct hesiod_p)); + if (ctx) { + *context = ctx; + if (!issetugid()) + configname = getenv("HESIOD_CONFIG"); + else + configname = NULL; + if (!configname) + configname = _PATH_HESIOD_CONF; + if (read_config_file(ctx, configname) >= 0) { + /* + * The default rhs can be overridden by an + * environment variable. + */ + if (!issetugid()) + p = getenv("HES_DOMAIN"); + else + p = NULL; + if (p) { + if (ctx->rhs) + free(ctx->rhs); + ctx->rhs = malloc(strlen(p) + 2); + if (ctx->rhs) { + *ctx->rhs = '.'; + strcpy(ctx->rhs + 1, + (*p == '.') ? p + 1 : p); + return 0; + } else + errno = ENOMEM; + } else + return 0; + } + } else + errno = ENOMEM; + + if (ctx->lhs) + free(ctx->lhs); + if (ctx->rhs) + free(ctx->rhs); + if (ctx) + free(ctx); + return -1; +} + +/* + * hesiod_end -- + * Deallocates the hesiod_p. + */ +void +hesiod_end(context) + void *context; +{ + struct hesiod_p *ctx = (struct hesiod_p *) context; + + free(ctx->rhs); + if (ctx->lhs) + free(ctx->lhs); + free(ctx); +} + +/* + * hesiod_to_bind -- + * takes a hesiod (name, type) and returns a DNS + * name which is to be resolved. + */ +char * +hesiod_to_bind(void *context, const char *name, const char *type) +{ + struct hesiod_p *ctx = (struct hesiod_p *) context; + char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL; + const char *rhs; + int len; + + if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) { + errno = EMSGSIZE; + return NULL; + } + + /* + * Find the right right hand side to use, possibly + * truncating bindname. + */ + p = strchr(bindname, '@'); + if (p) { + *p++ = 0; + if (strchr(p, '.')) + rhs = name + (p - bindname); + else { + rhs_list = hesiod_resolve(context, p, "rhs-extension"); + if (rhs_list) + rhs = *rhs_list; + else { + errno = ENOENT; + return NULL; + } + } + } else + rhs = ctx->rhs; + + /* See if we have enough room. */ + len = strlen(bindname) + 1 + strlen(type); + if (ctx->lhs) + len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0); + len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0); + if (len > sizeof(bindname) - 1) { + if (rhs_list) + hesiod_free_list(context, rhs_list); + errno = EMSGSIZE; + return NULL; + } + /* Put together the rest of the domain. */ + strcat(bindname, "."); + strcat(bindname, type); + /* Only append lhs if it isn't empty. */ + if (ctx->lhs && ctx->lhs[0] != '\0' ) { + if (ctx->lhs[0] != '.') + strcat(bindname, "."); + strcat(bindname, ctx->lhs); + } + if (rhs[0] != '.') + strcat(bindname, "."); + strcat(bindname, rhs); + + /* rhs_list is no longer needed, since we're done with rhs. */ + if (rhs_list) + hesiod_free_list(context, rhs_list); + + /* Make a copy of the result and return it to the caller. */ + ret = strdup(bindname); + if (!ret) + errno = ENOMEM; + return ret; +} + +/* + * hesiod_resolve -- + * Given a hesiod name and type, return an array of strings returned + * by the resolver. + */ +char ** +hesiod_resolve(context, name, type) + void *context; + const char *name; + const char *type; +{ + struct hesiod_p *ctx = (struct hesiod_p *) context; + char *bindname, **retvec; + + bindname = hesiod_to_bind(context, name, type); + if (!bindname) + return NULL; + + retvec = get_txt_records(ctx->classes[0], bindname); + if (retvec == NULL && errno == ENOENT && ctx->classes[1]) + retvec = get_txt_records(ctx->classes[1], bindname); + + free(bindname); + return retvec; +} + +/*ARGSUSED*/ +void +hesiod_free_list(context, list) + void *context; + char **list; +{ + char **p; + + if (list == NULL) + return; + for (p = list; *p; p++) + free(*p); + free(list); +} + + +/* read_config_file -- + * Parse the /etc/hesiod.conf file. Returns 0 on success, + * -1 on failure. On failure, it might leave values in ctx->lhs + * or ctx->rhs which need to be freed by the caller. + */ +static int +read_config_file(ctx, filename) + struct hesiod_p *ctx; + const char *filename; +{ + char *key, *data, *p, **which; + char buf[MAXDNAME + 7]; + int n; + FILE *fp; + + /* Set default query classes. */ + ctx->classes[0] = C_IN; + ctx->classes[1] = C_HS; + + /* Try to open the configuration file. */ + fp = fopen(filename, "r"); + if (!fp) { + /* Use compiled in default domain names. */ + ctx->lhs = strdup(DEF_LHS); + ctx->rhs = strdup(DEF_RHS); + if (ctx->lhs && ctx->rhs) + return 0; + else { + errno = ENOMEM; + return -1; + } + } + ctx->lhs = NULL; + ctx->rhs = NULL; + while (fgets(buf, sizeof(buf), fp) != NULL) { + p = buf; + if (*p == '#' || *p == '\n' || *p == '\r') + continue; + while (*p == ' ' || *p == '\t') + p++; + key = p; + while (*p != ' ' && *p != '\t' && *p != '=') + p++; + *p++ = 0; + + while (isspace(*p) || *p == '=') + p++; + data = p; + while (!isspace(*p)) + p++; + *p = 0; + + if (strcasecmp(key, "lhs") == 0 || + strcasecmp(key, "rhs") == 0) { + which = (strcasecmp(key, "lhs") == 0) + ? &ctx->lhs : &ctx->rhs; + *which = strdup(data); + if (!*which) { + errno = ENOMEM; + return -1; + } + } else { + if (strcasecmp(key, "classes") == 0) { + n = 0; + while (*data && n < 2) { + p = data; + while (*p && *p != ',') + p++; + if (*p) + *p++ = 0; + if (strcasecmp(data, "IN") == 0) + ctx->classes[n++] = C_IN; + else + if (strcasecmp(data, "HS") == 0) + ctx->classes[n++] = + C_HS; + data = p; + } + while (n < 2) + ctx->classes[n++] = 0; + } + } + } + fclose(fp); + + if (!ctx->rhs || ctx->classes[0] == 0 || + ctx->classes[0] == ctx->classes[1]) { + errno = ENOEXEC; + return -1; + } + return 0; +} + +/* + * get_txt_records -- + * Given a DNS class and a DNS name, do a lookup for TXT records, and + * return a list of them. + */ +static char ** +get_txt_records(qclass, name) + int qclass; + const char *name; +{ + HEADER *hp; + unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor; + char *dst, **list; + int ancount, qdcount, i, j, n, skip, type, class, len; + + /* Make sure the resolver is initialized. */ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return NULL; + + printf(":::: %d\n", __LINE__); + /* Construct the query. */ + n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0, + NULL, qbuf, PACKETSZ); + if (n < 0) + return NULL; + + printf(":::: %d\n", __LINE__); + /* Send the query. */ + n = res_send(qbuf, n, abuf, MAX_HESRESP); + if (n < 0 || n > MAX_HESRESP) { + printf("%s %d %d %d\n", name, errno, h_errno, n); + errno = ECONNREFUSED; /* XXX */ + return NULL; + } + + printf(":::: %d\n", __LINE__); + /* Parse the header of the result. */ + hp = (HEADER *) (void *) abuf; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + p = abuf + sizeof(HEADER); + eom = abuf + n; + + printf(":::: %d\n", __LINE__); + /* + * Skip questions, trying to get to the answer section + * which follows. + */ + for (i = 0; i < qdcount; i++) { + skip = dn_skipname(p, eom); + if (skip < 0 || p + skip + QFIXEDSZ > eom) { + errno = EMSGSIZE; + return NULL; + } + p += skip + QFIXEDSZ; + } + + printf(":::: %d\n", __LINE__); + /* Allocate space for the text record answers. */ + list = malloc((ancount + 1) * sizeof(char *)); + if (!list) { + errno = ENOMEM; + return NULL; + } + /* Parse the answers. */ + j = 0; + for (i = 0; i < ancount; i++) { + /* Parse the header of this answer. */ + skip = dn_skipname(p, eom); + if (skip < 0 || p + skip + 10 > eom) + break; + type = p[skip + 0] << 8 | p[skip + 1]; + class = p[skip + 2] << 8 | p[skip + 3]; + len = p[skip + 8] << 8 | p[skip + 9]; + p += skip + 10; + if (p + len > eom) { + errno = EMSGSIZE; + break; + } + /* Skip entries of the wrong class and type. */ + if (class != qclass || type != T_TXT) { + p += len; + continue; + } + /* Allocate space for this answer. */ + list[j] = malloc((size_t)len); + if (!list[j]) { + errno = ENOMEM; + break; + } + dst = list[j++]; + + /* Copy answer data into the allocated area. */ + eor = p + len; >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200606291720.k5THKT31096956>