From 23c088919f66de014ee7f9aad407468e51451405 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Apr 30 2012 15:49:04 +0000 Subject: Ticket #348 - crash in ldap_initialize with multiple threads https://fedorahosted.org/389/ticket/348 Resolves: Ticket #348 Bug Description: crash in ldap_initialize with multiple threads Reviewed by: mreynolds (Thanks!) Branch: master Fix Description: Protect calls to ldap_initialize() with a mutex to prevent multiple threads from calling it at the same time. Platforms tested: RHEL6 x86_64 Flag Day: no Doc impact: no --- diff --git a/ldap/servers/slapd/ldaputil.c b/ldap/servers/slapd/ldaputil.c index 545c703..80ab8cb 100644 --- a/ldap/servers/slapd/ldaputil.c +++ b/ldap/servers/slapd/ldaputil.c @@ -99,6 +99,24 @@ #if !defined(USE_OPENLDAP) #include #include +#else +/* need mutex around ldap_initialize - see https://fedorahosted.org/389/ticket/348 */ +static PRCallOnceType ol_init_callOnce = {0,0}; +static PRLock *ol_init_lock = NULL; + +static PRStatus +internal_ol_init_init(void) +{ + PR_ASSERT(NULL == ol_init_lock); + if ((ol_init_lock = PR_NewLock()) == NULL) { + PRErrorCode errorCode = PR_GetError(); + slapi_log_error(SLAPI_LOG_FATAL, "internal_ol_init_init", "PR_NewLock failed %d:%s\n", + errorCode, slapd_pr_strerror(errorCode)); + return PR_FAILURE; + } + + return PR_SUCCESS; +} #endif /* the server depends on the old, deprecated ldap_explode behavior which openldap @@ -737,7 +755,16 @@ slapi_ldap_init_ext( #if defined(USE_OPENLDAP) if (ldapurl) { + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", + "Could not perform internal ol_init init\n"); + rc = -1; + goto done; + } + + PR_Lock(ol_init_lock); rc = ldap_initialize(&ld, ldapurl); + PR_Unlock(ol_init_lock); if (rc) { slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", "Could not initialize LDAP connection to [%s]: %d:%s\n", @@ -751,7 +778,16 @@ slapi_ldap_init_ext( } else { /* host port */ makeurl = convert_to_openldap_uri(hostname, port, (secure == 1 ? "ldaps" : "ldap")); } + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", + "Could not perform internal ol_init init\n"); + rc = -1; + goto done; + } + + PR_Lock(ol_init_lock); rc = ldap_initialize(&ld, makeurl); + PR_Unlock(ol_init_lock); if (rc) { slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", "Could not initialize LDAP connection to [%s]: %d:%s\n", diff --git a/ldap/servers/slapd/tools/ldclt/ldapfct.c b/ldap/servers/slapd/tools/ldclt/ldapfct.c index 0e8a2fb..3f74fd0 100644 --- a/ldap/servers/slapd/tools/ldclt/ldapfct.c +++ b/ldap/servers/slapd/tools/ldclt/ldapfct.c @@ -708,6 +708,23 @@ done: return rc; } + +/* need mutex around ldap_initialize - see https://fedorahosted.org/389/ticket/348 */ +static PRCallOnceType ol_init_callOnce = {0,0}; +static PRLock *ol_init_lock = NULL; + +static PRStatus +internal_ol_init_init(void) +{ + PR_ASSERT(NULL == ol_init_lock); + if ((ol_init_lock = PR_NewLock()) == NULL) { + PRErrorCode errorCode = PR_GetError(); + printf("internal_ol_init_init PR_NewLock failed %d\n", errorCode); + return PR_FAILURE; + } + + return PR_SUCCESS; +} #endif /* USE_OPENLDAP */ /* mctx is a global */ @@ -735,12 +752,20 @@ connectToLDAP(thread_context *tttctx, const char *bufBindDN, const char *bufPass ldapurl = PR_smprintf("ldap%s://%s:%d/", (mode & SSL) ? "s" : "", mctx.hostname, mctx.port); + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + printf("Could not perform internal ol_init init\n"); + goto done; + } + + PR_Lock(ol_init_lock); if ((ret = ldap_initialize(&ld, ldapurl))) { + PR_Unlock(ol_init_lock); printf ("ldclt[%d]: T%03d: Cannot ldap_initialize (%s), errno=%d ldaperror=%d:%s\n", mctx.pid, thrdNum, ldapurl, errno, ret, my_ldap_err2string(ret)); fflush (stdout); goto done; } + PR_Unlock(ol_init_lock); PR_smprintf_free(ldapurl); ldapurl = NULL; if (mode & SSL) { diff --git a/ldap/servers/slapd/tools/rsearch/addthread.c b/ldap/servers/slapd/tools/rsearch/addthread.c index f01ba18..a3e5568 100644 --- a/ldap/servers/slapd/tools/rsearch/addthread.c +++ b/ldap/servers/slapd/tools/rsearch/addthread.c @@ -176,6 +176,25 @@ static void at_disconnect(AddThread *at) } #endif +#if defined(USE_OPENLDAP) +/* need mutex around ldap_initialize - see https://fedorahosted.org/389/ticket/348 */ +static PRCallOnceType ol_init_callOnce = {0,0}; +static PRLock *ol_init_lock = NULL; + +static PRStatus +internal_ol_init_init(void) +{ + PR_ASSERT(NULL == ol_init_lock); + if ((ol_init_lock = PR_NewLock()) == NULL) { + PRErrorCode errorCode = PR_GetError(); + fprintf(stderr, "internal_ol_init_init PR_NewLock failed %d\n", errorCode); + return PR_FAILURE; + } + + return PR_SUCCESS; +} +#endif + static void at_bind(AddThread *at) { int ret; @@ -185,7 +204,14 @@ static void at_bind(AddThread *at) at->ld = NULL; ldapurl = PR_smprintf("ldap://%s:%d", hostname, port); + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + fprintf(stderr, "Could not perform internal ol_init init\n"); + return; + } + + PR_Lock(ol_init_lock); ret = ldap_initialize(&at->ld, ldapurl); + PR_Unlock(ol_init_lock); PR_smprintf_free(ldapurl); ldapurl = NULL; if (ret) { diff --git a/ldap/servers/slapd/tools/rsearch/searchthread.c b/ldap/servers/slapd/tools/rsearch/searchthread.c index 9e2b0d6..8a74d58 100644 --- a/ldap/servers/slapd/tools/rsearch/searchthread.c +++ b/ldap/servers/slapd/tools/rsearch/searchthread.c @@ -180,6 +180,24 @@ static int st_bind_core(SearchThread *st, LDAP **ld, char *dn, char *pw) return 1; } +#if defined(USE_OPENLDAP) +/* need mutex around ldap_initialize - see https://fedorahosted.org/389/ticket/348 */ +static PRCallOnceType ol_init_callOnce = {0,0}; +static PRLock *ol_init_lock = NULL; + +static PRStatus +internal_ol_init_init(void) +{ + PR_ASSERT(NULL == ol_init_lock); + if ((ol_init_lock = PR_NewLock()) == NULL) { + PRErrorCode errorCode = PR_GetError(); + fprintf(stderr, "internal_ol_init_init PR_NewLock failed %d\n", errorCode); + return PR_FAILURE; + } + + return PR_SUCCESS; +} +#endif static int st_bind(SearchThread *st) { if (!st->ld) { @@ -189,7 +207,14 @@ static int st_bind(SearchThread *st) st->ld = NULL; ldapurl = PR_smprintf("ldap://%s:%d", hostname, port); + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + fprintf(stderr, "Could not perform internal ol_init init\n"); + return 0; + } + + PR_Lock(ol_init_lock); ret = ldap_initialize(&st->ld, ldapurl); + PR_Unlock(ol_init_lock); PR_smprintf_free(ldapurl); ldapurl = NULL; if (ret) { @@ -212,7 +237,14 @@ static int st_bind(SearchThread *st) st->ld2 = NULL; ldapurl = PR_smprintf("ldap://%s:%d", hostname, port); + if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) { + fprintf(stderr, "Could not perform internal ol_init init\n"); + return 0; + } + + PR_Lock(ol_init_lock); ret = ldap_initialize(&st->ld2, ldapurl); + PR_Unlock(ol_init_lock); PR_smprintf_free(ldapurl); ldapurl = NULL; if (ret) {