summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2014-11-25 09:47:15 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2014-11-25 09:47:15 +0000
commit83804ea07400d96725647571ae0b64a6a728f5bd (patch)
tree7af0b1c9ed178688ccdea34280f37bf58134427e
parent4ab8910605b5d9f4f934fae1181527a169f7f8f4 (diff)
downloadsrc-test2-83804ea07400d96725647571ae0b64a6a728f5bd.tar.gz
src-test2-83804ea07400d96725647571ae0b64a6a728f5bd.zip
Notes
-rw-r--r--lib/libc/net/nsdispatch.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
index c23315cbd108..4de1df3ffd16 100644
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -132,14 +132,17 @@ static void *nss_cache_cycle_prevention_func = NULL;
#endif
/*
- * When this is set to 1, nsdispatch won't use nsswitch.conf
- * but will consult the 'defaults' source list only.
- * NOTE: nested fallbacks (when nsdispatch calls fallback functions,
- * which in turn calls nsdispatch, which should call fallback
- * function) are not supported
+ * We keep track of nsdispatch() nesting depth in dispatch_depth. When a
+ * fallback method is invoked from nsdispatch(), we temporarily set
+ * fallback_depth to the current dispatch depth plus one. Subsequent
+ * calls at that exact depth will run in fallback mode (restricted to the
+ * same source as the call that was handled by the fallback method), while
+ * calls below that depth will be handled normally, allowing fallback
+ * methods to perform arbitrary lookups.
*/
struct fb_state {
- int fb_dispatch;
+ int dispatch_depth;
+ int fallback_depth;
};
static void fb_endstate(void *);
NSS_TLS_HANDLING(fb);
@@ -613,6 +616,7 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
void *mdata;
int isthreaded, serrno, i, result, srclistsize;
struct fb_state *st;
+ int saved_depth;
#ifdef NS_CACHING
nss_cache_data cache_data;
@@ -644,7 +648,8 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
result = NS_UNAVAIL;
goto fin;
}
- if (st->fb_dispatch == 0) {
+ ++st->dispatch_depth;
+ if (st->dispatch_depth > st->fallback_depth) {
dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
string_compare);
fb_method = nss_method_lookup(NSSRC_FALLBACK, database,
@@ -713,12 +718,13 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
break;
} else {
if (fb_method != NULL) {
- st->fb_dispatch = 1;
+ saved_depth = st->fallback_depth;
+ st->fallback_depth = st->dispatch_depth + 1;
va_start(ap, defaults);
result = fb_method(retval,
(void *)srclist[i].name, ap);
va_end(ap);
- st->fb_dispatch = 0;
+ st->fallback_depth = saved_depth;
} else
nss_log(LOG_DEBUG, "%s, %s, %s, not found, "
"and no fallback provided",
@@ -750,6 +756,7 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
if (isthreaded)
(void)_pthread_rwlock_unlock(&nss_lock);
+ --st->dispatch_depth;
fin:
errno = serrno;
return (result);