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