import 389-ds-base-1.3.6.1-28.el7_4

This commit is contained in:
CentOS Sources 2018-03-06 13:38:36 -05:00
parent a6639136ef
commit fb11493e67
5 changed files with 830 additions and 2 deletions

View file

@ -0,0 +1,263 @@
From 41a037c8310d204d21e9c3161d2015dd5177cff6 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <tbordaz@redhat.com>
Date: Tue, 19 Dec 2017 11:53:13 +0100
Subject: [PATCH] Ticket 49509 - Indexing of internationalized matching rules
is failing
Bug Description:
Indexing of the internationalized matching rules tests if a
matching rule indexer handle or not a given OID.
A side effect of https://pagure.io/389-ds-base/issue/49097 is that
the returned indexing callbacks are lost.
Indeed, the indexing callbacks (and potentially others fields) were
stored in the temporary pblock that was memcpy to the provided
pblock in case of success
Fix Description:
The fix basically restores the previous behavior but do not
memcpy pblock. It read/store the pblock fields that are
inputs/outputs of slapi_mr_indexer_create.
https://pagure.io/389-ds-base/issue/49509
Reviewed by: Ludwig Krispenz
Platforms tested: F23
Flag Day: no
Doc impact: no
---
ldap/servers/slapd/plugin_mr.c | 202 ++++++++++++++++++++++++++++++-----------
1 file changed, 148 insertions(+), 54 deletions(-)
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
index d216d12b9..b3cd4adf0 100644
--- a/ldap/servers/slapd/plugin_mr.c
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -145,6 +145,82 @@ plugin_mr_bind (char* oid, struct slapdplugin* plugin)
slapi_log_err(SLAPI_LOG_FILTER, "plugin_mr_bind", "<=\n");
}
+void
+mr_indexer_init_pb(Slapi_PBlock* src_pb, Slapi_PBlock* dst_pb)
+{
+ char* oid;
+ char *type;
+ uint32_t usage;
+ void *object;
+ IFP destroyFn;
+ IFP indexFn, indexSvFn;
+
+ /* matching rule plugin arguments */
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_MR_OID, &oid);
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_MR_TYPE, &type);
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_MR_USAGE, &usage);
+
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_MR_OID, oid);
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_MR_TYPE, type);
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_MR_USAGE, &usage);
+
+ /* matching rule plugin functions */
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn);
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexSvFn);
+
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_MR_INDEX_FN, indexFn);
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, indexSvFn);
+
+ /* common */
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_OBJECT, &object);
+ slapi_pblock_get(src_pb, SLAPI_PLUGIN_DESTROY_FN, &destroyFn);
+
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_OBJECT, object);
+ slapi_pblock_set(dst_pb, SLAPI_PLUGIN_DESTROY_FN, destroyFn);
+
+
+}
+
+/*
+ * Retrieves the matching rule plugin able to index/sort the provided OID/type
+ *
+ * The Matching rules able to index/sort a given OID are stored in a global list: global_mr_oids
+ *
+ * The retrieval is done in 3 phases:
+ * - It first searches (in global_mr_oids) for the already bound OID->MR
+ * - Else, look first in old style MR plugin
+ * for each registered 'syntax' and 'matchingrule' plugins having a
+ * SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, it binds (plugin_mr_bind) the first
+ * plugin that support the OID
+ * - Else, look in new style MR plugin
+ * for each registered 'syntax' and 'matchingrule' plugins, it binds (plugin_mr_bind) the first
+ * plugin that contains OID in its plg_mr_names
+ *
+ * Inputs:
+ * SLAPI_PLUGIN_MR_OID
+ * should contain the OID of the matching rule that you want used for indexing or sorting.
+ * SLAPI_PLUGIN_MR_TYPE
+ * should contain the attribute type that you want used for indexing or sorting.
+ * SLAPI_PLUGIN_MR_USAGE
+ * should specify if the indexer will be used for indexing (SLAPI_PLUGIN_MR_USAGE_INDEX)
+ * or for sorting (SLAPI_PLUGIN_MR_USAGE_SORT)
+ *
+ *
+ * Output:
+ *
+ * SLAPI_PLUGIN_MR_OID
+ * contain the OFFICIAL OID of the matching rule that you want used for indexing or sorting.
+ * SLAPI_PLUGIN_MR_INDEX_FN
+ * specifies the indexer function responsible for indexing or sorting of struct berval **
+ * SLAPI_PLUGIN_MR_INDEX_SV_FN
+ * specifies the indexer function responsible for indexing or sorting of Slapi_Value **
+ * SLAPI_PLUGIN_OBJECT
+ * contain any information that you want passed to the indexer function.
+ * SLAPI_PLUGIN_DESTROY_FN
+ * specifies the function responsible for freeing any memory allocated by this indexer factory function.
+ * For example, memory allocated for a structure that you pass to the indexer function using SLAPI_PLUGIN_OBJECT.
+ *
+ */
int /* an LDAP error code, hopefully LDAP_SUCCESS */
slapi_mr_indexer_create (Slapi_PBlock* opb)
{
@@ -152,60 +228,73 @@ slapi_mr_indexer_create (Slapi_PBlock* opb)
char* oid;
if (!(rc = slapi_pblock_get (opb, SLAPI_PLUGIN_MR_OID, &oid)))
{
- IFP createFn = NULL;
- struct slapdplugin* mrp = plugin_mr_find_registered (oid);
- if (mrp != NULL)
- {
- if (!(rc = slapi_pblock_set (opb, SLAPI_PLUGIN, mrp)) &&
- !(rc = slapi_pblock_get (opb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) &&
- createFn != NULL)
- {
- rc = createFn (opb);
- }
- }
- else
- {
- /* call each plugin, until one is able to handle this request. */
- rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
- for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next)
- {
- IFP indexFn = NULL;
- IFP indexSvFn = NULL;
- Slapi_PBlock pb;
- memcpy (&pb, opb, sizeof(Slapi_PBlock));
- slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp);
- if (slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) {
- /* plugin not a matchingrule type */
- continue;
- }
- if (createFn && !createFn(&pb)) {
- slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn);
- slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexSvFn);
- if (indexFn || indexSvFn) {
- /* Success: this plugin can handle it. */
- memcpy(opb, &pb, sizeof (Slapi_PBlock));
- plugin_mr_bind(oid, mrp); /* for future reference */
- rc = 0; /* success */
- break;
- }
-
- }
- }
- if (rc != 0) {
- /* look for a new syntax-style mr plugin */
- struct slapdplugin *pi = plugin_mr_find(oid);
- if (pi) {
- Slapi_PBlock pb;
- memcpy (&pb, opb, sizeof(Slapi_PBlock));
- slapi_pblock_set(&pb, SLAPI_PLUGIN, pi);
- rc = default_mr_indexer_create(&pb);
- if (!rc) {
- memcpy (opb, &pb, sizeof(Slapi_PBlock));
- plugin_mr_bind (oid, pi); /* for future reference */
- }
- }
- }
- }
+ IFP createFn = NULL;
+ struct slapdplugin* mrp = plugin_mr_find_registered(oid);
+ if (mrp != NULL) {
+ /* Great the matching OID -> MR plugin was already found, just reuse it */
+ if (!(rc = slapi_pblock_set(opb, SLAPI_PLUGIN, mrp)) &&
+ !(rc = slapi_pblock_get(opb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) &&
+ createFn != NULL) {
+ rc = createFn(opb);
+ }
+ } else {
+ /* We need to find in the MR plugins list, the MR plugin that will be able to handle OID
+ *
+ * It can be "old style" MR plugin (i.e. collation) that define indexer
+ *
+ * It can be "now style" MR plugin that contain OID string in 'plg_mr_names'
+ * (ie. ces, cis, bin...) where plg_mr_names is defined in 'mr_plugin_table' in each file
+ * ces.c, cis.c...
+ * New style MR plugin have NULL indexer create function but rather use a default indexer
+ */
+
+ /* Look for a old syntax-style mr plugin
+ * call each plugin, until one is able to handle this request.
+ */
+ rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+
+ for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next) {
+
+ Slapi_PBlock *pb = slapi_pblock_new();
+ mr_indexer_init_pb(opb, pb);
+ slapi_pblock_set(pb, SLAPI_PLUGIN, mrp);
+ /* This is associated with the pb_plugin struct, so it comes with mrp */
+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) {
+ /* plugin not a matchingrule type */
+ slapi_pblock_destroy(pb);
+ continue;
+ }
+
+ if (createFn && !createFn(pb)) {
+ IFP indexFn = NULL;
+ IFP indexSvFn = NULL;
+ /* These however, are in the pblock direct, so we need to copy them. */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexSvFn);
+ if (indexFn || indexSvFn) {
+ /* Success: this plugin can handle it. */
+ mr_indexer_init_pb(pb, opb);
+ plugin_mr_bind(oid, mrp); /* for future reference */
+ rc = 0; /* success */
+ slapi_pblock_destroy(pb);
+ break;
+ }
+ }
+ slapi_pblock_destroy(pb);
+ }
+ if (rc != 0) {
+ /* look for a new syntax-style mr plugin */
+ struct slapdplugin *pi = plugin_mr_find(oid);
+ if (pi) {
+ slapi_pblock_set(opb, SLAPI_PLUGIN, pi);
+ rc = default_mr_indexer_create(opb);
+ if (!rc) {
+ plugin_mr_bind(oid, pi); /* for future reference */
+ }
+ slapi_pblock_set(opb, SLAPI_PLUGIN, NULL);
+ }
+ }
+ }
}
return rc;
}
@@ -683,6 +772,11 @@ default_mr_indexer_create(Slapi_PBlock* pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn);
slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, mr_wrap_mr_index_sv_fn);
slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_indexer_destroy);
+
+ /* Note the two following setting are in the slapdplugin struct SLAPI_PLUGIN
+ * so they are not really output of the function but will just
+ * be stored in the bound (OID <--> plugin) list (plugin_mr_find_registered/plugin_mr_bind)
+ */
slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, default_mr_indexer_create);
slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, default_mr_filter_create);
rc = 0;
--
2.13.6

View file

@ -0,0 +1,292 @@
From 4219c54d9706f5597e8186d4f983b30587c2762e Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Tue, 13 Feb 2018 10:32:06 -0500
Subject: [PATCH] Ticket bz1525628 1.3.6 backport - invalid password migration
causes unauth bind
Bug Description: Slapi_ct_memcmp expects both inputs to be
at LEAST size n. If they are not, we only compared UP to n.
Invalid migrations of passwords (IE {CRYPT}XX) would create
a pw which is just salt and no hash. ct_memcmp would then
only verify the salt bits and would allow the authentication.
This relies on an administrative mistake both of allowing
password migration (nsslapd-allow-hashed-passwords) and then
subsequently migrating an INVALID password to the server.
Fix Description: slapi_ct_memcmp now access n1, n2 size
and will FAIL if they are not the same, but will still compare
n bytes, where n is the "longest" memory, to the first byte
of the other to prevent length disclosure of the shorter
value (generally the mis-migrated password)
https://bugzilla.redhat.com/show_bug.cgi?id=1525628
Author: wibrown
---
ldap/servers/plugins/pwdstorage/clear_pwd.c | 4 +-
ldap/servers/plugins/pwdstorage/crypt_pwd.c | 4 +-
ldap/servers/plugins/pwdstorage/md5_pwd.c | 14 +++----
ldap/servers/plugins/pwdstorage/sha_pwd.c | 18 +++++++--
ldap/servers/plugins/pwdstorage/smd5_pwd.c | 60 +++++++++++++++--------------
ldap/servers/slapd/ch_malloc.c | 37 +++++++++++++++---
ldap/servers/slapd/slapi-plugin.h | 2 +-
7 files changed, 88 insertions(+), 51 deletions(-)
diff --git a/ldap/servers/plugins/pwdstorage/clear_pwd.c b/ldap/servers/plugins/pwdstorage/clear_pwd.c
index b9b362d34..050e60dd7 100644
--- a/ldap/servers/plugins/pwdstorage/clear_pwd.c
+++ b/ldap/servers/plugins/pwdstorage/clear_pwd.c
@@ -39,7 +39,7 @@ clear_pw_cmp( const char *userpwd, const char *dbpwd )
* However, even if the first part of userpw matches dbpwd, but len !=, we
* have already failed anyawy. This prevents substring matching.
*/
- if (slapi_ct_memcmp(userpwd, dbpwd, len_dbp) != 0) {
+ if (slapi_ct_memcmp(userpwd, dbpwd, len_user, len_dbp) != 0) {
result = 1;
}
} else {
@@ -51,7 +51,7 @@ clear_pw_cmp( const char *userpwd, const char *dbpwd )
* dbpwd to itself. We have already got result == 1 if we are here, so we are
* just trying to take up time!
*/
- if (slapi_ct_memcmp(dbpwd, dbpwd, len_dbp)) {
+ if (slapi_ct_memcmp(dbpwd, dbpwd, len_dbp, len_dbp)) {
/* Do nothing, we have the if to fix a coverity check. */
}
}
diff --git a/ldap/servers/plugins/pwdstorage/crypt_pwd.c b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
index dfd5af94b..ff8eabb07 100644
--- a/ldap/servers/plugins/pwdstorage/crypt_pwd.c
+++ b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
@@ -56,13 +56,13 @@ crypt_close(Slapi_PBlock *pb __attribute__((unused)))
int
crypt_pw_cmp( const char *userpwd, const char *dbpwd )
{
- int rc;
+ int32_t rc;
char *cp;
PR_Lock(cryptlock);
/* we use salt (first 2 chars) of encoded password in call to crypt() */
cp = crypt( userpwd, dbpwd );
if (cp) {
- rc= slapi_ct_memcmp( dbpwd, cp, strlen(dbpwd));
+ rc= slapi_ct_memcmp(dbpwd, cp, strlen(dbpwd), strlen(cp));
} else {
rc = -1;
}
diff --git a/ldap/servers/plugins/pwdstorage/md5_pwd.c b/ldap/servers/plugins/pwdstorage/md5_pwd.c
index b27994667..88c11688b 100644
--- a/ldap/servers/plugins/pwdstorage/md5_pwd.c
+++ b/ldap/servers/plugins/pwdstorage/md5_pwd.c
@@ -30,12 +30,12 @@
int
md5_pw_cmp( const char *userpwd, const char *dbpwd )
{
- int rc=-1;
- char * bver;
- PK11Context *ctx=NULL;
+ int32_t rc=-1;
+ char *bver;
+ PK11Context *ctx = NULL;
unsigned int outLen;
unsigned char hash_out[MD5_HASH_LEN];
- unsigned char b2a_out[MD5_HASH_LEN*2]; /* conservative */
+ unsigned char b2a_out[MD5_HASH_LEN * 2]; /* conservative */
SECItem binary_item;
ctx = PK11_CreateDigestContext(SEC_OID_MD5);
@@ -57,10 +57,10 @@ md5_pw_cmp( const char *userpwd, const char *dbpwd )
bver = NSSBase64_EncodeItem(NULL, (char *)b2a_out, sizeof b2a_out, &binary_item);
/* bver points to b2a_out upon success */
if (bver) {
- rc = slapi_ct_memcmp(bver,dbpwd, strlen(dbpwd));
+ rc = slapi_ct_memcmp(bver,dbpwd, strlen(dbpwd), strlen(bver));
} else {
- slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
- "Could not base64 encode hashed value for password compare");
+ slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
+ "Could not base64 encode hashed value for password compare");
}
loser:
return rc;
diff --git a/ldap/servers/plugins/pwdstorage/sha_pwd.c b/ldap/servers/plugins/pwdstorage/sha_pwd.c
index 5f41c5b93..c9db8964a 100644
--- a/ldap/servers/plugins/pwdstorage/sha_pwd.c
+++ b/ldap/servers/plugins/pwdstorage/sha_pwd.c
@@ -49,7 +49,7 @@ sha_pw_cmp (const char *userpwd, const char *dbpwd, unsigned int shaLen )
char userhash[MAX_SHA_HASH_SIZE];
char quick_dbhash[MAX_SHA_HASH_SIZE + SHA_SALT_LENGTH + 3];
char *dbhash = quick_dbhash;
- struct berval salt;
+ struct berval salt = {0};
PRUint32 hash_len;
unsigned int secOID;
char *schemeName;
@@ -120,10 +120,20 @@ sha_pw_cmp (const char *userpwd, const char *dbpwd, unsigned int shaLen )
}
/* the proof is in the comparison... */
- if ( hash_len >= shaLen ) {
- result = slapi_ct_memcmp( userhash, dbhash, shaLen );
+ if (hash_len >= shaLen) {
+ /*
+ * This say "if the hash has a salt IE >, OR if they are equal, check the hash component ONLY.
+ * This is why we repeat shaLen twice, even though it seems odd. If you have a dbhast of ssha
+ * it's len is 28, and the userpw is 20, but 0 - 20 is the sha, and 21-28 is the salt, which
+ * has already been processed into userhash.
+ * The case where dbpwd is truncated is handled above in "invalid base64" arm.
+ */
+ result = slapi_ct_memcmp(userhash, dbhash, shaLen, shaLen);
} else {
- result = slapi_ct_memcmp( userhash, dbhash + OLD_SALT_LENGTH, hash_len - OLD_SALT_LENGTH );
+ /* This case is for if the salt is at the START, which only applies to DS40B1 case.
+ * May never be a valid check...
+ */
+ result = slapi_ct_memcmp(userhash, dbhash + OLD_SALT_LENGTH, shaLen, hash_len - OLD_SALT_LENGTH);
}
loser:
diff --git a/ldap/servers/plugins/pwdstorage/smd5_pwd.c b/ldap/servers/plugins/pwdstorage/smd5_pwd.c
index 2e9d195ea..f6b4bb4a0 100644
--- a/ldap/servers/plugins/pwdstorage/smd5_pwd.c
+++ b/ldap/servers/plugins/pwdstorage/smd5_pwd.c
@@ -52,35 +52,37 @@ smd5_pw_cmp( const char *userpwd, const char *dbpwd )
/*
* Decode hash stored in database.
*/
- hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
- if ( hash_len >= sizeof(quick_dbhash) ) { /* get more space: */
- dbhash = (char*) slapi_ch_calloc( hash_len + 1, sizeof(char) );
- if ( dbhash == NULL ) goto loser;
- } else {
- memset( quick_dbhash, 0, sizeof(quick_dbhash) );
- }
-
- hashresult = PL_Base64Decode( dbpwd, 0, dbhash );
- if (NULL == hashresult) {
- slapi_log_err(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
- "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
- "or is not properly encoded BASE64\n", dbpwd );
- goto loser;
- }
-
- salt.bv_val = (void*)(dbhash + MD5_LENGTH); /* salt starts after hash value */
- salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
-
- /* create the hash */
- memset( userhash, 0, sizeof(userhash) );
- PK11_DigestBegin(ctx);
- PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
- PK11_DigestOp(ctx, (unsigned char*)(salt.bv_val), salt.bv_len);
- PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
- PK11_DestroyContext(ctx, 1);
-
- /* Compare everything up to the salt. */
- rc = slapi_ct_memcmp( userhash, dbhash, MD5_LENGTH );
+ hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
+ if (hash_len >= sizeof(quick_dbhash)) { /* get more space: */
+ dbhash = (char *)slapi_ch_calloc(hash_len + 1, sizeof(char));
+ if (dbhash == NULL)
+ goto loser;
+ } else {
+ memset(quick_dbhash, 0, sizeof(quick_dbhash));
+ }
+
+ hashresult = PL_Base64Decode(dbpwd, 0, dbhash);
+ if (NULL == hashresult) {
+ slapi_log_err(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
+ "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
+ "or is not properly encoded BASE64\n",
+ dbpwd);
+ goto loser;
+ }
+
+ salt.bv_val = (void *)(dbhash + MD5_LENGTH); /* salt starts after hash value */
+ salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
+
+ /* create the hash */
+ memset(userhash, 0, sizeof(userhash));
+ PK11_DigestBegin(ctx);
+ PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
+ PK11_DigestOp(ctx, (unsigned char *)(salt.bv_val), salt.bv_len);
+ PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
+ PK11_DestroyContext(ctx, 1);
+
+ /* Compare everything up to the salt. */
+ rc = slapi_ct_memcmp(userhash, dbhash, MD5_LENGTH, MD5_LENGTH);
loser:
if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free_string( (char **)&dbhash );
diff --git a/ldap/servers/slapd/ch_malloc.c b/ldap/servers/slapd/ch_malloc.c
index 52ccb64e8..da0b5f6d8 100644
--- a/ldap/servers/slapd/ch_malloc.c
+++ b/ldap/servers/slapd/ch_malloc.c
@@ -343,8 +343,8 @@ slapi_ch_smprintf(const char *fmt, ...)
/* Constant time memcmp. Does not shortcircuit on failure! */
/* This relies on p1 and p2 both being size at least n! */
-int
-slapi_ct_memcmp( const void *p1, const void *p2, size_t n)
+int32_t
+slapi_ct_memcmp( const void *p1, const void *p2, size_t n1, size_t n2)
{
int result = 0;
const unsigned char *_p1 = (const unsigned char *)p1;
@@ -353,10 +353,35 @@ slapi_ct_memcmp( const void *p1, const void *p2, size_t n)
if (_p1 == NULL || _p2 == NULL) {
return 2;
}
-
- for (size_t i = 0; i < n; i++) {
- if (_p1[i] ^ _p2[i]) {
- result = 1;
+ if (n1 == n2) {
+ for (size_t i = 0; i < n1; i++) {
+ if (_p1[i] ^ _p2[i]) {
+ result = 1;
+ }
+ }
+ } else {
+ const unsigned char *_pa;
+ const unsigned char *_pb;
+ size_t nl;
+ if (n2 > n1) {
+ _pa = _p2;
+ _pb = _p2;
+ nl = n2;
+ } else {
+ _pa = _p1;
+ _pb = _p1;
+ nl = n1;
+ }
+ /* We already fail as n1 != n2 */
+ result = 3;
+ for (size_t i = 0; i < nl; i++) {
+ if (_pa[i] ^ _pb[i]) {
+ /*
+ * If we don't mutate result here, dead code elimination
+ * we remove for loop.
+ */
+ result = 4;
+ }
}
}
return result;
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 16aa1b711..8555be939 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5856,7 +5856,7 @@ char * slapi_ch_smprintf(const char *fmt, ...)
* \param n length in bytes of the content of p1 AND p2.
* \return 0 on match. 1 on non-match. 2 on presence of NULL pointer in p1 or p2.
*/
-int slapi_ct_memcmp( const void *p1, const void *p2, size_t n);
+int32_t slapi_ct_memcmp( const void *p1, const void *p2, size_t n1, size_t n2);
/*
* syntax plugin routines
--
2.13.6

View file

@ -0,0 +1,66 @@
From 73dd295434a03be28531cea40fde041ce7bd2d7e Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Tue, 13 Feb 2018 10:35:35 -0500
Subject: [PATCH] Ticket 49545 - final substring extended filter search returns
invalid result
Bug Description:
During a search (using extended filter with final substring), the server
checks the filter before returning the matching entries.
When checking the attribute value against the filter, it
uses the wrong value.
Fix Description:
Make suree it uses the right portion of the attribute value, in order
to generate the keys to compare.
https://pagure.io/389-ds-base/issue/49545
Reviewed by: Ludwig Krispenz
---
ldap/servers/plugins/collation/orfilter.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/ldap/servers/plugins/collation/orfilter.c b/ldap/servers/plugins/collation/orfilter.c
index 866936afe..8f10f81b6 100644
--- a/ldap/servers/plugins/collation/orfilter.c
+++ b/ldap/servers/plugins/collation/orfilter.c
@@ -180,17 +180,33 @@ ss_filter_match (or_filter_t* or, struct berval** vals)
} else { /* final */
auto size_t attempts = MAX_CHAR_COMBINING;
auto char* limit = v.bv_val;
+ auto char *end;
auto struct berval** vkeys;
auto struct berval* vals[2];
auto struct berval key;
+
rc = -1;
vals[0] = &v;
vals[1] = NULL;
key.bv_val = (*k)->bv_val;
key.bv_len = (*k)->bv_len - 1;
- v.bv_val = (*vals)->bv_val + (*vals)->bv_len;
+ /* In the following lines it will loop to find
+ * if the end of the attribute value matches the 'final' of the filter
+ * Short summary:
+ * vals contains the attribute value :for example "hello world"
+ * key contain the key generated from the indexing of final part of the filter.
+ * for example filter=(<attribut>=*ld), so key contains the indexing("ld").
+ *
+ * The loop will iterate over the attribute value (vals) from the end of string
+ * to the begining. So it will try to index('d'), index('ld'), index('rld'), index('orld')...
+ *
+ * At each iteration if the key generated from indexing the portion of vals, matches
+ * the key generate from the final part of the filter, then the loop stops => we are done
+ */
+ end = v.bv_val + v.bv_len - 1;
+ v.bv_val = end;
while(1) {
- v.bv_len = (*vals)->bv_len - (v.bv_val - (*vals)->bv_val);
+ v.bv_len = end - v.bv_val + 1;
vkeys = ix->ix_index (ix, vals, NULL);
if (vkeys && vkeys[0]) {
auto const struct berval* vkey = vkeys[0];
--
2.13.6

View file

@ -0,0 +1,189 @@
From 715bdd7fd707d4addf52c21051ec3ab90951a691 Mon Sep 17 00:00:00 2001
From: Thierry Bordaz <tbordaz@redhat.com>
Date: Wed, 6 Dec 2017 15:14:57 +0100
Subject: [PATCH] Ticket 49471 - heap-buffer-overflow in ss_unescape
Bug Description:
Two problems here
- when searching for wildcard and escape char, ss_unescape assumes the string
is at least 3 chars longs. So memcmp can overflow a shorter string
- while splitting a string into substring pattern, it loops over
wildcard and can overpass the string end
Fix Description:
For the first problem, it checks the string size is long enough to memcmp
a wildcard or an escape
For the second it exits from the loop as soon as the end of the string is reached
https://pagure.io/389-ds-base/issue/49471
Reviewed by: William Brown
Platforms tested: F23
Flag Day: no
Doc impact: no
(cherry picked from commit 5991388ce75fba8885579b769711d57acfd43cd3)
(cherry picked from commit 3fb1c408cb4065de8d9c0c1de050d08969d51bb0)
---
dirsrvtests/tests/tickets/ticket49471_test.py | 79 +++++++++++++++++++++++++++
ldap/servers/plugins/collation/orfilter.c | 48 +++++++++-------
2 files changed, 106 insertions(+), 21 deletions(-)
create mode 100644 dirsrvtests/tests/tickets/ticket49471_test.py
diff --git a/dirsrvtests/tests/tickets/ticket49471_test.py b/dirsrvtests/tests/tickets/ticket49471_test.py
new file mode 100644
index 000000000..0456a5182
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49471_test.py
@@ -0,0 +1,79 @@
+import logging
+import pytest
+import os
+import time
+import ldap
+from lib389._constants import *
+from lib389.topologies import topology_st as topo
+from lib389 import Entry
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+USER_CN='user_'
+def _user_get_dn(no):
+ cn = '%s%d' % (USER_CN, no)
+ dn = 'cn=%s,ou=people,%s' % (cn, SUFFIX)
+ return (cn, dn)
+
+def add_user(server, no, desc='dummy', sleep=True):
+ (cn, dn) = _user_get_dn(no)
+ log.fatal('Adding user (%s): ' % dn)
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'inetuser', 'userSecurityInformation'],
+ 'cn': [cn],
+ 'description': [desc],
+ 'sn': [cn],
+ 'description': ['add on that host']})))
+ if sleep:
+ time.sleep(2)
+
+def test_ticket49471(topo):
+ """Specify a test case purpose or name here
+
+ :id: 457ab172-9455-4eb2-89a0-150e3de5993f
+ :setup: Fill in set up configuration here
+ :steps:
+ 1. Fill in test case steps here
+ 2. And indent them like this (RST format requirement)
+ :expectedresults:
+ 1. Fill in the result that is expected
+ 2. For each test step
+ """
+
+ # If you need any test suite initialization,
+ # please, write additional fixture for that (including finalizer).
+ # Topology for suites are predefined in lib389/topologies.py.
+
+ # If you need host, port or any other data about instance,
+ # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
+
+ S1 = topo.standalone
+ add_user(S1, 1)
+
+ Filter = "(description:2.16.840.1.113730.3.3.2.1.1.6:=\*on\*)"
+ ents = S1.search_s(SUFFIX, ldap.SCOPE_SUBTREE, Filter)
+ assert len(ents) == 1
+
+ #
+ # The following is for the test 49491
+ # skipped here else it crashes in ASAN
+ #Filter = "(description:2.16.840.1.113730.3.3.2.1.1.6:=\*host)"
+ #ents = S1.search_s(SUFFIX, ldap.SCOPE_SUBTREE, Filter)
+ #assert len(ents) == 1
+
+ if DEBUGGING:
+ # Add debugging steps(if any)...
+ pass
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
+
diff --git a/ldap/servers/plugins/collation/orfilter.c b/ldap/servers/plugins/collation/orfilter.c
index 8f10f81b6..438efafef 100644
--- a/ldap/servers/plugins/collation/orfilter.c
+++ b/ldap/servers/plugins/collation/orfilter.c
@@ -317,19 +317,21 @@ ss_unescape (struct berval* val)
char* t = s;
char* limit = s + val->bv_len;
while (s < limit) {
- if (!memcmp (s, "\\2a", 3) ||
- !memcmp (s, "\\2A", 3)) {
- *t++ = WILDCARD;
- s += 3;
- } else if (!memcmp (s, "\\5c", 3) ||
- !memcmp (s, "\\5C", 3)) {
- *t++ = '\\';
- s += 3;
- } else {
- if (t == s) LDAP_UTF8INC (t);
- else t += LDAP_UTF8COPY (t, s);
- LDAP_UTF8INC (s);
- }
+ if (((limit - s) >= 3) &&
+ (!memcmp(s, "\\2a", 3) || !memcmp(s, "\\2A", 3))) {
+ *t++ = WILDCARD;
+ s += 3;
+ } else if ((limit - s) >= 3 &&
+ (!memcmp(s, "\\5c", 3) || !memcmp(s, "\\5C", 3))) {
+ *t++ = '\\';
+ s += 3;
+ } else {
+ if (t == s)
+ LDAP_UTF8INC(t);
+ else
+ t += LDAP_UTF8COPY(t, s);
+ LDAP_UTF8INC(s);
+ }
}
val->bv_len = t - val->bv_val;
}
@@ -405,14 +407,18 @@ ss_filter_values (struct berval* pattern, int* query_op)
n = 0;
s = pattern->bv_val;
for (p = s; p < plimit; LDAP_UTF8INC(p)) {
- switch (*p) {
- case WILDCARD:
- result[n++] = ss_filter_value (s, p-s, &val);
- while (++p != plimit && *p == WILDCARD);
- s = p;
- break;
- default: break;
- }
+ switch (*p) {
+ case WILDCARD:
+ result[n++] = ss_filter_value(s, p - s, &val);
+ while (p != plimit && *p == WILDCARD) p++;
+ s = p;
+ break;
+ default:
+ break;
+ }
+ if (p >= plimit) {
+ break;
+ }
}
if (p != s || s == plimit) {
result[n++] = ss_filter_value (s, p-s, &val);
--
2.13.6

View file

@ -30,7 +30,7 @@
Summary: 389 Directory Server (base)
Name: 389-ds-base
Version: 1.3.6.1
Release: %{?relprefix}26%{?prerel}%{?dist}
Release: %{?relprefix}28%{?prerel}%{?dist}
License: GPLv3+
URL: https://www.port389.org/
Group: System Environment/Daemons
@ -220,6 +220,10 @@ Patch83: 0083-Ticket-49410-opened-connection-can-remain-no-longer-.patc
Patch84: 0084-Ticket-48118-backport-changelog-can-be-erronously-re.patch
Patch85: 0085-Ticket-49495-Fix-memory-management-is-vattr.patch
Patch86: 0086-CVE-2017-15134-389-ds-base-Remote-DoS-via-search-fil.patch
Patch87: 0087-Ticket-49509-Indexing-of-internationalized-matching-.patch
Patch88: 0088-Ticket-bz1525628-1.3.6-backport-invalid-password-mig.patch
Patch89: 0089-Ticket-49545-final-substring-extended-filter-search-.patch
Patch90: 0090-Ticket-49471-heap-buffer-overflow-in-ss_unescape.patch
%description
389 Directory Server is an LDAPv3 compliant server. The base package includes
@ -376,6 +380,10 @@ cp %{SOURCE2} README.devel
%patch84 -p1
%patch85 -p1
%patch86 -p1
%patch87 -p1
%patch88 -p1
%patch89 -p1
%patch90 -p1
%build
@ -608,8 +616,18 @@ fi
%{_sysconfdir}/%{pkgname}/dirsrvtests
%changelog
* Mon Feb 26 2018 Mark Reynolds <mreynolds@redhat.com> - 1.3.6.1-28
- Bump version to 1.3.6.1-28
- Resolves: Bug 1540105 - CVE-2018-1054 - remote Denial of Service (DoS) via search filters in SetUnicodeStringFromUTF_8
* Tue Feb 13 2018 Mark Reynolds <mreynolds@redhat.com> - 1.3.6.1-27
- Bump version to 1.3.6.1-27
- Resolves: Bug 1536343 - Indexing of internationalized matching rules is failing
- Resolves: Bug 1535539 - CVE-2017-15135 - Authentication bypass due to lack of size check in slapi_ct_memcmp function
- Resolves: Bug 1540105 - CVE-2018-1054 - remote Denial of Service (DoS) via search filters in SetUnicodeStringFromUTF_8
* Tue Jan 16 2018 Mark Reynolds <mreynolds@redhat.com> - 1.3.6.1-26
- Bump version to 1.3.6.1-25
- Bump version to 1.3.6.1-26
- Resolves: Bug 1534430 - crash in slapi_filter_sprintf
* Mon Dec 18 2017 Mark Reynolds <mreynolds@redhat.com> - 1.3.6.1-25