import 389-ds-base-1.4.3.8-7.module+el8.3.0+10310+6e88d919

This commit is contained in:
CentOS Sources 2021-04-06 09:33:08 -04:00 committed by Andrew Lukoshko
parent b342bd146c
commit 6b2663c36d
7 changed files with 1341 additions and 9 deletions

View File

@ -0,0 +1,95 @@
From 340b81a59cee365e7300e57c1ca5f4866373954c Mon Sep 17 00:00:00 2001
From: tbordaz <tbordaz@redhat.com>
Date: Wed, 16 Dec 2020 16:30:28 +0100
Subject: [PATCH 1/4] Issue 4480 - Unexpected info returned to ldap request
(#4491)
Bug description:
If the bind entry does not exist, the bind result info
reports that 'No such entry'. It should not give any
information if the target entry exists or not
Fix description:
Does not return any additional information during a bind
relates: https://github.com/389ds/389-ds-base/issues/4480
Reviewed by: William Brown, Viktor Ashirov, Mark Reynolds (thank you all)
Platforms tested: F31
---
dirsrvtests/tests/suites/basic/basic_test.py | 30 ++++++++++++++++++++
ldap/servers/slapd/back-ldbm/ldbm_config.c | 2 +-
ldap/servers/slapd/result.c | 2 +-
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
index 120207321..e9afa1e7e 100644
--- a/dirsrvtests/tests/suites/basic/basic_test.py
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
@@ -1400,6 +1400,36 @@ def test_dscreate_multiple_dashes_name(dscreate_long_instance):
assert not dscreate_long_instance.exists()
+def test_bind_invalid_entry(topology_st):
+ """Test the failing bind does not return information about the entry
+
+ :id: 5cd9b083-eea6-426b-84ca-83c26fc49a6f
+
+ :setup: Standalone instance
+
+ :steps:
+ 1: bind as non existing entry
+ 2: check that bind info does not report 'No such entry'
+
+ :expectedresults:
+ 1: pass
+ 2: pass
+ """
+
+ topology_st.standalone.restart()
+ INVALID_ENTRY="cn=foooo,%s" % DEFAULT_SUFFIX
+ try:
+ topology_st.standalone.simple_bind_s(INVALID_ENTRY, PASSWORD)
+ except ldap.LDAPError as e:
+ log.info('test_bind_invalid_entry: Failed to bind as %s (expected)' % INVALID_ENTRY)
+ log.info('exception description: ' + e.args[0]['desc'])
+ if 'info' in e.args[0]:
+ log.info('exception info: ' + e.args[0]['info'])
+ assert e.args[0]['desc'] == 'Invalid credentials'
+ assert 'info' not in e.args[0]
+ pass
+
+ log.info('test_bind_invalid_entry: PASSED')
if __name__ == '__main__':
# Run isolated
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c
index 88c186359..dee5fc088 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c
@@ -1266,7 +1266,7 @@ ldbm_config_search_entry_callback(Slapi_PBlock *pb __attribute__((unused)),
if (attrs) {
for (size_t i = 0; attrs[i]; i++) {
if (ldbm_config_moved_attr(attrs[i])) {
- slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "at least one required attribute has been moved to the BDB scecific configuration entry");
+ slapi_pblock_set(pb, SLAPI_RESULT_TEXT, "at least one required attribute has been moved to the BDB scecific configuration entry");
break;
}
}
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
index 61efb6f8d..40c5dcc57 100644
--- a/ldap/servers/slapd/result.c
+++ b/ldap/servers/slapd/result.c
@@ -355,7 +355,7 @@ send_ldap_result_ext(
if (text) {
pbtext = text;
} else {
- slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &pbtext);
+ slapi_pblock_get(pb, SLAPI_RESULT_TEXT, &pbtext);
}
if (operation == NULL) {
--
2.26.2

View File

@ -0,0 +1,782 @@
From 2923940ffa0db88df986dd00d74ad812ccd71188 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Wed, 20 Jan 2021 16:42:15 -0500
Subject: [PATCH 2/4] Issue 5442 - Search results are different between RHDS10
and RHDS11
Bug Description: In 1.4.x we introduced a change that was overly strict about
how a search on a non-existent subtree returned its error code.
It was changed from returning an error 32 to an error 0 with
zero entries returned.
Fix Description: When finding the entry and processing acl's make sure to
gather the aci's that match the resource even if the resource
does not exist. This requires some extra checks when processing
the target attribute.
relates: https://github.com/389ds/389-ds-base/issues/4542
Reviewed by: firstyear, elkris, and tbordaz (Thanks!)
Apply Thierry's changes
round 2
Apply more suggestions from Thierry
---
dirsrvtests/tests/suites/acl/misc_test.py | 108 +++++++-
ldap/servers/plugins/acl/acl.c | 296 ++++++++++------------
ldap/servers/slapd/back-ldbm/findentry.c | 6 +-
src/lib389/lib389/_mapped_object.py | 4 +-
4 files changed, 239 insertions(+), 175 deletions(-)
diff --git a/dirsrvtests/tests/suites/acl/misc_test.py b/dirsrvtests/tests/suites/acl/misc_test.py
index 8f122b7a7..b64961c0c 100644
--- a/dirsrvtests/tests/suites/acl/misc_test.py
+++ b/dirsrvtests/tests/suites/acl/misc_test.py
@@ -11,7 +11,7 @@
import os
import pytest
-from lib389._constants import DEFAULT_SUFFIX, PW_DM
+from lib389._constants import DEFAULT_SUFFIX, PW_DM, DN_DM
from lib389.idm.user import UserAccount, UserAccounts
from lib389._mapped_object import DSLdapObject
from lib389.idm.account import Accounts, Anonymous
@@ -399,14 +399,112 @@ def test_do_bind_as_201_distinct_users(topo, clean, aci_of_user):
user = uas.create_test_user(uid=i, gid=i)
user.set('userPassword', PW_DM)
- for i in range(len(uas.list())):
- uas.list()[i].bind(PW_DM)
+ users = uas.list()
+ for user in users:
+ user.bind(PW_DM)
ACLPlugin(topo.standalone).replace("nsslapd-aclpb-max-selected-acls", '220')
topo.standalone.restart()
- for i in range(len(uas.list())):
- uas.list()[i].bind(PW_DM)
+ users = uas.list()
+ for user in users:
+ user.bind(PW_DM)
+
+
+def test_info_disclosure(request, topo):
+ """Test that a search returns 32 when base entry does not exist
+
+ :id: f6dec4c2-65a3-41e4-a4c0-146196863333
+ :setup: Standalone Instance
+ :steps:
+ 1. Add aci
+ 2. Add test user
+ 3. Bind as user and search for non-existent entry
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Error 32 is returned
+ """
+
+ ACI_TARGET = "(targetattr = \"*\")(target = \"ldap:///%s\")" % (DEFAULT_SUFFIX)
+ ACI_ALLOW = "(version 3.0; acl \"Read/Search permission for all users\"; allow (read,search)"
+ ACI_SUBJECT = "(userdn=\"ldap:///all\");)"
+ ACI = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+
+ # Get current ACi's so we can restore them when we are done
+ suffix = Domain(topo.standalone, DEFAULT_SUFFIX)
+ preserved_acis = suffix.get_attr_vals_utf8('aci')
+
+ def finofaci():
+ domain = Domain(topo.standalone, DEFAULT_SUFFIX)
+ try:
+ domain.remove_all('aci')
+ domain.replace_values('aci', preserved_acis)
+ except:
+ pass
+ request.addfinalizer(finofaci)
+
+ # Remove aci's
+ suffix.remove_all('aci')
+
+ # Add test user
+ USER_DN = "uid=test,ou=people," + DEFAULT_SUFFIX
+ users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
+ users.create(properties={
+ 'uid': 'test',
+ 'cn': 'test',
+ 'sn': 'test',
+ 'uidNumber': '1000',
+ 'gidNumber': '2000',
+ 'homeDirectory': '/home/test',
+ 'userPassword': PW_DM
+ })
+
+ # bind as user
+ conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
+
+ # Search fo existing base DN
+ test = Domain(conn, DEFAULT_SUFFIX)
+ try:
+ test.get_attr_vals_utf8_l('dc')
+ assert False
+ except IndexError:
+ pass
+
+ # Search for a non existent bases
+ subtree = Domain(conn, "ou=does_not_exist," + DEFAULT_SUFFIX)
+ try:
+ subtree.get_attr_vals_utf8_l('objectclass')
+ except IndexError:
+ pass
+ subtree = Domain(conn, "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX)
+ try:
+ subtree.get_attr_vals_utf8_l('objectclass')
+ except IndexError:
+ pass
+ # Try ONE level search instead of BASE
+ try:
+ Accounts(conn, "ou=does_not_exist," + DEFAULT_SUFFIX).filter("(objectclass=top)", ldap.SCOPE_ONELEVEL)
+ except IndexError:
+ pass
+
+ # add aci
+ suffix.add('aci', ACI)
+
+ # Search for a non existent entry which should raise an exception
+ with pytest.raises(ldap.NO_SUCH_OBJECT):
+ conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
+ subtree = Domain(conn, "ou=does_not_exist," + DEFAULT_SUFFIX)
+ subtree.get_attr_vals_utf8_l('objectclass')
+ with pytest.raises(ldap.NO_SUCH_OBJECT):
+ conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
+ subtree = Domain(conn, "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX)
+ subtree.get_attr_vals_utf8_l('objectclass')
+ with pytest.raises(ldap.NO_SUCH_OBJECT):
+ conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
+ DN = "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX
+ Accounts(conn, DN).filter("(objectclass=top)", ldap.SCOPE_ONELEVEL, strict=True)
+
if __name__ == "__main__":
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
index 41a909a18..4e811f73a 100644
--- a/ldap/servers/plugins/acl/acl.c
+++ b/ldap/servers/plugins/acl/acl.c
@@ -2111,10 +2111,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
aci_right = aci->aci_access;
res_right = aclpb->aclpb_access;
if (!(aci_right & res_right)) {
- /* If we are looking for read/search and the acl has read/search
- ** then go further because if targets match we may keep that
- ** acl in the entry cache list.
- */
+ /*
+ * If we are looking for read/search and the acl has read/search
+ * then go further because if targets match we may keep that
+ * acl in the entry cache list.
+ */
if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) &&
(aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)))) {
matches = ACL_FALSE;
@@ -2122,30 +2123,29 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
}
}
-
- /* first Let's see if the entry is under the subtree where the
- ** ACL resides. We can't let somebody affect a target beyond the
- ** scope of where the ACL resides
- ** Example: ACL is located in "ou=engineering, o=ace industry, c=us
- ** but if the target is "o=ace industry, c=us", then we are in trouble.
- **
- ** If the aci is in the rootdse and the entry is not, then we do not
- ** match--ie. acis in the rootdse do NOT apply below...for the moment.
- **
- */
+ /*
+ * First Let's see if the entry is under the subtree where the
+ * ACL resides. We can't let somebody affect a target beyond the
+ * scope of where the ACL resides
+ * Example: ACL is located in "ou=engineering, o=ace industry, c=us
+ * but if the target is "o=ace industry, c=us", then we are in trouble.
+ *
+ * If the aci is in the rootdse and the entry is not, then we do not
+ * match--ie. acis in the rootdse do NOT apply below...for the moment.
+ */
res_ndn = slapi_sdn_get_ndn(aclpb->aclpb_curr_entry_sdn);
aci_ndn = slapi_sdn_get_ndn(aci->aci_sdn);
- if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) || (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn))) {
-
- /* cant' poke around */
+ if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) ||
+ (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn)))
+ {
+ /* can't poke around */
matches = ACL_FALSE;
goto acl__resource_match_aci_EXIT;
}
/*
- ** We have a single ACI which we need to find if it applies to
- ** the resource or not.
- */
+ * We have a single ACI which we need to find if it applies to the resource or not.
+ */
if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) {
char *avaType;
struct berval *avaValue;
@@ -2173,25 +2173,23 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
char *avaType;
struct berval *avaValue;
char logbuf[1024];
-
- /* We are evaluating the moddn permission.
- * The aci contains target_to and target_from
- *
- * target_to filter must be checked against the resource ndn that was stored in
- * aclpb->aclpb_curr_entry_sdn
- *
- * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
- * (sdn was stored in the pblock)
- */
+ /*
+ * We are evaluating the moddn permission.
+ * The aci contains target_to and target_from
+ *
+ * target_to filter must be checked against the resource ndn that was stored in
+ * aclpb->aclpb_curr_entry_sdn
+ *
+ * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
+ * (sdn was stored in the pblock)
+ */
if (aci->target_to) {
f = aci->target_to;
dn_matched = ACL_TRUE;
/* Now check if the filter is a simple or substring filter */
if (aci->aci_type & ACI_TARGET_MODDN_TO_PATTERN) {
- /* This is a filter with substring
- * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
- */
+ /* This is a filter with substring e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com */
slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to substring: %s\n",
slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffix */)) != ACL_TRUE) {
@@ -2204,9 +2202,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
}
}
} else {
- /* This is a filter without substring
- * e.g. ldap:///cn=accounts,dc=example,dc=com
- */
+ /* This is a filter without substring e.g. ldap:///cn=accounts,dc=example,dc=com */
slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to: %s\n",
slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
slapi_filter_get_ava(f, &avaType, &avaValue);
@@ -2230,8 +2226,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
/* Now check if the filter is a simple or substring filter */
if (aci->aci_type & ACI_TARGET_MODDN_FROM_PATTERN) {
/* This is a filter with substring
- * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
- */
+ * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
+ */
slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from substring: %s\n",
slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
if ((rv = acl_match_substring(f, (char *)slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), 0 /* match suffix */)) != ACL_TRUE) {
@@ -2243,11 +2239,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
goto acl__resource_match_aci_EXIT;
}
}
-
} else {
- /* This is a filter without substring
- * e.g. ldap:///cn=accounts,dc=example,dc=com
- */
+ /* This is a filter without substring e.g. ldap:///cn=accounts,dc=example,dc=com */
slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from: %s\n",
slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
if (!slapi_dn_issuffix(slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), avaValue->bv_val)) {
@@ -2269,10 +2262,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
}
if (aci->aci_type & ACI_TARGET_PATTERN) {
-
f = aci->target;
dn_matched = ACL_TRUE;
-
if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) {
dn_matched = ACL_FALSE;
if (rv == ACL_ERR) {
@@ -2296,7 +2287,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
/*
* Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing.
- */
+ */
if (aci->aci_type & ACI_TARGET_MACRO_DN) {
/*
* See if the ($dn) component matches the string and
@@ -2306,8 +2297,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* entry is the same one don't recalculate it--
* this flag only works for search right now, could
* also optimise for mods by making it work for mods.
- */
-
+ */
if ((aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0) {
/*
* Here same entry so just look up the matched value,
@@ -2356,8 +2346,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* If there is already an entry for this aci in this
* aclpb then remove it--it's an old value for a
* different entry.
- */
-
+ */
acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht,
(PLHashNumber)aci->aci_index,
matched_val);
@@ -2381,30 +2370,27 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
}
/*
- ** Here, if there's a targetfilter field, see if it matches.
- **
- ** The commented out code below was an erroneous attempt to skip
- ** this test. It is wrong because: 1. you need to store
- ** whether the last test matched or not (you cannot just assume it did)
- ** and 2. It may not be the same aci, so the previous matched
- ** value is a function of the aci.
- ** May be interesting to build such a cache...but no evidence for
- ** for that right now. See Bug 383424.
- **
- **
- ** && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
- ** (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
- */
+ * Here, if there's a targetfilter field, see if it matches.
+ *
+ * The commented out code below was an erroneous attempt to skip
+ * this test. It is wrong because: 1. you need to store
+ * whether the last test matched or not (you cannot just assume it did)
+ * and 2. It may not be the same aci, so the previous matched
+ * value is a function of the aci.
+ * May be interesting to build such a cache...but no evidence for
+ * for that right now. See Bug 383424.
+ *
+ *
+ * && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
+ * (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
+ */
if (aci->aci_type & ACI_TARGET_FILTER) {
int filter_matched = ACL_TRUE;
-
/*
* Check for macros.
* For targetfilter we need to fake the lasinfo structure--it's
* created "naturally" for subjects but not targets.
- */
-
-
+ */
if (aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) {
lasInfo *lasinfo = NULL;
@@ -2419,11 +2405,9 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ACL_EVAL_TARGET_FILTER);
slapi_ch_free((void **)&lasinfo);
} else {
-
-
if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
aci->targetFilter,
- 0 /*don't do acess chk*/) != 0) {
+ 0 /*don't do access check*/) != 0) {
filter_matched = ACL_FALSE;
}
}
@@ -2450,7 +2434,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* Check to see if we need to evaluate any targetattrfilters.
* They look as follows:
* (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne),
- * del=sn:(sn=rob) && gn:(gn=byrne)")
+ * del=sn:(sn=rob) && gn:(gn=byrne)")
*
* For ADD/DELETE:
* If theres's a targetattrfilter then each add/del filter
@@ -2458,29 +2442,25 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* by each value of the attribute in the entry.
*
* For MODIFY:
- * If there's a targetattrfilter then the add/del filter
+ * If there's a targetattrfilter then the add/del filter
* must be satisfied by the attribute to be added/deleted.
* (MODIFY acl is evaluated one value at a time).
*
*
- */
-
+ */
if (((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
- (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
-
+ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
+ {
Targetattrfilter **attrFilterArray = NULL;
-
Targetattrfilter *attrFilter = NULL;
-
Slapi_Attr *attr_ptr = NULL;
Slapi_Value *sval;
const struct berval *attrVal;
int k;
int done;
-
if ((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
@@ -2497,28 +2477,20 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) {
attrFilter = attrFilterArray[num_attrs];
-
/*
- * If this filter applies to an attribute in the entry,
- * apply it to the entry.
- * Otherwise just ignore it.
- *
- */
-
- if (slapi_entry_attr_find(aclpb->aclpb_curr_entry,
- attrFilter->attr_str,
- &attr_ptr) == 0) {
-
+ * If this filter applies to an attribute in the entry,
+ * apply it to the entry.
+ * Otherwise just ignore it.
+ *
+ */
+ if (slapi_entry_attr_find(aclpb->aclpb_curr_entry, attrFilter->attr_str, &attr_ptr) == 0) {
/*
- * This is an applicable filter.
- * The filter is to be appplied to the entry being added
- * or deleted.
- * The filter needs to be satisfied by _each_ occurence
- * of the attribute in the entry--otherwise you
- * could satisfy the filter and then put loads of other
- * values in on the back of it.
- */
-
+ * This is an applicable filter.
+ * The filter is to be applied to the entry being added or deleted.
+ * The filter needs to be satisfied by _each_ occurrence of the
+ * attribute in the entry--otherwise you could satisfy the filter
+ * and then put loads of other values in on the back of it.
+ */
sval = NULL;
attrVal = NULL;
k = slapi_attr_first_value(attr_ptr, &sval);
@@ -2528,12 +2500,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
attrFilter->attr_str,
- (struct berval *)attrVal) == LDAP_SUCCESS) {
-
+ (struct berval *)attrVal) == LDAP_SUCCESS)
+ {
attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
attrFilter->filter,
- 1 /* Do filter sense evaluation below */
- );
+ 1 /* Do filter sense evaluation below */);
done = !attr_matched;
slapi_entry_free(aclpb->aclpb_filter_test_entry);
}
@@ -2542,19 +2513,19 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
} /* while */
/*
- * Here, we applied an applicable filter to the entry.
- * So if attr_matched is ACL_TRUE then every value
- * of the attribute in the entry satisfied the filter.
- * Otherwise, attr_matched is ACL_FALSE and not every
- * value satisfied the filter, so we will teminate the
- * scan of the filter list.
- */
+ * Here, we applied an applicable filter to the entry.
+ * So if attr_matched is ACL_TRUE then every value
+ * of the attribute in the entry satisfied the filter.
+ * Otherwise, attr_matched is ACL_FALSE and not every
+ * value satisfied the filter, so we will terminate the
+ * scan of the filter list.
+ */
}
num_attrs++;
} /* while */
-/*
+ /*
* Here, we've applied all the applicable filters to the entry.
* Each one must have been satisfied by all the values of the attribute.
* The result of this is stored in attr_matched.
@@ -2585,7 +2556,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
} else if (((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) &&
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) &&
- (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
+ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
+ {
/*
* Here, it's a modify add/del and we have attr filters.
* So, we need to scan the add/del filter list to find the filter
@@ -2629,11 +2601,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* Otherwise, ignore the targetattrfilters.
*/
if (found) {
-
if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
aclpb->aclpb_curr_attrEval->attrEval_name,
- aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS) {
-
+ aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS)
+ {
attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
attrFilter->filter,
1 /* Do filter sense evaluation below */
@@ -2651,20 +2622,21 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* Here this attribute appeared and was matched in a
* targetattrfilters list, so record this fact so we do
* not have to scan the targetattr list for the attribute.
- */
+ */
attr_matched_in_targetattrfilters = 1;
}
} /* targetvaluefilters */
- /* There are 3 cases by which acis are selected.
- ** 1) By scanning the whole list and picking based on the resource.
- ** 2) By picking a subset of the list which will be used for the whole
- ** acl evaluation.
- ** 3) A finer granularity, i.e, a selected list of acls which will be
- ** used for only that entry's evaluation.
- */
+ /*
+ * There are 3 cases by which acis are selected.
+ * 1) By scanning the whole list and picking based on the resource.
+ * 2) By picking a subset of the list which will be used for the whole
+ * acl evaluation.
+ * 3) A finer granularity, i.e, a selected list of acls which will be
+ * used for only that entry's evaluation.
+ */
if (!(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) &&
(res_right & SLAPI_ACL_SEARCH) &&
((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) {
@@ -2680,7 +2652,6 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
}
}
-
/* If we are suppose to skip attr eval, then let's skip it */
if ((aclpb->aclpb_access & SLAPI_ACL_SEARCH) && (!skip_attrEval) &&
(aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) {
@@ -2697,9 +2668,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
goto acl__resource_match_aci_EXIT;
}
- /* We need to check again because we don't want to select this handle
- ** if the right doesn't match for now.
- */
+ /*
+ * We need to check again because we don't want to select this handle
+ * if the right doesn't match for now.
+ */
if (!(aci_right & res_right)) {
matches = ACL_FALSE;
goto acl__resource_match_aci_EXIT;
@@ -2718,20 +2690,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
* rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN
* then we would not need this crappy way of telling it was a MODRDN
* request ie. SLAPI_ACL_WRITE && !(c_attrEval).
- */
-
+ */
c_attrEval = aclpb->aclpb_curr_attrEval;
/*
* If we've already matched on targattrfilter then do not
* bother to look at the attrlist.
- */
-
+ */
if (!attr_matched_in_targetattrfilters) {
-
/* match target attr */
- if ((c_attrEval) &&
- (aci->aci_type & ACI_TARGET_ATTR)) {
+ if ((c_attrEval) && (aci->aci_type & ACI_TARGET_ATTR)) {
/* there is a target ATTR */
Targetattr **attrArray = aci->targetAttr;
Targetattr *attr = NULL;
@@ -2773,46 +2741,43 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
matches = (attr_matched ? ACL_TRUE : ACL_FALSE);
}
-
aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
/* figure out how it matched, i.e star matched */
- if (matches && star_matched && num_attrs == 1 &&
- !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE))
+ if (matches && star_matched && num_attrs == 1 && !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE)) {
aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED;
- else {
+ } else {
/* we are here means that there is a specific
- ** attr in the rule for this resource.
- ** We need to avoid this case
- ** Rule 1: (targetattr = "uid")
- ** Rule 2: (targetattr = "*")
- ** we cannot use STAR optimization
- */
+ * attr in the rule for this resource.
+ * We need to avoid this case
+ * Rule 1: (targetattr = "uid")
+ * Rule 2: (targetattr = "*")
+ * we cannot use STAR optimization
+ */
aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE;
aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
}
- } else if ((c_attrEval) ||
- (aci->aci_type & ACI_TARGET_ATTR)) {
+ } else if ((c_attrEval) || (aci->aci_type & ACI_TARGET_ATTR)) {
if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) &&
(aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) {
/*
- ** Targetattr rule doesn't make any sense
- ** in this case. So select this rule
- ** default: matches = ACL_TRUE;
- */
+ * Targetattr rule doesn't make any sense
+ * in this case. So select this rule
+ * default: matches = ACL_TRUE;
+ */
;
- } else if (aci_right & SLAPI_ACL_WRITE &&
+ } else if ((aci_right & SLAPI_ACL_WRITE) &&
(aci->aci_type & ACI_TARGET_ATTR) &&
!(c_attrEval) &&
(aci->aci_type & ACI_HAS_ALLOW_RULE)) {
/* We need to handle modrdn operation. Modrdn doesn't
- ** change any attrs but changes the RDN and so (attr=NULL).
- ** Here we found an acl which has a targetattr but
- ** the resource doesn't need one. In that case, we should
- ** consider this acl.
- ** the opposite is true if it is a deny rule, only a deny without
- ** any targetattr should deny modrdn
- ** default: matches = ACL_TRUE;
- */
+ * change any attrs but changes the RDN and so (attr=NULL).
+ * Here we found an acl which has a targetattr but
+ * the resource doesn't need one. In that case, we should
+ * consider this acl.
+ * the opposite is true if it is a deny rule, only a deny without
+ * any targetattr should deny modrdn
+ * default: matches = ACL_TRUE;
+ */
;
} else {
matches = ACL_FALSE;
@@ -2821,16 +2786,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
} /* !attr_matched_in_targetattrfilters */
/*
- ** Here we are testing if we find a entry test rule (which should
- ** be rare). In that case, just remember it. An entry test rule
- ** doesn't have "(targetattr)".
- */
+ * Here we are testing if we find a entry test rule (which should
+ * be rare). In that case, just remember it. An entry test rule
+ * doesn't have "(targetattr)".
+ */
if ((aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) &&
(!(aci->aci_type & ACI_TARGET_ATTR))) {
aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE;
}
-/*
+ /*
* Generic exit point for this routine:
* matches is ACL_TRUE if the aci matches the target of the resource,
* ACL_FALSE othrewise.
@@ -2853,6 +2818,7 @@ acl__resource_match_aci_EXIT:
return (matches);
}
+
/* Macro to determine if the cached result is valid or not. */
#define ACL_CACHED_RESULT_VALID(result) \
(((result & ACLPB_CACHE_READ_RES_ALLOW) && \
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
index 6e53a0aea..bff751c88 100644
--- a/ldap/servers/slapd/back-ldbm/findentry.c
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
@@ -93,7 +93,6 @@ find_entry_internal_dn(
size_t tries = 0;
int isroot = 0;
int op_type;
- char *errbuf = NULL;
/* get the managedsait ldap message control */
slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
@@ -207,8 +206,8 @@ find_entry_internal_dn(
break;
}
if (acl_type > 0) {
- err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
- ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
+ char *dummy_attr = "1.1";
+ err = slapi_access_allowed(pb, me->ep_entry, dummy_attr, NULL, acl_type);
}
if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
/*
@@ -237,7 +236,6 @@ find_entry_internal_dn(
CACHE_RETURN(&inst->inst_cache, &me);
}
- slapi_ch_free_string(&errbuf);
slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal_dn", "<= Not found (%s)\n",
slapi_sdn_get_dn(sdn));
return (NULL);
diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
index c60837601..ca6ea6ef8 100644
--- a/src/lib389/lib389/_mapped_object.py
+++ b/src/lib389/lib389/_mapped_object.py
@@ -1190,7 +1190,7 @@ class DSLdapObjects(DSLogging, DSLints):
# Now actually commit the creation req
return co.ensure_state(rdn, properties, self._basedn)
- def filter(self, search, scope=None):
+ def filter(self, search, scope=None, strict=False):
# This will yield and & filter for objectClass with as many terms as needed.
if search:
search_filter = _gen_and([self._get_objectclass_filter(), search])
@@ -1211,5 +1211,7 @@ class DSLdapObjects(DSLogging, DSLints):
insts = [self._entry_to_instance(dn=r.dn, entry=r) for r in results]
except ldap.NO_SUCH_OBJECT:
# There are no objects to select from, se we return an empty array
+ if strict:
+ raise ldap.NO_SUCH_OBJECT
insts = []
return insts
--
2.26.2

View File

@ -0,0 +1,145 @@
From 4fb3023a55529c9d5332e3425ae8da590a8ebb69 Mon Sep 17 00:00:00 2001
From: tbordaz <tbordaz@redhat.com>
Date: Mon, 1 Feb 2021 09:28:25 +0100
Subject: [PATCH 3/4] Issue 4581 - A failed re-indexing leaves the database in
broken state (#4582)
Bug description:
During reindex the numsubordinates attribute is not updated in parent entries.
The consequence is that the internal counter job->numsubordinates==0.
Later when indexing the ancestorid, the server can show the progression of this
indexing with a ratio using job->numsubordinates==0.
Division with 0 -> SIGFPE
Fix description:
if the numsubordinates is NULL, log a message without a division.
relates: https://github.com/389ds/389-ds-base/issues/4581
Reviewed by: Pierre Rogier, Mark Reynolds, Simon Pichugin, Teko Mihinto (thanks !!)
Platforms tested: F31
---
.../slapd/back-ldbm/db-bdb/bdb_import.c | 72 ++++++++++++++-----
1 file changed, 54 insertions(+), 18 deletions(-)
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
index 15574e60f..9713b52f6 100644
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
@@ -468,18 +468,30 @@ bdb_get_nonleaf_ids(backend *be, DB_TXN *txn, IDList **idl, ImportJob *job)
}
key_count++;
if (!(key_count % PROGRESS_INTERVAL)) {
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
- "Gathering ancestorid non-leaf IDs: processed %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
+ "Gathering ancestorid non-leaf IDs: processed %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
+ "Gathering ancestorid non-leaf IDs: processed %d ancestors...",
+ key_count);
+ }
started_progress_logging = 1;
}
} while (ret == 0 && !(job->flags & FLAG_ABORT));
if (started_progress_logging) {
/* finish what we started logging */
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
- "Gathering ancestorid non-leaf IDs: processed %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
+ "Gathering ancestorid non-leaf IDs: processed %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
+ "Gathering ancestorid non-leaf IDs: processed %d ancestors",
+ key_count);
+ }
}
import_log_notice(job, SLAPI_LOG_INFO, "bdb_get_nonleaf_ids",
"Finished gathering ancestorid non-leaf IDs.");
@@ -660,9 +672,15 @@ bdb_ancestorid_default_create_index(backend *be, ImportJob *job)
key_count++;
if (!(key_count % PROGRESS_INTERVAL)) {
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
- "Creating ancestorid index: processed %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
+ "Creating ancestorid index: processed %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
+ "Creating ancestorid index: processed %d ancestors...",
+ key_count);
+ }
started_progress_logging = 1;
}
@@ -743,9 +761,15 @@ out:
if (ret == 0) {
if (started_progress_logging) {
/* finish what we started logging */
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
- "Creating ancestorid index: processed %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
+ "Creating ancestorid index: processed %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
+ "Creating ancestorid index: processed %d ancestors",
+ key_count);
+ }
}
import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_default_create_index",
"Created ancestorid index (old idl).");
@@ -869,9 +893,15 @@ bdb_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
key_count++;
if (!(key_count % PROGRESS_INTERVAL)) {
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
- "Creating ancestorid index: progress %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
+ "Creating ancestorid index: progress %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
+ "Creating ancestorid index: progress %d ancestors...",
+ key_count);
+ }
started_progress_logging = 1;
}
@@ -932,9 +962,15 @@ out:
if (ret == 0) {
if (started_progress_logging) {
/* finish what we started logging */
- import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
- "Creating ancestorid index: processed %d%% (ID count %d)",
- (key_count * 100 / job->numsubordinates), key_count);
+ if (job->numsubordinates) {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
+ "Creating ancestorid index: processed %d%% (ID count %d)",
+ (key_count * 100 / job->numsubordinates), key_count);
+ } else {
+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
+ "Creating ancestorid index: processed %d ancestors",
+ key_count);
+ }
}
import_log_notice(job, SLAPI_LOG_INFO, "bdb_ancestorid_new_idl_create_index",
"Created ancestorid index (new idl).");
--
2.26.2

View File

@ -0,0 +1,163 @@
From 861f17d2cb50fc649feee004be1ce08d2e3873f8 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Tue, 9 Feb 2021 14:02:59 -0500
Subject: [PATCH 4/4] Issue 4609 - CVE - info disclosure when authenticating
Description: If you bind as a user that does not exist. Error 49 is returned
instead of error 32. As error 32 discloses that the entry does
not exist. When you bind as an entry that does not have userpassword
set then error 48 (inappropriate auth) is returned, but this
discloses that the entry does indeed exist. Instead we should
always return error 49, even if the password is not set in the
entry. This way we do not disclose to an attacker if the Bind
DN exists or not.
Relates: https://github.com/389ds/389-ds-base/issues/4609
Reviewed by: tbordaz(Thanks!)
---
dirsrvtests/tests/suites/basic/basic_test.py | 72 +++++++++++++++++++-
ldap/servers/slapd/back-ldbm/ldbm_bind.c | 4 +-
ldap/servers/slapd/dse.c | 7 +-
3 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
index e9afa1e7e..6244782fa 100644
--- a/dirsrvtests/tests/suites/basic/basic_test.py
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
@@ -13,7 +13,7 @@
from subprocess import check_output, PIPE, run
from lib389 import DirSrv
-from lib389.idm.user import UserAccounts
+from lib389.idm.user import UserAccount, UserAccounts
import pytest
from lib389.tasks import *
from lib389.utils import *
@@ -1062,6 +1062,76 @@ def test_search_ou(topology_st):
assert len(entries) == 0
+def test_bind_invalid_entry(topology_st):
+ """Test the failing bind does not return information about the entry
+
+ :id: 5cd9b083-eea6-426b-84ca-83c26fc49a6f
+ :customerscenario: True
+ :setup: Standalone instance
+ :steps:
+ 1: bind as non existing entry
+ 2: check that bind info does not report 'No such entry'
+ :expectedresults:
+ 1: pass
+ 2: pass
+ """
+
+ topology_st.standalone.restart()
+ INVALID_ENTRY="cn=foooo,%s" % DEFAULT_SUFFIX
+ try:
+ topology_st.standalone.simple_bind_s(INVALID_ENTRY, PASSWORD)
+ except ldap.LDAPError as e:
+ log.info('test_bind_invalid_entry: Failed to bind as %s (expected)' % INVALID_ENTRY)
+ log.info('exception description: ' + e.args[0]['desc'])
+ if 'info' in e.args[0]:
+ log.info('exception info: ' + e.args[0]['info'])
+ assert e.args[0]['desc'] == 'Invalid credentials'
+ assert 'info' not in e.args[0]
+ pass
+
+ log.info('test_bind_invalid_entry: PASSED')
+
+ # reset credentials
+ topology_st.standalone.simple_bind_s(DN_DM, PW_DM)
+
+
+def test_bind_entry_missing_passwd(topology_st):
+ """
+ :id: af209149-8fb8-48cb-93ea-3e82dd7119d2
+ :setup: Standalone Instance
+ :steps:
+ 1. Bind as database entry that does not have userpassword set
+ 2. Bind as database entry that does not exist
+ 1. Bind as cn=config entry that does not have userpassword set
+ 2. Bind as cn=config entry that does not exist
+ :expectedresults:
+ 1. Fails with error 49
+ 2. Fails with error 49
+ 3. Fails with error 49
+ 4. Fails with error 49
+ """
+ user = UserAccount(topology_st.standalone, DEFAULT_SUFFIX)
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
+ # Bind as the suffix root entry which does not have a userpassword
+ user.bind("some_password")
+
+ user = UserAccount(topology_st.standalone, "cn=not here," + DEFAULT_SUFFIX)
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
+ # Bind as the entry which does not exist
+ user.bind("some_password")
+
+ # Test cn=config since it has its own code path
+ user = UserAccount(topology_st.standalone, "cn=config")
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
+ # Bind as the config entry which does not have a userpassword
+ user.bind("some_password")
+
+ user = UserAccount(topology_st.standalone, "cn=does not exist,cn=config")
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
+ # Bind as an entry under cn=config that does not exist
+ user.bind("some_password")
+
+
@pytest.mark.bz1044135
@pytest.mark.ds47319
def test_connection_buffer_size(topology_st):
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
index fa450ecd5..38d115a32 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_bind.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
@@ -76,8 +76,8 @@ ldbm_back_bind(Slapi_PBlock *pb)
case LDAP_AUTH_SIMPLE: {
Slapi_Value cv;
if (slapi_entry_attr_find(e->ep_entry, "userpassword", &attr) != 0) {
- slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
- NULL, 0, NULL);
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
CACHE_RETURN(&inst->inst_cache, &e);
rc = SLAPI_BIND_FAIL;
goto bail;
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
index 0e22d3cec..0d3268046 100644
--- a/ldap/servers/slapd/dse.c
+++ b/ldap/servers/slapd/dse.c
@@ -1443,7 +1443,8 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
ec = dse_get_entry_copy(pdse, sdn, DSE_USE_LOCK);
if (ec == NULL) {
- slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL);
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not exist");
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
return (SLAPI_BIND_FAIL);
}
@@ -1451,7 +1452,8 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
case LDAP_AUTH_SIMPLE: {
Slapi_Value cv;
if (slapi_entry_attr_find(ec, "userpassword", &attr) != 0) {
- slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
slapi_entry_free(ec);
return SLAPI_BIND_FAIL;
}
@@ -1459,6 +1461,7 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
slapi_value_init_berval(&cv, cred);
if (slapi_pw_find_sv(bvals, &cv) != 0) {
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
slapi_entry_free(ec);
value_done(&cv);
--
2.26.2

View File

@ -0,0 +1,97 @@
From 82db41ae6f76464a6ee3cbfdca8019bc809b3cf3 Mon Sep 17 00:00:00 2001
From: William Brown <william@blackhats.net.au>
Date: Thu, 26 Nov 2020 09:08:13 +1000
Subject: [PATCH] Issue 4460 - BUG - lib389 should use system tls policy
Bug Description: Due to some changes in dsrc for tlsreqcert
and how def open was structured in lib389, the system ldap.conf
policy was ignored.
Fix Description: Default to using the system ldap.conf policy
if undefined in lib389 or the tls_reqcert param in dsrc.
fixes: #4460
Author: William Brown <william@blackhats.net.au>
Review by: ???
---
src/lib389/lib389/__init__.py | 11 +++++++----
src/lib389/lib389/cli_base/dsrc.py | 16 +++++++++-------
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
index 63d44b60a..dc18b2bfe 100644
--- a/src/lib389/lib389/__init__.py
+++ b/src/lib389/lib389/__init__.py
@@ -962,7 +962,7 @@ class DirSrv(SimpleLDAPObject, object):
# Now, we are still an allocated ds object so we can be re-installed
self.state = DIRSRV_STATE_ALLOCATED
- def open(self, uri=None, saslmethod=None, sasltoken=None, certdir=None, starttls=False, connOnly=False, reqcert=ldap.OPT_X_TLS_HARD,
+ def open(self, uri=None, saslmethod=None, sasltoken=None, certdir=None, starttls=False, connOnly=False, reqcert=None,
usercert=None, userkey=None):
'''
It opens a ldap bound connection to dirsrv so that online
@@ -1025,9 +1025,12 @@ class DirSrv(SimpleLDAPObject, object):
try:
# Note this sets LDAP.OPT not SELF. Because once self has opened
# it can NOT change opts on reused (ie restart)
- self.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, reqcert)
- self.log.debug("Using certificate policy %s", reqcert)
- self.log.debug("ldap.OPT_X_TLS_REQUIRE_CERT = %s", reqcert)
+ if reqcert is not None:
+ self.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, reqcert)
+ self.log.debug("Using lib389 certificate policy %s", reqcert)
+ else:
+ self.log.debug("Using /etc/openldap/ldap.conf certificate policy")
+ self.log.debug("ldap.OPT_X_TLS_REQUIRE_CERT = %s", self.get_option(ldap.OPT_X_TLS_REQUIRE_CERT))
except ldap.LDAPError as e:
self.log.fatal('TLS negotiation failed: %s', e)
raise e
diff --git a/src/lib389/lib389/cli_base/dsrc.py b/src/lib389/lib389/cli_base/dsrc.py
index 9cad23437..8a4a2a55d 100644
--- a/src/lib389/lib389/cli_base/dsrc.py
+++ b/src/lib389/lib389/cli_base/dsrc.py
@@ -45,7 +45,7 @@ def dsrc_arg_concat(args, dsrc_inst):
'tls_cacertdir': None,
'tls_cert': None,
'tls_key': None,
- 'tls_reqcert': ldap.OPT_X_TLS_HARD,
+ 'tls_reqcert': None,
'starttls': args.starttls,
'prompt': False,
'pwdfile': None,
@@ -134,21 +134,23 @@ def dsrc_to_ldap(path, instance_name, log):
dsrc_inst['binddn'] = config.get(instance_name, 'binddn', fallback=None)
dsrc_inst['saslmech'] = config.get(instance_name, 'saslmech', fallback=None)
if dsrc_inst['saslmech'] is not None and dsrc_inst['saslmech'] not in ['EXTERNAL', 'PLAIN']:
- raise Exception("%s [%s] saslmech must be one of EXTERNAL or PLAIN" % (path, instance_name))
+ raise ValueError("%s [%s] saslmech must be one of EXTERNAL or PLAIN" % (path, instance_name))
dsrc_inst['tls_cacertdir'] = config.get(instance_name, 'tls_cacertdir', fallback=None)
dsrc_inst['tls_cert'] = config.get(instance_name, 'tls_cert', fallback=None)
dsrc_inst['tls_key'] = config.get(instance_name, 'tls_key', fallback=None)
- dsrc_inst['tls_reqcert'] = config.get(instance_name, 'tls_reqcert', fallback='hard')
- if dsrc_inst['tls_reqcert'] not in ['never', 'allow', 'hard']:
- raise Exception("dsrc tls_reqcert value invalid. %s [%s] tls_reqcert should be one of never, allow or hard" % (instance_name,
- path))
+ dsrc_inst['tls_reqcert'] = config.get(instance_name, 'tls_reqcert', fallback=None)
if dsrc_inst['tls_reqcert'] == 'never':
dsrc_inst['tls_reqcert'] = ldap.OPT_X_TLS_NEVER
elif dsrc_inst['tls_reqcert'] == 'allow':
dsrc_inst['tls_reqcert'] = ldap.OPT_X_TLS_ALLOW
- else:
+ elif dsrc_inst['tls_reqcert'] == 'hard':
dsrc_inst['tls_reqcert'] = ldap.OPT_X_TLS_HARD
+ elif dsrc_inst['tls_reqcert'] is None:
+ # Use system value
+ pass
+ else:
+ raise ValueError("dsrc tls_reqcert value invalid. %s [%s] tls_reqcert should be one of never, allow or hard" % (instance_name, path))
dsrc_inst['starttls'] = config.getboolean(instance_name, 'starttls', fallback=False)
dsrc_inst['pwdfile'] = None
dsrc_inst['prompt'] = False
--
2.26.2

View File

@ -0,0 +1,39 @@
From 2d6ca042adcf0dc2bbf9b898d698bbf62514c4a5 Mon Sep 17 00:00:00 2001
From: Firstyear <william@blackhats.net.au>
Date: Fri, 4 Dec 2020 10:14:33 +1000
Subject: [PATCH] Issue 4460 - BUG - add machine name to subject alt names in
SSCA (#4472)
Bug Description: During SSCA creation, the server cert did not have
the machine name, which meant that the cert would not work without
reqcert = never.
Fix Description: Add the machine name as an alt name during SSCA
creation. It is not guaranteed this value is correct, but it
is better than nothing.
relates: https://github.com/389ds/389-ds-base/issues/4460
Author: William Brown <william@blackhats.net.au>
Review by: mreynolds389, droideck
---
src/lib389/lib389/instance/setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py
index 45c7dfdd4..21260ee20 100644
--- a/src/lib389/lib389/instance/setup.py
+++ b/src/lib389/lib389/instance/setup.py
@@ -870,7 +870,7 @@ class SetupDs(object):
tlsdb_inst = NssSsl(dbpath=os.path.join(etc_dirsrv_path, dir))
tlsdb_inst.import_rsa_crt(ca)
- csr = tlsdb.create_rsa_key_and_csr()
+ csr = tlsdb.create_rsa_key_and_csr(alt_names=[general['full_machine_name']])
(ca, crt) = ssca.rsa_ca_sign_csr(csr)
tlsdb.import_rsa_crt(ca, crt)
if general['selinux']:
--
2.26.2

View File

@ -45,7 +45,7 @@ ExcludeArch: i686
Summary: 389 Directory Server (base)
Name: 389-ds-base
Version: 1.4.3.8
Release: %{?relprefix}6%{?prerel}%{?dist}
Release: %{?relprefix}7%{?prerel}%{?dist}
License: GPLv3+
URL: https://www.port389.org
Group: System Environment/Daemons
@ -207,7 +207,12 @@ Patch30: 0030-ticket-2058-Add-keep-alive-entry-after-on-line-initi.patc
Patch31: 0031-do-not-add-referrals-for-masters-with-different-data.patch
Patch32: 0032-Issue-4383-Do-not-normalize-escaped-spaces-in-a-DN.patch
Patch33: 0033-Issue-49300-entryUSN-is-duplicated-after-memberOf-op.patch
Patch34: 0034-Issue-4480-Unexpected-info-returned-to-ldap-request-.patch
Patch35: 0035-Issue-5442-Search-results-are-different-between-RHDS.patch
Patch36: 0036-Issue-4581-A-failed-re-indexing-leaves-the-database-.patch
Patch37: 0037-Issue-4609-CVE-info-disclosure-when-authenticating.patch
Patch38: 0038-Issue-4460-BUG-lib389-should-use-system-tls-policy.patch
Patch39: 0039-Issue-4460-BUG-add-machine-name-to-subject-alt-names.patch
%description
389 Directory Server is an LDAPv3 compliant server. The base package includes
@ -825,15 +830,21 @@ exit 0
%doc README.md
%changelog
* Thu Mar 11 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.8-7
- Bump version to 1.4.3.8-7
- Resolves: Bug 1908705 - CVE-2020-35518 389-ds:1.4/389-ds-base: information disclosure during the binding of a DN
- Resolves: Bug 1936461 - A failed re-indexing leaves the database in broken state.
- Resolves: Bug 1912481 - Server-Cert.crt created using dscreate has Subject:CN =localhost instead of hostname.
* Thu Dec 3 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.8-6
- Bump version to 1.4.3.8-6
- Resolves: Bug 1851973 - Duplicate entryUSN numbers for different LDAP entries in the same backend
- Resolves: Bug 1888863 - group rdn with leading space char and add fails error 21 invalid syntax and delete fails error 32
- Resolves: Bug 1859228 - do not add referrals for masters with different data generation
- Resolves: Bug 1859227 - create keep alive entry after on line init
- Resolves: Bug 1896850 - NULL dereference in revert_cache()
- Resolves: Bug 1861504 - ds-replcheck crashes in offline mode
- Resolves: Bug 1898850 - Entries conflict not resolved by replication
- Resolves: Bug 1904348 - Duplicate entryUSN numbers for different LDAP entries in the same backend
- Resolves: Bug 1904349 - group rdn with leading space char and add fails error 21 invalid syntax and delete fails error 32
- Resolves: Bug 1904350 - do not add referrals for masters with different data generation
- Resolves: Bug 1904351 - create keep alive entry after on line init
- Resolves: Bug 1904352 - NULL dereference in revert_cache()
- Resolves: Bug 1904353 - ds-replcheck crashes in offline mode
- Resolves: Bug 1904347 - Entries conflict not resolved by replication
* Wed Aug 5 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.8-5
- Bump version to 1.4.3.8-5