import 389-ds-base-1.3.4.0-32.el7_2

This commit is contained in:
CentOS Sources 2016-06-23 10:53:01 -04:00
parent ed61979b35
commit f5000ecbbb
6 changed files with 1687 additions and 2 deletions

View file

@ -0,0 +1,103 @@
From ce824731f4839f7812109b8c04ce704a56eeca4b Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Wed, 10 Feb 2016 11:36:32 -0800
Subject: [PATCH 90/93] Ticket #48492 - heap corruption at schema replication.
Description: 389-ds-base-1.3.2 and newer uses openldap schema parser,
which is more strict with the definition. For instance, the older
389-ds-base could have a schema such as SINTAX OID in single quotes,
which is not acceptable on the newer version. There was a bug to
handle the error case that caused a crash.
This patch adds
1) the null reference check to attr_syntax_free (attrsyntax.c),
2) a null init to the output arg in parse_at_str and parse_oc_str
(schema.c) and
3) an error logging to schema_berval_to_atlist & schema_berval_to_oclist
(schema.c) for troubleshooting.
https://fedorahosted.org/389/ticket/48492
Reviewed by wibrown@redhat.com and mreynolds@redhat.com (Thank you, William and Mark!)
(cherry picked from commit b5bfa2a0386e168ce2196a077169382ae53a94b4)
(cherry picked from commit 9bd53c297683e691fef174bf1aed6842f475fb9f)
---
ldap/servers/slapd/attrsyntax.c | 3 +++
ldap/servers/slapd/schema.c | 16 +++++++++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index 4cdcf86..8b2a77a 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -189,6 +189,9 @@ attr_syntax_check_oids()
void
attr_syntax_free( struct asyntaxinfo *a )
{
+ if (!a) {
+ return;
+ }
cool_charray_free( a->asi_aliases );
slapi_ch_free_string(&a->asi_name );
slapi_ch_free_string(&a->asi_desc );
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index 65cbad5..dd56599 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -263,6 +263,9 @@ static PRCallOnceType schema_dse_mandatory_init_callonce = { 0, 0, 0 };
static int parse_at_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf, size_t errorbufsize,
PRUint32 schema_flags, int is_user_defined, int schema_ds4x_compat, int is_remote)
{
+ if (asipp) {
+ *asipp = NULL;
+ }
#ifdef USE_OPENLDAP
return parse_attr_str(input, asipp, errorbuf, errorbufsize, schema_flags, is_user_defined,schema_ds4x_compat,is_remote);
#else
@@ -274,6 +277,9 @@ static int parse_oc_str(const char *input, struct objclass **oc, char *errorbuf,
size_t errorbufsize, PRUint32 schema_flags, int is_user_defined,
int schema_ds4x_compat, struct objclass* private_schema )
{
+ if (oc) {
+ *oc = NULL;
+ }
#ifdef USE_OPENLDAP
return parse_objclass_str (input, oc, errorbuf, errorbufsize, schema_flags, is_user_defined, schema_ds4x_compat, private_schema );
#else
@@ -7146,11 +7152,15 @@ schema_berval_to_oclist(struct berval **oc_berval)
oc_list = NULL;
oc_tail = NULL;
if (oc_berval != NULL) {
+ errorbuf[0] = '\0';
for (i = 0; oc_berval[i] != NULL; i++) {
/* parse the objectclass value */
if (LDAP_SUCCESS != (rc = parse_oc_str(oc_berval[i]->bv_val, &oc,
errorbuf, sizeof (errorbuf), DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0,
schema_ds4x_compat, oc_list))) {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema",
+ "parse_oc_str returned error: %s\n",
+ errorbuf[0]?errorbuf:"unknown");
oc_free(&oc);
rc = 1;
break;
@@ -7184,11 +7194,15 @@ schema_berval_to_atlist(struct berval **at_berval)
schema_ds4x_compat = config_get_ds4_compatible_schema();
if (at_berval != NULL) {
+ errorbuf[0] = '\0';
for (i = 0; at_berval[i] != NULL; i++) {
/* parse the objectclass value */
rc = parse_at_str(at_berval[i]->bv_val, &at, errorbuf, sizeof (errorbuf),
DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0, schema_ds4x_compat, 0);
- if(rc){
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema",
+ "parse_oc_str returned error: %s\n",
+ errorbuf[0]?errorbuf:"unknown");
attr_syntax_free(at);
break;
}
--
2.4.11

View file

@ -0,0 +1,218 @@
From bc3328ebbe1b8279f77ad1020bce9fb638d4c94c Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Fri, 8 Apr 2016 14:17:12 -0700
Subject: [PATCH 91/93] Ticket #48492 - heap corruption at schema replication.
Bug Description: If nsslapd-enquote-sup-oc is on, the server is supposed to
handle the quoted SYNTAX values although the spec is deprecated. Currently,
if nsslapd-enquote-sup-oc is on, it wraps SYNTAX values with quotes, but the
information is not passed to the openldap schema parser where the parsing the
schema fails.
Fix Description: This patch passes the info (flag LDAP_SCHEMA_ALLOW_QUOTED)
to the openldap API ldap_str2attributetype if nsslapd-enquote-sup-oc is on.
Additionally, to support the old style quoted SYNTAX values in the schema
files, loading the schema has to get the enquote information prior to the
configuration parameters evaluated. To pass the information, this patch
accepts the environment variable LDAP_SCHEMA_ALLOW_QUOTED. If it is defined
with any value, old style schema files are processed.
To set the environment variable, add
LDAP_SCHEMA_ALLOW_QUOTED="on"
to /etc/sysconfig/dirsrv-INSTANCE.
https://fedorahosted.org/389/ticket/48492
Reviewed by firstyear@redhat.com (Thank you, William!!)
(cherry picked from commit 955dc66d42511c2cc8d6ff18cf030508f6da2770)
(cherry picked from commit 7927e4420fb185ae328d56cfd4741583ae1f667b)
---
ldap/servers/slapd/schema.c | 66 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 51 insertions(+), 15 deletions(-)
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
index dd56599..806c38d 100644
--- a/ldap/servers/slapd/schema.c
+++ b/ldap/servers/slapd/schema.c
@@ -1638,6 +1638,16 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
}
if ( !aew->schema_ds4x_compat ) {
+#if defined (USE_OPENLDAP)
+ /*
+ * These values in quotes are not supported by the openldap parser.
+ * Even if nsslapd-enquote-sup-oc is on, quotes should not be added.
+ */
+ outp += put_tagged_oid( outp, "SUP ", asip->asi_superior, NULL, 0 );
+ outp += put_tagged_oid( outp, "EQUALITY ", asip->asi_mr_equality, NULL, 0 );
+ outp += put_tagged_oid( outp, "ORDERING ", asip->asi_mr_ordering, NULL, 0 );
+ outp += put_tagged_oid( outp, "SUBSTR ", asip->asi_mr_substring, NULL, 0 );
+#else
outp += put_tagged_oid( outp, "SUP ",
asip->asi_superior, NULL, aew->enquote_sup_oc );
outp += put_tagged_oid( outp, "EQUALITY ",
@@ -1646,6 +1656,7 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
asip->asi_mr_ordering, NULL, aew->enquote_sup_oc );
outp += put_tagged_oid( outp, "SUBSTR ",
asip->asi_mr_substring, NULL, aew->enquote_sup_oc );
+#endif
}
outp += put_tagged_oid( outp, "SYNTAX ", syntaxoid, syntaxlengthbuf,
@@ -4105,7 +4116,7 @@ parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
char **attr_names = NULL;
unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE;
/* If we ever accept openldap schema directly, then make parser_flags configurable */
- const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
+ unsigned int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
int invalid_syntax_error;
int syntaxlength = SLAPI_SYNTAXLENGTH_NONE;
int num_names = 0;
@@ -4113,6 +4124,17 @@ parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
int rc = 0;
int a, aa;
+ if (config_get_enquote_sup_oc()) {
+ parser_flags |= LDAP_SCHEMA_ALLOW_QUOTED;
+ } else if (getenv("LDAP_SCHEMA_ALLOW_QUOTED")) {
+ char ebuf[SLAPI_DSE_RETURNTEXT_SIZE];
+ parser_flags |= LDAP_SCHEMA_ALLOW_QUOTED;
+ if (config_set_enquote_sup_oc(CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, "on", ebuf, CONFIG_APPLY)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema", "Failed to enable %s: %s\n",
+ CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, ebuf);
+ }
+ }
+
/*
* OpenLDAP AttributeType struct
*
@@ -4159,7 +4181,7 @@ parse_attr_str(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
/* trim any leading spaces */
input++;
}
- if((atype = ldap_str2attributetype(input, &rc, &errp, parser_flags )) == NULL){
+ if((atype = ldap_str2attributetype(input, &rc, &errp, (const unsigned int)parser_flags )) == NULL){
schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, input,
"Failed to parse attribute, error(%d - %s) at (%s)", rc, ldap_scherr2str(rc), errp );
return invalid_syntax_error;
@@ -4478,12 +4500,23 @@ parse_objclass_str ( const char *input, struct objclass **oc, char *errorbuf,
char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray;
char *first_oc_name = NULL;
/* If we ever accept openldap schema directly, then make parser_flags configurable */
- const int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
+ unsigned int parser_flags = LDAP_SCHEMA_ALLOW_NONE | LDAP_SCHEMA_ALLOW_NO_OID;
PRUint8 flags = 0;
int invalid_syntax_error;
int i, j;
int rc = 0;
+ if (config_get_enquote_sup_oc()) {
+ parser_flags |= LDAP_SCHEMA_ALLOW_QUOTED;
+ } else if (getenv("LDAP_SCHEMA_ALLOW_QUOTED")) {
+ char ebuf[SLAPI_DSE_RETURNTEXT_SIZE];
+ parser_flags |= LDAP_SCHEMA_ALLOW_QUOTED;
+ if (config_set_enquote_sup_oc(CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, "on", ebuf, CONFIG_APPLY)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema", "Failed to enable %s: %s\n",
+ CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, ebuf);
+ }
+ }
+
/*
* openLDAP Objectclass struct
*
@@ -4521,10 +4554,10 @@ parse_objclass_str ( const char *input, struct objclass **oc, char *errorbuf,
* Parse the input and create the openLdap objectclass structure
*/
while(isspace(*input)){
- /* trim any leading spaces */
+ /* trim any leading spaces */
input++;
}
- if((objClass = ldap_str2objectclass(input, &rc, &errp, parser_flags )) == NULL){
+ if((objClass = ldap_str2objectclass(input, &rc, &errp, (const unsigned int)parser_flags )) == NULL){
schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, input,
"Failed to parse objectclass, error(%d) at (%s)", rc, errp );
return invalid_syntax_error;
@@ -5592,7 +5625,7 @@ get_tagged_oid( const char *tag, const char **inputp,
PR_ASSERT( NULL != *inputp );
PR_ASSERT( NULL != tag );
PR_ASSERT( '\0' != tag[ 0 ] );
- if('(' !=tag[0])
+ if('(' !=tag[0])
PR_ASSERT((' ' == tag[ strlen( tag ) - 1 ]) || ('(' == tag[ strlen( tag ) - 1 ]));
if ( NULL == strstr_fn ) {
@@ -5611,8 +5644,8 @@ get_tagged_oid( const char *tag, const char **inputp,
/* skip past the leading single quote, if present */
if ( *startp == '\'' ) {
++startp;
- /* skip past any extra white space */
- startp = skipWS( startp );
+ /* skip past any extra white space */
+ startp = skipWS( startp );
}
/* locate the end of the OID */
@@ -7155,6 +7188,7 @@ schema_berval_to_oclist(struct berval **oc_berval)
errorbuf[0] = '\0';
for (i = 0; oc_berval[i] != NULL; i++) {
/* parse the objectclass value */
+ oc = NULL;
if (LDAP_SUCCESS != (rc = parse_oc_str(oc_berval[i]->bv_val, &oc,
errorbuf, sizeof (errorbuf), DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0,
schema_ds4x_compat, oc_list))) {
@@ -7197,12 +7231,13 @@ schema_berval_to_atlist(struct berval **at_berval)
errorbuf[0] = '\0';
for (i = 0; at_berval[i] != NULL; i++) {
/* parse the objectclass value */
+ at = NULL;
rc = parse_at_str(at_berval[i]->bv_val, &at, errorbuf, sizeof (errorbuf),
DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_USE_PRIV_SCHEMA, 0, schema_ds4x_compat, 0);
if (rc) {
slapi_log_error(SLAPI_LOG_FATAL, "schema",
- "parse_oc_str returned error: %s\n",
- errorbuf[0]?errorbuf:"unknown");
+ "schema_berval_to_atlist: parse_at_str(%s) failed - %s\n",
+ at_berval[i]->bv_val, errorbuf[0]?errorbuf:"unknown");
attr_syntax_free(at);
break;
}
@@ -7217,6 +7252,7 @@ schema_berval_to_atlist(struct berval **at_berval)
}
if (rc) {
schema_atlist_free(head);
+ head = NULL;
}
return head;
@@ -7319,12 +7355,12 @@ schema_attributetypes_superset_check(struct berval **remote_schema, char *type)
static void
modify_schema_internal_mod(Slapi_DN *sdn, Slapi_Mods *smods)
{
- Slapi_PBlock *newpb;
+ Slapi_PBlock *newpb;
int op_result;
- CSN *schema_csn;
+ CSN *schema_csn;
- /* allocate internal mod components: pblock*/
- newpb = slapi_pblock_new();
+ /* allocate internal mod components: pblock*/
+ newpb = slapi_pblock_new();
slapi_modify_internal_set_pb_ext (
newpb,
@@ -7333,7 +7369,7 @@ modify_schema_internal_mod(Slapi_DN *sdn, Slapi_Mods *smods)
NULL, /* Controls */
NULL,
(void *)plugin_get_default_component_id(),
- 0);
+ 0);
/* do modify */
slapi_modify_internal_pb (newpb);
--
2.4.11

View file

@ -0,0 +1,39 @@
From 39a14eaab84e7eac940d1d707cabc9610ef570c6 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Tue, 26 Apr 2016 13:53:02 -0700
Subject: [PATCH 92/93] Ticket #48808 - Paged results search returns the blank
list of entries
Bug Description: When a simple paged results slot in a connection is
discarded due to an error, e.g., SIZELIMIT_EXCEEDED, the slot was not
properly cleaned up. Then, if the slot was reused, the leftover flag
confused the code and ended up returning the 0 search result.
Fix Description: This patch adds the clean up code when a slot is re-
used.
https://fedorahosted.org/389/ticket/48808
Reviewed by wibrown@redhat.com (Thank you, William!!)
(cherry picked from commit 09180b25570696d24c86e3a046fb497c15549c64)
(cherry picked from commit a8486ab3b364a9ae088d6404d025058b04ac358d)
---
ldap/servers/slapd/pagedresults.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
index d394dab..52d2158 100644
--- a/ldap/servers/slapd/pagedresults.c
+++ b/ldap/servers/slapd/pagedresults.c
@@ -124,6 +124,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
prp = conn->c_pagedresults.prl_list;
for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++, prp++) {
if (!prp->pr_current_be) { /* unused slot; take it */
+ _pr_cleanup_one_slot(prp);
prp->pr_current_be = be;
*index = i;
break;
--
2.4.11

View file

@ -0,0 +1,370 @@
From fc0ca25b9f143083528cc5f87dc89fe69baf38fd Mon Sep 17 00:00:00 2001
From: Simon Pichugin <spichugi@redhat.com>
Date: Thu, 28 Apr 2016 11:49:24 +0200
Subject: [PATCH 93/93] Ticket 48808 - Add test case
Description: Add test case for paged results search returns the blank
list of entries issue.
Bug description: After series of actions, paged result search that
should returns list of entries returns blank list of entries. It is
hardly reproducible manually, but it is easy to reproduce with python
automation.
https://fedorahosted.org/389/ticket/48808
Reviewed by: nhosoi and wbrown (Thanks!)
(cherry picked from commit 91f3e592713ea58602412ed773a497583f2ebd6c)
(cherry picked from commit 99b5048b09e64cea6f8bf5e7d524679960ce0a44)
---
dirsrvtests/tests/tickets/ticket48808_test.py | 337 ++++++++++++++++++++++++++
1 file changed, 337 insertions(+)
create mode 100644 dirsrvtests/tests/tickets/ticket48808_test.py
diff --git a/dirsrvtests/tests/tickets/ticket48808_test.py b/dirsrvtests/tests/tickets/ticket48808_test.py
new file mode 100644
index 0000000..3dbceac
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket48808_test.py
@@ -0,0 +1,337 @@
+import time
+import ldap
+import logging
+import pytest
+from random import sample
+from ldap.controls import SimplePagedResultsControl
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+log = logging.getLogger(__name__)
+
+TEST_USER_NAME = 'simplepaged_test'
+TEST_USER_DN = 'uid=%s,%s' % (TEST_USER_NAME, DEFAULT_SUFFIX)
+TEST_USER_PWD = 'simplepaged_test'
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+@pytest.fixture(scope="module")
+def topology(request):
+ # Creating standalone instance ...
+ standalone = DirSrv(verbose=False)
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ standalone.delete()
+ standalone.create()
+ standalone.open()
+
+ # Delete each instance in the end
+ def fin():
+ standalone.delete()
+ request.addfinalizer(fin)
+
+ # Clear out the tmp dir
+ standalone.clearTmpDir(__file__)
+
+ return TopologyStandalone(standalone)
+
+
+@pytest.fixture(scope="module")
+def test_user(topology):
+ """User for binding operation"""
+
+ try:
+ topology.standalone.add_s(Entry((TEST_USER_DN, {
+ 'objectclass': 'top person'.split(),
+ 'objectclass': 'organizationalPerson',
+ 'objectclass': 'inetorgperson',
+ 'cn': TEST_USER_NAME,
+ 'sn': TEST_USER_NAME,
+ 'userpassword': TEST_USER_PWD,
+ 'mail': '%s@redhat.com' % TEST_USER_NAME,
+ 'uid': TEST_USER_NAME
+ })))
+ except ldap.LDAPError as e:
+ log.error('Failed to add user (%s): error (%s)' % (TEST_USER_DN,
+ e.message['desc']))
+ raise e
+
+
+def add_users(topology, users_num):
+ """Add users to the default suffix
+ and return a list of added user DNs.
+ """
+
+ users_list = []
+ log.info('Adding %d users' % users_num)
+ for num in sample(range(1000), users_num):
+ num_ran = int(round(num))
+ USER_NAME = 'test%05d' % num_ran
+ USER_DN = 'uid=%s,%s' % (USER_NAME, DEFAULT_SUFFIX)
+ users_list.append(USER_DN)
+ try:
+ topology.standalone.add_s(Entry((USER_DN, {
+ 'objectclass': 'top person'.split(),
+ 'objectclass': 'organizationalPerson',
+ 'objectclass': 'inetorgperson',
+ 'cn': USER_NAME,
+ 'sn': USER_NAME,
+ 'userpassword': 'pass%s' % num_ran,
+ 'mail': '%s@redhat.com' % USER_NAME,
+ 'uid': USER_NAME
+ })))
+ except ldap.LDAPError as e:
+ log.error('Failed to add user (%s): error (%s)' % (USER_DN,
+ e.message['desc']))
+ raise e
+ return users_list
+
+
+def del_users(topology, users_list):
+ """Delete users with DNs from given list"""
+
+ log.info('Deleting %d users' % len(users_list))
+ for user_dn in users_list:
+ try:
+ topology.standalone.delete_s(user_dn)
+ except ldap.LDAPError as e:
+ log.error('Failed to delete user (%s): error (%s)' % (user_dn,
+ e.message['desc']))
+ raise e
+
+
+def change_conf_attr(topology, suffix, attr_name, attr_value):
+ """Change configurational attribute in the given suffix.
+ Funtion returns previous attribute value.
+ """
+
+ try:
+ entries = topology.standalone.search_s(suffix, ldap.SCOPE_BASE,
+ 'objectclass=top',
+ [attr_name])
+ attr_value_bck = entries[0].data.get(attr_name)
+ log.info('Set %s to %s. Previous value - %s. Modified suffix - %s.' % (
+ attr_name, attr_value, attr_value_bck, suffix))
+ if attr_value is None:
+ topology.standalone.modify_s(suffix, [(ldap.MOD_DELETE,
+ attr_name,
+ attr_value)])
+ else:
+ topology.standalone.modify_s(suffix, [(ldap.MOD_REPLACE,
+ attr_name,
+ attr_value)])
+ except ldap.LDAPError as e:
+ log.error('Failed to change attr value (%s): error (%s)' % (attr_name,
+ e.message['desc']))
+ raise e
+
+ return attr_value_bck
+
+
+def paged_search(topology, controls, search_flt, searchreq_attrlist):
+ """Search at the DEFAULT_SUFFIX with ldap.SCOPE_SUBTREE
+ using Simple Paged Control(should the first item in the
+ list controls.
+ Return the list with results summarized from all pages
+ """
+
+ pages = 0
+ pctrls = []
+ all_results = []
+ req_ctrl = controls[0]
+ msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ search_flt,
+ searchreq_attrlist,
+ serverctrls=controls)
+ while True:
+ log.info('Getting page %d' % (pages,))
+ rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
+ all_results.extend(rdata)
+ pages += 1
+ pctrls = [
+ c
+ for c in rctrls
+ if c.controlType == SimplePagedResultsControl.controlType
+ ]
+
+ if pctrls:
+ if pctrls[0].cookie:
+ # Copy cookie from response control to request control
+ req_ctrl.cookie = pctrls[0].cookie
+ msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ search_flt,
+ searchreq_attrlist,
+ serverctrls=controls)
+ else:
+ break # no more pages available
+ else:
+ break
+
+ assert not pctrls[0].cookie
+ return all_results
+
+
+def test_ticket48808(topology, test_user):
+ log.info('Run multiple paging controls on a single connection')
+ users_num = 100
+ page_size = 30
+ users_list = add_users(topology, users_num)
+ search_flt = r'(uid=test*)'
+ searchreq_attrlist = ['dn', 'sn']
+
+ log.info('Set user bind')
+ topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+
+ log.info('Create simple paged results control instance')
+ req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+ controls = [req_ctrl]
+
+ for ii in xrange(3):
+ log.info('Iteration %d' % ii)
+ msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ search_flt,
+ searchreq_attrlist,
+ serverctrls=controls)
+ rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
+ pctrls = [
+ c
+ for c in rctrls
+ if c.controlType == SimplePagedResultsControl.controlType
+ ]
+
+ req_ctrl.cookie = pctrls[0].cookie
+ msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ search_flt,
+ searchreq_attrlist,
+ serverctrls=controls)
+ log.info('Set Directory Manager bind back')
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ del_users(topology, users_list)
+
+ log.info('Abandon the search')
+ users_num = 10
+ page_size = 0
+ users_list = add_users(topology, users_num)
+ search_flt = r'(uid=test*)'
+ searchreq_attrlist = ['dn', 'sn']
+
+ log.info('Set user bind')
+ topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+
+ log.info('Create simple paged results control instance')
+ req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+ controls = [req_ctrl]
+
+ msgid = topology.standalone.search_ext(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ search_flt,
+ searchreq_attrlist,
+ serverctrls=controls)
+ rtype, rdata, rmsgid, rctrls = topology.standalone.result3(msgid)
+ pctrls = [
+ c
+ for c in rctrls
+ if c.controlType == SimplePagedResultsControl.controlType
+ ]
+ assert not pctrls[0].cookie
+
+ log.info('Set Directory Manager bind back')
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ del_users(topology, users_list)
+
+ log.info("Search should fail with 'nsPagedSizeLimit = 5'"
+ "and 'nsslapd-pagedsizelimit = 15' with 10 users")
+ conf_attr = '15'
+ user_attr = '5'
+ expected_rs = ldap.SIZELIMIT_EXCEEDED
+ users_num = 10
+ page_size = 10
+ users_list = add_users(topology, users_num)
+ search_flt = r'(uid=test*)'
+ searchreq_attrlist = ['dn', 'sn']
+ conf_attr_bck = change_conf_attr(topology, DN_CONFIG,
+ 'nsslapd-pagedsizelimit', conf_attr)
+ user_attr_bck = change_conf_attr(topology, TEST_USER_DN,
+ 'nsPagedSizeLimit', user_attr)
+
+ log.info('Set user bind')
+ topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+
+ log.info('Create simple paged results control instance')
+ req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+ controls = [req_ctrl]
+
+ log.info('Expect to fail with SIZELIMIT_EXCEEDED')
+ with pytest.raises(expected_rs):
+ all_results = paged_search(topology, controls,
+ search_flt, searchreq_attrlist)
+
+ log.info('Set Directory Manager bind back')
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ del_users(topology, users_list)
+ change_conf_attr(topology, DN_CONFIG,
+ 'nsslapd-pagedsizelimit', conf_attr_bck)
+ change_conf_attr(topology, TEST_USER_DN,
+ 'nsPagedSizeLimit', user_attr_bck)
+
+ log.info("Search should pass with 'nsPagedSizeLimit = 15'"
+ "and 'nsslapd-pagedsizelimit = 5' with 10 users")
+ conf_attr = '5'
+ user_attr = '15'
+ users_num = 10
+ page_size = 10
+ users_list = add_users(topology, users_num)
+ search_flt = r'(uid=test*)'
+ searchreq_attrlist = ['dn', 'sn']
+ conf_attr_bck = change_conf_attr(topology, DN_CONFIG,
+ 'nsslapd-pagedsizelimit', conf_attr)
+ user_attr_bck = change_conf_attr(topology, TEST_USER_DN,
+ 'nsPagedSizeLimit', user_attr)
+
+ log.info('Set user bind')
+ topology.standalone.simple_bind_s(TEST_USER_DN, TEST_USER_PWD)
+
+ log.info('Create simple paged results control instance')
+ req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+ controls = [req_ctrl]
+
+ log.info('Search should PASS')
+ all_results = paged_search(topology, controls,
+ search_flt, searchreq_attrlist)
+ log.info('%d results' % len(all_results))
+ assert len(all_results) == len(users_list)
+
+ log.info('Set Directory Manager bind back')
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ del_users(topology, users_list)
+ change_conf_attr(topology, DN_CONFIG,
+ 'nsslapd-pagedsizelimit', conf_attr_bck)
+ change_conf_attr(topology, TEST_USER_DN,
+ 'nsPagedSizeLimit', user_attr_bck)
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
--
2.4.11

View file

@ -0,0 +1,936 @@
From 72562d03b0f758902e0ee858fd43d5bcfbef379b Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Tue, 7 Jun 2016 10:02:42 -0400
Subject: [PATCH] Ticket 48862 - At startup DES to AES password conversion
causes timeout in start script
Bug Description: At server start all the backends are searches for entries that contain
DES password attributes as defined in the plugin. These are typically
unindexed searches, and if there is a very large backend this can cause
the server startup to timeout.
Fix Description: At startup only check "cn=config" for entries with DES password attributes.
A new "conversion" task has been created that can be run after startup
to search all backends(if a suffix is not specified), or specific backends.
dn: cn=convertPasswords, cn=des2aes,cn=tasks,cn=config
objectclass: top
objectclass: extensibleObject
suffix: dc=example,dc=com
suffix: dc=other,dc=suffix
Another bug was discovered in pw_rever_encode() in pw.c where a "for" loop
counter was accidentially reused by a second "for" loop. This could lead
to an infinite loop/hang.
Updated the CI test to perform the conversion task.
https://fedorahosted.org/389/ticket/48862
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 11f55f3dd2a2c44ddf7b5be54273401add13b1bc)
(cherry picked from commit c0ad918939c40779e463b71c41ab106e7ee890e2)
---
dirsrvtests/tickets/ticket47462_test.py | 133 ++++++++----
ldap/servers/slapd/daemon.c | 195 +++++-------------
ldap/servers/slapd/pw.c | 4 +-
ldap/servers/slapd/task.c | 346 +++++++++++++++++++++++++++++++-
4 files changed, 493 insertions(+), 185 deletions(-)
diff --git a/dirsrvtests/tickets/ticket47462_test.py b/dirsrvtests/tickets/ticket47462_test.py
index 17854fa..2d2c507 100644
--- a/dirsrvtests/tickets/ticket47462_test.py
+++ b/dirsrvtests/tickets/ticket47462_test.py
@@ -32,6 +32,7 @@ AGMT_DN = ''
USER_DN = 'cn=test_user,' + DEFAULT_SUFFIX
USER1_DN = 'cn=test_user1,' + DEFAULT_SUFFIX
TEST_REPL_DN = 'cn=test repl,' + DEFAULT_SUFFIX
+DES2AES_TASK_DN = 'cn=convert,cn=des2aes,cn=tasks,cn=config'
class TopologyMaster1Master2(object):
@@ -134,6 +135,11 @@ def topology(request):
# clear the tmp directory
master1.clearTmpDir(__file__)
+ def fin():
+ master1.delete()
+ master2.delete()
+ request.addfinalizer(fin)
+
return TopologyMaster1Master2(master1, master2)
@@ -144,11 +150,9 @@ def test_ticket47462(topology):
"""
#
- # First set config as if it's an older version. Set DES to use libdes-plugin,
- # MMR to depend on DES, delete the existing AES plugin, and set a DES password
- # for the replication agreement.
- #
-
+ # First set config as if it's an older version. Set DES to use
+ # libdes-plugin, MMR to depend on DES, delete the existing AES plugin,
+ # and set a DES password for the replication agreement.
#
# Add an extra attribute to the DES plugin args
#
@@ -168,7 +172,9 @@ def test_ticket47462(topology):
try:
topology.master1.modify_s(MMR_PLUGIN,
- [(ldap.MOD_DELETE, 'nsslapd-plugin-depends-on-named', 'AES')])
+ [(ldap.MOD_DELETE,
+ 'nsslapd-plugin-depends-on-named',
+ 'AES')])
except ldap.NO_SUCH_ATTRIBUTE:
pass
@@ -194,7 +200,8 @@ def test_ticket47462(topology):
# Get the agmt dn, and set the password
#
try:
- entry = topology.master1.search_s('cn=config', ldap.SCOPE_SUBTREE, 'objectclass=nsDS5ReplicationAgreement')
+ entry = topology.master1.search_s('cn=config', ldap.SCOPE_SUBTREE,
+ 'objectclass=nsDS5ReplicationAgreement')
if entry:
agmt_dn = entry[0].dn
log.info('Found agmt dn (%s)' % agmt_dn)
@@ -207,7 +214,8 @@ def test_ticket47462(topology):
try:
properties = {RA_BINDPW: "password"}
- topology.master1.agreement.setProperties(None, agmt_dn, None, properties)
+ topology.master1.agreement.setProperties(None, agmt_dn, None,
+ properties)
log.info('Successfully modified replication agreement')
except ValueError:
log.error('Failed to update replica agreement: ' + AGMT_DN)
@@ -220,12 +228,14 @@ def test_ticket47462(topology):
topology.master1.add_s(Entry((USER1_DN,
{'objectclass': "top person".split(),
'sn': 'sn',
+ 'description': 'DES value to convert',
'cn': 'test_user'})))
loop = 0
ent = None
while loop <= 10:
try:
- ent = topology.master2.getEntry(USER1_DN, ldap.SCOPE_BASE, "(objectclass=*)")
+ ent = topology.master2.getEntry(USER1_DN, ldap.SCOPE_BASE,
+ "(objectclass=*)")
break
except ldap.NO_SUCH_OBJECT:
time.sleep(1)
@@ -250,7 +260,8 @@ def test_ticket47462(topology):
# Check that the restart converted existing DES credentials
#
try:
- entry = topology.master1.search_s('cn=config', ldap.SCOPE_SUBTREE, 'nsDS5ReplicaCredentials=*')
+ entry = topology.master1.search_s('cn=config', ldap.SCOPE_SUBTREE,
+ 'nsDS5ReplicaCredentials=*')
if entry:
val = entry[0].getValue('nsDS5ReplicaCredentials')
if val.startswith('{AES-'):
@@ -259,22 +270,25 @@ def test_ticket47462(topology):
log.fatal('Failed to convert credentials from DES to AES!')
assert False
else:
- log.fatal('Failed to find any entries with nsDS5ReplicaCredentials ')
+ log.fatal('Failed to find entries with nsDS5ReplicaCredentials')
assert False
except ldap.LDAPError, e:
log.fatal('Failed to search for replica credentials: ' + e.message['desc'])
assert False
#
- # Check that the AES plugin exists, and has all the attributes listed in DES plugin.
- # The attributes might not be in the expected order so check all the attributes.
+ # Check that the AES plugin exists, and has all the attributes listed in
+ # DES plugin. The attributes might not be in the expected order so check
+ # all the attributes.
#
try:
- entry = topology.master1.search_s(AES_PLUGIN, ldap.SCOPE_BASE, 'objectclass=*')
+ entry = topology.master1.search_s(AES_PLUGIN, ldap.SCOPE_BASE,
+ 'objectclass=*')
if not entry[0].hasValue('nsslapd-pluginarg0', 'description') and \
not entry[0].hasValue('nsslapd-pluginarg1', 'description') and \
not entry[0].hasValue('nsslapd-pluginarg2', 'description'):
- log.fatal('The AES plugin did not have the DES attribute copied over correctly')
+ log.fatal('The AES plugin did not have the DES attribute copied ' +
+ 'over correctly')
assert False
else:
log.info('The AES plugin was correctly setup')
@@ -286,7 +300,8 @@ def test_ticket47462(topology):
# Check that the MMR plugin was updated
#
try:
- entry = topology.master1.search_s(MMR_PLUGIN, ldap.SCOPE_BASE, 'objectclass=*')
+ entry = topology.master1.search_s(MMR_PLUGIN, ldap.SCOPE_BASE,
+ 'objectclass=*')
if not entry[0].hasValue('nsslapd-plugin-depends-on-named', 'AES'):
log.fatal('The MMR Plugin was not correctly updated')
assert False
@@ -300,7 +315,8 @@ def test_ticket47462(topology):
# Check that the DES plugin was correctly updated
#
try:
- entry = topology.master1.search_s(DES_PLUGIN, ldap.SCOPE_BASE, 'objectclass=*')
+ entry = topology.master1.search_s(DES_PLUGIN, ldap.SCOPE_BASE,
+ 'objectclass=*')
if not entry[0].hasValue('nsslapd-pluginPath', 'libpbe-plugin'):
log.fatal('The DES Plugin was not correctly updated')
assert False
@@ -322,7 +338,8 @@ def test_ticket47462(topology):
ent = None
while loop <= 10:
try:
- ent = topology.master2.getEntry(USER_DN, ldap.SCOPE_BASE, "(objectclass=*)")
+ ent = topology.master2.getEntry(USER_DN, ldap.SCOPE_BASE,
+ "(objectclass=*)")
break
except ldap.NO_SUCH_OBJECT:
time.sleep(1)
@@ -336,30 +353,66 @@ def test_ticket47462(topology):
log.fatal('Failed to add test user: ' + e.message['desc'])
assert False
+ # Check the entry
+ log.info('Entry before running task...')
+ try:
+ entry = topology.master1.search_s(USER1_DN,
+ ldap.SCOPE_BASE,
+ 'objectclass=*')
+ if entry:
+ print(str(entry))
+ else:
+ log.fatal('Failed to find entries')
+ assert False
+ except ldap.LDAPError as e:
+ log.fatal('Failed to search for entries: ' +
+ e.message['desc'])
+ assert False
-def test_ticket47462_final(topology):
- topology.master1.delete()
- topology.master2.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- '''
- run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
- To run isolated without py.test, you need to
- - edit this file and comment '@pytest.fixture' line before 'topology' function.
- - set the installation prefix
- - run this program
- '''
- global installation1_prefix
- global installation2_prefix
- installation1_prefix = None
- installation2_prefix = None
+ #
+ # Test the DES2AES Task on USER1_DN
+ #
+ try:
+ topology.master1.add_s(Entry((DES2AES_TASK_DN,
+ {'objectclass': ['top',
+ 'extensibleObject'],
+ 'suffix': DEFAULT_SUFFIX,
+ 'cn': 'convert'})))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add task entry: ' + e.message['desc'])
+ assert False
- topo = topology(True)
- test_ticket47462(topo)
- test_ticket47462_final(topo)
+ # Wait for task
+ task_entry = Entry(DES2AES_TASK_DN)
+ (done, exitCode) = topology.master1.tasks.checkTask(task_entry, True)
+ if exitCode:
+ log.fatal("Error: des2aes task exited with %d" % (exitCode))
+ assert False
+ # Check the entry
+ try:
+ entry = topology.master1.search_s(USER1_DN,
+ ldap.SCOPE_BASE,
+ 'objectclass=*')
+ if entry:
+ val = entry[0].getValue('description')
+ print(str(entry[0]))
+ if val.startswith('{AES-'):
+ log.info('Task: DES credentials have been converted to AES')
+ else:
+ log.fatal('Task: Failed to convert credentials from DES to ' +
+ 'AES! (%s)' % (val))
+ assert False
+ else:
+ log.fatal('Failed to find entries')
+ assert False
+ except ldap.LDAPError as e:
+ log.fatal('Failed to search for entries: ' +
+ e.message['desc'])
+ assert False
if __name__ == '__main__':
- run_isolated()
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index d702129..29562ae 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -692,14 +692,12 @@ convert_pbe_des_to_aes()
Slapi_Entry **entries = NULL;
struct slapdplugin *plugin = NULL;
char **attrs = NULL;
- char **backends = NULL;
char *val = NULL;
int converted_des_passwd = 0;
- int disable_des = 1;
int result = -1;
int have_aes = 0;
int have_des = 0;
- int i = 0, ii = 0, be_idx = 0;
+ int i = 0, ii = 0;
/*
* Check that AES plugin is enabled, and grab all the unique
@@ -733,94 +731,56 @@ convert_pbe_des_to_aes()
if(have_aes && have_des){
/*
- * Build a list of all the backend dn's
+ * Find any entries in cn=config that contain DES passwords and convert
+ * them to AES
*/
- Slapi_Backend *be = NULL;
- struct suffixlist *list;
- char *cookie = NULL;
-
- LDAPDebug(LDAP_DEBUG_ANY, "convert_pbe_des_to_aes: "
- "Checking for DES passwords to convert to AES...\n",0,0,0);
-
- be = slapi_get_first_backend(&cookie);
- while (be){
- int suffix_idx = 0;
- int count = slapi_counter_get_value(be->be_suffixcounter);
-
- list = be->be_suffixlist;
- for (suffix_idx = 0; list && suffix_idx < count; suffix_idx++) {
- char *suffix = (char *)slapi_sdn_get_ndn(list->be_suffix);
- if(charray_inlist(backends, suffix) || strlen(suffix) == 0){
- list = list->next;
- continue;
- }
- charray_add(&backends, slapi_ch_strdup(suffix));
- list = list->next;
- }
- be = slapi_get_next_backend (cookie);
- }
- slapi_ch_free ((void **)&cookie);
+ slapi_log_error(SLAPI_LOG_HOUSE, "convert_pbe_des_to_aes",
+ "Converting DES passwords to AES...\n");
- /*
- * Search for the password attributes
- */
for (i = 0; attrs && attrs[i]; i++){
char *filter = PR_smprintf("%s=*", attrs[i]);
- /*
- * Loop over all the backends looking for the password attribute
- */
- for(be_idx = 0; backends && backends[be_idx]; be_idx++){
- pb = slapi_pblock_new();
- slapi_search_internal_set_pb(pb, backends[be_idx],
- LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
- (void *)plugin_get_default_component_id(),
- SLAPI_OP_FLAG_IGNORE_UNINDEXED);
- slapi_search_internal_pb(pb);
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
- if (LDAP_SUCCESS != result) {
- slapi_log_error(SLAPI_LOG_TRACE, "convert_pbe_des_to_aes: ",
- "Failed to search for password attribute (%s) error (%d), skipping suffix (%s)\n",
- attrs[i], result, backends[be_idx]);
- slapi_free_search_results_internal(pb);
- slapi_pblock_destroy(pb);
- pb = NULL;
- continue;
- }
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
- for (ii = 0; entries && entries[ii]; ii++){
- if((val = slapi_entry_attr_get_charptr(entries[ii], attrs[i]))){
- if(strlen(val) >= 5 && strncmp(val,"{DES}", 5) == 0){
- /*
- * We have a DES encoded password, convert it AES
- */
- Slapi_PBlock *mod_pb = NULL;
- Slapi_Value *sval = NULL;
- LDAPMod mod_replace;
- LDAPMod *mods[2];
- char *replace_val[2];
- char *passwd = NULL;
-
- /* decode the DES password */
- if(pw_rever_decode(val, &passwd, attrs[i]) == -1){
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
- "Failed to decode existing DES password for (%s)\n",
- slapi_entry_get_dn(entries[ii]), 0, 0);
- disable_des = 0;
- goto done;
- }
- /* encode the password */
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, "cn=config",
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(),
+ SLAPI_OP_FLAG_IGNORE_UNINDEXED);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (ii = 0; entries && entries[ii]; ii++){
+ if((val = slapi_entry_attr_get_charptr(entries[ii], attrs[i]))){
+ if(strlen(val) >= 5 && strncmp(val,"{DES}", 5) == 0){
+ /*
+ * We have a DES encoded password, convert it to AES
+ */
+ Slapi_PBlock *mod_pb = NULL;
+ Slapi_Value *sval = NULL;
+ LDAPMod mod_replace;
+ LDAPMod *mods[2];
+ char *replace_val[2];
+ char *passwd = NULL;
+ int rc = 0;
+
+ /* decode the DES password */
+ if(pw_rever_decode(val, &passwd, attrs[i]) == -1){
+ slapi_log_error(SLAPI_LOG_FATAL ,"convert_pbe_des_to_aes",
+ "Failed to decode existing DES password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ rc = -1;
+ }
+
+ /* encode the password */
+ if (rc == 0){
sval = slapi_value_new_string(passwd);
if(pw_rever_encode(&sval, attrs[i]) == -1){
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
+ slapi_log_error(SLAPI_LOG_FATAL, "convert_pbe_des_to_aes",
"failed to encode AES password for (%s)\n",
- slapi_entry_get_dn(entries[ii]), 0, 0);
- slapi_ch_free_string(&passwd);
- slapi_value_free(&sval);
- disable_des = 0;
- goto done;
+ slapi_entry_get_dn(entries[ii]));
+ rc = -1;
}
+ }
+ if (rc == 0){
/* replace the attribute in the entry */
replace_val[0] = (char *)slapi_value_get_string(sval);
replace_val[1] = NULL;
@@ -837,83 +797,34 @@ convert_pbe_des_to_aes()
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
if (LDAP_SUCCESS != result) {
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
+ slapi_log_error(SLAPI_LOG_FATAL, "convert_pbe_des_to_aes"
"Failed to convert password for (%s) error (%d)\n",
- slapi_entry_get_dn(entries[ii]), result, 0);
- disable_des = 0;
+ slapi_entry_get_dn(entries[ii]), result);
} else {
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
+ slapi_log_error(SLAPI_LOG_HOUSE, "convert_pbe_des_to_aes",
"Successfully converted password for (%s)\n",
- slapi_entry_get_dn(entries[ii]), result, 0);
+ slapi_entry_get_dn(entries[ii]));
converted_des_passwd = 1;
}
- slapi_ch_free_string(&passwd);
- slapi_value_free(&sval);
- slapi_pblock_destroy(mod_pb);
}
- slapi_ch_free_string(&val);
+ slapi_ch_free_string(&passwd);
+ slapi_value_free(&sval);
+ slapi_pblock_destroy(mod_pb);
}
+ slapi_ch_free_string(&val);
}
- slapi_free_search_results_internal(pb);
- slapi_pblock_destroy(pb);
- pb = NULL;
}
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ pb = NULL;
slapi_ch_free_string(&filter);
}
if (!converted_des_passwd){
- slapi_log_error(SLAPI_LOG_FATAL, "convert_pbe_des_to_aes",
+ slapi_log_error(SLAPI_LOG_HOUSE, "convert_pbe_des_to_aes",
"No DES passwords found to convert.\n");
}
}
-
-done:
charray_free(attrs);
- charray_free(backends);
- slapi_free_search_results_internal(pb);
- slapi_pblock_destroy(pb);
-
- if (have_aes && have_des){
- /*
- * If a conversion attempt did not fail then we can disable the DES plugin
- */
- if(converted_des_passwd && disable_des){
- /*
- * Disable the DES plugin - this also prevents potentially expensive
- * searches at every server startup.
- */
- LDAPMod mod_replace;
- LDAPMod *mods[2];
- char *replace_val[2];
- char *des_dn = "cn=DES,cn=Password Storage Schemes,cn=plugins,cn=config";
-
- replace_val[0] = "off";
- replace_val[1] = NULL;
- mod_replace.mod_op = LDAP_MOD_REPLACE;
- mod_replace.mod_type = "nsslapd-pluginEnabled";
- mod_replace.mod_values = replace_val;
- mods[0] = &mod_replace;
- mods[1] = 0;
-
- pb = slapi_pblock_new();
- slapi_modify_internal_set_pb(pb, des_dn, mods, 0, 0,
- (void *)plugin_get_default_component_id(), 0);
- slapi_modify_internal_pb(pb);
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
- if (LDAP_SUCCESS != result) {
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
- "Failed to disable DES plugin (%s), error (%d)\n",
- des_dn, result, 0);
- } else {
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
- "Successfully disabled DES plugin (%s)\n",
- des_dn, 0, 0);
- }
- slapi_pblock_destroy(pb);
- LDAPDebug(LDAP_DEBUG_ANY,"convert_pbe_des_to_aes: "
- "All DES passwords have been converted to AES.\n",
- 0, 0, 0);
- }
- }
}
#ifdef ENABLE_NUNC_STANS
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 4e222d7..883ef80 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -516,10 +516,10 @@ pw_rever_encode(Slapi_Value **vals, char * attr_name)
for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL; p = p->plg_next )
{
char *L_attr = NULL;
- int i = 0;
+ int i = 0, ii = 0;
/* Get the appropriate encoding function */
- for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i] )
+ for ( L_attr = p->plg_argv[ii]; ii<p->plg_argc; L_attr = p->plg_argv[++ii] )
{
if (slapi_attr_types_equivalent(L_attr, attr_name))
{
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index db3c222..405f0bf 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -53,6 +53,8 @@ static int shutting_down = 0;
#define TASK_TOMBSTONE_FIXUP_BACKEND "backend"
#define TASK_TOMBSTONE_FIXUP_SUFFIX "suffix"
#define TASK_TOMBSTONE_FIXUP_STRIPCSN "stripcsn"
+#define TASK_DES2AES "des2aes task"
+
#define LOG_BUFFER 256
/* if the cumul. log gets larger than this, it's truncated: */
@@ -83,8 +85,10 @@ 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);
+static void task_des2aes_thread(void *arg);
+static void des2aes_task_destructor(Slapi_Task *task);
+
/***********************************
* Public Functions
@@ -2425,6 +2429,345 @@ fixup_tombstone_task_destructor(Slapi_Task *task)
"fixup_tombstone_task_destructor <--\n" );
}
+/*
+ * des2aes Task
+ *
+ * Convert any DES passwords to AES
+ *
+ * dn: cn=convertPasswords, cn=des2aes,cn=tasks,cn=config
+ * objectclass: top
+ * objectclass: extensibleObject
+ * suffix: dc=example,dc=com (If empty all backends are checked)
+ * suffix: dc=other,dc=suffix
+ */
+struct task_des2aes_data
+{
+ char **suffixes;
+ Slapi_Task *task;
+};
+
+static int
+task_des2aes(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ struct task_des2aes_data *task_data = NULL;
+ PRThread *thread = NULL;
+ Slapi_Task *task = NULL;
+ char **suffix = NULL;
+ char **bases = NULL;
+ int rc = SLAPI_DSE_CALLBACK_OK;
+
+ /* Get the suffixes */
+ if((suffix = slapi_entry_attr_get_charray(e, "suffix"))){
+ int i;
+ for (i = 0; suffix && suffix[i]; i++){
+ /* Make sure "suffix" is NUL terminated string */
+ char *dn = slapi_create_dn_string("%s", suffix[i]);
+
+ if(dn){
+ if(slapi_dn_syntax_check(pb, dn, 1)){
+ /* invalid suffix name */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Invalid DN syntax (%s) specified for \"suffix\"\n",
+ suffix[i]);
+ *returncode = LDAP_INVALID_DN_SYNTAX;
+ slapi_ch_free_string(&dn);
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto error;
+ } else {
+ slapi_ch_array_add(&bases, dn);
+ }
+ } else{
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Invalid DN (%s) specified for \"suffix\"\n", suffix[i]);
+ *returncode = LDAP_INVALID_DN_SYNTAX;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ goto error;
+ }
+ }
+ }
+
+ /* Build the task data and fire off a thread to perform the conversion */
+ task = slapi_new_task(slapi_entry_get_ndn(e));
+
+ /* register our destructor for cleaning up our private data */
+ slapi_task_set_destructor_fn(task, des2aes_task_destructor);
+ task_data = (struct task_des2aes_data *)slapi_ch_calloc(1, sizeof(struct task_des2aes_data));
+ task_data->suffixes = bases;
+ task_data->task = task;
+
+ /* Start the conversion thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_des2aes_thread,
+ (void *)task_data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "unable to create des2aes thread!\n");
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "unable to create des2aes thread!\n");
+ *returncode = LDAP_OPERATIONS_ERROR;
+ slapi_task_finish(task, *returncode);
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+error:
+ if (rc == SLAPI_DSE_CALLBACK_ERROR){
+ slapi_ch_array_free(bases);
+ slapi_ch_array_free(suffix);
+ slapi_ch_free((void **)&task_data);
+ }
+ return rc;
+}
+
+static void
+task_des2aes_thread(void *arg)
+{
+ struct task_des2aes_data *task_data = arg;
+ Slapi_PBlock *pb = NULL;
+ Slapi_Entry **entries = NULL;
+ Slapi_Task *task = task_data->task;
+ struct slapdplugin *plugin = NULL;
+ char **attrs = NULL;
+ char **backends = NULL;
+ char *val = NULL;
+ int converted_des_passwd = 0;
+ int result = -1;
+ int have_aes = 0;
+ int have_des = 0;
+ int i = 0, ii = 0, be_idx = 0;
+ int rc = 0;
+
+ /*
+ * Check that AES plugin is enabled, and grab all the unique
+ * password attributes.
+ */
+ for ( plugin = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME);
+ plugin != NULL;
+ plugin = plugin->plg_next )
+ {
+ char *plugin_arg = NULL;
+
+ if(plugin->plg_started && strcasecmp(plugin->plg_name, "AES") == 0){
+ /* We have the AES plugin, and its enabled */
+ have_aes = 1;
+ }
+ if(plugin->plg_started && strcasecmp(plugin->plg_name, "DES") == 0){
+ /* We have the DES plugin, and its enabled */
+ have_des = 1;
+ }
+ /* Gather all the unique password attributes from all the PBE plugins */
+ for ( i = 0, plugin_arg = plugin->plg_argv[i];
+ i < plugin->plg_argc;
+ plugin_arg = plugin->plg_argv[++i] )
+ {
+ if(charray_inlist(attrs, plugin_arg)){
+ continue;
+ }
+ charray_add(&attrs, slapi_ch_strdup(plugin_arg));
+ }
+ }
+
+ if(have_aes && have_des){
+ if(task_data->suffixes == NULL){
+ /*
+ * Build a list of all the backend dn's
+ */
+ Slapi_Backend *be = NULL;
+ struct suffixlist *list;
+ char *cookie = NULL;
+
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "Checking for DES passwords to convert to AES...\n");
+ slapi_task_log_notice(task,
+ "Checking for DES passwords to convert to AES...\n");
+
+ be = slapi_get_first_backend(&cookie);
+ while (be){
+ int suffix_idx = 0;
+ int count = slapi_counter_get_value(be->be_suffixcounter);
+
+ list = be->be_suffixlist;
+ for (suffix_idx = 0; list && suffix_idx < count; suffix_idx++) {
+ char *suffix = (char *)slapi_sdn_get_ndn(list->be_suffix);
+ if(charray_inlist(backends, suffix) || strlen(suffix) == 0){
+ list = list->next;
+ continue;
+ }
+ charray_add(&backends, slapi_ch_strdup(suffix));
+ list = list->next;
+ }
+ be = slapi_get_next_backend (cookie);
+ }
+ slapi_ch_free ((void **)&cookie);
+ } else {
+ backends = task_data->suffixes;
+ }
+
+ /*
+ * Search for the password attributes
+ */
+ for (i = 0; attrs && attrs[i]; i++){
+ char *filter = PR_smprintf("%s=*", attrs[i]);
+ /*
+ * Loop over all the backends looking for the password attribute
+ */
+ for(be_idx = 0; backends && backends[be_idx]; be_idx++){
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, backends[be_idx],
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(),
+ SLAPI_OP_FLAG_IGNORE_UNINDEXED);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+ if (LDAP_SUCCESS != result) {
+ slapi_log_error(SLAPI_LOG_FATAL, "convert_pbe_des_to_aes: ",
+ "Failed to search for password attribute (%s) error (%d), skipping suffix (%s)\n",
+ attrs[i], result, backends[be_idx]);
+ slapi_task_log_notice(task,
+ "Failed to search for password attribute (%s) error (%d), skipping suffix (%s)\n",
+ attrs[i], result, backends[be_idx]);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ pb = NULL;
+ continue;
+ }
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (ii = 0; entries && entries[ii]; ii++){
+ if((val = slapi_entry_attr_get_charptr(entries[ii], attrs[i]))){
+ if(strlen(val) >= 5 && strncmp(val,"{DES}", 5) == 0){
+ /*
+ * We have a DES encoded password, convert it AES
+ */
+ Slapi_PBlock *mod_pb = NULL;
+ Slapi_Value *sval = NULL;
+ LDAPMod mod_replace;
+ LDAPMod *mods[2];
+ char *replace_val[2];
+ char *passwd = NULL;
+
+ /* Decode the DES password */
+ if(pw_rever_decode(val, &passwd, attrs[i]) == -1){
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "Failed to decode existing DES password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ slapi_task_log_notice(task,
+ "Failed to decode existing DES password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ rc = 1;
+ goto done;
+ }
+
+ /* Encode the password */
+ sval = slapi_value_new_string(passwd);
+ if(pw_rever_encode(&sval, attrs[i]) == -1){
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "failed to encode AES password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ slapi_task_log_notice(task,
+ "failed to encode AES password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ slapi_ch_free_string(&passwd);
+ slapi_value_free(&sval);
+ rc = 1;
+ goto done;
+ }
+
+ /* Replace the attribute in the entry */
+ replace_val[0] = (char *)slapi_value_get_string(sval);
+ replace_val[1] = NULL;
+ mod_replace.mod_op = LDAP_MOD_REPLACE;
+ mod_replace.mod_type = attrs[i];
+ mod_replace.mod_values = replace_val;
+ mods[0] = &mod_replace;
+ mods[1] = 0;
+
+ mod_pb = slapi_pblock_new();
+ slapi_modify_internal_set_pb(mod_pb, slapi_entry_get_dn(entries[ii]),
+ mods, 0, 0, (void *)plugin_get_default_component_id(), 0);
+ slapi_modify_internal_pb(mod_pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+ if (LDAP_SUCCESS != result) {
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "Failed to convert password for (%s) error (%d)\n",
+ slapi_entry_get_dn(entries[ii]), result);
+ slapi_task_log_notice(task,
+ "Failed to convert password for (%s) error (%d)\n",
+ slapi_entry_get_dn(entries[ii]), result);
+ rc = 1;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "Successfully converted password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ slapi_task_log_notice(task,
+ "Successfully converted password for (%s)\n",
+ slapi_entry_get_dn(entries[ii]));
+ converted_des_passwd = 1;
+ }
+ slapi_ch_free_string(&passwd);
+ slapi_value_free(&sval);
+ slapi_pblock_destroy(mod_pb);
+ }
+ slapi_ch_free_string(&val);
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ pb = NULL;
+ }
+ slapi_ch_free_string(&filter);
+ }
+ if (!converted_des_passwd){
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "No DES passwords found to convert.\n");
+ slapi_task_log_notice(task, "No DES passwords found to convert.\n");
+ }
+ } else {
+ /* No AES/DES */
+ if (!have_des){
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "DES plugin not enabled\n");
+ slapi_task_log_notice(task, "DES plugin not enabled\n");
+ }
+ if (!have_aes){
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "AES plugin not enabled\n");
+ slapi_task_log_notice(task, "AES plugin not enabled\n");
+ }
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_DES2AES,
+ "Unable to convert passwords\n");
+ slapi_task_log_notice(task, "Unable to convert passwords\n");
+ rc = 1;
+ }
+
+done:
+ charray_free(attrs);
+ charray_free(backends);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ slapi_task_finish(task, rc);
+}
+
+static void
+des2aes_task_destructor(Slapi_Task *task)
+{
+ slapi_log_error(SLAPI_LOG_TRACE, TASK_DES2AES,
+ "des2aes_task_destructor -->\n" );
+ if (task) {
+ struct task_des2aes_data *task_data = (struct task_des2aes_data *)slapi_task_get_data(task);
+ while (slapi_task_get_refcount(task) > 0) {
+ /* Yield to wait for the task to finish. */
+ DS_Sleep (PR_MillisecondsToInterval(100));
+ }
+ if (task_data) {
+ slapi_ch_array_free(task_data->suffixes);
+ slapi_ch_free((void **)&task_data);
+ }
+ }
+ slapi_log_error(SLAPI_LOG_TRACE, TASK_DES2AES,
+ "des2aes_task_destructor <--\n" );
+}
+
/* cleanup old tasks that may still be in the DSE from a previous session
* (this can happen if the server crashes [no matter how unlikely we like
* to think that is].)
@@ -2506,6 +2849,7 @@ void task_init(void)
slapi_task_register_handler("upgradedb", task_upgradedb_add);
slapi_task_register_handler("sysconfig reload", task_sysconfig_reload_add);
slapi_task_register_handler("fixup tombstones", task_fixup_tombstones_add);
+ slapi_task_register_handler("des2aes", task_des2aes);
}
/* called when the server is shutting down -- abort all existing tasks */
--
2.4.11

View file

@ -34,7 +34,7 @@
Summary: 389 Directory Server (base)
Name: 389-ds-base
Version: 1.3.4.0
Release: %{?relprefix}30%{?prerel}%{?dist}
Release: %{?relprefix}32%{?prerel}%{?dist}
License: GPLv3+
URL: http://port389.org/
Group: System Environment/Daemons
@ -212,6 +212,11 @@ Patch85: 0086-Ticket-48445-keep-alive-entries-can-break-replicatio.patc
Patch86: 0087-Ticket-48420-change-severity-of-some-messages-relate.patch
Patch87: 0088-Ticket-48757-License-tag-does-not-match-actual-licen.patch
Patch88: 0089-Ticket-47888-DES-to-AES-password-conversion-fails-if.patch
Patch89: 0090-Ticket-48492-heap-corruption-at-schema-replication.patch
Patch90: 0091-Ticket-48492-heap-corruption-at-schema-replication.patch
Patch91: 0092-Ticket-48808-Paged-results-search-returns-the-blank-.patch
Patch92: 0093-Ticket-48808-Add-test-case.patch
Patch93: 0094-Ticket-48862-At-startup-DES-to-AES-password-conversi.patch
%description
389 Directory Server is an LDAPv3 compliant server. The base package includes
@ -364,6 +369,11 @@ cp %{SOURCE2} README.devel
%patch86 -p1
%patch87 -p1
%patch88 -p1
%patch89 -p1
%patch90 -p1
%patch91 -p1
%patch92 -p1
%patch93 -p1
%build
%if %{use_nunc_stans}
@ -554,10 +564,19 @@ fi
%{_libdir}/%{pkgname}/libslapd.so.*
%{_libdir}/%{pkgname}/libns-dshttpd.so*
%if %{use_nunc_stans}
%{_libdir}/%{pkgname}/libnunc-stans.so*
%{_libdir}/%{pkgname}/libnunc-stans.so.*
%endif
%changelog
* Thu Jun 9 2016 Noriko Hosoi <nhosoi@redhat.com> - 1.3.4.0-32
- release 1.3.4.0-32
- Resolves: bug 1344293 - At startup DES to AES password conversion causes timeout in start script (DS 48862)
* Thu May 12 2016 Noriko Hosoi <nhosoi@redhat.com> - 1.3.4.0-31
- release 1.3.4.0-31
- Resolves: bug 1335423 - heap corruption at schema replication. (DS 48492)
- Resolves: bug 1335107 - Paged results search returns the blank list of entries (DS 48808)
* Wed Mar 30 2016 Noriko Hosoi <nhosoi@redhat.com> - 1.3.4.0-30
- release 1.3.4.0-30
- Resolves: bug 1321891 - DES to AES password conversion fails if a backend is empty (DS 48777)