diff --git a/SOURCES/0061-Ticket-49080-shadowExpire-should-not-be-a-calculated.patch b/SOURCES/0061-Ticket-49080-shadowExpire-should-not-be-a-calculated.patch new file mode 100644 index 0000000..c2a40e3 --- /dev/null +++ b/SOURCES/0061-Ticket-49080-shadowExpire-should-not-be-a-calculated.patch @@ -0,0 +1,100 @@ +From 50b73af8729b6753c71ba6206632561b5974523d Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Wed, 11 Jan 2017 14:14:40 -0800 +Subject: [PATCH 61/67] Ticket #49080 - shadowExpire should not be a calculated + value + +Description: Reverting the changes made on shadowExpire in the ticket 548. + +Thanks to Gordon Messmer (gordon.messmer@gmail.com) for providing the original patch. + +Reviewed by William Brown (Thanks!!). + +(cherry picked from commit 14eb192b0f99ae3d811fd8a5bb40713bc85ea533) +(cherry picked from commit 2ca12fc5b79dbbb8889eba6da7b4ce59cd6cb86d) +--- + ldap/servers/slapd/pw.c | 29 +++++------------------------ + 1 file changed, 5 insertions(+), 24 deletions(-) + +diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c +index 6f02f90..ce1ca2a 100644 +--- a/ldap/servers/slapd/pw.c ++++ b/ldap/servers/slapd/pw.c +@@ -2803,7 +2803,6 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + const char *dn = NULL; + passwdPolicy *pwpolicy = NULL; + long long shadowval = 0; +- long long exptime = 0; + Slapi_Mods *smods = NULL; + LDAPMod **mods; + long long sval; +@@ -2811,7 +2810,6 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + char *shmin = NULL; + char *shmax = NULL; + char *shwarn = NULL; +- char *shexp = NULL; + int rc = 0; + + if (!e || !*e) { +@@ -2861,7 +2859,6 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + /* shadowMax - the maximum number of days for which the user password remains valid. */ + if (pwpolicy->pw_maxage > 0) { + shadowval = pwpolicy->pw_maxage / _SEC_PER_DAY; +- exptime = time_plus_sec(current_time(), pwpolicy->pw_maxage); + if (shadowval > _MAX_SHADOW) { + shadowval = _MAX_SHADOW; + } +@@ -2903,22 +2900,6 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + shwarn = slapi_ch_smprintf("%lld", shadowval); + } + +- /* shadowExpire - the date on which the user login will be disabled. */ +- if (exptime) { +- shexp = slapi_entry_attr_get_charptr(*e, "shadowExpire"); +- exptime /= _SEC_PER_DAY; +- if (shexp) { +- sval = strtoll(shexp, NULL, 0); +- if (sval != exptime) { +- slapi_ch_free_string(&shexp); +- shexp = slapi_ch_smprintf("%lld", exptime); +- mod_num++; +- } +- } else { +- mod_num++; +- shexp = slapi_ch_smprintf("%lld", exptime); +- } +- } + smods = slapi_mods_new(); + slapi_mods_init(smods, mod_num); + if (shmin) { +@@ -2933,10 +2914,6 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowWarning", strlen(shwarn), shwarn); + slapi_ch_free_string(&shwarn); + } +- if (shexp) { +- slapi_mods_add(smods, LDAP_MOD_REPLACE, "shadowExpire", strlen(shexp), shexp); +- slapi_ch_free_string(&shexp); +- } + /* Apply the mods to create the resulting entry. */ + mods = slapi_mods_get_ldapmods_byref(smods); + if (mods) { +@@ -2947,11 +2924,15 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + } + slapi_mods_free(&smods); + +-#if 0 /* These 2 attributes are no need (or not able) to auto-fill. */ ++#if 0 /* These 3 attributes are no need (or not able) to auto-fill. */ + /* + * shadowInactive - the number of days of inactivity allowed for the user. + * Password Policy does not have the corresponding parameter. + * ++ * shadowExpire - the number of days since Jan 1, 1970 after which the ++ * account, not the password, will expire. This is not affected by the ++ * Password Policy. ++ * + * shadowFlag - not currently in use. + */ + #endif +-- +2.9.3 + diff --git a/SOURCES/0062-Ticket-49082-Fix-password-expiration-related-shadow-.patch b/SOURCES/0062-Ticket-49082-Fix-password-expiration-related-shadow-.patch new file mode 100644 index 0000000..c00b4d3 --- /dev/null +++ b/SOURCES/0062-Ticket-49082-Fix-password-expiration-related-shadow-.patch @@ -0,0 +1,145 @@ +From 96ad7ec4fa84dd32439e3473c0128612dd5f9d49 Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Wed, 11 Jan 2017 15:04:42 -0800 +Subject: [PATCH 62/67] Ticket #49082 - Fix password expiration related shadow + attributes + +The original patch was provided by Gordon Messmer (gordon.messmer@gmail.com) +with the description: + Bug description: + Shadow attributes (in /etc/shadow and in LDAP) are typically unset when no + policy is in place. 389-ds will incorrectly return values (possibly set to 0) + when there is no policy. + + Fix description: + Only auto-fill shadow attributes when a password policy is available. These + are empty when no policy is in place. + + Don't auto-fill expiration related shadow attributes if passwords never expire. + +Reviewed by William Brown (Thanks!!). + +(cherry picked from commit 5bcd966b73708f6b558f01e6b11a7a11e8d3b126) +(cherry picked from commit faae0fa5a4a6b3d590c1a9e068d9436965cc49c9) +--- + ldap/servers/slapd/pw.c | 74 +++++++++++++++++++++++++------------------------ + 1 file changed, 38 insertions(+), 36 deletions(-) + +diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c +index ce1ca2a..30a2cb9 100644 +--- a/ldap/servers/slapd/pw.c ++++ b/ldap/servers/slapd/pw.c +@@ -2802,7 +2802,7 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + { + const char *dn = NULL; + passwdPolicy *pwpolicy = NULL; +- long long shadowval = 0; ++ long long shadowval = -1; + Slapi_Mods *smods = NULL; + LDAPMod **mods; + long long sval; +@@ -2840,64 +2840,66 @@ add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e) + if (shadowval > _MAX_SHADOW) { + shadowval = _MAX_SHADOW; + } +- } else { +- shadowval = 0; + } +- shmin = slapi_entry_attr_get_charptr(*e, "shadowMin"); +- if (shmin) { +- sval = strtoll(shmin, NULL, 0); +- if (sval != shadowval) { +- slapi_ch_free_string(&shmin); +- shmin = slapi_ch_smprintf("%lld", shadowval); ++ if (shadowval > 0) { ++ shmin = slapi_entry_attr_get_charptr(*e, "shadowMin"); ++ if (shmin) { ++ sval = strtoll(shmin, NULL, 0); ++ if (sval != shadowval) { ++ slapi_ch_free_string(&shmin); ++ shmin = slapi_ch_smprintf("%lld", shadowval); ++ mod_num++; ++ } ++ } else { + mod_num++; ++ shmin = slapi_ch_smprintf("%lld", shadowval); + } +- } else { +- mod_num++; +- shmin = slapi_ch_smprintf("%lld", shadowval); + } + + /* shadowMax - the maximum number of days for which the user password remains valid. */ +- if (pwpolicy->pw_maxage > 0) { ++ shadowval = -1; ++ if (pwpolicy->pw_exp == 1 && pwpolicy->pw_maxage > 0) { + shadowval = pwpolicy->pw_maxage / _SEC_PER_DAY; + if (shadowval > _MAX_SHADOW) { + shadowval = _MAX_SHADOW; + } +- } else { +- shadowval = _MAX_SHADOW; + } +- shmax = slapi_entry_attr_get_charptr(*e, "shadowMax"); +- if (shmax) { +- sval = strtoll(shmax, NULL, 0); +- if (sval != shadowval) { +- slapi_ch_free_string(&shmax); +- shmax = slapi_ch_smprintf("%lld", shadowval); ++ if (shadowval > 0) { ++ shmax = slapi_entry_attr_get_charptr(*e, "shadowMax"); ++ if (shmax) { ++ sval = strtoll(shmax, NULL, 0); ++ if (sval != shadowval) { ++ slapi_ch_free_string(&shmax); ++ shmax = slapi_ch_smprintf("%lld", shadowval); ++ mod_num++; ++ } ++ } else { + mod_num++; ++ shmax = slapi_ch_smprintf("%lld", shadowval); + } +- } else { +- mod_num++; +- shmax = slapi_ch_smprintf("%lld", shadowval); + } + + /* shadowWarning - the number of days of advance warning given to the user before the user password expires. */ +- if (pwpolicy->pw_warning > 0) { ++ shadowval = -1; ++ if (pwpolicy->pw_exp == 1 && pwpolicy->pw_warning > 0) { + shadowval = pwpolicy->pw_warning / _SEC_PER_DAY; + if (shadowval > _MAX_SHADOW) { + shadowval = _MAX_SHADOW; + } +- } else { +- shadowval = 0; + } +- shwarn = slapi_entry_attr_get_charptr(*e, "shadowWarning"); +- if (shwarn) { +- sval = strtoll(shwarn, NULL, 0); +- if (sval != shadowval) { +- slapi_ch_free_string(&shwarn); +- shwarn = slapi_ch_smprintf("%lld", shadowval); ++ if (shadowval > 0) { ++ shwarn = slapi_entry_attr_get_charptr(*e, "shadowWarning"); ++ if (shwarn) { ++ sval = strtoll(shwarn, NULL, 0); ++ if (sval != shadowval) { ++ slapi_ch_free_string(&shwarn); ++ shwarn = slapi_ch_smprintf("%lld", shadowval); ++ mod_num++; ++ } ++ } else { + mod_num++; ++ shwarn = slapi_ch_smprintf("%lld", shadowval); + } +- } else { +- mod_num++; +- shwarn = slapi_ch_smprintf("%lld", shadowval); + } + + smods = slapi_mods_new(); +-- +2.9.3 + diff --git a/SOURCES/0063-Ticket-49082-Adjusted-the-CI-test-case-to-the-fix.patch b/SOURCES/0063-Ticket-49082-Adjusted-the-CI-test-case-to-the-fix.patch new file mode 100644 index 0000000..97fb5d1 --- /dev/null +++ b/SOURCES/0063-Ticket-49082-Adjusted-the-CI-test-case-to-the-fix.patch @@ -0,0 +1,33 @@ +From ee9b5c5dc3f4382ee73abefb9d2e3c275e62d6c8 Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Wed, 11 Jan 2017 15:14:07 -0800 +Subject: [PATCH 63/67] Ticket #49082 - Adjusted the CI test case to the fix. + +Description: Fix password expiration related shadow attributes +(cherry picked from commit 5a6a5a18d0458bd147af57a06158245f329ddba3) +(cherry picked from commit b9e565df5d304ba9fb516b987ad62480590a5845) +--- + dirsrvtests/tests/tickets/ticket548_test.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/dirsrvtests/tests/tickets/ticket548_test.py b/dirsrvtests/tests/tickets/ticket548_test.py +index d29fa53..dea7c3c 100644 +--- a/dirsrvtests/tests/tickets/ticket548_test.py ++++ b/dirsrvtests/tests/tickets/ticket548_test.py +@@ -98,6 +98,13 @@ def set_global_pwpolicy(topology, min_=1, max_=10, warn=3): + log.error('Failed to set passwordMinAge: error ' + e.message['desc']) + assert False + ++ log.info(" Set global password Expiration -- on\n") ++ try: ++ topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordExp', 'on')]) ++ except ldap.LDAPError as e: ++ log.error('Failed to set passwordExp: error ' + e.message['desc']) ++ assert False ++ + log.info(" Set global password Max Age -- %s days\n" % max_) + try: + topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordMaxAge', '%s' % max_secs)]) +-- +2.9.3 + diff --git a/SOURCES/0064-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch b/SOURCES/0064-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch new file mode 100644 index 0000000..32d1bbb --- /dev/null +++ b/SOURCES/0064-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch @@ -0,0 +1,631 @@ +From d1477e4a03d85aec79b497db4531d9e484029139 Mon Sep 17 00:00:00 2001 +From: Ludwig Krispenz +Date: Tue, 24 Jan 2017 15:07:19 +0100 +Subject: [PATCH 64/67] Ticket 49008 backport 1.3.5 : aborted operation can + leave RUV in incorrect state + + Bug description: + If a plugin operation succeeded, but the operation itself fails and is aborted the RUV is in an incorrect state (rolled up to the succesful plugin op) + + Fix Decription: + Introduce a "primary_csn", this is the csn of the main operation, either a client operation or a replicated operation. + csns generated by internal operations, eg by plugins are secondary csn. + + Maintain the primary csn in thread local data, like it is used for the agreement name (or txn stack): prim_csn. + + Extend the data structure of the pending list to keep prim_csn for each inserted csn + + If a csn is created or received check prim_csn: if it exists use it, if it doesn't exist set it + + when inserting a csn to the pending list pass the prim_csn + + when cancelling a csn, if it is the prim_csn also cancell all secondary csns + + when committing a csn, + + if it is not the primary csn, do nothing + + if it is the prim_csn trigger the pending list rollup, stop at the first not committed csn + + if the RID of the prim_csn is not the local RID also rollup the pending list for the local RID. + + Reviewed by: Thierry, Thanks + +(cherry picked from commit 79a3deafe943a3ce5c31c50272939146d17bd7ac) +--- + ldap/servers/plugins/replication/csnpl.c | 75 +++++++++++++++++++++--- + ldap/servers/plugins/replication/csnpl.h | 5 +- + ldap/servers/plugins/replication/repl5.h | 2 + + ldap/servers/plugins/replication/repl5_init.c | 22 +++++++ + ldap/servers/plugins/replication/repl5_plugins.c | 40 ++++++++----- + ldap/servers/plugins/replication/repl5_replica.c | 6 +- + ldap/servers/plugins/replication/repl5_ruv.c | 74 +++++++++++++++++------ + ldap/servers/plugins/replication/repl5_ruv.h | 4 +- + ldap/servers/slapd/csn.c | 15 +++++ + ldap/servers/slapd/slapi-private.h | 2 + + 10 files changed, 195 insertions(+), 50 deletions(-) + +diff --git a/ldap/servers/plugins/replication/csnpl.c b/ldap/servers/plugins/replication/csnpl.c +index acd38d0..db1ae13 100644 +--- a/ldap/servers/plugins/replication/csnpl.c ++++ b/ldap/servers/plugins/replication/csnpl.c +@@ -24,8 +24,9 @@ struct csnpl + + typedef struct _csnpldata + { +- PRBool committed; /* True if CSN committed */ +- CSN *csn; /* The actual CSN */ ++ PRBool committed; /* True if CSN committed */ ++ CSN *csn; /* The actual CSN */ ++ const CSN *prim_csn; /* The primary CSN of an operation consising of multiple sub ops*/ + } csnpldata; + + /* forward declarations */ +@@ -103,7 +104,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) ++int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSN *prim_csn) + { + int rc; + csnpldata *csnplnode; +@@ -131,6 +132,7 @@ int csnplInsert (CSNPL *csnpl, const CSN *csn) + csnplnode = (csnpldata *)slapi_ch_malloc(sizeof(csnpldata)); + csnplnode->committed = PR_FALSE; + csnplnode->csn = csn_dup(csn); ++ csnplnode->prim_csn = prim_csn; + csn_as_string(csn, PR_FALSE, csn_str); + rc = llistInsertTail (csnpl->csnList, csn_str, csnplnode); + +@@ -186,6 +188,57 @@ int csnplRemove (CSNPL *csnpl, const CSN *csn) + return 0; + } + ++int csnplRemoveAll (CSNPL *csnpl, const CSN *csn) ++{ ++ csnpldata *data; ++ void *iterator; ++ ++ slapi_rwlock_wrlock (csnpl->csnLock); ++ data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); ++ while (NULL != data) ++ { ++ if (csn_is_equal(data->csn, csn) || ++ csn_is_equal(data->prim_csn, csn)) { ++ csnpldata_free(&data); ++ data = (csnpldata *)llistRemoveCurrentAndGetNext(csnpl->csnList, &iterator); ++ } else { ++ data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator); ++ } ++ } ++#ifdef DEBUG ++ _csnplDumpContentNoLock(csnpl, "csnplRemoveAll"); ++#endif ++ slapi_rwlock_unlock (csnpl->csnLock); ++ return 0; ++} ++ ++ ++int csnplCommitAll (CSNPL *csnpl, const CSN *csn) ++{ ++ csnpldata *data; ++ void *iterator; ++ char csn_str[CSN_STRSIZE]; ++ ++ csn_as_string(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); ++ data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); ++ while (NULL != data) ++ { ++ 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)) { ++ data->committed = PR_TRUE; ++ } ++ data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator); ++ } ++ slapi_rwlock_unlock (csnpl->csnLock); ++ return 0; ++} ++ + int csnplCommit (CSNPL *csnpl, const CSN *csn) + { + csnpldata *data; +@@ -276,13 +329,12 @@ csnplRollUp(CSNPL *csnpl, CSN **first_commited) + *first_commited = NULL; + } + data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); +- while (NULL != data) ++ while (NULL != data && data->committed) + { + if (NULL != largest_committed_csn && freeit) + { + csn_free(&largest_committed_csn); + } +- if (data->committed) { + freeit = PR_TRUE; + largest_committed_csn = data->csn; /* Save it */ + if (first_commited && (*first_commited == NULL)) { +@@ -294,9 +346,6 @@ csnplRollUp(CSNPL *csnpl, CSN **first_commited) + data->csn = NULL; + csnpldata_free(&data); + data = (csnpldata *)llistRemoveCurrentAndGetNext(csnpl->csnList, &iterator); +- } else { +- data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator); +- } + } + + #ifdef DEBUG +@@ -326,6 +375,7 @@ static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller) + csnpldata *data; + void *iterator; + char csn_str[CSN_STRSIZE]; ++ char primcsn_str[CSN_STRSIZE]; + + data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); + if (data) { +@@ -334,11 +384,18 @@ static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller) + } + while (data) + { +- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s, %s\n", ++ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s,(prim %s), %s\n", + csn_as_string(data->csn, PR_FALSE, csn_str), ++ data->prim_csn ? csn_as_string(data->prim_csn, PR_FALSE, primcsn_str) : " ", + data->committed ? "committed" : "not committed"); + data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator); + } + } + #endif + ++/* wrapper around csn_free, to satisfy NSPR thread context API */ ++void ++csnplFreeCSN (void *arg) ++{ ++ csn_free((CSN **)&arg); ++} +diff --git a/ldap/servers/plugins/replication/csnpl.h b/ldap/servers/plugins/replication/csnpl.h +index 32e3ff7..f5c28f5 100644 +--- a/ldap/servers/plugins/replication/csnpl.h ++++ b/ldap/servers/plugins/replication/csnpl.h +@@ -22,10 +22,13 @@ typedef struct csnpl CSNPL; + + CSNPL* csnplNew (); + void csnplFree (CSNPL **csnpl); +-int csnplInsert (CSNPL *csnpl, const CSN *csn); ++int csnplInsert (CSNPL *csnpl, const CSN *csn, const CSN *prim_csn); + int csnplRemove (CSNPL *csnpl, const CSN *csn); ++int csnplRemoveAll (CSNPL *csnpl, const CSN *csn); ++int csnplCommitAll (CSNPL *csnpl, const CSN *csn); + CSN* csnplGetMinCSN (CSNPL *csnpl, PRBool *committed); + int csnplCommit (CSNPL *csnpl, const CSN *csn); + CSN *csnplRollUp(CSNPL *csnpl, CSN ** first); + void csnplDumpContent(CSNPL *csnpl, const char *caller); ++ + #endif +diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h +index 4ab2355..27ad416 100644 +--- a/ldap/servers/plugins/replication/repl5.h ++++ b/ldap/servers/plugins/replication/repl5.h +@@ -232,6 +232,8 @@ int multimaster_be_betxnpostop_modify (Slapi_PBlock *pb); + extern int repl5_is_betxn; + char* get_thread_private_agmtname (); + void set_thread_private_agmtname (const char *agmtname); ++void set_thread_primary_csn (const CSN *prim_csn); ++CSN* get_thread_primary_csn(void); + void* get_thread_private_cache (); + void set_thread_private_cache (void *buf); + char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn); +diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c +index 0304ed5..1570655 100644 +--- a/ldap/servers/plugins/replication/repl5_init.c ++++ b/ldap/servers/plugins/replication/repl5_init.c +@@ -136,6 +136,7 @@ static int multimaster_started_flag = 0; + /* Thread private data and interface */ + static PRUintn thread_private_agmtname; /* thread private index for logging*/ + static PRUintn thread_private_cache; ++static PRUintn thread_primary_csn; + + char* + get_thread_private_agmtname() +@@ -153,6 +154,26 @@ set_thread_private_agmtname(const char *agmtname) + PR_SetThreadPrivate(thread_private_agmtname, (void *)agmtname); + } + ++CSN* ++get_thread_primary_csn(void) ++{ ++ CSN *prim_csn = NULL; ++ if (thread_primary_csn) ++ prim_csn = (CSN *)PR_GetThreadPrivate(thread_primary_csn); ++ return prim_csn; ++} ++void ++set_thread_primary_csn(const CSN *prim_csn) ++{ ++ if (thread_primary_csn) { ++ if (prim_csn) { ++ PR_SetThreadPrivate(thread_primary_csn, (void *)csn_dup(prim_csn)); ++ } else { ++ PR_SetThreadPrivate(thread_primary_csn, NULL); ++ } ++ } ++} ++ + void* + get_thread_private_cache () + { +@@ -721,6 +742,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); + + /* 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 b331c81..84624e9 100644 +--- a/ldap/servers/plugins/replication/repl5_plugins.c ++++ b/ldap/servers/plugins/replication/repl5_plugins.c +@@ -1033,9 +1033,11 @@ static int + write_changelog_and_ruv (Slapi_PBlock *pb) + { + Slapi_Operation *op = NULL; ++ CSN *opcsn; ++ CSN *prim_csn; + int rc; + slapi_operation_parameters *op_params = NULL; +- Object *repl_obj; ++ Object *repl_obj = NULL; + int return_value = SLAPI_PLUGIN_SUCCESS; + Replica *r; + Slapi_Backend *be; +@@ -1063,17 +1065,17 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + { + return return_value; + } ++ /* we only log changes for operations applied to a replica */ ++ repl_obj = replica_get_replica_for_op (pb); ++ if (repl_obj == NULL) ++ return return_value; + + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc); + if (rc) { /* op failed - just return */ +- return return_value; ++ cancel_opcsn(pb); ++ goto common_return; + } + +- /* we only log changes for operations applied to a replica */ +- repl_obj = replica_get_replica_for_op (pb); +- if (repl_obj == NULL) +- return return_value; +- + r = (Replica*)object_get_data (repl_obj); + PR_ASSERT (r); + +@@ -1108,7 +1110,7 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + + slapi_pblock_get (pb, SLAPI_OPERATION_PARAMETERS, &op_params); + if (NULL == op_params) { +- return return_value; ++ goto common_return; + } + + /* need to set uniqueid operation parameter */ +@@ -1127,19 +1129,18 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + slapi_pblock_get (pb, SLAPI_ENTRY_PRE_OP, &e); + } + if (NULL == e) { +- return return_value; ++ goto common_return; + } + uniqueid = slapi_entry_get_uniqueid (e); + if (NULL == uniqueid) { +- return return_value; ++ goto common_return; + } + op_params->target_address.uniqueid = slapi_ch_strdup (uniqueid); + } + + if( op_params->csn && is_cleaned_rid(csn_get_replicaid(op_params->csn))){ + /* this RID has been cleaned */ +- object_release (repl_obj); +- return return_value; ++ goto common_return; + } + + /* we might have stripped all the mods - in that case we do not +@@ -1152,7 +1153,7 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "write_changelog_and_ruv: Skipped due to DISKFULL\n"); +- return return_value; ++ goto common_return; + } + slapi_pblock_get(pb, SLAPI_TXN, &txn); + rc = cl5WriteOperationTxn(repl_name, repl_gen, op_params, +@@ -1188,7 +1189,6 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + */ + if (0 == return_value) { + char csn_str[CSN_STRSIZE] = {'\0'}; +- CSN *opcsn; + int rc; + const char *dn = op_params ? REPL_GET_DN(&op_params->target_address) : "unknown"; + Slapi_DN *sdn = op_params ? (&op_params->target_address)->sdn : NULL; +@@ -1220,7 +1220,15 @@ write_changelog_and_ruv (Slapi_PBlock *pb) + } + } + +- object_release (repl_obj); ++common_return: ++ opcsn = operation_get_csn(op); ++ prim_csn = get_thread_primary_csn(); ++ if (csn_is_equal(opcsn, prim_csn)) { ++ set_thread_primary_csn(NULL); ++ } ++ if (repl_obj) { ++ object_release (repl_obj); ++ } + return return_value; + } + +@@ -1417,7 +1425,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); ++ ruv_cancel_csn_inprogress ((RUV*)object_get_data (ruv_obj), opcsn, replica_get_rid(r)); + object_release (ruv_obj); + } + +diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c +index 7360d97..602653a 100644 +--- a/ldap/servers/plugins/replication/repl5_replica.c ++++ b/ldap/servers/plugins/replication/repl5_replica.c +@@ -903,7 +903,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, rid == r->repl_rid); ++ rc = ruv_update_ruv (ruv, updated_csn, replica_purl, r->repl_rid); + if (RUV_COVERS_CSN == rc) + { + slapi_log_error(SLAPI_LOG_REPL, +@@ -3626,7 +3626,7 @@ assign_csn_callback(const CSN *csn, void *data) + + if (NULL != r->min_csn_pl) + { +- if (csnplInsert(r->min_csn_pl, csn) != 0) ++ if (csnplInsert(r->min_csn_pl, csn, NULL) != 0) + { + char csn_str[CSN_STRSIZE]; /* For logging only */ + /* Ack, we can't keep track of min csn. Punt. */ +@@ -3674,7 +3674,7 @@ abort_csn_callback(const CSN *csn, void *data) + } + } + +- ruv_cancel_csn_inprogress (ruv, csn); ++ ruv_cancel_csn_inprogress (ruv, csn, replica_get_rid(r)); + replica_unlock(r->repl_lock); + + object_release (ruv_obj); +diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c +index 5d6e1c3..c2d3bb4 100644 +--- a/ldap/servers/plugins/replication/repl5_ruv.c ++++ b/ldap/servers/plugins/replication/repl5_ruv.c +@@ -77,6 +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); + + /* API implementation */ + +@@ -1602,6 +1603,7 @@ int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn) + char csn_str[CSN_STRSIZE]; + int rc = RUV_SUCCESS; + int rid = csn_get_replicaid (csn); ++ CSN *prim_csn; + + PR_ASSERT (ruv && csn); + +@@ -1639,8 +1641,12 @@ int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn) + rc = RUV_COVERS_CSN; + goto done; + } +- +- rc = csnplInsert (replica->csnpl, csn); ++ prim_csn = get_thread_primary_csn(); ++ if (prim_csn == NULL) { ++ set_thread_primary_csn(csn); ++ prim_csn = get_thread_primary_csn(); ++ } ++ rc = csnplInsert (replica->csnpl, csn, prim_csn); + if (rc == 1) /* we already seen this csn */ + { + if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) { +@@ -1648,6 +1654,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); + rc = RUV_COVERS_CSN; + } + else if(rc != 0) +@@ -1672,24 +1679,36 @@ done: + return rc; + } + +-int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn) ++int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn, ReplicaId local_rid) + { + RUVElement* replica; + int rc = RUV_SUCCESS; ++ CSN *prim_csn = NULL; ++ + + PR_ASSERT (ruv && csn); + ++ prim_csn = get_thread_primary_csn(); + /* locate ruvElement */ + slapi_rwlock_wrlock (ruv->lock); + replica = ruvGetReplica (ruv, csn_get_replicaid (csn)); +- if (replica == NULL) +- { ++ if (replica == NULL) { + /* ONREPL - log error */ +- rc = RUV_NOTFOUND; +- goto done; +- } +- +- rc = csnplRemove (replica->csnpl, csn); ++ 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) { ++ replica = ruvGetReplica (ruv, local_rid); ++ rc = csnplRemoveAll (replica->csnpl, prim_csn); ++ } ++ } else { ++ rc = csnplRemove (replica->csnpl, csn); ++ } + if (rc != 0) + rc = RUV_NOTFOUND; + else +@@ -1700,19 +1719,37 @@ done: + return rc; + } + +-int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool isLocal) ++int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, ReplicaId local_rid) ++{ ++ int rc=RUV_SUCCESS; ++ RUVElement *replica; ++ ReplicaId prim_rid; ++ ++ CSN *prim_csn = get_thread_primary_csn(); ++ ++ if (! csn_is_equal(csn, prim_csn)) { ++ /* not a primary csn, nothing to do */ ++ return rc; ++ } ++ slapi_rwlock_wrlock (ruv->lock); ++ 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_unlock (ruv->lock); ++ return rc; ++} ++static int ++ruv_update_ruv_element (RUV *ruv, RUVElement *replica, const CSN *csn, const char *replica_purl, PRBool isLocal) + { + int rc=RUV_SUCCESS; + char csn_str[CSN_STRSIZE]; + CSN *max_csn; + CSN *first_csn = NULL; +- RUVElement *replica; + +- PR_ASSERT (ruv && csn); +- +- slapi_rwlock_wrlock (ruv->lock); +- +- replica = ruvGetReplica (ruv, csn_get_replicaid (csn)); + if (replica == NULL) + { + /* we should have a ruv element at this point because it would have +@@ -1722,7 +1759,7 @@ int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool i + goto done; + } + +- if (csnplCommit(replica->csnpl, csn) != 0) ++ if (csnplCommitAll(replica->csnpl, csn) != 0) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "ruv_update_ruv: cannot commit csn %s\n", + csn_as_string(csn, PR_FALSE, csn_str)); +@@ -1763,7 +1800,6 @@ int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool i + } + + done: +- slapi_rwlock_unlock (ruv->lock); + + return rc; + } +diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h +index e9eff5a..c8960fd 100644 +--- a/ldap/servers/plugins/replication/repl5_ruv.h ++++ b/ldap/servers/plugins/replication/repl5_ruv.h +@@ -109,8 +109,8 @@ 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); +-int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool isLocal); ++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_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/csn.c b/ldap/servers/slapd/csn.c +index a3f4815..175f82a 100644 +--- a/ldap/servers/slapd/csn.c ++++ b/ldap/servers/slapd/csn.c +@@ -268,6 +268,21 @@ csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss) + return s; + } + ++int ++csn_is_equal(const CSN *csn1, const CSN *csn2) ++{ ++ int retval = 0; ++ if ((csn1 == NULL && csn2 == NULL) || ++ (csn1 && csn2 && ++ csn1->tstamp == csn2->tstamp && ++ csn1->seqnum == csn2->seqnum && ++ csn1->rid == csn2->rid && ++ csn1->subseqnum == csn2->subseqnum)) { ++ retval = 1; ++ } ++ return retval; ++} ++ + int + csn_compare_ext(const CSN *csn1, const CSN *csn2, unsigned int flags) + { +diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h +index 52d1c4a..e909e9c 100644 +--- a/ldap/servers/slapd/slapi-private.h ++++ b/ldap/servers/slapd/slapi-private.h +@@ -166,6 +166,7 @@ time_t csn_get_time(const CSN *csn); + PRUint16 csn_get_seqnum(const CSN *csn); + PRUint16 csn_get_subseqnum(const CSN *csn); + char *csn_as_string(const CSN *csn, PRBool replicaIdOrder, char *ss); /* WARNING: ss must be CSN_STRSIZE bytes, or NULL. */ ++int csn_is_equal(const CSN *csn1, const CSN *csn2); + int csn_compare(const CSN *csn1, const CSN *csn2); + int csn_compare_ext(const CSN *csn1, const CSN *csn2, unsigned int flags); + #define CSN_COMPARE_SKIP_SUBSEQ 0x1 +@@ -181,6 +182,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); + /* + * csnset.c + */ +-- +2.9.3 + diff --git a/SOURCES/0065-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch b/SOURCES/0065-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch new file mode 100644 index 0000000..b0782d4 --- /dev/null +++ b/SOURCES/0065-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch @@ -0,0 +1,36 @@ +From 0085cfb4c4ff6722898e97704a67dcdfcba53388 Mon Sep 17 00:00:00 2001 +From: Noriko Hosoi +Date: Wed, 25 Jan 2017 13:39:08 -0800 +Subject: [PATCH 65/67] Ticket 49008 backport 1.3.5 : aborted operation can + leave RUV in incorrect state + +Description: Fixed 2 backport errors in commit 79a3deafe943a3ce5c31c50272939146d17bd7ac. +(cherry picked from commit 3fa6596bdc677cdb3fb65b7baf6fd567485c91a7) +--- + ldap/servers/plugins/replication/csnpl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ldap/servers/plugins/replication/csnpl.c b/ldap/servers/plugins/replication/csnpl.c +index db1ae13..a696fc1 100644 +--- a/ldap/servers/plugins/replication/csnpl.c ++++ b/ldap/servers/plugins/replication/csnpl.c +@@ -220,14 +220,14 @@ int csnplCommitAll (CSNPL *csnpl, const CSN *csn) + char csn_str[CSN_STRSIZE]; + + csn_as_string(csn, PR_FALSE, csn_str); +- slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, ++ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "csnplCommitALL: committing all csns for csn %s\n", csn_str); + slapi_rwlock_wrlock (csnpl->csnLock); + data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator); + while (NULL != data) + { + csn_as_string(data->csn, PR_FALSE, csn_str); +- slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, ++ slapi_log_error(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)) { +-- +2.9.3 + diff --git a/SOURCES/0066-Ticket-49079-deadlock-on-cos-cache-rebuild.patch b/SOURCES/0066-Ticket-49079-deadlock-on-cos-cache-rebuild.patch new file mode 100644 index 0000000..af757e4 --- /dev/null +++ b/SOURCES/0066-Ticket-49079-deadlock-on-cos-cache-rebuild.patch @@ -0,0 +1,207 @@ +From 5391c666e58af5841eab88c98505f99c8ed20d6b Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Tue, 10 Jan 2017 14:32:53 +0100 +Subject: [PATCH 66/67] Ticket 49079: deadlock on cos cache rebuild + +Bug Description: + To rebuild the cache cos_cache_creation the thread gets cos definitions from backend. + It means change_lock is held then cos_cache_creation will acquire some backend pages. + + A deadlock can happen if cos_post_op is called while backend is locked. + For example if a bepreop (urp) does an internal update on a cos definition. + Then the thread holds backend pages, that will be needed by cos_cache_creation, + and will acquire change_lock for notification of the cos_cache thread + +Fix Description: + + Let cos cache rebuild thread run without holding change_lock. + The lock prevents parallel run but a flag can do the same. + +https://fedorahosted.org/389/ticket/49079 + +Reviewed by: William Brown and Ludwig Krispenz (thanks to you both !!) + +Platforms tested: F23 + +Flag Day: no + +Doc impact: no + +(cherry picked from commit ac44337bd97fe63071e7d83e9dcd788f2af1feab) +(cherry picked from commit 3ac12cb94a8873b0fa4ddb12f924cc58bd9c9872) +--- + ldap/servers/plugins/cos/cos_cache.c | 73 ++++++++++++++++++++++++++++++------ + 1 file changed, 61 insertions(+), 12 deletions(-) + +diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c +index 8a32630..87b4ba5 100644 +--- a/ldap/servers/plugins/cos/cos_cache.c ++++ b/ldap/servers/plugins/cos/cos_cache.c +@@ -111,7 +111,9 @@ void * cos_get_plugin_identity(); + /* the global plugin handle */ + static volatile vattr_sp_handle *vattr_handle = NULL; + ++/* both variables are protected by change_lock */ + static int cos_cache_notify_flag = 0; ++static PRBool cos_cache_at_work = PR_FALSE; + + /* service definition cache structs */ + +@@ -199,7 +201,8 @@ typedef struct _cos_cache cosCache; + static cosCache *pCache; /* always the current global cache, only use getref to get */ + + /* the place to start if you want a new cache */ +-static int cos_cache_create(); ++static int cos_cache_create_unlock(void); ++static int cos_cache_creation_lock(void); + + /* cache index related functions */ + static int cos_cache_index_all(cosCache *pCache); +@@ -386,7 +389,7 @@ static void cos_cache_wait_on_change(void *arg) + pCache = 0; + + /* create initial cache */ +- cos_cache_create(); ++ cos_cache_creation_lock(); + + slapi_lock_mutex(start_lock); + started = 1; +@@ -419,7 +422,7 @@ static void cos_cache_wait_on_change(void *arg) + * before we go running off doing lots of stuff lets check if we should stop + */ + if(keeprunning) { +- cos_cache_create(); ++ cos_cache_creation_lock(); + } + cos_cache_notify_flag = 0; /* Dealt with it */ + }/* while */ +@@ -431,22 +434,25 @@ static void cos_cache_wait_on_change(void *arg) + LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_wait_on_change thread exit\n",0,0,0); + } + ++ + /* +- cos_cache_create ++ cos_cache_create_unlock + --------------------- + Walks the definitions in the DIT and creates the cache. + Once created, it swaps the new cache for the old one, + releasing its refcount to the old cache and allowing it + to be destroyed. ++ ++ called while change_lock is NOT held + */ +-static int cos_cache_create() ++static int cos_cache_create_unlock(void) + { + int ret = -1; + cosCache *pNewCache; + static int firstTime = 1; + int cache_built = 0; + +- LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_create\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_create_unlock\n",0,0,0); + + pNewCache = (cosCache*)slapi_ch_malloc(sizeof(cosCache)); + if(pNewCache) +@@ -509,21 +515,21 @@ static int cos_cache_create() + { + /* we should not go on without proper schema checking */ + cos_cache_release(pNewCache); +- LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: failed to cache the schema\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create_unlock: failed to cache the schema\n",0,0,0); + } + } + else + { + /* currently we cannot go on without the indexes */ + cos_cache_release(pNewCache); +- LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: failed to index cache\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create_unlock: failed to index cache\n",0,0,0); + } + } + else + { + if(firstTime) + { +- LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_create: cos disabled\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_create_unlock: cos disabled\n",0,0,0); + firstTime = 0; + } + +@@ -531,7 +537,7 @@ static int cos_cache_create() + } + } + else +- LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: memory allocation failure\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create_unlock: memory allocation failure\n",0,0,0); + + + /* make sure we have a new cache */ +@@ -563,10 +569,53 @@ static int cos_cache_create() + + } + +- LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_create\n",0,0,0); ++ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_create_unlock\n",0,0,0); + return ret; + } + ++/* cos_cache_creation_lock is called with change_lock being hold: ++ * slapi_lock_mutex(change_lock) ++ * ++ * To rebuild the cache cos_cache_creation gets cos definitions from backend, that ++ * means change_lock is held then cos_cache_creation will acquire some backend pages. ++ * ++ * A deadlock can happen if cos_post_op is called while backend is locked. ++ * For example if a bepreop (urp) does an internal update on a cos definition, ++ * the thread holds backend pages that will be needed by cos_cache_creation. ++ * ++ * A solution is to use a flag 'cos_cache_at_work' protected by change_lock, ++ * release change_lock, recreate the cos_cache, acquire change_lock reset the flag. ++ * ++ * returned value: result of cos_cache_create_unlock ++ * ++ */ ++static int cos_cache_creation_lock(void) ++{ ++ int ret = -1; ++ int max_tries = 10; ++ ++ for (; max_tries != 0; max_tries--) { ++ /* if the cos_cache is already under work (cos_cache_create_unlock) ++ * wait 1 second ++ */ ++ if (cos_cache_at_work) { ++ slapi_log_error(SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_creation_lock already rebuilding cos_cache... retry\n"); ++ DS_Sleep (PR_MillisecondsToInterval(1000)); ++ continue; ++ } ++ cos_cache_at_work = PR_TRUE; ++ slapi_unlock_mutex(change_lock); ++ ret = cos_cache_create_unlock(); ++ slapi_lock_mutex(change_lock); ++ cos_cache_at_work = PR_FALSE; ++ break; ++ } ++ if (!max_tries) { ++ slapi_log_error(SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_creation_lock rebuilt was to long, skip this rebuild\n"); ++ } ++ ++ return ret; ++} + + /* + cos_cache_build_definition_list +@@ -1639,7 +1688,7 @@ int cos_cache_getref(cos_cache **pptheCache) + slapi_lock_mutex(change_lock); + if(pCache == NULL) + { +- if(cos_cache_create()) ++ if(cos_cache_creation_lock()) + { + /* there was a problem or no COS definitions were found */ + LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_getref: no cos cache created\n",0,0,0); +-- +2.9.3 + diff --git a/SOURCES/0067-Ticket-49016-un-register-migration-remove-may-fail-i.patch b/SOURCES/0067-Ticket-49016-un-register-migration-remove-may-fail-i.patch new file mode 100644 index 0000000..b2fa67d --- /dev/null +++ b/SOURCES/0067-Ticket-49016-un-register-migration-remove-may-fail-i.patch @@ -0,0 +1,50 @@ +From 451838933f9989d1ff9c46dbb3cae7619166a4d8 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Fri, 21 Oct 2016 16:28:59 +0200 +Subject: [PATCH 67/67] Ticket 49016 - (un)register/migration/remove may fail + if there is no suffix on 'userRoot' backend + +Bug Description: + If an instance has no suffix on 'userRoot' backend, then the info structure + may contain empty 'Suffix'. + In fact if the last backend has no suffix (like cn=config), it overwite all + previsously found value. + This affect register (and possibly unregister/migrate/remove) + +Fix Description: + Before overwriting the 'Suffix' value, check that the found backend contains + 'nsslapd-suffix'. + +https://fedorahosted.org/389/ticket/49016 + +Reviewed by: Noriko Hosoi (Thank you Noriko) + +Platforms tested: RHEL 7.2 + +Flag Day: no + +Doc impact: no + +(cherry picked from commit 1bafab5ae1e894ae3680679e03e457b9ace7e7d2) +--- + ldap/admin/src/scripts/DSUtil.pm.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ldap/admin/src/scripts/DSUtil.pm.in b/ldap/admin/src/scripts/DSUtil.pm.in +index 756d6ea..eac59a3 100644 +--- a/ldap/admin/src/scripts/DSUtil.pm.in ++++ b/ldap/admin/src/scripts/DSUtil.pm.in +@@ -975,7 +975,9 @@ sub createInfFromConfig { + } + # use the userRoot suffix if available + while ($ent) { +- $suffix = $ent->getValues('nsslapd-suffix'); ++ if ($ent->getValues('nsslapd-suffix')) { ++ $suffix = $ent->getValues('nsslapd-suffix'); ++ } + last if ($ent->hasValue('cn', 'userRoot', 1)); + $ent = $conn->nextEntry(); + } +-- +2.9.3 + diff --git a/SOURCES/0068-Ticket-49016-un-register-migration-remove-may-fail-i.patch b/SOURCES/0068-Ticket-49016-un-register-migration-remove-may-fail-i.patch new file mode 100644 index 0000000..ba32e9c --- /dev/null +++ b/SOURCES/0068-Ticket-49016-un-register-migration-remove-may-fail-i.patch @@ -0,0 +1,59 @@ +From 99a0def5c6b9910616d95ee7cd15ecad5b406951 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Mon, 30 Jan 2017 17:38:01 +0100 +Subject: [PATCH] Ticket 49016 - (un)register/migration/remove may fail if + there is no suffix on 'userRoot' backend + +Bug Description: + Previous fix was incomplete in case none of the backend entries have + 'nsslapd-suffix' value + +Fix Description: + + Just return if $suffix keep unmodified + +https://fedorahosted.org/389/ticket/49016 + +Reviewed by: nhosoi + +Platforms tested: F23, F25 + +Flag Day: no + +Doc impact: no + +(cherry picked from commit bd5fdfc8f4a560eae99672b712235c1260ee42b0) +(cherry picked from commit 1abb0ffb2930d019f58d5dac1937ddbb56c9287f) +--- + ldap/admin/src/scripts/DSUtil.pm.in | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ldap/admin/src/scripts/DSUtil.pm.in b/ldap/admin/src/scripts/DSUtil.pm.in +index eac59a3..c8eb14d 100644 +--- a/ldap/admin/src/scripts/DSUtil.pm.in ++++ b/ldap/admin/src/scripts/DSUtil.pm.in +@@ -965,7 +965,7 @@ sub createInfFromConfig { + $inf->{slapd}->{ServerPort} = $ent->getValues('nsslapd-port'); + $inf->{slapd}->{ServerIdentifier} = $id; + +- my $suffix; ++ my $suffix = ""; + $ent = $conn->search("cn=ldbm database,cn=plugins,cn=config", + "one", "(objectclass=*)"); + if (!$ent) { +@@ -981,6 +981,12 @@ sub createInfFromConfig { + last if ($ent->hasValue('cn', 'userRoot', 1)); + $ent = $conn->nextEntry(); + } ++ if ( "" eq "$suffix" ) ++ { ++ push @{$errs}, "error_opening_dseldif", $fname, $!; ++ $conn->close(); ++ return 0; ++ } + + # we also need the instance dir + $ent = $conn->search("cn=config", "base", "(objectclass=*)"); +-- +2.9.3 + diff --git a/SOURCES/0069-fix-for-reg-in-49008-check-if-ruv-element-exists.patch b/SOURCES/0069-fix-for-reg-in-49008-check-if-ruv-element-exists.patch new file mode 100644 index 0000000..e85d043 --- /dev/null +++ b/SOURCES/0069-fix-for-reg-in-49008-check-if-ruv-element-exists.patch @@ -0,0 +1,34 @@ +From 7a5d77d8a65d65ed7c5fa94abf952669993f45c2 Mon Sep 17 00:00:00 2001 +From: Ludwig Krispenz +Date: Tue, 7 Feb 2017 17:02:00 +0100 +Subject: [PATCH] fix for reg in 49008, check if ruv element exists + +(cherry picked from commit 23d98baa8aadab80691680ba065563ad1e35591c) +--- + ldap/servers/plugins/replication/repl5_ruv.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c +index c2d3bb4..5086313 100644 +--- a/ldap/servers/plugins/replication/repl5_ruv.c ++++ b/ldap/servers/plugins/replication/repl5_ruv.c +@@ -1703,8 +1703,14 @@ int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn, ReplicaId local_rid) + replica = ruvGetReplica (ruv, prim_rid); + rc = csnplRemoveAll (replica->csnpl, prim_csn); + if (prim_rid != local_rid) { +- replica = ruvGetReplica (ruv, local_rid); +- rc = csnplRemoveAll (replica->csnpl, prim_csn); ++ if( local_rid != READ_ONLY_REPLICA_ID) { ++ replica = ruvGetReplica (ruv, local_rid); ++ if (replica) { ++ rc = csnplRemoveAll (replica->csnpl, prim_csn); ++ } else { ++ rc = RUV_NOTFOUND; ++ } ++ } + } + } else { + rc = csnplRemove (replica->csnpl, csn); +-- +2.7.4 + diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index 02002a0..cdda586 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -34,9 +34,9 @@ Summary: 389 Directory Server (base) Name: 389-ds-base Version: 1.3.5.10 -Release: %{?relprefix}15%{?prerel}%{?dist} +Release: %{?relprefix}18%{?prerel}%{?dist} License: GPLv3+ -URL: https://port389.org/ +URL: https://www.port389.org/ Group: System Environment/Daemons BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Obsoletes: %{name}-selinux @@ -196,6 +196,15 @@ Patch57: 0057-Ticket-49020-do-not-treat-missing-csn-as-fatal.patch Patch58: 0058-Ticket-48964-cleanallruv-changelog-purging-removes-w.patch Patch59: 0059-Ticket-48964-should-not-free-repl-name-after-purging.patch Patch60: 0060-Ticket-49074-incompatible-nsEncryptionConfig-object-.patch +Patch61: 0061-Ticket-49080-shadowExpire-should-not-be-a-calculated.patch +Patch62: 0062-Ticket-49082-Fix-password-expiration-related-shadow-.patch +Patch63: 0063-Ticket-49082-Adjusted-the-CI-test-case-to-the-fix.patch +Patch64: 0064-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch +Patch65: 0065-Ticket-49008-backport-1.3.5-aborted-operation-can-le.patch +Patch66: 0066-Ticket-49079-deadlock-on-cos-cache-rebuild.patch +Patch67: 0067-Ticket-49016-un-register-migration-remove-may-fail-i.patch +Patch68: 0068-Ticket-49016-un-register-migration-remove-may-fail-i.patch +Patch69: 0069-fix-for-reg-in-49008-check-if-ruv-element-exists.patch %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -342,6 +351,15 @@ cp %{SOURCE2} README.devel %patch58 -p1 %patch59 -p1 %patch60 -p1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 %build %if %{use_nunc_stans} @@ -579,6 +597,21 @@ fi %{_sysconfdir}/%{pkgname}/dirsrvtests %changelog +* Thu Feb 16 2017 Mark Reynolds - 1.3.5.10-18 +- Release 1.3.5.10-18 +- Resolves: bug 1387340 - Aborted operation can leave RUV in incorrect state + +* Tue Jan 31 2017 Noriko Hosoi - 1.3.5.10-17 +- Release 1.3.5.10-17 +- Resolves: bug 1414677 - (un)register/migration/remove may fail if there is no suffix (DS 49016) + +* Wed Jan 25 2017 Noriko Hosoi - 1.3.5.10-16 +- Release 1.3.5.10-16 +- Resolves: bug 1414677 - (un)register/migration/remove may fail if there is no suffix (DS 49016) +- Resolves: bug 1414678 - deadlock on cos cache rebuild (DS 49079) +- Resolves: bug 1414679 - Release 1.3.5 may allow expired accounts access to systems (DS 49080, DS 49082) +- Resolves: bug 1416368 - Aborted operation can leave RUV in incorrect state (DS 49008) + * Wed Jan 4 2017 Noriko Hosoi - 1.3.5.10-15 - Release 1.3.5.10-15 - Resolves: bug 1402325 - do not treat missing csn as fatal (DS 48964)