From 433de7e0ad8e33818db4cce65efaa4bb2597edc5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jan 29 2019 15:25:13 +0000 Subject: import 389-ds-base-1.3.8.4-22.el7_6 --- diff --git a/SOURCES/0013-Ticket-49915-Master-ns-slapd-had-100-CPU-usage-after.patch b/SOURCES/0013-Ticket-49915-Master-ns-slapd-had-100-CPU-usage-after.patch new file mode 100644 index 0000000..34d9d01 --- /dev/null +++ b/SOURCES/0013-Ticket-49915-Master-ns-slapd-had-100-CPU-usage-after.patch @@ -0,0 +1,354 @@ +From 6d67faa0de58cb0b66fc72d43f24b1c9669f88f8 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Mon, 3 Sep 2018 15:36:52 +0200 +Subject: [PATCH] Ticket 49915 - Master ns-slapd had 100% CPU usage after + starting replication and replication cannot finish + +Bug Description: + During a total initialization the supplier builds a candidate list of the entries to send. + Because of https://fedorahosted.org/389/ticket/48755, the candidate list relies on parentid attribute. + All entries, except tombstones and suffix itself, have parentid. + There is an assumption that the first found key (i.e. '=1') contains the suffix children. + So when it finally finds the suffix key it adds its children to a leftover list rather to the candidate list. + Later idl_new_range_fetch loops for ever trying to add suffix children from leftover to candidate list. + +Fix Description: + The fix consist to store the suffix_id (if it does not exist already) in the parentid index (with the key '=0'). + Then get it to detect the suffix key from the index in idl_new_range_fetch. + +https://pagure.io/389-ds-base/issue/49915 + +Reviewed by: Ludwig Krispenz, William Brown (thanks !) + +Platforms tested: F27 + +Flag Day: no + +Doc impact: no +--- + .../plugins/replication/repl5_tot_protocol.c | 48 ++++++++ + ldap/servers/slapd/back-ldbm/dblayer.c | 8 ++ + ldap/servers/slapd/back-ldbm/idl_new.c | 34 +++++- + ldap/servers/slapd/back-ldbm/index.c | 114 ++++++++++++++++++ + ldap/servers/slapd/slapi-plugin.h | 10 +- + 5 files changed, 209 insertions(+), 5 deletions(-) + +diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c +index ee3c9dcb0..1dbbe694f 100644 +--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c ++++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c +@@ -283,6 +283,53 @@ repl5_tot_waitfor_async_results(callback_data *cb_data) + } + } + ++/* This routine checks that the entry id of the suffix is ++ * stored in the parentid index ++ * The entry id of the suffix is stored with the equality key 0 (i.e. '=0') ++ * It first checks if the key '=0' exists. If it does not exists or if the first value ++ * stored with that key, does not match the suffix entryid (stored in the suffix entry ++ * from id2entry.db then it updates the value ++ */ ++static void ++check_suffix_entryID(Slapi_Backend *be, Slapi_Entry *suffix) ++{ ++ u_int32_t entryid; ++ char *entryid_str; ++ struct _back_info_index_key bck_info; ++ ++ /* we are using a specific key in parentid to store the suffix entry id: '=0' */ ++ bck_info.index = SLAPI_ATTR_PARENTID; ++ bck_info.key = "0"; ++ ++ /* First try to retrieve from parentid index the suffix entryID */ ++ if (slapi_back_get_info(be, BACK_INFO_INDEX_KEY, (void **) &bck_info)) { ++ slapi_log_err(SLAPI_LOG_REPL, "check_suffix_entryID", "Total update: fail to retrieve suffix entryID. Let's try to write it\n"); ++ } ++ ++ /* Second retrieve the suffix entryid from the suffix entry itself */ ++ entryid_str = slapi_entry_attr_get_charptr(suffix, "entryid"); ++ if (entryid_str == NULL) { ++ char *dn; ++ dn = slapi_entry_get_ndn(suffix); ++ slapi_log_err(SLAPI_LOG_ERR, "check_suffix_entryID", "Unable to retrieve entryid of the suffix entry %s\n", dn ? dn : ""); ++ slapi_ch_free_string(&entryid_str); ++ return; ++ } ++ entryid = (u_int32_t) atoi(entryid_str); ++ slapi_ch_free_string(&entryid_str); ++ ++ if (!bck_info.key_found || bck_info.id != entryid) { ++ /* The suffix entryid is not present in parentid index ++ * or differs from what is in id2entry (entry 'suffix') ++ * So write it to the parentid so that the range index used ++ * during total init will know the entryid of the suffix ++ */ ++ bck_info.id = entryid; ++ if (slapi_back_set_info(be, BACK_INFO_INDEX_KEY, (void **) &bck_info)) { ++ slapi_log_err(SLAPI_LOG_ERR, "check_suffix_entryID", "Total update: fail to register suffix entryid, continue assuming suffix is the first entry\n"); ++ } ++ } ++} + + /* + * Completely refresh a replica. The basic protocol interaction goes +@@ -467,6 +514,7 @@ retry: + replica_subentry_check(area_sdn, rid); + + /* Send the subtree of the suffix in the order of parentid index plus ldapsubentry and nstombstone. */ ++ check_suffix_entryID(be, suffix); + slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(area_sdn), + LDAP_SCOPE_SUBTREE, "(parentid>=1)", NULL, 0, ctrls, NULL, + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), OP_FLAG_BULK_IMPORT); +diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c +index e84cb7695..fa931ccbf 100644 +--- a/ldap/servers/slapd/back-ldbm/dblayer.c ++++ b/ldap/servers/slapd/back-ldbm/dblayer.c +@@ -7295,6 +7295,10 @@ ldbm_back_get_info(Slapi_Backend *be, int cmd, void **info) + *(int *)info = entryrdn_get_switch(); + break; + } ++ case BACK_INFO_INDEX_KEY : { ++ rc = get_suffix_key(be, (struct _back_info_index_key *)info); ++ break; ++ } + default: + break; + } +@@ -7311,6 +7315,10 @@ ldbm_back_set_info(Slapi_Backend *be, int cmd, void *info) + } + + switch (cmd) { ++ case BACK_INFO_INDEX_KEY : { ++ rc = set_suffix_key(be, (struct _back_info_index_key *)info); ++ break; ++ } + default: + break; + } +diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c +index 4e28e3fc2..102265c47 100644 +--- a/ldap/servers/slapd/back-ldbm/idl_new.c ++++ b/ldap/servers/slapd/back-ldbm/idl_new.c +@@ -320,6 +320,9 @@ typedef struct _range_id_pair + * In the total update (bulk import), an entry requires its ancestors already added. + * To guarantee it, the range search with parentid is used with setting the flag + * SLAPI_OP_RANGE_NO_IDL_SORT in operator. ++ * In bulk import the range search is parentid>=1 to retrieve all the entries ++ * But we need to order the IDL with the parents first => retrieve the suffix entry ID ++ * to store the children + * + * If the flag is set, + * 1. the IDList is not sorted by the ID. +@@ -366,6 +369,23 @@ idl_new_range_fetch( + if (NULL == flag_err) { + return NULL; + } ++ if (operator & SLAPI_OP_RANGE_NO_IDL_SORT) { ++ struct _back_info_index_key bck_info; ++ int rc; ++ /* We are doing a bulk import ++ * try to retrieve the suffix entry id from the index ++ */ ++ ++ bck_info.index = SLAPI_ATTR_PARENTID; ++ bck_info.key = "0"; ++ ++ if (rc = slapi_back_get_info(be, BACK_INFO_INDEX_KEY, (void **)&bck_info)) { ++ slapi_log_err(SLAPI_LOG_WARNING, "idl_new_range_fetch", "Total update: fail to retrieve suffix entryID, continue assuming it is the first entry\n"); ++ } ++ if (bck_info.key_found) { ++ suffix = bck_info.id; ++ } ++ } + + if (NEW_IDL_NOOP == *flag_err) { + return NULL; +@@ -455,7 +475,7 @@ idl_new_range_fetch( + *flag_err = LDAP_TIMELIMIT_EXCEEDED; + goto error; + } +- if (operator&SLAPI_OP_RANGE_NO_IDL_SORT) { ++ if (operator & SLAPI_OP_RANGE_NO_IDL_SORT) { + key = (ID)strtol((char *)cur_key.data + 1, (char **)NULL, 10); + } + while (PR_TRUE) { +@@ -487,9 +507,13 @@ idl_new_range_fetch( + /* note the last id read to check for dups */ + lastid = id; + /* we got another ID, add it to our IDL */ +- if (operator&SLAPI_OP_RANGE_NO_IDL_SORT) { +- if (count == 0) { +- /* First time. Keep the suffix ID. */ ++ if (operator & SLAPI_OP_RANGE_NO_IDL_SORT) { ++ if ((count == 0) && (suffix == 0)) { ++ /* First time. Keep the suffix ID. ++ * note that 'suffix==0' mean we did not retrieve the suffix entry id ++ * from the parentid index (key '=0'), so let assume the first ++ * found entry is the one from the suffix ++ */ + suffix = key; + idl_rc = idl_append_extend(&idl, id); + } else if ((key == suffix) || idl_id_is_in_idlist(idl, key)) { +@@ -615,9 +639,11 @@ error: + } + if (operator&SLAPI_OP_RANGE_NO_IDL_SORT) { + size_t remaining = leftovercnt; ++ + while(remaining > 0) { + for (size_t i = 0; i < leftovercnt; i++) { + if (leftover[i].key > 0 && idl_id_is_in_idlist(idl, leftover[i].key) != 0) { ++ /* if the leftover key has its parent in the idl */ + idl_rc = idl_append_extend(&idl, leftover[i].id); + if (idl_rc) { + slapi_log_err(SLAPI_LOG_ERR, "idl_new_range_fetch", +diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c +index 222f64dff..dea6e9a3e 100644 +--- a/ldap/servers/slapd/back-ldbm/index.c ++++ b/ldap/servers/slapd/back-ldbm/index.c +@@ -1236,6 +1236,120 @@ error: + return ret; + } + ++/* This routine add in a given index (parentid) ++ * the key/value = '=0'/ ++ * Input: ++ * info->key contains the key to lookup (i.e. '0') ++ * info->index index name used to retrieve syntax and db file ++ * info->id the entryID of the suffix ++ */ ++int ++set_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info) ++{ ++ struct ldbminfo *li; ++ int rc; ++ back_txn txn; ++ Slapi_Value *sv_key[2]; ++ Slapi_Value tmpval; ++ ++ if (info->index== NULL || info->key == NULL) { ++ slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Invalid index %s or key %s\n", ++ info->index ? info->index : "NULL", ++ info->key ? info->key : "NULL"); ++ return -1; ++ } ++ ++ /* Start a txn */ ++ li = (struct ldbminfo *)be->be_database->plg_private; ++ dblayer_txn_init(li, &txn); ++ if (rc = dblayer_txn_begin(be, txn.back_txn_txn, &txn)) { ++ slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): txn begin fails\n", ++ info->index, info->key, info->id); ++ return rc; ++ } ++ ++ sv_key[0] = &tmpval; ++ sv_key[1] = NULL; ++ slapi_value_init_string(sv_key[0], info->key); ++ ++ if (rc = index_addordel_values_sv(be, info->index, sv_key, NULL, info->id, BE_INDEX_ADD, &txn)) { ++ value_done(sv_key[0]); ++ dblayer_txn_abort(be, &txn); ++ slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): index_addordel_values_sv fails\n", ++ info->index, info->key, info->id); ++ return rc; ++ } ++ ++ value_done(sv_key[0]); ++ if (rc = dblayer_txn_commit(be, &txn)) { ++ slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): commit fails\n", ++ info->index, info->key, info->id); ++ return rc; ++ } ++ ++ return 0; ++} ++/* This routine retrieves from a given index (parentid) ++ * the key/value = '=0'/ ++ * Input: ++ * info->key contains the key to lookup (i.e. '0') ++ * info->index index name used to retrieve syntax and db file ++ * Output ++ * info->id It returns the first id that is found for the key. ++ * If the key is not found, or there is no value for the key ++ * it contains '0' ++ * info->key_found Boolean that says if the key leads to a valid ID in info->id ++ */ ++int ++get_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info) ++{ ++ struct berval bv; ++ int err; ++ IDList *idl = NULL; ++ ID id; ++ int rc = 0; ++ ++ if (info->index== NULL || info->key == NULL) { ++ slapi_log_err(SLAPI_LOG_ERR, "get_suffix_key", "Invalid index %s or key %s\n", ++ info->index ? info->index : "NULL", ++ info->key ? info->key : "NULL"); ++ return -1; ++ } ++ ++ /* This is the key to retrieve */ ++ bv.bv_val = info->key; ++ bv.bv_len = strlen(bv.bv_val); ++ ++ /* Assuming we are not going to find the key*/ ++ info->key_found = PR_FALSE; ++ id = 0; ++ idl = index_read(be, info->index, indextype_EQUALITY, &bv, NULL, &err); ++ ++ if (idl == NULL) { ++ if (err != 0 && err != DB_NOTFOUND) { ++ slapi_log_err(SLAPI_LOG_ERR, "get_suffix_key", "Fail to read key %s (err=%d)\n", ++ info->key ? info->key : "NULL", ++ err); ++ rc = err; ++ } ++ } else { ++ /* info->key was found */ ++ id = idl_firstid(idl); ++ if (id != NOID) { ++ info->key_found = PR_TRUE; ++ } else { ++ /* there is no ID in that key, make it as it was not found */ ++ id = 0; ++ } ++ idl_free(&idl); ++ } ++ ++ /* now set the returned id */ ++ info->id = id; ++ ++ return rc; ++} ++ + IDList * + index_range_read_ext( + Slapi_PBlock *pb, +diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h +index 0646cdfdd..4b75654e7 100644 +--- a/ldap/servers/slapd/slapi-plugin.h ++++ b/ldap/servers/slapd/slapi-plugin.h +@@ -7763,9 +7763,17 @@ enum + BACK_INFO_CRYPT_DECRYPT_VALUE, /* Ctrl: clcrypt_decrypt_value */ + BACK_INFO_DIRECTORY, /* Get the directory path */ + BACK_INFO_LOG_DIRECTORY, /* Get the txn log directory */ +- BACK_INFO_IS_ENTRYRDN /* Get the flag for entryrdn */ ++ BACK_INFO_IS_ENTRYRDN, /* Get the flag for entryrdn */ ++ BACK_INFO_INDEX_KEY /* Get the status of a key in an index */ + }; + ++struct _back_info_index_key ++{ ++ char *index; /* input: name of the index (parentid) */ ++ char *key; /* input: searched key (0) with equality -> '=0' */ ++ PRBool key_found; /* output: TRUE if '=0' is found in the index */ ++ u_int32_t id; /* output: if key_found it is the first value (suffix entryID) */ ++}; + struct _back_info_crypt_init + { + char *dn; /* input -- entry to store nsSymmetricKey */ +-- +2.17.2 + diff --git a/SOURCES/0014-Ticket-49950-PassSync-not-setting-pwdLastSet-attribu.patch b/SOURCES/0014-Ticket-49950-PassSync-not-setting-pwdLastSet-attribu.patch new file mode 100644 index 0000000..0395971 --- /dev/null +++ b/SOURCES/0014-Ticket-49950-PassSync-not-setting-pwdLastSet-attribu.patch @@ -0,0 +1,521 @@ +From 0d2456fd9e2678f6db075b224528727b741ff205 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Fri, 14 Sep 2018 11:24:35 -0400 +Subject: [PATCH] Ticket 49950 - PassSync not setting pwdLastSet attribute in + Active Directory after Pw update from LDAP sync for normal user + +Bug Description: + +If a user's password was reset by an "Admin" or directory manager, the +password policy requires a user must change their password after it's +been "reset", and the user then resets their password in DS, this +information was not sent to AD. Then if the user logged in AD after +resetting their password in DS they still get forced to change their +password again in AD. + +Fix Description: + +When sending a password update to AD, and AD is enforcing password must +be reset, check if the user's did reset thier password. If so, set the +correct "pwdLastSet" value to prevent AD from forcing that user to +change their password again. + +But this only works going from DS to AD. The information needed to make +it work from AD -> DS is not available to passSync, and if it was available +it could not be correctly sent to DS anyway (not without a major redesign). + +Side Note: + +Also moved iand consolidated the function "fetch_attr" to util.c. It +was reused and redefined in many plugins. So I added the definition +to slapi-plugin.h and removed the duplicate definitions. + +https://pagure.io/389-ds-base/issue/49950 + +Reviewed by: tbordaz(Thanks!) + +(cherry picked from commit d9437be2e60fdbd6a5f1364f5887e1a3c89cda68) +(cherry picked from commit ac500d378aa22d5e818b110074ac9cd3e421e38d) +--- + ldap/servers/plugins/automember/automember.c | 20 ----- + ldap/servers/plugins/linkedattrs/fixup_task.c | 20 ----- + ldap/servers/plugins/memberof/memberof.c | 17 ---- + .../plugins/posix-winsync/posix-group-task.c | 18 +--- + .../replication/repl5_replica_config.c | 13 --- + .../replication/windows_protocol_util.c | 90 ++++++++++++++----- + .../plugins/schema_reload/schema_reload.c | 17 ---- + ldap/servers/plugins/syntaxes/validate_task.c | 20 ----- + ldap/servers/slapd/slapi-plugin.h | 2 + + ldap/servers/slapd/task.c | 17 ---- + ldap/servers/slapd/test-plugins/sampletask.c | 16 ---- + ldap/servers/slapd/util.c | 17 ++++ + 12 files changed, 89 insertions(+), 178 deletions(-) + +diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c +index c91aa4e8e..d982d49a3 100644 +--- a/ldap/servers/plugins/automember/automember.c ++++ b/ldap/servers/plugins/automember/automember.c +@@ -74,7 +74,6 @@ static void automember_free_regex_rule(struct automemberRegexRule *rule); + static int automember_parse_grouping_attr(char *value, char **grouping_attr, char **grouping_value); + static int automember_update_membership(struct configEntry *config, Slapi_Entry *e, PRFileDesc *ldif_fd); + static int automember_add_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd); +-const char *fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val); + + /* + * task functions +@@ -1927,25 +1926,6 @@ typedef struct _task_data + int scope; + } task_data; + +-/* +- * extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Value *val = NULL; +- Slapi_Attr *attr; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) { +- return default_val; +- } +- slapi_attr_first_value(attr, &val); +- +- return slapi_value_get_string(val); +-} +- + static void + automember_task_destructor(Slapi_Task *task) + { +diff --git a/ldap/servers/plugins/linkedattrs/fixup_task.c b/ldap/servers/plugins/linkedattrs/fixup_task.c +index 900ee1135..4929714b4 100644 +--- a/ldap/servers/plugins/linkedattrs/fixup_task.c ++++ b/ldap/servers/plugins/linkedattrs/fixup_task.c +@@ -22,7 +22,6 @@ static void linked_attrs_fixup_task_thread(void *arg); + static void linked_attrs_fixup_links(struct configEntry *config); + static int linked_attrs_remove_backlinks_callback(Slapi_Entry *e, void *callback_data); + static int linked_attrs_add_backlinks_callback(Slapi_Entry *e, void *callback_data); +-static const char *fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val); + + /* + * Function Implementations +@@ -459,22 +458,3 @@ done: + + return rc; + } +- +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) { +- return default_val; +- } +- +- slapi_attr_first_value(attr, &val); +- +- return slapi_value_get_string(val); +-} +diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c +index 87313ff19..26236dc68 100644 +--- a/ldap/servers/plugins/memberof/memberof.c ++++ b/ldap/servers/plugins/memberof/memberof.c +@@ -142,7 +142,6 @@ static int memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *con + static int memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, Slapi_DN *group_sdn, Slapi_DN *op_this_sdn, Slapi_DN *replace_with_sdn, Slapi_DN *op_to_sdn, memberofstringll *stack); + static int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg); + static void memberof_task_destructor(Slapi_Task *task); +-static const char *fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val); + static void memberof_fixup_task_thread(void *arg); + static int memberof_fix_memberof(MemberOfConfig *config, Slapi_Task *task, task_data *td); + static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data); +@@ -2871,22 +2870,6 @@ done: + "memberof_fixup_task_thread - refcount decremented.\n"); + } + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- slapi_attr_first_value(attr, &val); +- return slapi_value_get_string(val); +-} +- + int + memberof_task_add(Slapi_PBlock *pb, + Slapi_Entry *e, +diff --git a/ldap/servers/plugins/posix-winsync/posix-group-task.c b/ldap/servers/plugins/posix-winsync/posix-group-task.c +index b4c507595..d8b6addd4 100644 +--- a/ldap/servers/plugins/posix-winsync/posix-group-task.c ++++ b/ldap/servers/plugins/posix-winsync/posix-group-task.c +@@ -42,22 +42,6 @@ posix_group_fixup_task_thread(void *arg); + static int + posix_group_fix_memberuid_callback(Slapi_Entry *e, void *callback_data); + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- slapi_attr_first_value(attr, &val); +- return slapi_value_get_string(val); +-} +- + /* e configEntry */ + int + posix_group_task_add(Slapi_PBlock *pb __attribute__((unused)), +@@ -82,7 +66,7 @@ posix_group_task_add(Slapi_PBlock *pb __attribute__((unused)), + + /* get arg(s) */ + /* default: set replication basedn */ +- if ((dn = fetch_attr(e, "basedn", slapi_sdn_get_dn(posix_winsync_config_get_suffix()))) == NULL) { ++ if ((dn = fetch_attr(e, "basedn", (char *)slapi_sdn_get_dn(posix_winsync_config_get_suffix()))) == NULL) { + *returncode = LDAP_OBJECT_CLASS_VIOLATION; + rv = SLAPI_DSE_CALLBACK_ERROR; + goto out; +diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c +index ea430d9a4..84e02639b 100644 +--- a/ldap/servers/plugins/replication/repl5_replica_config.c ++++ b/ldap/servers/plugins/replication/repl5_replica_config.c +@@ -1353,19 +1353,6 @@ replica_execute_cleanruv_task(Object *r, ReplicaId rid, char *returntext __attri + return LDAP_SUCCESS; + } + +-const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- +- slapi_attr_first_value(attr, &val); +- return slapi_value_get_string(val); +-} +- + static int + replica_cleanall_ruv_task(Slapi_PBlock *pb __attribute__((unused)), + Slapi_Entry *e, +diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c +index f350b6d34..f6898d018 100644 +--- a/ldap/servers/plugins/replication/windows_protocol_util.c ++++ b/ldap/servers/plugins/replication/windows_protocol_util.c +@@ -720,39 +720,79 @@ send_password_modify(Slapi_DN *sdn, + } else { + Slapi_Attr *attr = NULL; + int force_reset_pw = 0; ++ int pwd_already_reset = 0; ++ int ds_must_change = config_get_pw_must_change(); ++ + /* +- * If AD entry has password must change flag is set, +- * we keep the flag (pwdLastSet == 0). +- * msdn.microsoft.com: Windows Dev Centor - Desktop +- * To force a user to change their password at next logon, +- * set the pwdLastSet attribute to zero (0). +- */ ++ * If AD entry has password must change flag is set, ++ * we keep the flag (pwdLastSet == 0). ++ * msdn.microsoft.com: Windows Dev Centor - Desktop ++ * To force a user to change their password at next logon, ++ * set the pwdLastSet attribute to zero (0). ++ */ + if (remote_entry && + (0 == slapi_entry_attr_find(remote_entry, "pwdLastSet", &attr)) && +- attr) { ++ attr) ++ { + Slapi_Value *v = NULL; + int i = 0; ++ + for (i = slapi_attr_first_value(attr, &v); + v && (i != -1); +- i = slapi_attr_next_value(attr, i, &v)) { ++ i = slapi_attr_next_value(attr, i, &v)) ++ { + const char *s = slapi_value_get_string(v); + if (NULL == s) { + continue; + } + if (0 == strcmp(s, "0")) { +- slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, +- "%s: AD entry %s set \"user must change password at next logon\". ", +- agmt_get_long_name(prp->agmt), slapi_entry_get_dn(remote_entry)); + force_reset_pw = 1; ++ if (ds_must_change) { ++ /* ++ * DS already enforces "password must be changed after reset". ++ * Do an internal search and check the passwordExpirationtime ++ * to see if is it actually needs to be reset. If it doesn't, ++ * then set pwdLastSet to -1 ++ */ ++ char *expiration_val; ++ int rc = 0; ++ Slapi_DN *local_sdn = NULL; ++ ++ rc = map_entry_dn_inbound(remote_entry, &local_sdn, prp->agmt); ++ if ((0 == rc) && local_sdn) { ++ Slapi_Entry *local_entry = NULL; ++ /* Get the local entry if it exists */ ++ rc = windows_get_local_entry(local_sdn, &local_entry); ++ if ((0 == rc) && local_entry) { ++ expiration_val = (char *)fetch_attr(local_entry, "passwordExpirationtime", NULL); ++ if (expiration_val && parse_genTime(expiration_val) != NO_TIME){ ++ /* The user did reset their password */ ++ slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, ++ "send_password_modify - entry (%s) password was reset by user send that info to AD\n", ++ slapi_sdn_get_dn(local_sdn)); ++ pwd_already_reset = 1; ++ force_reset_pw = 0; ++ } ++ slapi_entry_free(local_entry); ++ } ++ } ++ slapi_sdn_free(&local_sdn); ++ } else { ++ slapi_log_err(SLAPI_LOG_REPL, windows_repl_plugin_name, ++ "%s: AD entry %s set \"user must change password at next logon\n", ++ agmt_get_long_name(prp->agmt), slapi_entry_get_dn(remote_entry));; ++ } + } + } + } +- /* We will attempt to bind to AD with the new password first. We do +- * this to avoid playing a password change that originated from AD +- * back to AD. If we just played the password change back, then +- * both sides would be in sync, but AD would contain the new password +- * twice in it's password history, which undermines the password +- * history policies in AD. */ ++ /* ++ * We will attempt to bind to AD with the new password first. We do ++ * this to avoid playing a password change that originated from AD ++ * back to AD. If we just played the password change back, then ++ * both sides would be in sync, but AD would contain the new password ++ * twice in it's password history, which undermines the password ++ * history policies in AD. ++ */ + if (windows_check_user_password(prp->conn, sdn, password)) { + char *quoted_password = NULL; + /* AD wants the password in quotes ! */ +@@ -792,9 +832,18 @@ send_password_modify(Slapi_DN *sdn, + pw_mod.mod_bvalues = bvals; + + pw_mods[0] = &pw_mod; +- if (force_reset_pw) { +- reset_bv.bv_len = 1; +- reset_bv.bv_val = "0"; ++ ++ if (force_reset_pw || pwd_already_reset) { ++ if (force_reset_pw) { ++ reset_bv.bv_val = "0"; ++ reset_bv.bv_len = 1; ++ } else if (pwd_already_reset) { ++ /* Password was reset by the user, there is no ++ * need to make the user change their password ++ * again in AD so set pwdLastSet to -1 */ ++ reset_bv.bv_val = "-1"; ++ reset_bv.bv_len = 2; ++ } + reset_bvals[0] = &reset_bv; + reset_bvals[1] = NULL; + reset_pw_mod.mod_type = "pwdLastSet"; +@@ -807,7 +856,6 @@ send_password_modify(Slapi_DN *sdn, + } + + pw_return = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(sdn), pw_mods, NULL, NULL); +- + slapi_ch_free((void **)&unicode_password); + } + PR_smprintf_free(quoted_password); +diff --git a/ldap/servers/plugins/schema_reload/schema_reload.c b/ldap/servers/plugins/schema_reload/schema_reload.c +index ee3b00c3c..c2399e5c3 100644 +--- a/ldap/servers/plugins/schema_reload/schema_reload.c ++++ b/ldap/servers/plugins/schema_reload/schema_reload.c +@@ -187,23 +187,6 @@ schemareload_thread(void *arg) + "schemareload_thread <-- refcount decremented.\n"); + } + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- slapi_attr_first_value(attr, &val); +- +- return slapi_value_get_string(val); +-} +- + static void + schemareload_destructor(Slapi_Task *task) + { +diff --git a/ldap/servers/plugins/syntaxes/validate_task.c b/ldap/servers/plugins/syntaxes/validate_task.c +index 2c625ba71..afec9ef7a 100644 +--- a/ldap/servers/plugins/syntaxes/validate_task.c ++++ b/ldap/servers/plugins/syntaxes/validate_task.c +@@ -43,7 +43,6 @@ static int syntax_validate_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entr + static void syntax_validate_task_destructor(Slapi_Task *task); + static void syntax_validate_task_thread(void *arg); + static int syntax_validate_task_callback(Slapi_Entry *e, void *callback_data); +-static const char *fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val); + static void syntax_validate_set_plugin_id(void *plugin_id); + static void *syntax_validate_get_plugin_id(void); + +@@ -258,25 +257,6 @@ bail: + return rc; + } + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) { +- return default_val; +- } +- +- slapi_attr_first_value(attr, &val); +- +- return slapi_value_get_string(val); +-} +- + /* + * Plug-in identity management helper functions + */ +diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h +index 4b75654e7..bdad4e59e 100644 +--- a/ldap/servers/slapd/slapi-plugin.h ++++ b/ldap/servers/slapd/slapi-plugin.h +@@ -8294,6 +8294,8 @@ int32_t slapi_atomic_decr_32(int32_t *ptr, int memorder); + */ + uint64_t slapi_atomic_decr_64(uint64_t *ptr, int memorder); + ++/* helper function */ ++const char * fetch_attr(Slapi_Entry *e, const char *attrname, char *default_val); + + #ifdef __cplusplus + } +diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c +index 3f9d5d995..698ee19b9 100644 +--- a/ldap/servers/slapd/task.c ++++ b/ldap/servers/slapd/task.c +@@ -80,7 +80,6 @@ static void destroy_task(time_t when, void *arg); + static int task_modify(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg); + static int task_deny(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg); + static void task_generic_destructor(Slapi_Task *task); +-static const char *fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val); + static Slapi_Entry *get_internal_entry(Slapi_PBlock *pb, char *dn); + static void modify_internal_entry(char *dn, LDAPMod **mods); + static void fixup_tombstone_task_destructor(Slapi_Task *task); +@@ -684,22 +683,6 @@ destroy_task(time_t when, void *arg) + slapi_ch_free((void **)&task); + } + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- slapi_attr_first_value(attr, &val); +- return slapi_value_get_string(val); +-} +- + /* supply the pblock, destroy it when you're done */ + static Slapi_Entry * + get_internal_entry(Slapi_PBlock *pb, char *dn) +diff --git a/ldap/servers/slapd/test-plugins/sampletask.c b/ldap/servers/slapd/test-plugins/sampletask.c +index d04f21b3d..22d43dd48 100644 +--- a/ldap/servers/slapd/test-plugins/sampletask.c ++++ b/ldap/servers/slapd/test-plugins/sampletask.c +@@ -116,22 +116,6 @@ task_sampletask_thread(void *arg) + slapi_task_finish(task, rv); + } + +-/* extract a single value from the entry (as a string) -- if it's not in the +- * entry, the default will be returned (which can be NULL). +- * you do not need to free anything returned by this. +- */ +-static const char * +-fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val) +-{ +- Slapi_Attr *attr; +- Slapi_Value *val = NULL; +- +- if (slapi_entry_attr_find(e, attrname, &attr) != 0) +- return default_val; +- slapi_attr_first_value(attr, &val); +- return slapi_value_get_string(val); +-} +- + static void + task_sampletask_destructor(Slapi_Task *task) + { +diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c +index cb46efb3d..8563c5d27 100644 +--- a/ldap/servers/slapd/util.c ++++ b/ldap/servers/slapd/util.c +@@ -1579,3 +1579,20 @@ slapi_create_errormsg( + va_end(ap); + } + } ++ ++/* ++ * Extract a single value from an entry (as a string) -- if it's not in the ++ * entry, the default will be returned (which can be NULL). You do not need ++ * to free the returned string value. ++ */ ++const char * ++fetch_attr(Slapi_Entry *e, const char *attrname, char *default_val) ++{ ++ Slapi_Attr *attr; ++ Slapi_Value *val = NULL; ++ ++ if (slapi_entry_attr_find(e, attrname, &attr) != 0) ++ return default_val; ++ slapi_attr_first_value(attr, &val); ++ return slapi_value_get_string(val); ++} +-- +2.17.2 + diff --git a/SOURCES/0015-Ticket-49915-fix-compiler-warnings.patch b/SOURCES/0015-Ticket-49915-fix-compiler-warnings.patch new file mode 100644 index 0000000..4357858 --- /dev/null +++ b/SOURCES/0015-Ticket-49915-fix-compiler-warnings.patch @@ -0,0 +1,57 @@ +From b1cc97c13bbbcaa6a3c217d285283203809fa90b Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Tue, 16 Oct 2018 10:49:29 +0200 +Subject: [PATCH] Ticket 49915 - fix compiler warnings + +--- + ldap/servers/slapd/back-ldbm/idl_new.c | 2 +- + ldap/servers/slapd/back-ldbm/index.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c +index 102265c47..81172f590 100644 +--- a/ldap/servers/slapd/back-ldbm/idl_new.c ++++ b/ldap/servers/slapd/back-ldbm/idl_new.c +@@ -379,7 +379,7 @@ idl_new_range_fetch( + bck_info.index = SLAPI_ATTR_PARENTID; + bck_info.key = "0"; + +- if (rc = slapi_back_get_info(be, BACK_INFO_INDEX_KEY, (void **)&bck_info)) { ++ if ((rc = slapi_back_get_info(be, BACK_INFO_INDEX_KEY, (void **)&bck_info))) { + slapi_log_err(SLAPI_LOG_WARNING, "idl_new_range_fetch", "Total update: fail to retrieve suffix entryID, continue assuming it is the first entry\n"); + } + if (bck_info.key_found) { +diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c +index dea6e9a3e..f0b969ff4 100644 +--- a/ldap/servers/slapd/back-ldbm/index.c ++++ b/ldap/servers/slapd/back-ldbm/index.c +@@ -1262,7 +1262,7 @@ set_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info) + /* Start a txn */ + li = (struct ldbminfo *)be->be_database->plg_private; + dblayer_txn_init(li, &txn); +- if (rc = dblayer_txn_begin(be, txn.back_txn_txn, &txn)) { ++ if ((rc = dblayer_txn_begin(be, txn.back_txn_txn, &txn))) { + slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): txn begin fails\n", + info->index, info->key, info->id); + return rc; +@@ -1272,7 +1272,7 @@ set_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info) + sv_key[1] = NULL; + slapi_value_init_string(sv_key[0], info->key); + +- if (rc = index_addordel_values_sv(be, info->index, sv_key, NULL, info->id, BE_INDEX_ADD, &txn)) { ++ if ((rc = index_addordel_values_sv(be, info->index, sv_key, NULL, info->id, BE_INDEX_ADD, &txn))) { + value_done(sv_key[0]); + dblayer_txn_abort(be, &txn); + slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): index_addordel_values_sv fails\n", +@@ -1281,7 +1281,7 @@ set_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info) + } + + value_done(sv_key[0]); +- if (rc = dblayer_txn_commit(be, &txn)) { ++ if ((rc = dblayer_txn_commit(be, &txn))) { + slapi_log_err(SLAPI_LOG_ERR, "set_suffix_key", "Fail to update %s index with %s/%d (key/ID): commit fails\n", + info->index, info->key, info->id); + return rc; +-- +2.17.2 + diff --git a/SOURCES/0016-Ticket-49915-fix-compiler-warnings-2nd.patch b/SOURCES/0016-Ticket-49915-fix-compiler-warnings-2nd.patch new file mode 100644 index 0000000..ce463a8 --- /dev/null +++ b/SOURCES/0016-Ticket-49915-fix-compiler-warnings-2nd.patch @@ -0,0 +1,25 @@ +From 309b90041dcaa2ddc1931dddea0827cef0cbb9bf Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Tue, 16 Oct 2018 15:06:38 +0200 +Subject: [PATCH] Ticket 49915 - fix compiler warnings (2nd) + +--- + ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +index a3241b078..61c3313c5 100644 +--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +@@ -305,6 +305,8 @@ int index_buffer_init(size_t size, int flags, void **h); + int index_buffer_flush(void *h, backend *be, DB_TXN *txn, struct attrinfo *a); + int index_buffer_terminate(void *h); + ++int get_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info); ++int set_suffix_key(Slapi_Backend *be, struct _back_info_index_key *info); + char *index_index2prefix(const char *indextype); + void index_free_prefix(char *); + +-- +2.17.2 + diff --git a/SOURCES/0017-Ticket-49618-Increase-cachememsize-and-dncachememsize.patch b/SOURCES/0017-Ticket-49618-Increase-cachememsize-and-dncachememsize.patch new file mode 100644 index 0000000..7b4ae87 --- /dev/null +++ b/SOURCES/0017-Ticket-49618-Increase-cachememsize-and-dncachememsize.patch @@ -0,0 +1,51 @@ +From 60c0e7dfb30fbd8100d45e79d11141956f51656f Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Fri, 14 Dec 2018 17:34:34 +0100 +Subject: [PATCH] Issue 49618 - Increase cachememsize and dncachememsize + variable sizes + +Description: nssapld-cachememsize is reverted to a smaller value +if the cap is reached. Increase it to UINT64. + +https://pagure.io/389-ds-base/issue/49618 + +Reviewed by: tbordaz, mreynolds (Thanks!) +--- + ldap/servers/slapd/back-ldbm/ldbm_config.c | 2 +- + ldap/servers/slapd/back-ldbm/ldbm_instance_config.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c +index 4e1a94341..144c5efc5 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_config.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c +@@ -2118,7 +2118,7 @@ ldbm_config_get(void *arg, config_info *config, char *buf) + break; + case CONFIG_TYPE_SIZE_T: + val = (size_t)config->config_get_fn(arg); +- sprintf(buf, "%lu", (long unsigned int)val); ++ sprintf(buf, "%" PRIu32, (uint32_t)val); + break; + case CONFIG_TYPE_UINT64: + val = (uint64_t)((uintptr_t)config->config_get_fn(arg)); +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c +index 643628c85..5eac1c1df 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c +@@ -366,11 +366,11 @@ ldbm_instance_config_require_index_set(void *arg, + *----------------------------------------------------------------------*/ + static config_info ldbm_instance_config[] = { + {CONFIG_INSTANCE_CACHESIZE, CONFIG_TYPE_LONG, "-1", &ldbm_instance_config_cachesize_get, &ldbm_instance_config_cachesize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, +- {CONFIG_INSTANCE_CACHEMEMSIZE, CONFIG_TYPE_SIZE_T, DEFAULT_CACHE_SIZE_STR, &ldbm_instance_config_cachememsize_get, &ldbm_instance_config_cachememsize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, ++ {CONFIG_INSTANCE_CACHEMEMSIZE, CONFIG_TYPE_UINT64, DEFAULT_CACHE_SIZE_STR, &ldbm_instance_config_cachememsize_get, &ldbm_instance_config_cachememsize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, + {CONFIG_INSTANCE_READONLY, CONFIG_TYPE_ONOFF, "off", &ldbm_instance_config_readonly_get, &ldbm_instance_config_readonly_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, + {CONFIG_INSTANCE_REQUIRE_INDEX, CONFIG_TYPE_ONOFF, "off", &ldbm_instance_config_require_index_get, &ldbm_instance_config_require_index_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, + {CONFIG_INSTANCE_DIR, CONFIG_TYPE_STRING, NULL, &ldbm_instance_config_instance_dir_get, &ldbm_instance_config_instance_dir_set, CONFIG_FLAG_ALWAYS_SHOW}, +- {CONFIG_INSTANCE_DNCACHEMEMSIZE, CONFIG_TYPE_SIZE_T, DEFAULT_DNCACHE_SIZE_STR, &ldbm_instance_config_dncachememsize_get, &ldbm_instance_config_dncachememsize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, ++ {CONFIG_INSTANCE_DNCACHEMEMSIZE, CONFIG_TYPE_UINT64, DEFAULT_DNCACHE_SIZE_STR, &ldbm_instance_config_dncachememsize_get, &ldbm_instance_config_dncachememsize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, + {NULL, 0, NULL, NULL, NULL, 0}}; + + void +-- +2.17.2 + diff --git a/SOURCES/0018-Ticket-50020-during-MODRDN-referential-integrity-can.patch b/SOURCES/0018-Ticket-50020-during-MODRDN-referential-integrity-can.patch new file mode 100644 index 0000000..bd10630 --- /dev/null +++ b/SOURCES/0018-Ticket-50020-during-MODRDN-referential-integrity-can.patch @@ -0,0 +1,209 @@ +From 70fd6e1fa6667734f39146cef53de6e3ff22d765 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Fri, 9 Nov 2018 17:07:11 +0100 +Subject: [PATCH] Ticket 50020 - during MODRDN referential integrity can fail + erronously while updating large groups + +Bug Description: + During a MODRDN of a group member, referential integrity will update the groups containing this member. + Under specific conditions, the MODRDN can fail (err=1). + + on MODRDN Referential integrity checks if the original DN of the target MODRDN entry is + member of a given group. If it is then it updates the group. + The returned code of the group update is using the variable 'rc'. + It does a normalized DN comparison to compare original DN with members DN, to determine if + a group needs to be updated. + If the group does not need to be updated, 'rc' is not set. + The bug is that it uses 'rc' to normalize the DN and if the group is not updated + the returned code reflects the normalization returned code rather that the group update. + + The bug is hit in specific conditions + + One of the evaluated group contains more than 128 members + the last member (last value) of the group is not the moved entry + the last member (last value) of the group is a DN value that contains escaped chars + +Fix Description: + Use a local variable to check the result of the DN normalization + +https://pagure.io/389-ds-base/issue/50020 + +Reviewed by: Simon Pichugin, Mark Reynolds (thanks) + +Platforms tested: F27 + +Flag Day: no +--- + .../tests/suites/plugins/referint_test.py | 103 ++++++++++++++++++ + ldap/servers/plugins/referint/referint.c | 18 +-- + 2 files changed, 113 insertions(+), 8 deletions(-) + create mode 100644 dirsrvtests/tests/suites/plugins/referint_test.py + +diff --git a/dirsrvtests/tests/suites/plugins/referint_test.py b/dirsrvtests/tests/suites/plugins/referint_test.py +new file mode 100644 +index 000000000..67a11de9e +--- /dev/null ++++ b/dirsrvtests/tests/suites/plugins/referint_test.py +@@ -0,0 +1,103 @@ ++# --- BEGIN COPYRIGHT BLOCK --- ++# Copyright (C) 2016 Red Hat, Inc. ++# All rights reserved. ++# ++# License: GPL (version 3 or any later version). ++# See LICENSE for details. ++# --- END COPYRIGHT BLOCK --- ++# ++''' ++Created on Dec 12, 2019 ++ ++@author: tbordaz ++''' ++import logging ++import subprocess ++import pytest ++from lib389 import Entry ++from lib389.utils import * ++from lib389.plugins import * ++from lib389._constants import * ++from lib389.idm.user import UserAccounts, UserAccount ++from lib389.idm.group import Groups ++from lib389.topologies import topology_st as topo ++ ++log = logging.getLogger(__name__) ++ ++ESCAPED_RDN_BASE = "foo\,oo" ++def _user_get_dn(no): ++ uid = '%s%d' % (ESCAPED_RDN_BASE, no) ++ dn = 'uid=%s,%s' % (uid, SUFFIX) ++ return (uid, dn) ++ ++def add_escaped_user(server, no): ++ (uid, dn) = _user_get_dn(no) ++ log.fatal('Adding user (%s): ' % dn) ++ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'], ++ 'uid': [uid], ++ 'sn' : [uid], ++ 'cn' : [uid]}))) ++ return dn ++ ++@pytest.mark.ds50020 ++def test_referential_false_failure(topo): ++ """On MODRDN referential integrity can erronously fail ++ ++ :id: f77aeb80-c4c4-471b-8c1b-4733b714778b ++ :setup: Standalone Instance ++ :steps: ++ 1. Configure the plugin ++ 2. Create a group ++ - 1rst member the one that will be move ++ - more than 128 members ++ - last member is a DN containing escaped char ++ 3. Rename the 1rst member ++ :expectedresults: ++ 1. should succeed ++ 2. should succeed ++ 3. should succeed ++ """ ++ ++ inst = topo[0] ++ ++ # stop the plugin, and start it ++ plugin = ReferentialIntegrityPlugin(inst) ++ plugin.disable() ++ plugin.enable() ++ ++ ############################################################################ ++ # Configure plugin ++ ############################################################################ ++ GROUP_CONTAINER = "ou=groups,%s" % DEFAULT_SUFFIX ++ plugin.replace('referint-membership-attr', 'member') ++ plugin.replace('nsslapd-plugincontainerscope', GROUP_CONTAINER) ++ ++ ############################################################################ ++ # Creates a group with members having escaped DN ++ ############################################################################ ++ # Add some users and a group ++ users = UserAccounts(inst, DEFAULT_SUFFIX, None) ++ user1 = users.create_test_user(uid=1001) ++ user2 = users.create_test_user(uid=1002) ++ ++ groups = Groups(inst, GROUP_CONTAINER, None) ++ group = groups.create(properties={'cn': 'group'}) ++ group.add('member', user2.dn) ++ group.add('member', user1.dn) ++ ++ # Add more than 128 members so that referint follows the buggy path ++ for i in range(130): ++ escaped_user = add_escaped_user(inst, i) ++ group.add('member', escaped_user) ++ ++ ############################################################################ ++ # Check that the MODRDN succeeds ++ ########################################################################### ++ # Here we need to restart so that member values are taken in the right order ++ # the last value is the escaped one ++ inst.restart() ++ ++ # Here if the bug is fixed, referential is able to update the member value ++ inst.rename_s(user1.dn, 'uid=new_test_user_1001', newsuperior=SUFFIX, delold=0) ++ ++ +diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c +index f6d1c27a2..9e4e680d3 100644 +--- a/ldap/servers/plugins/referint/referint.c ++++ b/ldap/servers/plugins/referint/referint.c +@@ -824,20 +824,21 @@ _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */ + */ + for (nval = slapi_attr_first_value(attr, &v); nval != -1; + nval = slapi_attr_next_value(attr, nval, &v)) { ++ int normalize_rc; + p = NULL; + dnlen = 0; + + /* DN syntax, which should be a string */ + sval = slapi_ch_strdup(slapi_value_get_string(v)); +- rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); +- if (rc == 0) { /* sval is passed in; not terminated */ ++ normalize_rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); ++ if (normalize_rc == 0) { /* sval is passed in; not terminated */ + *(p + dnlen) = '\0'; + sval = p; +- } else if (rc > 0) { ++ } else if (normalize_rc > 0) { + slapi_ch_free_string(&sval); + sval = p; + } +- /* else: (rc < 0) Ignore the DN normalization error for now. */ ++ /* else: (normalize_rc < 0) Ignore the DN normalization error for now. */ + + p = PL_strstr(sval, slapi_sdn_get_ndn(origDN)); + if (p == sval) { +@@ -1013,20 +1014,21 @@ _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */ + for (nval = slapi_attr_first_value(attr, &v); + nval != -1; + nval = slapi_attr_next_value(attr, nval, &v)) { ++ int normalize_rc; + p = NULL; + dnlen = 0; + + /* DN syntax, which should be a string */ + sval = slapi_ch_strdup(slapi_value_get_string(v)); +- rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); +- if (rc == 0) { /* sval is passed in; not terminated */ ++ normalize_rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); ++ if (normalize_rc == 0) { /* sval is passed in; not terminated */ + *(p + dnlen) = '\0'; + sval = p; +- } else if (rc > 0) { ++ } else if (normalize_rc > 0) { + slapi_ch_free_string(&sval); + sval = p; + } +- /* else: (rc < 0) Ignore the DN normalization error for now. */ ++ /* else: normalize_rc < 0) Ignore the DN normalization error for now. */ + + p = PL_strstr(sval, slapi_sdn_get_ndn(origDN)); + if (p == sval) { +-- +2.17.2 + diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index cc73e59..200a9de 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -39,7 +39,7 @@ Summary: 389 Directory Server (%{variant}) Name: 389-ds-base Version: 1.3.8.4 -Release: %{?relprefix}18%{?prerel}%{?dist} +Release: %{?relprefix}22%{?prerel}%{?dist} License: GPLv3+ URL: https://www.port389.org/ Group: System Environment/Daemons @@ -159,6 +159,13 @@ Patch09: 0009-Bug-1624004-fix-regression-in-empty-attribute-list.patch Patch10: 0010-Ticket-49968-Confusing-CRITICAL-message-list_candida.patch Patch11: 0011-Ticket-49967-entry-cache-corruption-after-failed-MOD.patch Patch12: 0012-Ticket-49958-extended-search-fail-to-match-entries.patch +Patch13: 0013-Ticket-49915-Master-ns-slapd-had-100-CPU-usage-after.patch +Patch14: 0014-Ticket-49950-PassSync-not-setting-pwdLastSet-attribu.patch +Patch15: 0015-Ticket-49915-fix-compiler-warnings.patch +Patch16: 0016-Ticket-49915-fix-compiler-warnings-2nd.patch +Patch17: 0017-Ticket-49618-Increase-cachememsize-and-dncachememsize.patch +Patch21: 0018-Ticket-50020-during-MODRDN-referential-integrity-can.patch + %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -507,6 +514,24 @@ fi %{_sysconfdir}/%{pkgname}/dirsrvtests %changelog +* Mon Dec 17 2018 Mark Reynolds - 1.3.8.4-22 +- Bump version to 1.3.8.4-22 +- Resolves: Bug 1660120 - certmap fails when Issuer DN has comma in name + +* Mon Dec 17 2018 Mark Reynolds - 1.3.8.4-21 +- Bump version to 1.3.8.4-21 +- Resolves: Bug 1659510 - during MODRDN referential integrity can fail erronously while updating large groups +- Resolves: Bug 1659936 - After RHEL 7.6 HTB update, unable to set nsslapd-cachememsize (RHDS 10) to custom value + +* Tue Dec 4 2018 Mark Reynolds - 1.3.8.4-20 +- Bump version to 1.3.8.4-20 +- Resolves: Bug 1645197 - Fix compiler warnings + +* Tue Dec 4 2018 Mark Reynolds - 1.3.8.4-19 +- Bump version to 1.3.8.4-19 +- Resolves: Bug 1653820 - PassSync not setting pwdLastSet attribute in Active Directory after Pw update from LDAP sync for normal user +- Resolves: Bug 1645197 - on-line re-initialization hangs + * Mon Oct 29 2018 Mark Reynolds - 1.3.8.4-18 - Bump version to 1.3.8.4-18 - Resolves: Bug 1638516 - CRIT - list_candidates - NULL idl was recieved from filter_candidates_ex