PERFORCE change 100298 for review

Michael Bushkov bushman at FreeBSD.org
Thu Jun 29 17:20:32 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100298

Change 100298 by bushman at 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) <<<


More information about the p4-projects mailing list