This isn't particularly elegant or exhaustive, and the maximum recursion depth is purely an arbitrary value, but keeping a per-thread depth count manages to avoid infinite recursion crashes which happen when we hit nesting through nss_ldap->libldap->gethostbyXXX->nss_ldap calls. diff -ur nss_ldap/configure.in nss_ldap/configure.in --- nss_ldap/configure.in 2007-09-20 14:35:18.000000000 -0400 +++ nss_ldap/configure.in 2007-09-20 13:43:49.000000000 -0400 @@ -243,6 +243,17 @@ ], AC_MSG_RESULT(no)) +AC_MSG_CHECKING(for thread-local storage) +AC_TRY_COMPILE([#ifdef HAVE_PTHREAD_H + #include <pthread.h> + #endif], + [static __thread int foo = 1;], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_THREAD_LOCAL_STORAGE,1,[Define if your toolchain supports thread-local storage.]) + ], + AC_MSG_RESULT(no)) + AC_MSG_CHECKING(for socklen_t) AC_TRY_COMPILE([#include <sys/types.h> #include <sys/socket.h>], diff -ur nss_ldap/ldap-nss.c nss_ldap/ldap-nss.c --- nss_ldap-257/ldap-nss.c 2007-09-20 14:35:18.000000000 -0400 +++ nss_ldap-257/ldap-nss.c 2007-09-20 14:33:01.000000000 -0400 @@ -119,6 +120,11 @@ NSS_LDAP_DEFINE_LOCK (__lock); +#ifdef HAVE_THREAD_LOCAL_STORAGE +static __thread int _nss_ldap_init_recursion_depth; +static __thread int _nss_ldap_search_recursion_depth; +#endif + /* * the configuration is read by the first call to do_open(). * Pointers to elements of the list are passed around but should not @@ -1100,6 +1106,19 @@ NSS_STATUS stat; int sd=-1; +#ifdef HAVE_THREAD_LOCAL_STORAGE + if (_nss_ldap_init_recursion_depth > 5) + { + /* the reasoning here is just a guess, but why else? */ + syslog (LOG_ERR, "nss_ldap: unable to connect to DSA without " + "information which may need to be retrieved from the DSA"); + debug ("<=> do_init: recursed too far, failing"); + return NSS_NOTFOUND; + } + + _nss_ldap_init_recursion_depth++; +#endif + debug ("==> do_init"); if (_nss_ldap_validateconfig (__config) != NSS_SUCCESS) @@ -1227,6 +1246,9 @@ if (__session.ls_state == LS_CONNECTED_TO_DSA) { debug ("<== do_init (cached session)"); +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return NSS_SUCCESS; } } @@ -1239,6 +1261,9 @@ if (pthread_once (&__once, do_atfork_setup) != 0) { debug ("<== do_init (pthread_once failed)"); +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return NSS_UNAVAIL; } #elif defined(HAVE_PTHREAD_ATFORK) && ( defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H) ) @@ -1280,6 +1305,9 @@ { debug ("<== do_init (failed to read config)"); __config = NULL; +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return NSS_UNAVAIL; } } @@ -1328,6 +1356,9 @@ && (rc = ldapssl_client_init (cfg->ldc_sslpath, NULL)) != LDAP_SUCCESS) { debug ("<== do_init (ldapssl_client_init failed with rc = %d)", rc); +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return NSS_UNAVAIL; } __ssl_initialized = 1; @@ -1345,6 +1376,9 @@ if (stat != NSS_SUCCESS) { debug ("<== do_init (failed to initialize LDAP session)"); +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return stat; } @@ -1353,6 +1387,9 @@ debug ("<== do_init (initialized session)"); +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_init_recursion_depth--; +#endif return NSS_SUCCESS; } @@ -1660,7 +1697,7 @@ ldap_err2string (rc)); stat = do_map_error (rc); do_close (); - debug ("<== do_open (failed to bind to DSA"); + debug ("<== do_open (failed to bind to DSA)"); } else { @@ -2513,6 +2550,19 @@ NSS_STATUS stat = NSS_UNAVAIL; int maxtries; +#ifdef HAVE_THREAD_LOCAL_STORAGE + if (_nss_ldap_search_recursion_depth > 5) + { + /* the reasoning here is just a guess, but why else? */ + syslog (LOG_ERR, "nss_ldap: unable to connect to DSA without " + "information which may need to be retrieved from the DSA"); + debug ("<=> do_with_reconnect: recursed too far, failing"); + return NSS_NOTFOUND; + } + + _nss_ldap_search_recursion_depth++; +#endif + debug ("==> do_with_reconnect"); /* caller must successfully call do_init() first */ @@ -2621,6 +2671,11 @@ } debug ("<== do_with_reconnect"); + +#ifdef HAVE_THREAD_LOCAL_STORAGE + _nss_ldap_search_recursion_depth--; +#endif + return stat; }