From 1c155e2849f9e223ad45a722c994b3a019908d71 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 05 2017 07:18:30 +0000 Subject: import 389-ds-base-1.3.6.1-19.el7_4 --- diff --git a/SOURCES/0056-Ticket-49313-Change-the-retrochangelog-default-cache.patch b/SOURCES/0056-Ticket-49313-Change-the-retrochangelog-default-cache.patch new file mode 100644 index 0000000..c1089ec --- /dev/null +++ b/SOURCES/0056-Ticket-49313-Change-the-retrochangelog-default-cache.patch @@ -0,0 +1,47 @@ +From 0fc3c803c34311eb05c5c7a7e710c8591b592649 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Thu, 27 Jul 2017 18:10:05 +0200 +Subject: [PATCH] Ticket 49313 - Change the retrochangelog default cache size + +Bug Description: + Default retroCL backend entry cache size is 2Mb. + It has been reported in many deployments that DB corruption could + be prevented by increasing entry cache to 200Mb. + There is no identified reproducible steps to debug this DB corruption. + So to prevent this problem we are increasing the entry cache + +Fix Description: + Set default cn=changelog cache to 200Mb (based on production cases) + An other option would be to set a maximum number of entries but + as we do not know if it works to prevent DB corruption, let's prefere + entry cache size + +https://pagure.io/389-ds-base/issue/49313 + +Reviewed by: William Brown + +Platforms tested: F23 + +Flag Day: no + +Doc impact: no +--- + ldap/servers/plugins/retrocl/retrocl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h +index 6963d4b..eef1a17 100644 +--- a/ldap/servers/plugins/retrocl/retrocl.h ++++ b/ldap/servers/plugins/retrocl/retrocl.h +@@ -58,7 +58,7 @@ typedef struct _cnumRet { + #else + #define RETROCL_DLL_DEFAULT_THREAD_STACKSIZE 131072L + #endif +-#define RETROCL_BE_CACHEMEMSIZE "2097152" ++#define RETROCL_BE_CACHEMEMSIZE "209715200" + #define RETROCL_BE_CACHESIZE "-1" + #define RETROCL_PLUGIN_NAME "DSRetroclPlugin" + +-- +2.9.4 + diff --git a/SOURCES/0057-Ticket-49287-v3-extend-csnpl-handling-to-multiple-ba.patch b/SOURCES/0057-Ticket-49287-v3-extend-csnpl-handling-to-multiple-ba.patch new file mode 100644 index 0000000..8a71d55 --- /dev/null +++ b/SOURCES/0057-Ticket-49287-v3-extend-csnpl-handling-to-multiple-ba.patch @@ -0,0 +1,795 @@ +From 6b5aa0e288f1ea5553d4dd5d220d4e5daf50a247 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Mon, 31 Jul 2017 14:45:50 -0400 +Subject: [PATCH] Ticket 49287 - v3 extend csnpl handling to multiple backends + + The csn pending list mechanism failed if internal operation affected multiple backends + + This fix is an extension to the fix in ticket 49008, the thread local data now also contains + a list of all affected replicas. + + http://www.port389.org/docs/389ds/design/csn-pending-lists-and-ruv-update.html + + Reviewed by: William, Thierry - thanks +--- + ldap/servers/plugins/replication/csnpl.c | 85 ++++++++-- + ldap/servers/plugins/replication/csnpl.h | 8 +- + ldap/servers/plugins/replication/repl5.h | 22 ++- + ldap/servers/plugins/replication/repl5_init.c | 48 +++++- + ldap/servers/plugins/replication/repl5_plugins.c | 16 +- + ldap/servers/plugins/replication/repl5_replica.c | 18 ++- + ldap/servers/plugins/replication/repl5_ruv.c | 191 ++++++++++++++--------- + ldap/servers/plugins/replication/repl5_ruv.h | 6 +- + ldap/servers/slapd/slapi-private.h | 2 +- + 9 files changed, 283 insertions(+), 113 deletions(-) + +diff --git a/ldap/servers/plugins/replication/csnpl.c b/ldap/servers/plugins/replication/csnpl.c +index 4a0f5f5..12a0bb8 100644 +--- a/ldap/servers/plugins/replication/csnpl.c ++++ b/ldap/servers/plugins/replication/csnpl.c +@@ -14,7 +14,6 @@ + + #include "csnpl.h" + #include "llist.h" +-#include "repl_shared.h" + + struct csnpl + { +@@ -22,13 +21,17 @@ struct csnpl + Slapi_RWLock* csnLock; /* lock to serialize access to PL */ + }; + ++ + typedef struct _csnpldata + { + PRBool committed; /* True if CSN committed */ + CSN *csn; /* The actual CSN */ ++ Replica * prim_replica; /* The replica where the prom csn was generated */ + const CSN *prim_csn; /* The primary CSN of an operation consising of multiple sub ops*/ + } csnpldata; + ++static PRBool csn_primary_or_nested(csnpldata *csn_data, const CSNPL_CTX *csn_ctx); ++ + /* forward declarations */ + #ifdef DEBUG + static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller); +@@ -104,7 +107,7 @@ void csnplFree (CSNPL **csnpl) + * 1 if the csn has already been seen + * -1 for any other kind of errors + */ +-int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSN *prim_csn) ++int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSNPL_CTX *prim_csn) + { + int rc; + csnpldata *csnplnode; +@@ -129,10 +132,13 @@ int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSN *prim_csn) + return 1; + } + +- csnplnode = (csnpldata *)slapi_ch_malloc(sizeof(csnpldata)); ++ csnplnode = (csnpldata *)slapi_ch_calloc(1, sizeof(csnpldata)); + csnplnode->committed = PR_FALSE; + csnplnode->csn = csn_dup(csn); +- csnplnode->prim_csn = prim_csn; ++ if (prim_csn) { ++ csnplnode->prim_csn = prim_csn->prim_csn; ++ csnplnode->prim_replica = prim_csn->prim_repl; ++ } + csn_as_string(csn, PR_FALSE, csn_str); + rc = llistInsertTail (csnpl->csnList, csn_str, csnplnode); + +@@ -187,8 +193,58 @@ int csnplRemove (CSNPL *csnpl, const CSN *csn) + + return 0; + } ++PRBool csn_primary(Replica *replica, const CSN *csn, const CSNPL_CTX *csn_ctx) ++{ ++ if (csn_ctx == NULL) ++ return PR_FALSE; ++ ++ if (replica != csn_ctx->prim_repl) { ++ /* The CSNs are not from the same replication topology ++ * so even if the csn values are equal they are not related ++ * to the same operation ++ */ ++ return PR_FALSE; ++ } ++ ++ /* Here the two CSNs belong to the same replication topology */ ++ ++ /* check if the CSN identifies the primary update */ ++ if (csn_is_equal(csn, csn_ctx->prim_csn)) { ++ return PR_TRUE; ++ } ++ ++ return PR_FALSE; ++} ++ ++static PRBool csn_primary_or_nested(csnpldata *csn_data, const CSNPL_CTX *csn_ctx) ++{ ++ if ((csn_data == NULL) || (csn_ctx == NULL)) ++ return PR_FALSE; ++ ++ if (csn_data->prim_replica != csn_ctx->prim_repl) { ++ /* The CSNs are not from the same replication topology ++ * so even if the csn values are equal they are not related ++ * to the same operation ++ */ ++ return PR_FALSE; ++ } ++ ++ /* Here the two CSNs belong to the same replication topology */ ++ ++ /* First check if the CSN identifies the primary update */ ++ if (csn_is_equal(csn_data->csn, csn_ctx->prim_csn)) { ++ return PR_TRUE; ++ } ++ ++ /* Second check if the CSN identifies a nested update */ ++ if (csn_is_equal(csn_data->prim_csn, csn_ctx->prim_csn)) { ++ return PR_TRUE; ++ } ++ ++ return PR_FALSE; ++} + +-int csnplRemoveAll (CSNPL *csnpl, const CSN *csn) ++int csnplRemoveAll (CSNPL *csnpl, const CSNPL_CTX *csn_ctx) + { + csnpldata *data; + void *iterator; +@@ -197,8 +253,7 @@ int csnplRemoveAll (CSNPL *csnpl, const CSN *csn) + data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); + while (NULL != data) + { +- if (csn_is_equal(data->csn, csn) || +- csn_is_equal(data->prim_csn, csn)) { ++ if (csn_primary_or_nested(data, csn_ctx)) { + csnpldata_free(&data); + data = (csnpldata *)llistRemoveCurrentAndGetNext(csnpl->csnList, &iterator); + } else { +@@ -213,13 +268,13 @@ int csnplRemoveAll (CSNPL *csnpl, const CSN *csn) + } + + +-int csnplCommitAll (CSNPL *csnpl, const CSN *csn) ++int csnplCommitAll (CSNPL *csnpl, const CSNPL_CTX *csn_ctx) + { + csnpldata *data; + void *iterator; + char csn_str[CSN_STRSIZE]; + +- csn_as_string(csn, PR_FALSE, csn_str); ++ csn_as_string(csn_ctx->prim_csn, PR_FALSE, csn_str); + slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, + "csnplCommitALL: committing all csns for csn %s\n", csn_str); + slapi_rwlock_wrlock (csnpl->csnLock); +@@ -229,8 +284,7 @@ int csnplCommitAll (CSNPL *csnpl, const CSN *csn) + csn_as_string(data->csn, PR_FALSE, csn_str); + slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, + "csnplCommitALL: processing data csn %s\n", csn_str); +- if (csn_is_equal(data->csn, csn) || +- csn_is_equal(data->prim_csn, csn)) { ++ if (csn_primary_or_nested(data, csn_ctx)) { + data->committed = PR_TRUE; + } + data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator); +@@ -395,7 +449,12 @@ static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller) + + /* wrapper around csn_free, to satisfy NSPR thread context API */ + void +-csnplFreeCSN (void *arg) ++csnplFreeCSNPL_CTX (void *arg) + { +- csn_free((CSN **)&arg); ++ CSNPL_CTX *csnpl_ctx = (CSNPL_CTX *)arg; ++ csn_free(&csnpl_ctx->prim_csn); ++ if (csnpl_ctx->sec_repl) { ++ slapi_ch_free((void **)&csnpl_ctx->sec_repl); ++ } ++ slapi_ch_free((void **)&csnpl_ctx); + } +diff --git a/ldap/servers/plugins/replication/csnpl.h b/ldap/servers/plugins/replication/csnpl.h +index 594c8f2..1036c62 100644 +--- a/ldap/servers/plugins/replication/csnpl.h ++++ b/ldap/servers/plugins/replication/csnpl.h +@@ -17,15 +17,17 @@ + #define CSNPL_H + + #include "slapi-private.h" ++#include "repl5.h" + + typedef struct csnpl CSNPL; + + CSNPL* csnplNew(void); + void csnplFree (CSNPL **csnpl); +-int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSN *prim_csn); ++int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSNPL_CTX *prim_csn); + int csnplRemove (CSNPL *csnpl, const CSN *csn); +-int csnplRemoveAll (CSNPL *csnpl, const CSN *csn); +-int csnplCommitAll (CSNPL *csnpl, const CSN *csn); ++int csnplRemoveAll (CSNPL *csnpl, const CSNPL_CTX *csn_ctx); ++int csnplCommitAll (CSNPL *csnpl, const CSNPL_CTX *csn_ctx); ++PRBool csn_primary(Replica *replica, const CSN *csn, const CSNPL_CTX *csn_ctx); + CSN* csnplGetMinCSN (CSNPL *csnpl, PRBool *committed); + int csnplCommit (CSNPL *csnpl, const CSN *csn); + CSN *csnplRollUp(CSNPL *csnpl, CSN ** first); +diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h +index 1d8989c..718f64e 100644 +--- a/ldap/servers/plugins/replication/repl5.h ++++ b/ldap/servers/plugins/replication/repl5.h +@@ -228,12 +228,27 @@ int multimaster_be_betxnpostop_delete (Slapi_PBlock *pb); + int multimaster_be_betxnpostop_add (Slapi_PBlock *pb); + int multimaster_be_betxnpostop_modify (Slapi_PBlock *pb); + ++/* In repl5_replica.c */ ++typedef struct replica Replica; ++ ++/* csn pending lists */ ++#define CSNPL_CTX_REPLCNT 4 ++typedef struct CSNPL_CTX ++{ ++ CSN *prim_csn; ++ size_t repl_alloc; /* max number of replicas */ ++ size_t repl_cnt; /* number of replicas affected by operation */ ++ Replica *prim_repl; /* pirmary replica */ ++ Replica **sec_repl; /* additional replicas affected */ ++} CSNPL_CTX; ++ + /* In repl5_init.c */ + extern int repl5_is_betxn; + char* get_thread_private_agmtname(void); + void set_thread_private_agmtname (const char *agmtname); +-void set_thread_primary_csn (const CSN *prim_csn); +-CSN* get_thread_primary_csn(void); ++void set_thread_primary_csn (const CSN *prim_csn, Replica *repl); ++void add_replica_to_primcsn(CSNPL_CTX *prim_csn, Replica *repl); ++CSNPL_CTX* get_thread_primary_csn(void); + void* get_thread_private_cache(void); + void set_thread_private_cache (void *buf); + char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn); +@@ -302,7 +317,6 @@ typedef struct repl_bos Repl_Bos; + + /* In repl5_agmt.c */ + typedef struct repl5agmt Repl_Agmt; +-typedef struct replica Replica; + + #define TRANSPORT_FLAG_SSL 1 + #define TRANSPORT_FLAG_TLS 2 +@@ -629,6 +643,8 @@ PRUint64 replica_get_precise_purging(Replica *r); + void replica_set_precise_purging(Replica *r, PRUint64 on_off); + PRBool ignore_error_and_keep_going(int error); + void replica_check_release_timeout(Replica *r, Slapi_PBlock *pb); ++void replica_lock_replica(Replica *r); ++void replica_unlock_replica(Replica *r); + + /* The functions below handles the state flag */ + /* Current internal state flags */ +diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c +index edffb84..b0bc515 100644 +--- a/ldap/servers/plugins/replication/repl5_init.c ++++ b/ldap/servers/plugins/replication/repl5_init.c +@@ -154,26 +154,62 @@ set_thread_private_agmtname(const char *agmtname) + PR_SetThreadPrivate(thread_private_agmtname, (void *)agmtname); + } + +-CSN* ++CSNPL_CTX* + get_thread_primary_csn(void) + { +- CSN *prim_csn = NULL; ++ CSNPL_CTX *prim_csn = NULL; + if (thread_primary_csn) +- prim_csn = (CSN *)PR_GetThreadPrivate(thread_primary_csn); ++ prim_csn = (CSNPL_CTX *)PR_GetThreadPrivate(thread_primary_csn); ++ + return prim_csn; + } + void +-set_thread_primary_csn(const CSN *prim_csn) ++set_thread_primary_csn (const CSN *prim_csn, Replica *repl) + { + if (thread_primary_csn) { + if (prim_csn) { +- PR_SetThreadPrivate(thread_primary_csn, (void *)csn_dup(prim_csn)); ++ CSNPL_CTX *csnpl_ctx = (CSNPL_CTX *)slapi_ch_calloc(1,sizeof(CSNPL_CTX)); ++ csnpl_ctx->prim_csn = csn_dup(prim_csn); ++ /* repl_alloc, repl_cnt and sec_repl are 0 by calloc */ ++ csnpl_ctx->prim_repl = repl; ++ PR_SetThreadPrivate(thread_primary_csn, (void *)csnpl_ctx); + } else { + PR_SetThreadPrivate(thread_primary_csn, NULL); + } + } + } + ++void ++add_replica_to_primcsn(CSNPL_CTX *csnpl_ctx, Replica *repl) ++{ ++ size_t found = 0; ++ size_t it = 0; ++ ++ if (repl == csnpl_ctx->prim_repl) return; ++ ++ while (it < csnpl_ctx->repl_cnt) { ++ if (csnpl_ctx->sec_repl[it] == repl) { ++ found = 1; ++ break; ++ } ++ it++; ++ } ++ if (found) return; ++ ++ if (csnpl_ctx->repl_cnt < csnpl_ctx->repl_alloc) { ++ csnpl_ctx->sec_repl[csnpl_ctx->repl_cnt++] = repl; ++ return; ++ } ++ csnpl_ctx->repl_alloc += CSNPL_CTX_REPLCNT; ++ if (csnpl_ctx->repl_cnt == 0) { ++ csnpl_ctx->sec_repl = (Replica **)slapi_ch_calloc(csnpl_ctx->repl_alloc, sizeof(Replica *)); ++ } else { ++ csnpl_ctx->sec_repl = (Replica **)slapi_ch_realloc((char *)csnpl_ctx->sec_repl, csnpl_ctx->repl_alloc * sizeof(Replica *)); ++ } ++ csnpl_ctx->sec_repl[csnpl_ctx->repl_cnt++] = repl; ++ return; ++} ++ + void* + get_thread_private_cache () + { +@@ -740,7 +776,7 @@ multimaster_start( Slapi_PBlock *pb ) + /* Initialize thread private data for logging. Ignore if fails */ + PR_NewThreadPrivateIndex (&thread_private_agmtname, NULL); + PR_NewThreadPrivateIndex (&thread_private_cache, NULL); +- PR_NewThreadPrivateIndex (&thread_primary_csn, csnplFreeCSN); ++ PR_NewThreadPrivateIndex (&thread_primary_csn, csnplFreeCSNPL_CTX); + + /* Decode the command line args to see if we're dumping to LDIF */ + is_ldif_dump = check_for_ldif_dump(pb); +diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c +index 9ef06af..c31d9d5 100644 +--- a/ldap/servers/plugins/replication/repl5_plugins.c ++++ b/ldap/servers/plugins/replication/repl5_plugins.c +@@ -45,6 +45,7 @@ + #include "repl.h" + #include "cl5_api.h" + #include "urp.h" ++#include "csnpl.h" + + static char *local_purl = NULL; + static char *purl_attrs[] = {"nsslapd-localhost", "nsslapd-port", "nsslapd-secureport", NULL}; +@@ -1034,7 +1035,7 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + { + Slapi_Operation *op = NULL; + CSN *opcsn; +- CSN *prim_csn; ++ CSNPL_CTX *prim_csn; + int rc; + slapi_operation_parameters *op_params = NULL; + Object *repl_obj = NULL; +@@ -1070,14 +1071,15 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + if (repl_obj == NULL) + return return_value; + ++ r = (Replica*)object_get_data (repl_obj); ++ PR_ASSERT (r); ++ + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc); + if (rc) { /* op failed - just return */ + cancel_opcsn(pb); + goto common_return; + } + +- r = (Replica*)object_get_data (repl_obj); +- PR_ASSERT (r); + + replica_check_release_timeout(r, pb); + +@@ -1223,12 +1225,12 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + common_return: + opcsn = operation_get_csn(op); + prim_csn = get_thread_primary_csn(); +- if (csn_is_equal(opcsn, prim_csn)) { ++ if (csn_primary(r, opcsn, prim_csn)) { + if (return_value == 0) { + /* the primary csn was succesfully committed + * unset it in the thread local data + */ +- set_thread_primary_csn(NULL); ++ set_thread_primary_csn(NULL, NULL); + } + } + if (repl_obj) { +@@ -1430,7 +1432,7 @@ cancel_opcsn (Slapi_PBlock *pb) + + ruv_obj = replica_get_ruv (r); + PR_ASSERT (ruv_obj); +- ruv_cancel_csn_inprogress ((RUV*)object_get_data (ruv_obj), opcsn, replica_get_rid(r)); ++ ruv_cancel_csn_inprogress (r, (RUV*)object_get_data (ruv_obj), opcsn, replica_get_rid(r)); + object_release (ruv_obj); + } + +@@ -1491,7 +1493,7 @@ process_operation (Slapi_PBlock *pb, const CSN *csn) + ruv = (RUV*)object_get_data (ruv_obj); + PR_ASSERT (ruv); + +- rc = ruv_add_csn_inprogress (ruv, csn); ++ rc = ruv_add_csn_inprogress (r, ruv, csn); + + object_release (ruv_obj); + object_release (r_obj); +diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c +index 1bdc138..7927ac3 100644 +--- a/ldap/servers/plugins/replication/repl5_replica.c ++++ b/ldap/servers/plugins/replication/repl5_replica.c +@@ -923,7 +923,7 @@ replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl) + } + } + /* Update max csn for local and remote replicas */ +- rc = ruv_update_ruv (ruv, updated_csn, replica_purl, r->repl_rid); ++ rc = ruv_update_ruv (ruv, updated_csn, replica_purl, r, r->repl_rid); + if (RUV_COVERS_CSN == rc) + { + slapi_log_err(SLAPI_LOG_REPL, +@@ -3663,7 +3663,7 @@ assign_csn_callback(const CSN *csn, void *data) + } + } + +- ruv_add_csn_inprogress (ruv, csn); ++ ruv_add_csn_inprogress (r, ruv, csn); + + replica_unlock(r->repl_lock); + +@@ -3692,13 +3692,13 @@ abort_csn_callback(const CSN *csn, void *data) + { + int rc = csnplRemove(r->min_csn_pl, csn); + if (rc) { +- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "abort_csn_callback - csnplRemove failed"); ++ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "abort_csn_callback - csnplRemove failed\n"); + replica_unlock(r->repl_lock); + return; + } + } + +- ruv_cancel_csn_inprogress (ruv, csn, replica_get_rid(r)); ++ ruv_cancel_csn_inprogress (r, ruv, csn, replica_get_rid(r)); + replica_unlock(r->repl_lock); + + object_release (ruv_obj); +@@ -4489,3 +4489,13 @@ replica_check_release_timeout(Replica *r, Slapi_PBlock *pb) + } + replica_unlock(r->repl_lock); + } ++void ++replica_lock_replica(Replica *r) ++{ ++ replica_lock(r->repl_lock); ++} ++void ++replica_unlock_replica(Replica *r) ++{ ++ replica_unlock(r->repl_lock); ++} +diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c +index d59e6d2..39449b6 100644 +--- a/ldap/servers/plugins/replication/repl5_ruv.c ++++ b/ldap/servers/plugins/replication/repl5_ruv.c +@@ -77,7 +77,7 @@ static char *get_replgen_from_berval(const struct berval *bval); + static const char * const prefix_replicageneration = "{replicageneration}"; + static const char * const prefix_ruvcsn = "{replica "; /* intentionally missing '}' */ + +-static int ruv_update_ruv_element (RUV *ruv, RUVElement *replica, const CSN *csn, const char *replica_purl, PRBool isLocal); ++static int ruv_update_ruv_element (RUV *ruv, RUVElement *replica, const CSNPL_CTX *prim_csn, const char *replica_purl, PRBool isLocal); + + /* API implementation */ + +@@ -1599,13 +1599,13 @@ ruv_dump(const RUV *ruv, char *ruv_name, PRFileDesc *prFile) + + /* this function notifies the ruv that there are operations in progress so that + they can be added to the pending list for the appropriate client. */ +-int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn) ++int ruv_add_csn_inprogress (void *repl, RUV *ruv, const CSN *csn) + { + RUVElement* replica; + char csn_str[CSN_STRSIZE]; + int rc = RUV_SUCCESS; + int rid = csn_get_replicaid (csn); +- CSN *prim_csn; ++ CSNPL_CTX *prim_csn; + + PR_ASSERT (ruv && csn); + +@@ -1645,8 +1645,13 @@ int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn) + } + prim_csn = get_thread_primary_csn(); + if (prim_csn == NULL) { +- set_thread_primary_csn(csn); ++ set_thread_primary_csn(csn, (Replica *)repl); + prim_csn = get_thread_primary_csn(); ++ } else { ++ /* the prim csn data already exist, need to check if ++ * current replica is already present ++ */ ++ add_replica_to_primcsn(prim_csn, (Replica *)repl); + } + rc = csnplInsert (replica->csnpl, csn, prim_csn); + if (rc == 1) /* we already seen this csn */ +@@ -1656,7 +1661,7 @@ int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn) + "The csn %s has already be seen - ignoring\n", + csn_as_string (csn, PR_FALSE, csn_str)); + } +- set_thread_primary_csn(NULL); ++ set_thread_primary_csn(NULL, NULL); + rc = RUV_COVERS_CSN; + } + else if(rc != 0) +@@ -1681,11 +1686,13 @@ done: + return rc; + } + +-int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn, ReplicaId local_rid) ++int ruv_cancel_csn_inprogress (void *repl, RUV *ruv, const CSN *csn, ReplicaId local_rid) + { +- RUVElement* replica; ++ RUVElement* repl_ruv; + int rc = RUV_SUCCESS; +- CSN *prim_csn = NULL; ++ CSNPL_CTX *prim_csn = NULL; ++ Replica *repl_it; ++ size_t it; + + + PR_ASSERT (ruv && csn); +@@ -1693,29 +1700,53 @@ int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn, ReplicaId local_rid) + prim_csn = get_thread_primary_csn(); + /* locate ruvElement */ + slapi_rwlock_wrlock (ruv->lock); +- replica = ruvGetReplica (ruv, csn_get_replicaid (csn)); +- if (replica == NULL) { ++ repl_ruv = ruvGetReplica (ruv, csn_get_replicaid (csn)); ++ if (repl_ruv == NULL) { + /* ONREPL - log error */ + rc = RUV_NOTFOUND; + goto done; + } +- if (csn_is_equal(csn, prim_csn)) { +- /* the prim csn is cancelled, lets remove all dependent csns */ +- ReplicaId prim_rid = csn_get_replicaid (csn); +- replica = ruvGetReplica (ruv, prim_rid); +- rc = csnplRemoveAll (replica->csnpl, prim_csn); +- if (prim_rid != local_rid) { +- if( local_rid != READ_ONLY_REPLICA_ID) { +- replica = ruvGetReplica (ruv, local_rid); +- if (replica) { +- rc = csnplRemoveAll (replica->csnpl, prim_csn); +- } else { +- rc = RUV_NOTFOUND; +- } +- } +- } ++ if (csn_primary(repl, csn, prim_csn)) { ++ /* the prim csn is cancelled, lets remove all dependent csns */ ++ /* for the primary replica we can have modifications for two RIDS: ++ * - the local RID for direct or internal operations ++ * - a remote RID if the primary csn is for a replciated op. ++ */ ++ ReplicaId prim_rid = csn_get_replicaid(csn); ++ repl_ruv = ruvGetReplica(ruv, prim_rid); ++ if (!repl_ruv) { ++ rc = RUV_NOTFOUND; ++ goto done; ++ } ++ rc = csnplRemoveAll(repl_ruv->csnpl, prim_csn); ++ ++ if (prim_rid != local_rid && local_rid != READ_ONLY_REPLICA_ID) { ++ repl_ruv = ruvGetReplica(ruv, local_rid); ++ if (!repl_ruv) { ++ rc = RUV_NOTFOUND; ++ goto done; ++ } ++ rc = csnplRemoveAll(repl_ruv->csnpl, prim_csn); ++ } ++ ++ for (it = 0; it < prim_csn->repl_cnt; it++) { ++ repl_it = prim_csn->sec_repl[it]; ++ replica_lock_replica(repl_it); ++ local_rid = replica_get_rid(repl_it); ++ if (local_rid != READ_ONLY_REPLICA_ID) { ++ Object *ruv_obj = replica_get_ruv(repl_it); ++ RUV *ruv_it = object_get_data(ruv_obj); ++ repl_ruv = ruvGetReplica(ruv_it, local_rid); ++ if (repl_ruv) { ++ rc = csnplRemoveAll(repl_ruv->csnpl, prim_csn); ++ } else { ++ rc = RUV_NOTFOUND; ++ } ++ } ++ replica_unlock_replica(repl_it); ++ } + } else { +- rc = csnplRemove (replica->csnpl, csn); ++ rc = csnplRemove (repl_ruv->csnpl, csn); + } + if (rc != 0) + rc = RUV_NOTFOUND; +@@ -1727,86 +1758,100 @@ done: + return rc; + } + +-int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, ReplicaId local_rid) ++int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, void *replica, ReplicaId local_rid) + { + int rc=RUV_SUCCESS; +- RUVElement *replica; ++ RUVElement *repl_ruv; + ReplicaId prim_rid; ++ Replica *repl_it = NULL; ++ size_t it = 0; + +- CSN *prim_csn = get_thread_primary_csn(); ++ CSNPL_CTX *prim_csn = get_thread_primary_csn(); + +- if (! csn_is_equal(csn, prim_csn)) { ++ if (! csn_primary(replica, csn, prim_csn)) { + /* not a primary csn, nothing to do */ + return rc; + } +- slapi_rwlock_wrlock (ruv->lock); ++ ++ /* first handle primary replica ++ * there can be two ruv elements affected ++ */ + prim_rid = csn_get_replicaid (csn); +- replica = ruvGetReplica (ruv, local_rid); +- rc = ruv_update_ruv_element(ruv, replica, csn, replica_purl, PR_TRUE); +- if ( rc || local_rid == prim_rid) goto done; +- replica = ruvGetReplica (ruv, prim_rid); +- rc = ruv_update_ruv_element(ruv, replica, csn, replica_purl, PR_FALSE); +-done: ++ slapi_rwlock_wrlock (ruv->lock); ++ if ( local_rid != prim_rid) { ++ repl_ruv = ruvGetReplica (ruv, prim_rid); ++ rc = ruv_update_ruv_element(ruv, repl_ruv, prim_csn, replica_purl, PR_FALSE); ++ } ++ repl_ruv = ruvGetReplica (ruv, local_rid); ++ rc = ruv_update_ruv_element(ruv, repl_ruv, prim_csn, replica_purl, PR_TRUE); + slapi_rwlock_unlock (ruv->lock); ++ if (rc) return rc; ++ ++ /* now handle secondary replicas */ ++ for (it=0; itrepl_cnt; it++) { ++ repl_it = prim_csn->sec_repl[it]; ++ replica_lock_replica(repl_it); ++ Object *ruv_obj = replica_get_ruv (repl_it); ++ RUV *ruv_it = object_get_data (ruv_obj); ++ slapi_rwlock_wrlock (ruv_it->lock); ++ repl_ruv = ruvGetReplica (ruv_it, replica_get_rid(repl_it)); ++ rc = ruv_update_ruv_element(ruv_it, repl_ruv, prim_csn, replica_purl, PR_TRUE); ++ slapi_rwlock_unlock (ruv_it->lock); ++ replica_unlock_replica(repl_it); ++ if (rc) break; ++ } + return rc; + } ++ + static int +-ruv_update_ruv_element (RUV *ruv, RUVElement *replica, const CSN *csn, const char *replica_purl, PRBool isLocal) ++ruv_update_ruv_element (RUV *ruv, RUVElement *replica, const CSNPL_CTX *prim_csn, const char *replica_purl, PRBool isLocal) + { + int rc=RUV_SUCCESS; + char csn_str[CSN_STRSIZE]; + CSN *max_csn; + CSN *first_csn = NULL; + +- if (replica == NULL) +- { ++ if (replica == NULL) { + /* we should have a ruv element at this point because it would have + been added by ruv_add_inprogress function */ + slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv - " +- "Can't locate RUV element for replica %d\n", csn_get_replicaid (csn)); ++ "Can't locate RUV element for replica %d\n", csn_get_replicaid (prim_csn->prim_csn)); + goto done; + } + +- if (csnplCommitAll(replica->csnpl, csn) != 0) +- { +- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "ruv_update_ruv - Cannot commit csn %s\n", +- csn_as_string(csn, PR_FALSE, csn_str)); ++ if (csnplCommitAll(replica->csnpl, prim_csn) != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "ruv_update_ruv - Cannot commit csn %s\n", ++ csn_as_string(prim_csn->prim_csn, PR_FALSE, csn_str)); + rc = RUV_CSNPL_ERROR; + goto done; +- } +- else +- { ++ } else { + if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) { + slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv - " +- "Successfully committed csn %s\n", csn_as_string(csn, PR_FALSE, csn_str)); ++ "Successfully committed csn %s\n", csn_as_string(prim_csn->prim_csn, PR_FALSE, csn_str)); + } + } + +- if ((max_csn = csnplRollUp(replica->csnpl, &first_csn)) != NULL) +- { +-#ifdef DEBUG +- slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv - Rolled up to csn %s\n", +- csn_as_string(max_csn, PR_FALSE, csn_str)); /* XXXggood remove debugging */ +-#endif ++ if ((max_csn = csnplRollUp(replica->csnpl, &first_csn)) != NULL) { ++ slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv - Rolled up to csn %s\n", ++ csn_as_string(max_csn, PR_FALSE, csn_str)); /* XXXggood remove debugging */ + /* replica object sets min csn for local replica */ +- if (!isLocal && replica->min_csn == NULL) { +- /* bug 559223 - it seems that, under huge stress, a server might pass +- * through this code when more than 1 change has already been sent and commited into +- * the pending lists... Therefore, as we are trying to set the min_csn ever +- * generated by this replica, we need to set the first_csn as the min csn in the +- * ruv */ +- set_min_csn_nolock(ruv, first_csn, replica_purl); +- } +- /* only update the max_csn in the RUV if it is greater than the existing one */ +- rc = set_max_csn_nolock_ext(ruv, max_csn, replica_purl, PR_TRUE /* must be greater */); +- /* It is possible that first_csn points to max_csn. +- We need to free it once */ +- if (max_csn != first_csn) { +- csn_free(&first_csn); +- } +- csn_free(&max_csn); +- } +- ++ if (!isLocal && replica->min_csn == NULL) { ++ /* bug 559223 - it seems that, under huge stress, a server might pass ++ * through this code when more than 1 change has already been sent and commited into ++ * the pending lists... Therefore, as we are trying to set the min_csn ever ++ * generated by this replica, we need to set the first_csn as the min csn in the ++ * ruv */ ++ set_min_csn_nolock(ruv, first_csn, replica_purl); ++ } ++ /* only update the max_csn in the RUV if it is greater than the existing one */ ++ rc = set_max_csn_nolock_ext(ruv, max_csn, replica_purl, PR_TRUE /* must be greater */); ++ /* It is possible that first_csn points to max_csn. ++ We need to free it once */ ++ if (max_csn != first_csn) { ++ csn_free(&first_csn); ++ } ++ csn_free(&max_csn); ++ } + done: + + return rc; +diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h +index c8960fd..f3cd38b 100644 +--- a/ldap/servers/plugins/replication/repl5_ruv.h ++++ b/ldap/servers/plugins/replication/repl5_ruv.h +@@ -108,9 +108,9 @@ int ruv_to_bervals(const RUV *ruv, struct berval ***bvals); + PRInt32 ruv_replica_count (const RUV *ruv); + char **ruv_get_referrals(const RUV *ruv); + void ruv_dump(const RUV *ruv, char *ruv_name, PRFileDesc *prFile); +-int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn); +-int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn, ReplicaId rid); +-int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, ReplicaId local_rid); ++int ruv_add_csn_inprogress (void *repl, RUV *ruv, const CSN *csn); ++int ruv_cancel_csn_inprogress (void *repl, RUV *ruv, const CSN *csn, ReplicaId rid); ++int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, void *replica, ReplicaId local_rid); + int ruv_move_local_supplier_to_first(RUV *ruv, ReplicaId rid); + int ruv_get_first_id_and_purl(RUV *ruv, ReplicaId *rid, char **replica_purl ); + int ruv_local_contains_supplier(RUV *ruv, ReplicaId rid); +diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h +index 0836d66..3910dbe 100644 +--- a/ldap/servers/slapd/slapi-private.h ++++ b/ldap/servers/slapd/slapi-private.h +@@ -193,7 +193,7 @@ const CSN *csn_max(const CSN *csn1,const CSN *csn2); + a csn from the set.*/ + int csn_increment_subsequence (CSN *csn); + +-void csnplFreeCSN (void *arg); ++void csnplFreeCSNPL_CTX (void *arg); + /* + * csnset.c + */ +-- +2.9.4 + diff --git a/SOURCES/0058-Ticket-49336-SECURITY-Locked-account-provides-differ.patch b/SOURCES/0058-Ticket-49336-SECURITY-Locked-account-provides-differ.patch new file mode 100644 index 0000000..c110f0a --- /dev/null +++ b/SOURCES/0058-Ticket-49336-SECURITY-Locked-account-provides-differ.patch @@ -0,0 +1,201 @@ +From 95b39e29361812a62f2e038c89a88d717c82794e Mon Sep 17 00:00:00 2001 +From: William Brown +Date: Mon, 31 Jul 2017 14:13:49 +1000 +Subject: [PATCH] Ticket 49336 - SECURITY: Locked account provides different + return code + +Bug Description: The directory server password lockout policy prevents binds + from operating once a threshold of failed passwords has been met. During + this lockout, if you bind with a successful password, a different error code + is returned. This means that an attacker has no ratelimit or penalty during + an account lock, and can continue to attempt passwords via bruteforce, using + the change in return code to ascertain a sucessful password auth. + +Fix Description: Move the account lock check *before* the password bind +check. If the account is locked, we do not mind disclosing this as the +attacker will either ignore it (and will not bind anyway), or they will +be forced to back off as the attack is not working preventing the +bruteforce. + +https://pagure.io/389-ds-base/issue/49336 + +Author: wibrown + +Review by: tbordaz (Thanks!) + +Signed-off-by: Mark Reynolds +--- + .../suites/password/pwd_lockout_bypass_test.py | 55 ++++++++++++++++++++++ + ldap/servers/slapd/bind.c | 29 ++++++++---- + ldap/servers/slapd/pw_verify.c | 15 +++--- + 3 files changed, 84 insertions(+), 15 deletions(-) + create mode 100644 dirsrvtests/tests/suites/password/pwd_lockout_bypass_test.py + +diff --git a/dirsrvtests/tests/suites/password/pwd_lockout_bypass_test.py b/dirsrvtests/tests/suites/password/pwd_lockout_bypass_test.py +new file mode 100644 +index 0000000..e4add72 +--- /dev/null ++++ b/dirsrvtests/tests/suites/password/pwd_lockout_bypass_test.py +@@ -0,0 +1,55 @@ ++# --- BEGIN COPYRIGHT BLOCK --- ++# Copyright (C) 2017 Red Hat, Inc. ++# All rights reserved. ++# ++# License: GPL (version 3 or any later version). ++# See LICENSE for details. ++# --- END COPYRIGHT BLOCK --- ++# ++import pytest ++from lib389.tasks import * ++from lib389.utils import * ++from lib389.topologies import topology_st ++from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES ++import ldap ++ ++# The irony of these names is not lost on me. ++GOOD_PASSWORD = 'password' ++BAD_PASSWORD = 'aontseunao' ++ ++logging.getLogger(__name__).setLevel(logging.INFO) ++log = logging.getLogger(__name__) ++ ++def test_lockout_bypass(topology_st): ++ inst = topology_st.standalone ++ ++ # Configure the lock policy ++ inst.config.set('passwordMaxFailure', '1') ++ inst.config.set('passwordLockoutDuration', '99999') ++ inst.config.set('passwordLockout', 'on') ++ ++ # Create the account ++ users = UserAccounts(inst, DEFAULT_SUFFIX) ++ testuser = users.create(properties=TEST_USER_PROPERTIES) ++ testuser.set('userPassword', GOOD_PASSWORD) ++ ++ conn = testuser.bind(GOOD_PASSWORD) ++ assert conn != None ++ conn.unbind_s() ++ ++ # Bind with bad creds twice ++ # This is the failure. ++ with pytest.raises(ldap.INVALID_CREDENTIALS): ++ conn = testuser.bind(BAD_PASSWORD) ++ # Now we should not be able to ATTEMPT the bind. It doesn't matter that ++ # we disclose that we have hit the rate limit here, what matters is that ++ # it exists. ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ conn = testuser.bind(BAD_PASSWORD) ++ ++ # now bind with good creds ++ # Should be error 19 still. ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ conn = testuser.bind(GOOD_PASSWORD) ++ ++ +diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c +index 7f4414f..064ace1 100644 +--- a/ldap/servers/slapd/bind.c ++++ b/ldap/servers/slapd/bind.c +@@ -662,12 +662,14 @@ do_bind( Slapi_PBlock *pb ) + /* We could be serving multiple database backends. Select the appropriate one */ + /* pw_verify_be_dn will select the backend we need for us. */ + +- if (auto_bind) { +- /* We have no password material. We should just check who we are binding as. */ +- rc = pw_validate_be_dn(pb, &referral); +- } else { +- rc = pw_verify_be_dn(pb, &referral); +- } ++ /* ++ * WARNING: We have to validate *all* other conditions *first* before ++ * we attempt the bind! ++ * ++ * this is because ldbm_bind.c will SEND THE FAILURE. ++ */ ++ ++ rc = pw_validate_be_dn(pb, &referral); + + if (rc == SLAPI_BIND_NO_BACKEND) { + send_nobackend_ldap_result( pb ); +@@ -736,8 +738,18 @@ do_bind( Slapi_PBlock *pb ) + myrc = 0; + } + if (!auto_bind) { +- /* +- * There could be a race that bind_target_entry was not added ++ /* ++ * Okay, we've made it here. FINALLY check if the entry really ++ * can bind or not. THIS IS THE PASSWORD CHECK. ++ */ ++ rc = pw_verify_be_dn(pb, &referral); ++ if (rc != SLAPI_BIND_SUCCESS) { ++ /* Invalid pass - lets bail ... */ ++ goto bind_failed; ++ } ++ ++ /* ++ * There could be a race that bind_target_entry was not added + * when bind_target_entry was retrieved before be_bind, but it + * was in be_bind. Since be_bind returned SLAPI_BIND_SUCCESS, + * the entry is in the DS. So, we need to retrieve it once more. +@@ -786,6 +798,7 @@ do_bind( Slapi_PBlock *pb ) + } + } + } else { /* if auto_bind || rc == slapi_bind_success | slapi_bind_anonymous */ ++ bind_failed: + if (rc == LDAP_OPERATIONS_ERROR) { + send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL ); + goto free_and_return; +diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c +index 852b027..cb182ed 100644 +--- a/ldap/servers/slapd/pw_verify.c ++++ b/ldap/servers/slapd/pw_verify.c +@@ -55,7 +55,7 @@ pw_verify_root_dn(const char *dn, const Slapi_Value *cred) + int + pw_verify_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + { +- int rc = 0; ++ int rc = SLAPI_BIND_SUCCESS; + Slapi_Backend *be = NULL; + + if (slapi_mapping_tree_select(pb, &be, referral, NULL, 0) != LDAP_SUCCESS) { +@@ -109,14 +109,10 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &cred); + slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method); + +- if (pb_sdn != NULL || cred != NULL) { ++ if (pb_sdn == NULL) { + return LDAP_OPERATIONS_ERROR; + } + +- if (*referral) { +- return SLAPI_BIND_REFERRAL; +- } +- + /* We need a slapi_sdn_isanon? */ + if (method == LDAP_AUTH_SIMPLE && cred->bv_len == 0) { + return SLAPI_BIND_ANONYMOUS; +@@ -130,7 +126,11 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + if (slapi_mapping_tree_select(pb, &be, referral, NULL, 0) != LDAP_SUCCESS) { + return SLAPI_BIND_NO_BACKEND; + } +- slapi_be_Unlock(be); ++ ++ if (*referral) { ++ slapi_be_Unlock(be); ++ return SLAPI_BIND_REFERRAL; ++ } + + slapi_pblock_set(pb, SLAPI_BACKEND, be); + slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database); +@@ -138,6 +138,7 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + set_db_default_result_handlers(pb); + + /* The backend associated with this identity is real. */ ++ slapi_be_Unlock(be); + + return SLAPI_BIND_SUCCESS; + } +-- +2.9.4 + diff --git a/SOURCES/0059-Ticket-49298-force-sync-on-shutdown.patch b/SOURCES/0059-Ticket-49298-force-sync-on-shutdown.patch new file mode 100644 index 0000000..4d900fb --- /dev/null +++ b/SOURCES/0059-Ticket-49298-force-sync-on-shutdown.patch @@ -0,0 +1,177 @@ +From ba30cc562f5ebd58955502a19edbf9720a45b655 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 8 Aug 2017 13:02:53 -0400 +Subject: [PATCH] Ticket 49298 - force sync() on shutdown + + Bug Description: During shutdown on xfs we would occasionally + see a broke dse.ldif (specifically, empty). This happens due to + a bug in xfs where the directory isn't synced on rename(). + + Fix Description: As we shutdown call sync() to force all our + writes to disk - dse.ldif, logs, db, all of it. + + https://pagure.io/389-ds-base/issue/49298 +--- + ldap/servers/slapd/dse.c | 59 +++++++++++++++++++++++++++++------------------ + ldap/servers/slapd/main.c | 9 ++++---- + 2 files changed, 42 insertions(+), 26 deletions(-) + +diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c +index 5715c83..fa1aacc 100644 +--- a/ldap/servers/slapd/dse.c ++++ b/ldap/servers/slapd/dse.c +@@ -40,6 +40,8 @@ + #include "slap.h" + #include + ++#include /* provides fsync/close */ ++ + /* #define SLAPI_DSE_DEBUG */ /* define this to force trace log */ + /* messages to always be logged */ + +@@ -72,11 +74,11 @@ + struct dse_callback + { + int operation; +- int flags; +- Slapi_DN *base; +- int scope; +- char *filter; /* NULL means match all entries */ +- Slapi_Filter *slapifilter; /* NULL means match all entries */ ++ int flags; ++ Slapi_DN *base; ++ int scope; ++ char *filter; /* NULL means match all entries */ ++ Slapi_Filter *slapifilter; /* NULL means match all entries */ + int (*fn)(Slapi_PBlock *,Slapi_Entry *,Slapi_Entry *,int*,char*,void *); + void *fn_arg; + struct slapdplugin *plugin; +@@ -89,13 +91,14 @@ struct dse + char *dse_tmpfile; /* and written to when changes are made via LDAP */ + char *dse_fileback; /* contain the latest info, just before a new change */ + char *dse_filestartOK; /* contain the latest info with which the server has successfully started */ ++ char *dse_configdir; /* The location of config files - allows us to fsync the dir post rename */ + Avlnode *dse_tree; + struct dse_callback *dse_callback; + Slapi_RWLock *dse_rwlock; /* a read-write lock to protect the whole dse backend */ +- char **dse_filelist; /* these are additional read only files used to */ +- /* initialize the dse */ +- int dse_is_updateable; /* if non-zero, this DSE can be written to */ +- int dse_readonly_error_reported; /* used to ensure that read-only errors are logged only once */ ++ char **dse_filelist; /* these are additional read only files used to */ ++ /* initialize the dse */ ++ int dse_is_updateable; /* if non-zero, this DSE can be written to */ ++ int dse_readonly_error_reported; /* used to ensure that read-only errors are logged only once */ + }; + + struct dse_node +@@ -361,37 +364,39 @@ dse_new( char *filename, char *tmpfilename, char *backfilename, char *startokfil + if (!strstr(filename, realconfigdir)) + { + pdse->dse_filename = slapi_ch_smprintf("%s/%s", realconfigdir, filename ); +- } +- else ++ } else { + pdse->dse_filename = slapi_ch_strdup(filename); ++ } + + if (!strstr(tmpfilename, realconfigdir)) { + pdse->dse_tmpfile = slapi_ch_smprintf("%s/%s", realconfigdir, tmpfilename ); +- } +- else ++ } else { + pdse->dse_tmpfile = slapi_ch_strdup(tmpfilename); ++ } ++ ++ pdse->dse_configdir = slapi_ch_strdup(realconfigdir); + + if ( backfilename != NULL ) + { + if (!strstr(backfilename, realconfigdir)) { + pdse->dse_fileback = slapi_ch_smprintf("%s/%s", realconfigdir, backfilename ); +- } +- else ++ } else { + pdse->dse_fileback = slapi_ch_strdup(backfilename); +- } +- else ++ } ++ } else { + pdse->dse_fileback = NULL; ++ } + + if ( startokfilename != NULL ) + { + if (!strstr(startokfilename, realconfigdir)) { + pdse->dse_filestartOK = slapi_ch_smprintf("%s/%s", realconfigdir, startokfilename ); +- } +- else ++ } else { + pdse->dse_filestartOK = slapi_ch_strdup(startokfilename); +- } +- else ++ } ++ } else { + pdse->dse_filestartOK = NULL; ++ } + + pdse->dse_tree= NULL; + pdse->dse_callback= NULL; +@@ -440,6 +445,7 @@ dse_destroy(struct dse *pdse) + slapi_ch_free((void **)&(pdse->dse_tmpfile)); + slapi_ch_free((void **)&(pdse->dse_fileback)); + slapi_ch_free((void **)&(pdse->dse_filestartOK)); ++ slapi_ch_free((void **)&(pdse->dse_configdir)); + dse_callback_deletelist(&pdse->dse_callback); + charray_free(pdse->dse_filelist); + nentries = avl_free(pdse->dse_tree, dse_internal_delete_entry); +@@ -991,8 +997,9 @@ dse_write_file_nolock(struct dse* pdse) + FPWrapper fpw; + int rc = 0; + +- if (dont_ever_write_dse_files) ++ if (dont_ever_write_dse_files) { + return rc; ++ } + + fpw.fpw_rc = 0; + fpw.fpw_prfd = NULL; +@@ -1042,6 +1049,14 @@ dse_write_file_nolock(struct dse* pdse) + pdse->dse_tmpfile, pdse->dse_filename, + rc, slapd_system_strerror( rc )); + } ++ /* ++ * We have now written to the tmp location, and renamed it ++ * we need to open and fsync the dir to make the rename stick. ++ */ ++ int fp_configdir = open(pdse->dse_configdir, O_PATH | O_DIRECTORY); ++ fsync(fp_configdir); ++ close(fp_configdir); ++ + } + } + if (fpw.fpw_prfd) +diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c +index ba1f5e8..3351464 100644 +--- a/ldap/servers/slapd/main.c ++++ b/ldap/servers/slapd/main.c +@@ -1154,11 +1154,12 @@ cleanup: + ndn_cache_destroy(); + NSS_Shutdown(); + PR_Cleanup(); +-#if defined( hpux ) +- exit( return_value ); +-#else ++ /* ++ * Server has stopped, lets force everything to disk: logs ++ * db, dse.ldif, all of it. ++ */ ++ sync(); + return return_value; +-#endif + } + + +-- +2.9.4 + diff --git a/SOURCES/0060-Ticket-49334-fix-backup-restore-if-changelog-exists.patch b/SOURCES/0060-Ticket-49334-fix-backup-restore-if-changelog-exists.patch new file mode 100644 index 0000000..25d4010 --- /dev/null +++ b/SOURCES/0060-Ticket-49334-fix-backup-restore-if-changelog-exists.patch @@ -0,0 +1,37 @@ +From c903f66194f04e97fc684f5a9654cedb27530931 Mon Sep 17 00:00:00 2001 +From: Ludwig Krispenz +Date: Mon, 31 Jul 2017 10:51:08 +0200 +Subject: [PATCH 1/3] Ticket 49334 - fix backup restore if changelog exists + +The corrcect flag to copy a directory in backup/restore must be passed for the changelog directory + +Reviewed by: William, thanks +--- + ldap/servers/slapd/back-ldbm/dblayer.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c +index ff97aa4..3a97f2f 100644 +--- a/ldap/servers/slapd/back-ldbm/dblayer.c ++++ b/ldap/servers/slapd/back-ldbm/dblayer.c +@@ -6143,7 +6143,7 @@ dblayer_backup(struct ldbminfo *li, char *dest_dir, Slapi_Task *task) + return_value = dblayer_copy_directory(li, task, changelogdir, + changelog_destdir, + 0 /* backup */, +- &cnt, 1, 0, 0); ++ &cnt, 0, 0, 1); + if (return_value) { + slapi_log_err(SLAPI_LOG_ERR, + "dblayer_backup", "Error in copying directory " +@@ -6823,7 +6823,7 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char * + *cldirname = '\0'; + return_value = dblayer_copy_directory(li, task, filename1, + changelogdir, 1 /* restore */, +- &cnt, 1, 0 ,0); ++ &cnt, 0, 0 ,1); + *cldirname = '/'; + if (return_value) { + slapi_log_err(SLAPI_LOG_ERR, +-- +2.9.4 + diff --git a/SOURCES/0061-Ticket-49356-mapping-tree-crash-can-occur-during-tot.patch b/SOURCES/0061-Ticket-49356-mapping-tree-crash-can-occur-during-tot.patch new file mode 100644 index 0000000..23540e5 --- /dev/null +++ b/SOURCES/0061-Ticket-49356-mapping-tree-crash-can-occur-during-tot.patch @@ -0,0 +1,502 @@ +From b0954a5df7841330732a5ab532c528a68cf380cf Mon Sep 17 00:00:00 2001 +From: William Brown +Date: Fri, 18 Aug 2017 13:00:46 +1000 +Subject: [PATCH] Ticket 49356 - mapping tree crash can occur during tot init + +Bug Description: Two faults were found in the handling of the mapping +tree of 389 directory server. The first fault was that the tree-free +check was not performed atomically and may cause an incorrect operations +error to be returned. The second was that during a total init the referral +would not lock the be, but the pw_verify code assumed a be was locked. +This caused a segfault. + +Fix Description: Fix the freed check to use atomics. Fix the pw_verify +to assert be is NULL (which is correct, there is no backend). + +https://pagure.io/389-ds-base/issue/49356 + +Author: wibrown + +Review by: mreynolds (THanks!) +--- + .../mapping_tree/referral_during_tot_init.py | 57 ++++++++ + ldap/servers/slapd/fedse.c | 10 ++ + ldap/servers/slapd/main.c | 10 -- + ldap/servers/slapd/mapping_tree.c | 150 +++++++++++---------- + ldap/servers/slapd/pw_verify.c | 8 +- + 5 files changed, 150 insertions(+), 85 deletions(-) + create mode 100644 dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py + +diff --git a/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py +new file mode 100644 +index 0000000..e5aee7d +--- /dev/null ++++ b/dirsrvtests/tests/suites/mapping_tree/referral_during_tot_init.py +@@ -0,0 +1,57 @@ ++# --- BEGIN COPYRIGHT BLOCK --- ++# Copyright (C) 2017 Red Hat, Inc. ++# All rights reserved. ++# ++# License: GPL (version 3 or any later version). ++# See LICENSE for details. ++# --- END COPYRIGHT BLOCK --- ++# ++import ldap ++import pytest ++from lib389.topologies import topology_m2 ++from lib389._constants import (DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2, TASK_WAIT) ++ ++from lib389.idm.user import (TEST_USER_PROPERTIES, UserAccounts) ++ ++def test_referral_during_tot(topology_m2): ++ ++ master1 = topology_m2.ms["master1"] ++ master2 = topology_m2.ms["master2"] ++ ++ # Create a bunch of entries on master1 ++ ldif_dir = master1.get_ldif_dir() ++ import_ldif = ldif_dir + '/ref_during_tot_import.ldif' ++ master1.buildLDIF(10000, import_ldif) ++ ++ master1.stop() ++ try: ++ master1.ldif2db(bename=None, excludeSuffixes=None, encrypt=False, suffixes=[DEFAULT_SUFFIX], import_file=import_ldif) ++ except: ++ pass ++ # master1.tasks.importLDIF(suffix=DEFAULT_SUFFIX, input_file=import_ldif, args={TASK_WAIT: True}) ++ master1.start() ++ users = UserAccounts(master1, DEFAULT_SUFFIX, rdn='ou=Accounting') ++ ++ u = users.create(properties=TEST_USER_PROPERTIES) ++ u.set('userPassword', 'password') ++ ++ binddn = u.dn ++ bindpw = 'password' ++ ++ # Now export them to master2 ++ master1.agreement.init(DEFAULT_SUFFIX, HOST_MASTER_2, PORT_MASTER_2) ++ ++ # While that's happening try to bind as a user to master 2 ++ # This should trigger the referral code. ++ for i in range(0, 100): ++ conn = ldap.initialize(master2.toLDAPURL()) ++ conn.set_option(ldap.OPT_REFERRALS, False) ++ try: ++ conn.simple_bind_s(binddn, bindpw) ++ conn.unbind_s() ++ except ldap.REFERRAL: ++ pass ++ ++ # Done. ++ ++ +diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c +index 13a3c74..c2a862b 100644 +--- a/ldap/servers/slapd/fedse.c ++++ b/ldap/servers/slapd/fedse.c +@@ -1853,6 +1853,16 @@ setup_internal_backends(char *configdir) + be_addsuffix(be,&monitor); + be_addsuffix(be,&config); + ++ /* ++ * Now that the be's are in place, we can ++ * setup the mapping tree. ++ */ ++ ++ if (mapping_tree_init()) { ++ slapi_log_err(SLAPI_LOG_EMERG, "setup_internal_backends", "Failed to init mapping tree\n"); ++ exit(1); ++ } ++ + add_internal_entries(); + + add_easter_egg_entry(); +diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c +index 552d54d..1d9afce 100644 +--- a/ldap/servers/slapd/main.c ++++ b/ldap/servers/slapd/main.c +@@ -1034,16 +1034,6 @@ main( int argc, char **argv) + + ps_init_psearch_system(); /* must come before plugin_startall() */ + +- /* Initailize the mapping tree */ +- +- if (mapping_tree_init()) +- { +- slapi_log_err(SLAPI_LOG_EMERG, "main", "Failed to init mapping tree\n"); +- return_value = 1; +- goto cleanup; +- } +- +- + /* initialize UniqueID generator - must be done once backends are started + and event queue is initialized but before plugins are started */ + /* Note: This DN is no need to be normalized. */ +diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c +index 1b8d2d9..dfb6584 100644 +--- a/ldap/servers/slapd/mapping_tree.c ++++ b/ldap/servers/slapd/mapping_tree.c +@@ -88,13 +88,13 @@ struct mt_node + * release backend lock + * + */ +-static Slapi_RWLock *myLock; /* global lock on the mapping tree structures */ ++static Slapi_RWLock *myLock = NULL; /* global lock on the mapping tree structures */ + + + static mapping_tree_node *mapping_tree_root = NULL; +-static int mapping_tree_inited = 0; +-static int mapping_tree_freed = 0; +-static int extension_type = -1; /* type returned from the factory */ ++static int32_t mapping_tree_inited = 0; ++static int32_t mapping_tree_freed = 0; ++static int extension_type = -1; /* type returned from the factory */ + + /* The different states a mapping tree node can be in. */ + #define MTN_DISABLED 0 /* The server acts like the node isn't there. */ +@@ -1659,22 +1659,24 @@ add_internal_mapping_tree_node(const char *subtree, Slapi_Backend *be, mapping_t + { + Slapi_DN *dn; + mapping_tree_node *node; +- backend ** be_list = (backend **) slapi_ch_malloc(sizeof(backend *)); ++ backend **be_list = (backend **)slapi_ch_malloc(sizeof(backend *)); ++ int *be_states = (int *)slapi_ch_malloc(sizeof(int)); + + be_list[0] = be; ++ be_states[0] = SLAPI_BE_STATE_ON; + + dn = slapi_sdn_new_dn_byval(subtree); +- node= mapping_tree_node_new( +- dn, +- be_list, +- NULL, /* backend_name */ +- NULL, +- 1, /* number of backends at this node */ +- 1, /* size of backend list structure */ +- NULL, /* referral */ +- parent, +- MTN_BACKEND, +- 1, /* The config node is a private node. ++ node = mapping_tree_node_new( ++ dn, ++ be_list, ++ NULL, /* backend_name */ ++ be_states, /* be state */ ++ 1, /* number of backends at this node */ ++ 1, /* size of backend list structure */ ++ NULL, /* referral */ ++ parent, ++ MTN_BACKEND, ++ 1, /* The config node is a private node. + * People can't see or change it. */ + NULL, NULL, NULL, 0); /* no distribution */ + return node; +@@ -1722,17 +1724,20 @@ mapping_tree_init() + + /* we call this function from a single thread, so it should be ok */ + +- if(mapping_tree_freed){ +- /* shutdown has been detected */ +- return 0; +- } +- +- if (mapping_tree_inited) ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { ++ /* shutdown has been detected */ + return 0; ++ } + +- /* ONREPL - I have moved this up because otherwise we can endup calling this ++ /* ONREPL - I have moved this up because otherwise we can endup calling this + * function recursively */ ++ if (myLock != NULL) { ++ return 0; ++ } ++ myLock = slapi_new_rwlock(); ++ slapi_rwlock_wrlock(myLock); + ++ /* Should be fenced by the rwlock. */ + mapping_tree_inited = 1; + + slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_OID, +@@ -1740,10 +1745,8 @@ mapping_tree_init() + slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID, + SLAPI_OPERATION_SEARCH); + +- myLock = slapi_new_rwlock(); +- +- be= slapi_be_select_by_instance_name(DSE_BACKEND); +- mapping_tree_root= add_internal_mapping_tree_node("", be, NULL); ++ be = slapi_be_select_by_instance_name(DSE_BACKEND); ++ mapping_tree_root = add_internal_mapping_tree_node("", be, NULL); + + /* We also need to add the config and schema backends to the mapping tree. + * They are special in that users will not know about it's node in the +@@ -1757,17 +1760,23 @@ mapping_tree_init() + node= add_internal_mapping_tree_node("cn=schema", be, mapping_tree_root); + mapping_tree_node_add_child(mapping_tree_root, node); + +- /* ++ slapi_rwlock_unlock(myLock); ++ ++ /* + * Now we need to look under cn=mapping tree, cn=config to find the rest + * of the mapping tree entries. + * Builds the mapping tree from entries in the DIT. This function just + * calls mapping_tree_node_get_children with the special case for the + * root node. + */ +- if (mapping_tree_node_get_children(mapping_tree_root, 1)) ++ ++ if (mapping_tree_node_get_children(mapping_tree_root, 1)) { + return -1; ++ } + ++ slapi_rwlock_wrlock(myLock); + mtn_create_extension(mapping_tree_root); ++ slapi_rwlock_unlock(myLock); + + /* setup the dse callback functions for the ldbm instance config entry */ + { +@@ -1840,8 +1849,8 @@ mapping_tree_free () + */ + slapi_unregister_backend_state_change_all(); + /* recursively free tree nodes */ +- mtn_free_node (&mapping_tree_root); +- mapping_tree_freed = 1; ++ mtn_free_node(&mapping_tree_root); ++ __atomic_store_4(&mapping_tree_freed, 1, __ATOMIC_RELAXED); + } + + /* This function returns the first node to parse when a search is done +@@ -2083,14 +2092,12 @@ int slapi_dn_write_needs_referral(Slapi_DN *target_sdn, Slapi_Entry **referral) + mapping_tree_node *target_node = NULL; + int ret = 0; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + goto done; + } + +- if(!mapping_tree_inited) { +- mapping_tree_init(); +- } ++ PR_ASSERT(mapping_tree_inited == 1); + + if (target_sdn) { + mtn_lock(); +@@ -2157,8 +2164,8 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry + int fixup = 0; + + +- if(mapping_tree_freed){ +- /* shutdown detected */ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { ++ /* shutdown detected */ + return LDAP_OPERATIONS_ERROR; + } + +@@ -2175,9 +2182,7 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry + target_sdn = operation_get_target_spec (op); + fixup = operation_is_flag_set(op, OP_FLAG_TOMBSTONE_FIXUP); + +- if(!mapping_tree_inited) { +- mapping_tree_init(); +- } ++ PR_ASSERT(mapping_tree_inited == 1); + + be[0] = NULL; + if (referral) { +@@ -2188,8 +2193,9 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry + + /* Get the mapping tree node that is the best match for the target dn. */ + target_node = slapi_get_mapping_tree_node_by_dn(target_sdn); +- if (target_node == NULL) ++ if (target_node == NULL) { + target_node = mapping_tree_root; ++ } + + /* The processing of the base scope root DSE search and all other LDAP operations on "" + * will be transferred to the internal DSE backend +@@ -2266,8 +2272,8 @@ int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list, + Slapi_DN *sdn = NULL; + int flag_partial_result = 0; + int op_type; +- +- if(mapping_tree_freed){ ++ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + return LDAP_OPERATIONS_ERROR; + } + +@@ -2287,9 +2293,7 @@ int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list, + slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type); + slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope); + +- if(!mapping_tree_inited){ +- mapping_tree_init(); +- } ++ PR_ASSERT(mapping_tree_inited == 1); + + mtn_lock(); + +@@ -2448,8 +2452,8 @@ int slapi_mapping_tree_select_and_check(Slapi_PBlock *pb,char *newdn, Slapi_Back + Slapi_Operation *op; + int ret; + int need_unlock = 0; +- +- if(mapping_tree_freed){ ++ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + return LDAP_OPERATIONS_ERROR; + } + +@@ -2635,7 +2639,7 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb, + int flag_stop = 0; + struct slapi_componentid *cid = NULL; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shut down detected */ + return LDAP_OPERATIONS_ERROR; + } +@@ -2719,21 +2723,22 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb, + } else { + /* This MTN has not been linked to its backend + * instance yet. */ +- target_node->mtn_be[*index] = +- slapi_be_select_by_instance_name( +- target_node->mtn_backend_names[*index]); +- *be = target_node->mtn_be[*index]; +- if(*be==NULL) { +- slapi_log_err(SLAPI_LOG_BACKLDBM, "mtn_get_be", +- "Warning: Mapping tree node entry for %s " +- "point to an unknown backend : %s\n", +- slapi_sdn_get_dn(target_node->mtn_subtree), +- target_node->mtn_backend_names[*index]); +- /* Well there's still not backend instance for +- * this MTN, so let's have the default backend +- * deal with this. +- */ +- *be = defbackend_get_backend(); ++ /* WARNING: internal memory dse backends don't provide NAMES */ ++ if (target_node->mtn_backend_names != NULL) { ++ target_node->mtn_be[*index] = slapi_be_select_by_instance_name(target_node->mtn_backend_names[*index]); ++ *be = target_node->mtn_be[*index]; ++ if (*be == NULL) { ++ slapi_log_err(SLAPI_LOG_BACKLDBM, "mtn_get_be", ++ "Warning: Mapping tree node entry for %s " ++ "point to an unknown backend : %s\n", ++ slapi_sdn_get_dn(target_node->mtn_subtree), ++ target_node->mtn_backend_names[*index]); ++ /* Well there's still not backend instance for ++ * this MTN, so let's have the default backend ++ * deal with this. ++ */ ++ *be = defbackend_get_backend(); ++ } + } + } + } +@@ -2745,10 +2750,11 @@ static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb, + result = LDAP_OPERATIONS_ERROR; + *be = defbackend_get_backend(); + } +- if (flag_stop) ++ if (flag_stop) { + *index = SLAPI_BE_NO_BACKEND; +- else ++ } else { + (*index)++; ++ } + } + } + } else { +@@ -2822,7 +2828,7 @@ static mapping_tree_node *best_matching_child(mapping_tree_node *parent, + mapping_tree_node *highest_match_node = NULL; + mapping_tree_node *current; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +@@ -2849,7 +2855,7 @@ mtn_get_mapping_tree_node_by_entry(mapping_tree_node* node, const Slapi_DN *dn) + { + mapping_tree_node *found_node = NULL; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +@@ -2895,7 +2901,7 @@ slapi_get_mapping_tree_node_by_dn(const Slapi_DN *dn) + mapping_tree_node *current_best_match = mapping_tree_root; + mapping_tree_node *next_best_match = mapping_tree_root; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +@@ -2929,7 +2935,7 @@ get_mapping_tree_node_by_name(mapping_tree_node * node, char * be_name) + int i; + mapping_tree_node *found_node = NULL; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +@@ -2980,7 +2986,7 @@ slapi_get_mapping_tree_node_configdn (const Slapi_DN *root) + { + char *dn = NULL; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +@@ -3007,7 +3013,7 @@ slapi_get_mapping_tree_node_configsdn (const Slapi_DN *root) + char *dn = NULL; + Slapi_DN *sdn = NULL; + +- if(mapping_tree_freed){ ++ if (__atomic_load_4(&mapping_tree_freed, __ATOMIC_RELAXED)) { + /* shutdown detected */ + return NULL; + } +diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c +index cb182ed..1f0c18a 100644 +--- a/ldap/servers/slapd/pw_verify.c ++++ b/ldap/servers/slapd/pw_verify.c +@@ -58,12 +58,14 @@ pw_verify_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + int rc = SLAPI_BIND_SUCCESS; + Slapi_Backend *be = NULL; + +- if (slapi_mapping_tree_select(pb, &be, referral, NULL, 0) != LDAP_SUCCESS) { ++ int mt_result = slapi_mapping_tree_select(pb, &be, referral, NULL, 0); ++ if (mt_result != LDAP_SUCCESS) { + return SLAPI_BIND_NO_BACKEND; + } + + if (*referral) { +- slapi_be_Unlock(be); ++ /* If we have a referral, this is NULL */ ++ PR_ASSERT(be == NULL); + return SLAPI_BIND_REFERRAL; + } + +@@ -128,7 +130,7 @@ pw_validate_be_dn(Slapi_PBlock *pb, Slapi_Entry **referral) + } + + if (*referral) { +- slapi_be_Unlock(be); ++ PR_ASSERT(be == NULL); + return SLAPI_BIND_REFERRAL; + } + +-- +2.9.4 + diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index f8c6789..fd533d0 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -7,8 +7,6 @@ # also need the relprefix field for a pre-release e.g. .0 - also comment out for official release #% global relprefix 0. -%global use_openldap 1 -%global use_db4 0 # If perl-Socket-2.000 or newer is available, set 0 to use_Socket6. %global use_Socket6 0 %global use_nunc_stans 1 @@ -32,7 +30,7 @@ Summary: 389 Directory Server (base) Name: 389-ds-base Version: 1.3.6.1 -Release: %{?relprefix}16%{?prerel}%{?dist} +Release: %{?relprefix}19%{?prerel}%{?dist} License: GPLv3+ URL: https://www.port389.org/ Group: System Environment/Daemons @@ -43,17 +41,9 @@ Provides: ldif2ldbm >= 0 BuildRequires: nspr-devel BuildRequires: nss-devel -BuildRequires: svrcore-devel >= 4.1.2 -%if %{use_openldap} +BuildRequires: svrcore-devel >= 4.1.3 BuildRequires: openldap-devel -%else -BuildRequires: mozldap-devel -%endif -%if %{use_db4} -BuildRequires: db4-devel -%else BuildRequires: libdb-devel -%endif BuildRequires: cyrus-sasl-devel BuildRequires: icu BuildRequires: libicu-devel @@ -93,11 +83,7 @@ Requires: libsemanage-python Requires: selinux-policy >= 3.13.1-137 # the following are needed for some of our scripts -%if %{use_openldap} Requires: openldap-clients -%else -Requires: mozldap-tools -%endif # use_openldap assumes perl-Mozilla-LDAP is built with openldap support Requires: perl-Mozilla-LDAP @@ -112,11 +98,7 @@ Requires: cyrus-sasl-md5 Requires: cyrus-sasl-plain # this is needed for verify-db.pl -%if %{use_db4} -Requires: db4-utils -%else Requires: libdb-utils -%endif # This picks up libperl.so as a Requires, so we add this versioned one Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) @@ -137,7 +119,7 @@ Requires: perl-Socket %endif Requires: perl-NetAddr-IP Requires: systemd-libs -Requires: svrcore >= 4.1.2 +Requires: svrcore >= 4.1.3 # upgrade path from monolithic % {name} (including -libs & -devel) to % {name} + % {name}-snmp Obsoletes: %{name} <= 1.3.5.4 @@ -207,6 +189,12 @@ Patch52: 0052-Ticket-49257-Reject-nsslapd-cachememsize-nsslapd-cac.patc Patch53: 0053-Ticket-49257-Reject-dbcachesize-updates-while-auto-c.patch Patch54: 0054-Ticket-49184-adjust-logging-level-in-MO-plugin.patch Patch55: 0055-Ticket-49241-add-symblic-link-location-to-db2bak.pl-.patch +Patch56: 0056-Ticket-49313-Change-the-retrochangelog-default-cache.patch +Patch57: 0057-Ticket-49287-v3-extend-csnpl-handling-to-multiple-ba.patch +Patch58: 0058-Ticket-49336-SECURITY-Locked-account-provides-differ.patch +Patch59: 0059-Ticket-49298-force-sync-on-shutdown.patch +Patch60: 0060-Ticket-49334-fix-backup-restore-if-changelog-exists.patch +Patch61: 0061-Ticket-49356-mapping-tree-crash-can-occur-during-tot.patch %description @@ -218,17 +206,9 @@ Summary: Core libraries for 389 Directory Server Group: System Environment/Daemons BuildRequires: nspr-devel BuildRequires: nss-devel -BuildRequires: svrcore-devel >= 4.1.2 -%if %{use_openldap} +BuildRequires: svrcore-devel >= 4.1.3 BuildRequires: openldap-devel -%else -BuildRequires: mozldap-devel -%endif -%if %{use_db4} -BuildRequires: db4-devel -%else BuildRequires: libdb-devel -%endif BuildRequires: cyrus-sasl-devel BuildRequires: libicu-devel BuildRequires: pcre-devel @@ -251,12 +231,8 @@ Requires: %{name}-libs = %{version}-%{release} Requires: pkgconfig Requires: nspr-devel Requires: nss-devel -Requires: svrcore-devel >= 4.1.2 -%if %{use_openldap} +Requires: svrcore-devel >= 4.1.3 Requires: openldap-devel -%else -Requires: mozldap-devel -%endif %if %{use_nunc_stans} Requires: libtalloc Requires: libevent @@ -345,12 +321,15 @@ cp %{SOURCE2} README.devel %patch53 -p1 %patch54 -p1 %patch55 -p1 - +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch59 -p1 +%patch60 -p1 +%patch61 -p1 %build -%if %{use_openldap} OPENLDAP_FLAG="--with-openldap" -%endif %{?with_tmpfiles_d: TMPFILES_FLAG="--with-tmpfiles-d=%{with_tmpfiles_d}"} # hack hack hack https://bugzilla.redhat.com/show_bug.cgi?id=833529 NSSARGS="--with-svrcore-inc=%{_includedir} --with-svrcore-lib=%{_libdir} --with-nss-lib=%{_libdir} --with-nss-inc=%{_includedir}/nss3" @@ -442,11 +421,7 @@ HOMEDIR="/usr/share/dirsrv" getent group $GROUPNAME >/dev/null || /usr/sbin/groupadd -f -g $ALLOCATED_GID -r $GROUPNAME if ! getent passwd $USERNAME >/dev/null ; then - if ! getent passwd $ALLOCATED_UID >/dev/null ; then - /usr/sbin/useradd -r -u $ALLOCATED_UID -g $GROUPNAME -d $HOMEDIR -s /sbin/nologin -c "user for 389-ds-base" $USERNAME - else - /usr/sbin/useradd -r -g $GROUPNAME -d $HOMEDIR -s /sbin/nologin -c "user for 389-ds-base" $USERNAME - fi + /usr/sbin/useradd -r -u $ALLOCATED_UID -g $GROUPNAME -d $HOMEDIR -s /sbin/nologin -c "user for 389-ds-base" $USERNAME fi echo looking for instances in %{_sysconfdir}/%{pkgname} > $output 2>&1 || : @@ -583,6 +558,23 @@ fi %{_sysconfdir}/%{pkgname}/dirsrvtests %changelog +* Mon Aug 21 2017 Mark Reynolds - 1.3.6.19-1 +- Bump version to 1.3.6.19-1 +- Remove old mozldap and db4 requirements +- Resolves: Bug 1483865 - Crash while binding to a server during replication online init + +* Tue Aug 8 2017 Mark Reynolds - 1.3.6.1-18 +- Bump version to 1.3.6.1-18 +- Require srvcore 4.1.3 +- Resolves: Bug 1479757 - dse.ldif and fsync +- Resolves: Bug 1479755 - backup fails if changelog is enabled +- Resolves: Bug 1479756 - Locked account provides different return code if password is correct + +* Mon Jul 31 2017 Mark Reynolds - 1.3.6.1-17 +- Bump version to 1.3.6.1-17 +- Resolves: Bug 1476161 - replication halt - pending list first CSN not committed, pending list increasing +- Resolves: Bug 1476162 - Change the retrochangelog default cache size + * Tue Jun 6 2017 Mark Reynolds - 1.3.6.1-16 - Bump version to 1.3.6.1-16 - Resolves: Bug 1444938 - nsslapd-allowed-sasl-mechanisms doesn't reset to default values without a restart