Compare commits
9 Commits
imports/c8
...
c8-stream-
Author | SHA1 | Date | |
---|---|---|---|
4a9b4e4bb8 | |||
456f49d8a3 | |||
62ada8d853 | |||
7e6d0bfb15 | |||
91e5547fc3 | |||
|
e1f2cae548 | ||
|
a7a184d43c | ||
|
69d0b88d75 | ||
|
ceb31709f5 |
@ -1,3 +1,3 @@
|
||||
9274c7088190993255749ea90bbb770c5c5e0f5c SOURCES/389-ds-base-1.4.3.28.tar.bz2
|
||||
9e06b5cc57fd185379d007696da153893cf73e30 SOURCES/jemalloc-5.2.1.tar.bz2
|
||||
c6875530163f0e217ed2e0e5b768506db3d07447 SOURCES/vendor-1.4.3.28-1.tar.gz
|
||||
bd9aab32d9cbf9231058d585479813f3420dc872 SOURCES/389-ds-base-1.4.3.39.tar.bz2
|
||||
1c8f2d0dfbf39fa8cd86363bf3314351ab21f8d4 SOURCES/jemalloc-5.3.0.tar.bz2
|
||||
978b7c5e4a9e5784fddb23ba1abe4dc5a071589f SOURCES/vendor-1.4.3.39-1.tar.gz
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
SOURCES/389-ds-base-1.4.3.28.tar.bz2
|
||||
SOURCES/jemalloc-5.2.1.tar.bz2
|
||||
SOURCES/vendor-1.4.3.28-1.tar.gz
|
||||
SOURCES/389-ds-base-1.4.3.39.tar.bz2
|
||||
SOURCES/jemalloc-5.3.0.tar.bz2
|
||||
SOURCES/vendor-1.4.3.39-1.tar.gz
|
||||
|
@ -1,738 +0,0 @@
|
||||
From 67e19da62a9e8958458de54173dcd9bcaf53164d Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Thu, 30 Sep 2021 15:59:40 +0200
|
||||
Subject: [PATCH 01/12] Issue 4678 - RFE automatique disable of virtual
|
||||
attribute checking (#4918)
|
||||
|
||||
Bug description:
|
||||
Virtual attributes are configured via Roles or COS definitions
|
||||
and registered during initialization of those plugins.
|
||||
Virtual attributes are processed during search evaluation of
|
||||
filter and returned attributes. This processing is expensive
|
||||
and prone to create contention between searches.
|
||||
Use of virtual attribute is not frequent. So many of the
|
||||
deployement process virtual attribute even if there is none.
|
||||
|
||||
Fix description:
|
||||
The fix configure the server to ignore virtual attribute by
|
||||
default (nsslapd-ignore-virtual-attrs: on).
|
||||
At startup, if a new virtual attribute is registered or
|
||||
it exists Roles/COS definitions, then the server is
|
||||
configured to process the virtual attributes
|
||||
(nsslapd-ignore-virtual-attrs: off)
|
||||
design: https://www.port389.org/docs/389ds/design/vattr-automatic-toggle.html
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4678
|
||||
|
||||
Reviewed by: William Brown, Simon Pichugin, Mark Reynolds (Thanks !!)
|
||||
|
||||
Platforms tested: F34
|
||||
---
|
||||
.../tests/suites/config/config_test.py | 40 +++-
|
||||
dirsrvtests/tests/suites/cos/cos_test.py | 94 ++++++--
|
||||
dirsrvtests/tests/suites/roles/basic_test.py | 200 +++++++++++++++++-
|
||||
ldap/servers/plugins/roles/roles_cache.c | 9 +
|
||||
ldap/servers/slapd/libglobs.c | 2 +-
|
||||
ldap/servers/slapd/main.c | 2 +
|
||||
ldap/servers/slapd/proto-slap.h | 1 +
|
||||
ldap/servers/slapd/vattr.c | 127 +++++++++++
|
||||
src/lib389/lib389/idm/role.py | 4 +
|
||||
9 files changed, 455 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/config/config_test.py b/dirsrvtests/tests/suites/config/config_test.py
|
||||
index 2ecff8f98..19232c87d 100644
|
||||
--- a/dirsrvtests/tests/suites/config/config_test.py
|
||||
+++ b/dirsrvtests/tests/suites/config/config_test.py
|
||||
@@ -351,7 +351,7 @@ def test_ignore_virtual_attrs(topo):
|
||||
:setup: Standalone instance
|
||||
:steps:
|
||||
1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
- 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
3. Set the valid values i.e. on/ON and off/OFF for nsslapd-ignore-virtual-attrs
|
||||
4. Set invalid value for attribute nsslapd-ignore-virtual-attrs
|
||||
5. Set nsslapd-ignore-virtual-attrs=off
|
||||
@@ -374,8 +374,8 @@ def test_ignore_virtual_attrs(topo):
|
||||
log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
|
||||
- log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
- assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "off"
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
|
||||
log.info("Set the valid values i.e. on/ON and off/OFF for nsslapd-ignore-virtual-attrs")
|
||||
for attribute_value in ['on', 'off', 'ON', 'OFF']:
|
||||
@@ -415,6 +415,40 @@ def test_ignore_virtual_attrs(topo):
|
||||
log.info("Test if virtual attribute i.e. postal code not shown while nsslapd-ignore-virtual-attrs: on")
|
||||
assert not test_user.present('postalcode', '117')
|
||||
|
||||
+def test_ignore_virtual_attrs_after_restart(topo):
|
||||
+ """Test nsslapd-ignore-virtual-attrs configuration attribute
|
||||
+ The attribute is ON by default. If it set to OFF, it keeps
|
||||
+ its value on restart
|
||||
+
|
||||
+ :id: ac368649-4fda-473c-9ef8-e0c728b162af
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
+ 3. Set nsslapd-ignore-virtual-attrs=off
|
||||
+ 4. restart the instance
|
||||
+ 5. Check the attribute nsslapd-ignore-virtual-attrs is OFF
|
||||
+ :expectedresults:
|
||||
+ 1. This should be successful
|
||||
+ 2. This should be successful
|
||||
+ 3. This should be successful
|
||||
+ 4. This should be successful
|
||||
+ 5. This should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
+
|
||||
+ log.info("Set nsslapd-ignore-virtual-attrs = off")
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'off')
|
||||
+
|
||||
+ topo.standalone.restart()
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
|
||||
@pytest.mark.bz918694
|
||||
@pytest.mark.ds408
|
||||
diff --git a/dirsrvtests/tests/suites/cos/cos_test.py b/dirsrvtests/tests/suites/cos/cos_test.py
|
||||
index d6a498c73..d1f99f96f 100644
|
||||
--- a/dirsrvtests/tests/suites/cos/cos_test.py
|
||||
+++ b/dirsrvtests/tests/suites/cos/cos_test.py
|
||||
@@ -6,6 +6,8 @@
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
|
||||
+import logging
|
||||
+import time
|
||||
import pytest, os, ldap
|
||||
from lib389.cos import CosClassicDefinition, CosClassicDefinitions, CosTemplate
|
||||
from lib389._constants import DEFAULT_SUFFIX
|
||||
@@ -14,26 +16,37 @@ from lib389.idm.role import FilteredRoles
|
||||
from lib389.idm.nscontainer import nsContainer
|
||||
from lib389.idm.user import UserAccount
|
||||
|
||||
+logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
pytestmark = pytest.mark.tier1
|
||||
+@pytest.fixture(scope="function")
|
||||
+def reset_ignore_vattr(topo, request):
|
||||
+ default_ignore_vattr_value = topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs')
|
||||
+ def fin():
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', default_ignore_vattr_value)
|
||||
|
||||
-def test_positive(topo):
|
||||
- """
|
||||
- :id: a5a74235-597f-4fe8-8c38-826860927472
|
||||
- :setup: server
|
||||
- :steps:
|
||||
- 1. Add filter role entry
|
||||
- 2. Add ns container
|
||||
- 3. Add cos template
|
||||
- 4. Add CosClassic Definition
|
||||
- 5. Cos entries should be added and searchable
|
||||
- 6. employeeType attribute should be there in user entry as per the cos plugin property
|
||||
- :expectedresults:
|
||||
- 1. Operation should success
|
||||
- 2. Operation should success
|
||||
- 3. Operation should success
|
||||
- 4. Operation should success
|
||||
- 5. Operation should success
|
||||
- 6. Operation should success
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+def test_positive(topo, reset_ignore_vattr):
|
||||
+ """CoS positive tests
|
||||
+
|
||||
+ :id: a5a74235-597f-4fe8-8c38-826860927472
|
||||
+ :setup: server
|
||||
+ :steps:
|
||||
+ 1. Add filter role entry
|
||||
+ 2. Add ns container
|
||||
+ 3. Add cos template
|
||||
+ 4. Add CosClassic Definition
|
||||
+ 5. Cos entries should be added and searchable
|
||||
+ 6. employeeType attribute should be there in user entry as per the cos plugin property
|
||||
+ :expectedresults:
|
||||
+ 1. Operation should success
|
||||
+ 2. Operation should success
|
||||
+ 3. Operation should success
|
||||
+ 4. Operation should success
|
||||
+ 5. Operation should success
|
||||
+ 6. Operation should success
|
||||
"""
|
||||
# Adding ns filter role
|
||||
roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
@@ -77,7 +90,52 @@ def test_positive(topo):
|
||||
|
||||
# CoS definition entry's cosSpecifier attribute specifies the employeeType attribute
|
||||
assert user.present('employeeType')
|
||||
+ cosdef.delete()
|
||||
+
|
||||
+def test_vattr_on_cos_definition(topo, reset_ignore_vattr):
|
||||
+ """Test nsslapd-ignore-virtual-attrs configuration attribute
|
||||
+ The attribute is ON by default. If a cos definition is
|
||||
+ added it is moved to OFF
|
||||
+
|
||||
+ :id: e7ef5254-386f-4362-bbb4-9409f3f51b08
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
+ 3. Create a cos definition for employeeType
|
||||
+ 4. Check the value of nsslapd-ignore-virtual-attrs should be OFF (with a delay for postop processing)
|
||||
+ 5. Check a message "slapi_vattrspi_regattr - Because employeeType,.." in error logs
|
||||
+ :expectedresults:
|
||||
+ 1. This should be successful
|
||||
+ 2. This should be successful
|
||||
+ 3. This should be successful
|
||||
+ 4. This should be successful
|
||||
+ 5. This should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
+
|
||||
+ # creating CosClassicDefinition
|
||||
+ log.info("Create a cos definition")
|
||||
+ properties = {'cosTemplateDn': 'cn=cosClassicGenerateEmployeeTypeUsingnsroleTemplates,{}'.format(DEFAULT_SUFFIX),
|
||||
+ 'cosAttribute': 'employeeType',
|
||||
+ 'cosSpecifier': 'nsrole',
|
||||
+ 'cn': 'cosClassicGenerateEmployeeTypeUsingnsrole'}
|
||||
+ cosdef = CosClassicDefinition(topo.standalone,'cn=cosClassicGenerateEmployeeTypeUsingnsrole,{}'.format(DEFAULT_SUFFIX))\
|
||||
+ .create(properties=properties)
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ time.sleep(2)
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
|
||||
+ topo.standalone.stop()
|
||||
+ assert topo.standalone.searchErrorsLog("slapi_vattrspi_regattr - Because employeeType is a new registered virtual attribute , nsslapd-ignore-virtual-attrs was set to \'off\'")
|
||||
+ topo.standalone.start()
|
||||
+ cosdef.delete()
|
||||
|
||||
if __name__ == "__main__":
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
diff --git a/dirsrvtests/tests/suites/roles/basic_test.py b/dirsrvtests/tests/suites/roles/basic_test.py
|
||||
index 47a531794..bec3aedfc 100644
|
||||
--- a/dirsrvtests/tests/suites/roles/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/roles/basic_test.py
|
||||
@@ -11,6 +11,8 @@
|
||||
Importing necessary Modules.
|
||||
"""
|
||||
|
||||
+import logging
|
||||
+import time
|
||||
import os
|
||||
import pytest
|
||||
|
||||
@@ -22,6 +24,9 @@ from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.role import FilteredRoles, ManagedRoles, NestedRoles
|
||||
from lib389.idm.domain import Domain
|
||||
|
||||
+logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
DNBASE = "o=acivattr,{}".format(DEFAULT_SUFFIX)
|
||||
@@ -35,7 +40,7 @@ FILTERROLESALESROLE = "cn=FILTERROLESALESROLE,{}".format(DNBASE)
|
||||
FILTERROLEENGROLE = "cn=FILTERROLEENGROLE,{}".format(DNBASE)
|
||||
|
||||
|
||||
-def test_filterrole(topo):
|
||||
+def test_filterrole(topo, request):
|
||||
"""Test Filter Role
|
||||
|
||||
:id: 8ada4064-786b-11e8-8634-8c16451d917b
|
||||
@@ -136,8 +141,20 @@ def test_filterrole(topo):
|
||||
SALES_OU, DNBASE]:
|
||||
UserAccount(topo.standalone, dn_dn).delete()
|
||||
|
||||
+ def fin():
|
||||
+ topo.standalone.restart()
|
||||
+ try:
|
||||
+ filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in filtered_roles.list():
|
||||
+ i.delete()
|
||||
+ except:
|
||||
+ pass
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
|
||||
-def test_managedrole(topo):
|
||||
+def test_managedrole(topo, request):
|
||||
"""Test Managed Role
|
||||
|
||||
:id: d52a9c00-3bf6-11e9-9b7b-8c16451d917b
|
||||
@@ -209,6 +226,16 @@ def test_managedrole(topo):
|
||||
for i in roles.list():
|
||||
i.delete()
|
||||
|
||||
+ def fin():
|
||||
+ topo.standalone.restart()
|
||||
+ try:
|
||||
+ role = ManagedRoles(topo.standalone, DEFAULT_SUFFIX).get('ROLE1')
|
||||
+ role.delete()
|
||||
+ except:
|
||||
+ pass
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def _final(request, topo):
|
||||
@@ -220,6 +247,7 @@ def _final(request, topo):
|
||||
def finofaci():
|
||||
"""
|
||||
Removes and Restores ACIs and other users after the test.
|
||||
+ And restore nsslapd-ignore-virtual-attrs to default
|
||||
"""
|
||||
domain = Domain(topo.standalone, DEFAULT_SUFFIX)
|
||||
domain.remove_all('aci')
|
||||
@@ -234,6 +262,8 @@ def _final(request, topo):
|
||||
for i in aci_list:
|
||||
domain.add("aci", i)
|
||||
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
request.addfinalizer(finofaci)
|
||||
|
||||
|
||||
@@ -296,6 +326,172 @@ def test_nestedrole(topo, _final):
|
||||
conn = users.get('test_user_3').bind(PW_DM)
|
||||
assert UserAccounts(conn, DEFAULT_SUFFIX).list()
|
||||
|
||||
+def test_vattr_on_filtered_role(topo, request):
|
||||
+ """Test nsslapd-ignore-virtual-attrs configuration attribute
|
||||
+ The attribute is ON by default. If a filtered role is
|
||||
+ added it is moved to OFF
|
||||
+
|
||||
+ :id: 88b3ad3c-f39a-4eb7-a8c9-07c685f11908
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
+ 3. Create a filtered role
|
||||
+ 4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
|
||||
+ 5. Check a message "roles_cache_trigger_update_role - Because of virtual attribute.." in error logs
|
||||
+ :expectedresults:
|
||||
+ 1. This should be successful
|
||||
+ 2. This should be successful
|
||||
+ 3. This should be successful
|
||||
+ 4. This should be successful
|
||||
+ 5. This should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
+
|
||||
+ log.info("Create a filtered role")
|
||||
+ try:
|
||||
+ Organization(topo.standalone).create(properties={"o": "acivattr"}, basedn=DEFAULT_SUFFIX)
|
||||
+ except:
|
||||
+ pass
|
||||
+ roles = FilteredRoles(topo.standalone, DNBASE)
|
||||
+ roles.create(properties={'cn': 'FILTERROLEENGROLE', 'nsRoleFilter': 'cn=eng*'})
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
+
|
||||
+ topo.standalone.stop()
|
||||
+ assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
|
||||
+
|
||||
+ def fin():
|
||||
+ topo.standalone.restart()
|
||||
+ try:
|
||||
+ filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in filtered_roles.list():
|
||||
+ i.delete()
|
||||
+ except:
|
||||
+ pass
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+def test_vattr_on_filtered_role_restart(topo, request):
|
||||
+ """Test nsslapd-ignore-virtual-attrs configuration attribute
|
||||
+ If it exists a filtered role definition at restart then
|
||||
+ nsslapd-ignore-virtual-attrs should be set to 'off'
|
||||
+
|
||||
+ :id: 972183f7-d18f-40e0-94ab-580e7b7d78d0
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
+ 3. Create a filtered role
|
||||
+ 4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
|
||||
+ 5. restart the instance
|
||||
+ 6. Check the presence of virtual attribute is detected
|
||||
+ 7. Check the value of nsslapd-ignore-virtual-attrs should be OFF
|
||||
+ :expectedresults:
|
||||
+ 1. This should be successful
|
||||
+ 2. This should be successful
|
||||
+ 3. This should be successful
|
||||
+ 4. This should be successful
|
||||
+ 5. This should be successful
|
||||
+ 6. This should be successful
|
||||
+ 7. This should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
+
|
||||
+ log.info("Create a filtered role")
|
||||
+ try:
|
||||
+ Organization(topo.standalone).create(properties={"o": "acivattr"}, basedn=DEFAULT_SUFFIX)
|
||||
+ except:
|
||||
+ pass
|
||||
+ roles = FilteredRoles(topo.standalone, DNBASE)
|
||||
+ roles.create(properties={'cn': 'FILTERROLEENGROLE', 'nsRoleFilter': 'cn=eng*'})
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
+
|
||||
+
|
||||
+ log.info("Check the virtual attribute definition is found (after a required delay)")
|
||||
+ topo.standalone.restart()
|
||||
+ time.sleep(5)
|
||||
+ assert topo.standalone.searchErrorsLog("Found a role/cos definition in")
|
||||
+ assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
+
|
||||
+ def fin():
|
||||
+ topo.standalone.restart()
|
||||
+ try:
|
||||
+ filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in filtered_roles.list():
|
||||
+ i.delete()
|
||||
+ except:
|
||||
+ pass
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+
|
||||
+def test_vattr_on_managed_role(topo, request):
|
||||
+ """Test nsslapd-ignore-virtual-attrs configuration attribute
|
||||
+ The attribute is ON by default. If a managed role is
|
||||
+ added it is moved to OFF
|
||||
+
|
||||
+ :id: 664b722d-c1ea-41e4-8f6c-f9c87a212346
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
|
||||
+ 2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
|
||||
+ 3. Create a managed role
|
||||
+ 4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
|
||||
+ 5. Check a message "roles_cache_trigger_update_role - Because of virtual attribute.." in error logs
|
||||
+ :expectedresults:
|
||||
+ 1. This should be successful
|
||||
+ 2. This should be successful
|
||||
+ 3. This should be successful
|
||||
+ 4. This should be successful
|
||||
+ 5. This should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
|
||||
+ assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
|
||||
+
|
||||
+ log.info("Create a managed role")
|
||||
+ roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ role = roles.create(properties={"cn": 'ROLE1'})
|
||||
+
|
||||
+ log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
|
||||
+ assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
|
||||
+
|
||||
+ topo.standalone.stop()
|
||||
+ assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
|
||||
+
|
||||
+ def fin():
|
||||
+ topo.standalone.restart()
|
||||
+ try:
|
||||
+ filtered_roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in filtered_roles.list():
|
||||
+ i.delete()
|
||||
+ except:
|
||||
+ pass
|
||||
+ topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
|
||||
if __name__ == "__main__":
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c
|
||||
index 3d076a4cb..cd00e0aba 100644
|
||||
--- a/ldap/servers/plugins/roles/roles_cache.c
|
||||
+++ b/ldap/servers/plugins/roles/roles_cache.c
|
||||
@@ -530,6 +530,15 @@ roles_cache_trigger_update_role(char *dn, Slapi_Entry *roles_entry, Slapi_DN *be
|
||||
}
|
||||
|
||||
slapi_rwlock_unlock(global_lock);
|
||||
+ {
|
||||
+ /* A role definition has been updated, enable vattr handling */
|
||||
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
|
||||
+ errorbuf[0] = '\0';
|
||||
+ config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
|
||||
+ slapi_log_err(SLAPI_LOG_INFO,
|
||||
+ "roles_cache_trigger_update_role",
|
||||
+ "Because of virtual attribute definition (role), %s was set to 'off'\n", CONFIG_IGNORE_VATTRS);
|
||||
+ }
|
||||
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_trigger_update_role: %p \n", roles_list);
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
|
||||
index 2ea4cd760..f6dacce30 100644
|
||||
--- a/ldap/servers/slapd/libglobs.c
|
||||
+++ b/ldap/servers/slapd/libglobs.c
|
||||
@@ -1803,7 +1803,7 @@ FrontendConfig_init(void)
|
||||
init_ndn_cache_enabled = cfg->ndn_cache_enabled = LDAP_ON;
|
||||
cfg->ndn_cache_max_size = SLAPD_DEFAULT_NDN_SIZE;
|
||||
init_sasl_mapping_fallback = cfg->sasl_mapping_fallback = LDAP_OFF;
|
||||
- init_ignore_vattrs = cfg->ignore_vattrs = LDAP_OFF;
|
||||
+ init_ignore_vattrs = cfg->ignore_vattrs = LDAP_ON;
|
||||
cfg->sasl_max_bufsize = SLAPD_DEFAULT_SASL_MAXBUFSIZE;
|
||||
cfg->unhashed_pw_switch = SLAPD_DEFAULT_UNHASHED_PW_SWITCH;
|
||||
init_return_orig_type = cfg->return_orig_type = LDAP_OFF;
|
||||
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
|
||||
index 4931a4ca4..61ed40b7d 100644
|
||||
--- a/ldap/servers/slapd/main.c
|
||||
+++ b/ldap/servers/slapd/main.c
|
||||
@@ -1042,6 +1042,8 @@ main(int argc, char **argv)
|
||||
eq_start(); /* must be done after plugins started - DEPRECATED */
|
||||
eq_start_rel(); /* must be done after plugins started */
|
||||
|
||||
+ vattr_check(); /* Check if it exists virtual attribute definitions */
|
||||
+
|
||||
#ifdef HPUX10
|
||||
/* HPUX linker voodoo */
|
||||
if (collation_init == NULL) {
|
||||
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
|
||||
index c143f3772..442a621aa 100644
|
||||
--- a/ldap/servers/slapd/proto-slap.h
|
||||
+++ b/ldap/servers/slapd/proto-slap.h
|
||||
@@ -1462,6 +1462,7 @@ void subentry_create_filter(Slapi_Filter **filter);
|
||||
*/
|
||||
void vattr_init(void);
|
||||
void vattr_cleanup(void);
|
||||
+void vattr_check(void);
|
||||
|
||||
/*
|
||||
* slapd_plhash.c - supplement to NSPR plhash
|
||||
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
|
||||
index 09dab6ecf..24750a57c 100644
|
||||
--- a/ldap/servers/slapd/vattr.c
|
||||
+++ b/ldap/servers/slapd/vattr.c
|
||||
@@ -64,6 +64,10 @@
|
||||
#define SOURCEFILE "vattr.c"
|
||||
static char *sourcefile = SOURCEFILE;
|
||||
|
||||
+/* stolen from roles_cache.h, must remain in sync */
|
||||
+#define NSROLEATTR "nsRole"
|
||||
+static Slapi_Eq_Context vattr_check_ctx = {0};
|
||||
+
|
||||
/* Define only for module test code */
|
||||
/* #define VATTR_TEST_CODE */
|
||||
|
||||
@@ -130,6 +134,112 @@ vattr_cleanup()
|
||||
{
|
||||
/* We need to free and remove anything that was inserted first */
|
||||
vattr_map_destroy();
|
||||
+ slapi_eq_cancel_rel(vattr_check_ctx);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+vattr_check_thread(void *arg)
|
||||
+{
|
||||
+ Slapi_Backend *be = NULL;
|
||||
+ char *cookie = NULL;
|
||||
+ Slapi_DN *base_sdn = NULL;
|
||||
+ Slapi_PBlock *search_pb = NULL;
|
||||
+ Slapi_Entry **entries = NULL;
|
||||
+ int32_t rc;
|
||||
+ int32_t check_suffix; /* used to skip suffixes in ignored_backend */
|
||||
+ PRBool exist_vattr_definition = PR_FALSE;
|
||||
+ char *ignored_backend[5] = {"cn=config", "cn=schema", "cn=monitor", "cn=changelog", NULL}; /* suffixes to ignore */
|
||||
+ char *suffix;
|
||||
+ int ignore_vattrs;
|
||||
+
|
||||
+ ignore_vattrs = config_get_ignore_vattrs();
|
||||
+
|
||||
+ if (!ignore_vattrs) {
|
||||
+ /* Nothing to do more, we are already evaluating virtual attribute */
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ search_pb = slapi_pblock_new();
|
||||
+ be = slapi_get_first_backend(&cookie);
|
||||
+ while (be && !exist_vattr_definition && !slapi_is_shutting_down()) {
|
||||
+ base_sdn = (Slapi_DN *) slapi_be_getsuffix(be, 0);
|
||||
+ suffix = (char *) slapi_sdn_get_dn(base_sdn);
|
||||
+
|
||||
+ if (suffix) {
|
||||
+ /* First check that we need to check that suffix */
|
||||
+ check_suffix = 1;
|
||||
+ for (size_t i = 0; ignored_backend[i]; i++) {
|
||||
+ if (strcasecmp(suffix, ignored_backend[i]) == 0) {
|
||||
+ check_suffix = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* search for a role or cos definition */
|
||||
+ if (check_suffix) {
|
||||
+ slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn),
|
||||
+ LDAP_SCOPE_SUBTREE, "(&(objectclass=ldapsubentry)(|(objectclass=nsRoleDefinition)(objectclass=cosSuperDefinition)))",
|
||||
+ NULL, 0, NULL, NULL, (void *) plugin_get_default_component_id(), 0);
|
||||
+ slapi_search_internal_pb(search_pb);
|
||||
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
+
|
||||
+ if (rc == LDAP_SUCCESS) {
|
||||
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
|
||||
+ if (entries && entries[0]) {
|
||||
+ /* it exists at least a cos or role definition */
|
||||
+ exist_vattr_definition = PR_TRUE;
|
||||
+ slapi_log_err(SLAPI_LOG_INFO,
|
||||
+ "vattr_check_thread",
|
||||
+ "Found a role/cos definition in %s\n", slapi_entry_get_dn(entries[0]));
|
||||
+ } else {
|
||||
+ slapi_log_err(SLAPI_LOG_INFO,
|
||||
+ "vattr_check_thread",
|
||||
+ "No role/cos definition in %s\n", slapi_sdn_get_dn(base_sdn));
|
||||
+ }
|
||||
+ }
|
||||
+ slapi_free_search_results_internal(search_pb);
|
||||
+ } /* check_suffix */
|
||||
+ } /* suffix */
|
||||
+ be = (backend *) slapi_get_next_backend(cookie);
|
||||
+ }
|
||||
+ slapi_pblock_destroy(search_pb);
|
||||
+ slapi_ch_free_string(&cookie);
|
||||
+
|
||||
+ /* Now if a virtual attribute is defined, then CONFIG_IGNORE_VATTRS -> off */
|
||||
+ if (exist_vattr_definition) {
|
||||
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
|
||||
+ errorbuf[0] = '\0';
|
||||
+ config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
|
||||
+ slapi_log_err(SLAPI_LOG_INFO,
|
||||
+ "vattr_check_thread",
|
||||
+ "Because of virtual attribute definition, %s was set to 'off'\n", CONFIG_IGNORE_VATTRS);
|
||||
+ }
|
||||
+}
|
||||
+static void
|
||||
+vattr_check_schedule_once(time_t when __attribute__((unused)), void *arg)
|
||||
+{
|
||||
+ if (PR_CreateThread(PR_USER_THREAD,
|
||||
+ vattr_check_thread,
|
||||
+ (void *) arg,
|
||||
+ PR_PRIORITY_NORMAL,
|
||||
+ PR_GLOBAL_THREAD,
|
||||
+ PR_UNJOINABLE_THREAD,
|
||||
+ SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR,
|
||||
+ "vattr_check_schedule_once",
|
||||
+ "Fails to check if %s needs to be toggled to FALSE\n", CONFIG_IGNORE_VATTRS);
|
||||
+ }
|
||||
+}
|
||||
+#define VATTR_CHECK_DELAY 3
|
||||
+void
|
||||
+vattr_check()
|
||||
+{
|
||||
+ /* Schedule running a callback that will create a thread
|
||||
+ * but make sure it is called a first thing when event loop is created */
|
||||
+ time_t now;
|
||||
+
|
||||
+ now = slapi_current_rel_time_t();
|
||||
+ vattr_check_ctx = slapi_eq_once_rel(vattr_check_schedule_once, NULL, now + VATTR_CHECK_DELAY);
|
||||
}
|
||||
|
||||
/* The public interface functions start here */
|
||||
@@ -1631,6 +1741,9 @@ slapi_vattrspi_regattr(vattr_sp_handle *h, char *type_name_to_register, char *DN
|
||||
char *type_to_add;
|
||||
int free_type_to_add = 0;
|
||||
Slapi_DN original_dn;
|
||||
+ int ignore_vattrs;
|
||||
+
|
||||
+ ignore_vattrs = config_get_ignore_vattrs();
|
||||
|
||||
slapi_sdn_init(&original_dn);
|
||||
|
||||
@@ -1676,6 +1789,20 @@ slapi_vattrspi_regattr(vattr_sp_handle *h, char *type_name_to_register, char *DN
|
||||
if (free_type_to_add) {
|
||||
slapi_ch_free((void **)&type_to_add);
|
||||
}
|
||||
+ if (ignore_vattrs && strcasecmp(type_name_to_register, NSROLEATTR)) {
|
||||
+ /* A new virtual attribute is registered.
|
||||
+ * This new vattr being *different* than the default roles vattr 'nsRole'
|
||||
+ * It is time to allow vattr lookup
|
||||
+ */
|
||||
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
|
||||
+ errorbuf[0] = '\0';
|
||||
+ config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
|
||||
+ slapi_log_err(SLAPI_LOG_INFO,
|
||||
+ "slapi_vattrspi_regattr",
|
||||
+ "Because %s is a new registered virtual attribute , %s was set to 'off'\n",
|
||||
+ type_name_to_register,
|
||||
+ CONFIG_IGNORE_VATTRS);
|
||||
+ }
|
||||
|
||||
return ret;
|
||||
}
|
||||
diff --git a/src/lib389/lib389/idm/role.py b/src/lib389/lib389/idm/role.py
|
||||
index fe91aab6f..9a2bff3d6 100644
|
||||
--- a/src/lib389/lib389/idm/role.py
|
||||
+++ b/src/lib389/lib389/idm/role.py
|
||||
@@ -252,6 +252,8 @@ class FilteredRole(Role):
|
||||
self._rdn_attribute = 'cn'
|
||||
self._create_objectclasses = ['nsComplexRoleDefinition', 'nsFilteredRoleDefinition']
|
||||
|
||||
+ self._protected = False
|
||||
+
|
||||
|
||||
|
||||
class FilteredRoles(Roles):
|
||||
@@ -285,6 +287,7 @@ class ManagedRole(Role):
|
||||
self._rdn_attribute = 'cn'
|
||||
self._create_objectclasses = ['nsSimpleRoleDefinition', 'nsManagedRoleDefinition']
|
||||
|
||||
+ self._protected = False
|
||||
|
||||
class ManagedRoles(Roles):
|
||||
"""DSLdapObjects that represents all Managed Roles entries
|
||||
@@ -320,6 +323,7 @@ class NestedRole(Role):
|
||||
self._rdn_attribute = 'cn'
|
||||
self._create_objectclasses = ['nsComplexRoleDefinition', 'nsNestedRoleDefinition']
|
||||
|
||||
+ self._protected = False
|
||||
|
||||
class NestedRoles(Roles):
|
||||
"""DSLdapObjects that represents all NestedRoles entries in suffix.
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,119 @@
|
||||
From dddb14210b402f317e566b6387c76a8e659bf7fa Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Tue, 14 Feb 2023 13:34:10 +0100
|
||||
Subject: [PATCH 1/2] issue 5647 - covscan: memory leak in audit log when
|
||||
adding entries (#5650)
|
||||
|
||||
covscan reported an issue about "vals" variable in auditlog.c:231 and indeed a charray_free is missing.
|
||||
Issue: 5647
|
||||
Reviewed by: @mreynolds389, @droideck
|
||||
---
|
||||
ldap/servers/slapd/auditlog.c | 71 +++++++++++++++++++----------------
|
||||
1 file changed, 38 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c
|
||||
index 68cbc674d..3128e0497 100644
|
||||
--- a/ldap/servers/slapd/auditlog.c
|
||||
+++ b/ldap/servers/slapd/auditlog.c
|
||||
@@ -177,6 +177,40 @@ write_auditfail_log_entry(Slapi_PBlock *pb)
|
||||
slapi_ch_free_string(&audit_config);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Write the attribute values to the audit log as "comments"
|
||||
+ *
|
||||
+ * Slapi_Attr *entry - the attribute begin logged.
|
||||
+ * char *attrname - the attribute name.
|
||||
+ * lenstr *l - the audit log buffer
|
||||
+ *
|
||||
+ * Resulting output in the log:
|
||||
+ *
|
||||
+ * #ATTR: VALUE
|
||||
+ * #ATTR: VALUE
|
||||
+ */
|
||||
+static void
|
||||
+log_entry_attr(Slapi_Attr *entry_attr, char *attrname, lenstr *l)
|
||||
+{
|
||||
+ Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
+ for(size_t i = 0; vals && vals[i]; i++) {
|
||||
+ char log_val[256] = "";
|
||||
+ const struct berval *bv = slapi_value_get_berval(vals[i]);
|
||||
+ if (bv->bv_len >= 256) {
|
||||
+ strncpy(log_val, bv->bv_val, 252);
|
||||
+ strcpy(log_val+252, "...");
|
||||
+ } else {
|
||||
+ strncpy(log_val, bv->bv_val, bv->bv_len);
|
||||
+ log_val[bv->bv_len] = 0;
|
||||
+ }
|
||||
+ addlenstr(l, "#");
|
||||
+ addlenstr(l, attrname);
|
||||
+ addlenstr(l, ": ");
|
||||
+ addlenstr(l, log_val);
|
||||
+ addlenstr(l, "\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Write "requested" attributes from the entry to the audit log as "comments"
|
||||
*
|
||||
@@ -212,21 +246,9 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
for (req_attr = ldap_utf8strtok_r(display_attrs, ", ", &last); req_attr;
|
||||
req_attr = ldap_utf8strtok_r(NULL, ", ", &last))
|
||||
{
|
||||
- char **vals = slapi_entry_attr_get_charray(entry, req_attr);
|
||||
- for(size_t i = 0; vals && vals[i]; i++) {
|
||||
- char log_val[256] = {0};
|
||||
-
|
||||
- if (strlen(vals[i]) > 256) {
|
||||
- strncpy(log_val, vals[i], 252);
|
||||
- strcat(log_val, "...");
|
||||
- } else {
|
||||
- strcpy(log_val, vals[i]);
|
||||
- }
|
||||
- addlenstr(l, "#");
|
||||
- addlenstr(l, req_attr);
|
||||
- addlenstr(l, ": ");
|
||||
- addlenstr(l, log_val);
|
||||
- addlenstr(l, "\n");
|
||||
+ slapi_entry_attr_find(entry, req_attr, &entry_attr);
|
||||
+ if (entry_attr) {
|
||||
+ log_entry_attr(entry_attr, req_attr, l);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -234,7 +256,6 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
for (; entry_attr; entry_attr = entry_attr->a_next) {
|
||||
Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
char *attr = NULL;
|
||||
- const char *val = NULL;
|
||||
|
||||
slapi_attr_get_type(entry_attr, &attr);
|
||||
if (strcmp(attr, PSEUDO_ATTR_UNHASHEDUSERPASSWORD) == 0) {
|
||||
@@ -251,23 +272,7 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
addlenstr(l, ": ****************************\n");
|
||||
continue;
|
||||
}
|
||||
-
|
||||
- for(size_t i = 0; vals && vals[i]; i++) {
|
||||
- char log_val[256] = {0};
|
||||
-
|
||||
- val = slapi_value_get_string(vals[i]);
|
||||
- if (strlen(val) > 256) {
|
||||
- strncpy(log_val, val, 252);
|
||||
- strcat(log_val, "...");
|
||||
- } else {
|
||||
- strcpy(log_val, val);
|
||||
- }
|
||||
- addlenstr(l, "#");
|
||||
- addlenstr(l, attr);
|
||||
- addlenstr(l, ": ");
|
||||
- addlenstr(l, log_val);
|
||||
- addlenstr(l, "\n");
|
||||
- }
|
||||
+ log_entry_attr(entry_attr, attr, l);
|
||||
}
|
||||
}
|
||||
slapi_ch_free_string(&display_attrs);
|
||||
--
|
||||
2.43.0
|
||||
|
@ -1,621 +0,0 @@
|
||||
From 968ad6b5039d839bfbc61da755c252cc7598415b Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 25 Oct 2021 17:09:57 +0200
|
||||
Subject: [PATCH 02/12] Issue 4943 - Fix csn generator to limit time skew drift
|
||||
- PR 4946
|
||||
|
||||
---
|
||||
ldap/servers/slapd/csngen.c | 433 +++++++++++++++++-------------
|
||||
ldap/servers/slapd/slapi-plugin.h | 9 +
|
||||
2 files changed, 255 insertions(+), 187 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/csngen.c b/ldap/servers/slapd/csngen.c
|
||||
index fcd88b4cc..c7c5c2ba8 100644
|
||||
--- a/ldap/servers/slapd/csngen.c
|
||||
+++ b/ldap/servers/slapd/csngen.c
|
||||
@@ -18,8 +18,9 @@
|
||||
#include "prcountr.h"
|
||||
#include "slap.h"
|
||||
|
||||
+
|
||||
#define CSN_MAX_SEQNUM 0xffff /* largest sequence number */
|
||||
-#define CSN_MAX_TIME_ADJUST 24 * 60 * 60 /* maximum allowed time adjustment (in seconds) = 1 day */
|
||||
+#define CSN_MAX_TIME_ADJUST _SEC_PER_DAY /* maximum allowed time adjustment (in seconds) = 1 day */
|
||||
#define ATTR_CSN_GENERATOR_STATE "nsState" /* attribute that stores csn state information */
|
||||
#define STATE_FORMAT "%8x%8x%8x%4hx%4hx"
|
||||
#define STATE_LENGTH 32
|
||||
@@ -27,6 +28,8 @@
|
||||
#define CSN_CALC_TSTAMP(gen) ((gen)->state.sampled_time + \
|
||||
(gen)->state.local_offset + \
|
||||
(gen)->state.remote_offset)
|
||||
+#define TIME_DIFF_WARNING_DELAY (30*_SEC_PER_DAY) /* log an info message when difference
|
||||
+ between clock is greater than this delay */
|
||||
|
||||
/*
|
||||
* **************************************************************************
|
||||
@@ -63,6 +66,7 @@ typedef struct csngen_state
|
||||
struct csngen
|
||||
{
|
||||
csngen_state state; /* persistent state of the generator */
|
||||
+ int32_t (*gettime)(struct timespec *tp); /* Get local time */
|
||||
callback_list callbacks; /* list of callbacks registered with the generator */
|
||||
Slapi_RWLock *lock; /* concurrency control */
|
||||
};
|
||||
@@ -78,7 +82,7 @@ static int _csngen_init_callbacks(CSNGen *gen);
|
||||
static void _csngen_call_callbacks(const CSNGen *gen, const CSN *csn, PRBool abort);
|
||||
static int _csngen_cmp_callbacks(const void *el1, const void *el2);
|
||||
static void _csngen_free_callbacks(CSNGen *gen);
|
||||
-static int _csngen_adjust_local_time(CSNGen *gen, time_t cur_time);
|
||||
+static int _csngen_adjust_local_time(CSNGen *gen);
|
||||
|
||||
/*
|
||||
* **************************************************************************
|
||||
@@ -121,6 +125,7 @@ csngen_new(ReplicaId rid, Slapi_Attr *state)
|
||||
_csngen_init_callbacks(gen);
|
||||
|
||||
gen->state.rid = rid;
|
||||
+ gen->gettime = slapi_clock_utc_gettime;
|
||||
|
||||
if (state) {
|
||||
rc = _csngen_parse_state(gen, state);
|
||||
@@ -164,10 +169,7 @@ csngen_free(CSNGen **gen)
|
||||
int
|
||||
csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify)
|
||||
{
|
||||
- struct timespec now = {0};
|
||||
int rc = CSN_SUCCESS;
|
||||
- time_t cur_time;
|
||||
- int delta;
|
||||
|
||||
if (gen == NULL || csn == NULL) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, "csngen_new_csn", "Invalid argument\n");
|
||||
@@ -180,39 +182,13 @@ csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify)
|
||||
return CSN_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
- if ((rc = slapi_clock_gettime(&now)) != 0) {
|
||||
- /* Failed to get system time, we must abort */
|
||||
- slapi_log_err(SLAPI_LOG_ERR, "csngen_new_csn",
|
||||
- "Failed to get system time (%s)\n",
|
||||
- slapd_system_strerror(rc));
|
||||
- return CSN_TIME_ERROR;
|
||||
- }
|
||||
- cur_time = now.tv_sec;
|
||||
-
|
||||
slapi_rwlock_wrlock(gen->lock);
|
||||
|
||||
- /* check if the time should be adjusted */
|
||||
- delta = cur_time - gen->state.sampled_time;
|
||||
- if (delta > _SEC_PER_DAY || delta < (-1 * _SEC_PER_DAY)) {
|
||||
- /* We had a jump larger than a day */
|
||||
- slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn",
|
||||
- "Detected large jump in CSN time. Delta: %d (current time: %ld vs previous time: %ld)\n",
|
||||
- delta, cur_time, gen->state.sampled_time);
|
||||
- }
|
||||
- if (delta > 0) {
|
||||
- rc = _csngen_adjust_local_time(gen, cur_time);
|
||||
- if (rc != CSN_SUCCESS) {
|
||||
- slapi_rwlock_unlock(gen->lock);
|
||||
- return rc;
|
||||
- }
|
||||
+ rc = _csngen_adjust_local_time(gen);
|
||||
+ if (rc != CSN_SUCCESS) {
|
||||
+ slapi_rwlock_unlock(gen->lock);
|
||||
+ return rc;
|
||||
}
|
||||
- /* if (delta < 0) this means the local system time was set back
|
||||
- * the new csn will be generated based on sampled time, which is
|
||||
- * ahead of system time and previously generated csns.
|
||||
- * the time stamp of the csn will not change until system time
|
||||
- * catches up or is corrected by remote csns.
|
||||
- * But we need to ensure that the seq_num does not overflow.
|
||||
- */
|
||||
|
||||
if (gen->state.seq_num == CSN_MAX_SEQNUM) {
|
||||
slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn", "Sequence rollover; "
|
||||
@@ -261,13 +237,36 @@ csngen_rewrite_rid(CSNGen *gen, ReplicaId rid)
|
||||
}
|
||||
|
||||
/* this function should be called when a remote CSN for the same part of
|
||||
- the dit becomes known to the server (for instance, as part of RUV during
|
||||
- replication session. In response, the generator would adjust its notion
|
||||
- of time so that it does not generate smaller csns */
|
||||
+ * the dit becomes known to the server (for instance, as part of RUV during
|
||||
+ * replication session. In response, the generator would adjust its notion
|
||||
+ * of time so that it does not generate smaller csns
|
||||
+ *
|
||||
+ * The following counters are updated
|
||||
+ * - when a new csn is generated
|
||||
+ * - when csngen is adjusted (beginning of a incoming (extop) or outgoing
|
||||
+ * (inc_protocol) session)
|
||||
+ *
|
||||
+ * sampled_time: It takes the value of current system time.
|
||||
+ *
|
||||
+ * remote offset: it is updated when 'csn' argument is ahead of the next csn
|
||||
+ * that the csn generator will generate. It is the MAX jump ahead, it is not
|
||||
+ * cumulative counter (e.g. if remote_offset=7 and 'csn' is 5sec ahead
|
||||
+ * remote_offset stays the same. The jump ahead (5s) pour into the local offset.
|
||||
+ * It is not clear of the interest of this counter. It gives an indication of
|
||||
+ * the maximum jump ahead but not much.
|
||||
+ *
|
||||
+ * local offset: it is increased if
|
||||
+ * - system time is going backward (compare sampled_time)
|
||||
+ * - if 'csn' argument is ahead of csn that the csn generator would generate
|
||||
+ * AND diff('csn', csngen.new_csn) < remote_offset
|
||||
+ * then the diff "pour" into local_offset
|
||||
+ * It is decreased as the clock is ticking, local offset is "consumed" as
|
||||
+ * sampled_time progresses.
|
||||
+ */
|
||||
int
|
||||
csngen_adjust_time(CSNGen *gen, const CSN *csn)
|
||||
{
|
||||
- time_t remote_time, remote_offset, cur_time;
|
||||
+ time_t remote_time, remote_offset, cur_time, old_time, new_time;
|
||||
PRUint16 remote_seqnum;
|
||||
int rc;
|
||||
extern int config_get_ignore_time_skew(void);
|
||||
@@ -281,6 +280,11 @@ csngen_adjust_time(CSNGen *gen, const CSN *csn)
|
||||
|
||||
slapi_rwlock_wrlock(gen->lock);
|
||||
|
||||
+ /* Get last local csn time */
|
||||
+ old_time = CSN_CALC_TSTAMP(gen);
|
||||
+ /* update local offset and sample_time */
|
||||
+ rc = _csngen_adjust_local_time(gen);
|
||||
+
|
||||
if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
cur_time = CSN_CALC_TSTAMP(gen);
|
||||
slapi_log_err(SLAPI_LOG_REPL, "csngen_adjust_time",
|
||||
@@ -290,79 +294,60 @@ csngen_adjust_time(CSNGen *gen, const CSN *csn)
|
||||
gen->state.local_offset,
|
||||
gen->state.remote_offset);
|
||||
}
|
||||
- /* make sure we have the current time */
|
||||
- cur_time = slapi_current_utc_time();
|
||||
-
|
||||
- /* make sure sampled_time is current */
|
||||
- /* must only call adjust_local_time if the current time is greater than
|
||||
- the generator state time */
|
||||
- if ((cur_time > gen->state.sampled_time) &&
|
||||
- (CSN_SUCCESS != (rc = _csngen_adjust_local_time(gen, cur_time)))) {
|
||||
+ if (rc != CSN_SUCCESS) {
|
||||
/* _csngen_adjust_local_time will log error */
|
||||
slapi_rwlock_unlock(gen->lock);
|
||||
- csngen_dump_state(gen);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_DEBUG);
|
||||
return rc;
|
||||
}
|
||||
|
||||
- cur_time = CSN_CALC_TSTAMP(gen);
|
||||
- if (remote_time >= cur_time) {
|
||||
- time_t new_time = 0;
|
||||
-
|
||||
- if (remote_seqnum > gen->state.seq_num) {
|
||||
- if (remote_seqnum < CSN_MAX_SEQNUM) {
|
||||
- gen->state.seq_num = remote_seqnum + 1;
|
||||
- } else {
|
||||
- remote_time++;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- remote_offset = remote_time - cur_time;
|
||||
- if (remote_offset > gen->state.remote_offset) {
|
||||
- if (ignore_time_skew || (remote_offset <= CSN_MAX_TIME_ADJUST)) {
|
||||
- gen->state.remote_offset = remote_offset;
|
||||
- } else /* remote_offset > CSN_MAX_TIME_ADJUST */
|
||||
- {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, "csngen_adjust_time",
|
||||
- "Adjustment limit exceeded; value - %ld, limit - %ld\n",
|
||||
- remote_offset, (long)CSN_MAX_TIME_ADJUST);
|
||||
- slapi_rwlock_unlock(gen->lock);
|
||||
- csngen_dump_state(gen);
|
||||
- return CSN_LIMIT_EXCEEDED;
|
||||
- }
|
||||
- } else if (remote_offset > 0) { /* still need to account for this */
|
||||
- gen->state.local_offset += remote_offset;
|
||||
+ remote_offset = remote_time - CSN_CALC_TSTAMP(gen);
|
||||
+ if (remote_offset > 0) {
|
||||
+ if (!ignore_time_skew && (gen->state.remote_offset + remote_offset > CSN_MAX_TIME_ADJUST)) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "csngen_adjust_time",
|
||||
+ "Adjustment limit exceeded; value - %ld, limit - %ld\n",
|
||||
+ remote_offset, (long)CSN_MAX_TIME_ADJUST);
|
||||
+ slapi_rwlock_unlock(gen->lock);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_DEBUG);
|
||||
+ return CSN_LIMIT_EXCEEDED;
|
||||
}
|
||||
-
|
||||
- new_time = CSN_CALC_TSTAMP(gen);
|
||||
- /* let's revisit the seq num - if the new time is > the old
|
||||
- tiem, we should reset the seq number to remote + 1 if
|
||||
- this won't cause a wrap around */
|
||||
- if (new_time >= cur_time) {
|
||||
- /* just set seq_num regardless of whether the current one
|
||||
- is < or > than the remote one - the goal of this function
|
||||
- is to make sure we generate CSNs > the remote CSN - if
|
||||
- we have increased the time, we can decrease the seqnum
|
||||
- and still guarantee that any new CSNs generated will be
|
||||
- > any current CSNs we have generated */
|
||||
- if (remote_seqnum < gen->state.seq_num) {
|
||||
- gen->state.seq_num ++;
|
||||
- } else {
|
||||
- gen->state.seq_num = remote_seqnum + 1;
|
||||
- }
|
||||
+ gen->state.remote_offset += remote_offset;
|
||||
+ /* To avoid beat phenomena between suppliers let put 1 second in local_offset
|
||||
+ * it will be eaten at next clock tick rather than increasing remote offset
|
||||
+ * If we do not do that we will have a time skew drift of 1 second per 2 seconds
|
||||
+ * if suppliers are desynchronized by 0.5 second
|
||||
+ */
|
||||
+ if (gen->state.local_offset == 0) {
|
||||
+ gen->state.local_offset++;
|
||||
+ gen->state.remote_offset--;
|
||||
}
|
||||
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
- slapi_log_err(SLAPI_LOG_REPL, "csngen_adjust_time",
|
||||
- "gen state after %08lx%04x:%ld:%ld:%ld\n",
|
||||
- new_time, gen->state.seq_num,
|
||||
- gen->state.sampled_time,
|
||||
- gen->state.local_offset,
|
||||
- gen->state.remote_offset);
|
||||
+ }
|
||||
+ /* Time to compute seqnum so that
|
||||
+ * new csn >= remote csn and new csn >= old local csn
|
||||
+ */
|
||||
+ new_time = CSN_CALC_TSTAMP(gen);
|
||||
+ PR_ASSERT(new_time >= old_time);
|
||||
+ PR_ASSERT(new_time >= remote_time);
|
||||
+ if (new_time > old_time) {
|
||||
+ /* Can reset (local) seqnum */
|
||||
+ gen->state.seq_num = 0;
|
||||
+ }
|
||||
+ if (new_time == remote_time && remote_seqnum >= gen->state.seq_num) {
|
||||
+ if (remote_seqnum >= CSN_MAX_SEQNUM) {
|
||||
+ gen->state.seq_num = 0;
|
||||
+ gen->state.local_offset++;
|
||||
+ } else {
|
||||
+ gen->state.seq_num = remote_seqnum + 1;
|
||||
}
|
||||
- } else if (gen->state.remote_offset > 0) {
|
||||
- /* decrease remote offset? */
|
||||
- /* how to decrease remote offset but ensure that we don't
|
||||
- generate a duplicate CSN, or a CSN smaller than one we've already
|
||||
- generated? */
|
||||
+ }
|
||||
+
|
||||
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
+ slapi_log_err(SLAPI_LOG_REPL, "csngen_adjust_time",
|
||||
+ "gen state after %08lx%04x:%ld:%ld:%ld\n",
|
||||
+ new_time, gen->state.seq_num,
|
||||
+ gen->state.sampled_time,
|
||||
+ gen->state.local_offset,
|
||||
+ gen->state.remote_offset);
|
||||
}
|
||||
|
||||
slapi_rwlock_unlock(gen->lock);
|
||||
@@ -435,16 +420,16 @@ csngen_unregister_callbacks(CSNGen *gen, void *cookie)
|
||||
|
||||
/* debugging function */
|
||||
void
|
||||
-csngen_dump_state(const CSNGen *gen)
|
||||
+csngen_dump_state(const CSNGen *gen, int severity)
|
||||
{
|
||||
if (gen) {
|
||||
slapi_rwlock_rdlock(gen->lock);
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "CSN generator's state:\n");
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "\treplica id: %d\n", gen->state.rid);
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "\tsampled time: %ld\n", gen->state.sampled_time);
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "\tlocal offset: %ld\n", gen->state.local_offset);
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "\tremote offset: %ld\n", gen->state.remote_offset);
|
||||
- slapi_log_err(SLAPI_LOG_DEBUG, "csngen_dump_state", "\tsequence number: %d\n", gen->state.seq_num);
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "CSN generator's state:\n");
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "\treplica id: %d\n", gen->state.rid);
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "\tsampled time: %ld\n", gen->state.sampled_time);
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "\tlocal offset: %ld\n", gen->state.local_offset);
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "\tremote offset: %ld\n", gen->state.remote_offset);
|
||||
+ slapi_log_err(severity, "csngen_dump_state", "\tsequence number: %d\n", gen->state.seq_num);
|
||||
slapi_rwlock_unlock(gen->lock);
|
||||
}
|
||||
}
|
||||
@@ -459,7 +444,7 @@ csngen_test()
|
||||
CSNGen *gen = csngen_new(255, NULL);
|
||||
|
||||
slapi_log_err(SLAPI_LOG_DEBUG, "csngen_test", "staring csn generator test ...");
|
||||
- csngen_dump_state(gen);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_INFO);
|
||||
|
||||
rc = _csngen_start_test_threads(gen);
|
||||
if (rc == 0) {
|
||||
@@ -469,7 +454,7 @@ csngen_test()
|
||||
}
|
||||
|
||||
_csngen_stop_test_threads();
|
||||
- csngen_dump_state(gen);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_INFO);
|
||||
slapi_log_err(SLAPI_LOG_DEBUG, "csngen_test", "csn generator test is complete...");
|
||||
}
|
||||
|
||||
@@ -574,94 +559,93 @@ _csngen_cmp_callbacks(const void *el1, const void *el2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/* Get time and adjust local offset */
|
||||
static int
|
||||
-_csngen_adjust_local_time(CSNGen *gen, time_t cur_time)
|
||||
+_csngen_adjust_local_time(CSNGen *gen)
|
||||
{
|
||||
extern int config_get_ignore_time_skew(void);
|
||||
int ignore_time_skew = config_get_ignore_time_skew();
|
||||
- time_t time_diff = cur_time - gen->state.sampled_time;
|
||||
+ struct timespec now = {0};
|
||||
+ time_t time_diff;
|
||||
+ time_t cur_time;
|
||||
+ int rc;
|
||||
|
||||
+
|
||||
+ if ((rc = gen->gettime(&now)) != 0) {
|
||||
+ /* Failed to get system time, we must abort */
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "csngen_new_csn",
|
||||
+ "Failed to get system time (%s)\n",
|
||||
+ slapd_system_strerror(rc));
|
||||
+ return CSN_TIME_ERROR;
|
||||
+ }
|
||||
+ cur_time = now.tv_sec;
|
||||
+ time_diff = cur_time - gen->state.sampled_time;
|
||||
+
|
||||
+ /* check if the time should be adjusted */
|
||||
if (time_diff == 0) {
|
||||
/* This is a no op - _csngen_adjust_local_time should never be called
|
||||
in this case, because there is nothing to adjust - but just return
|
||||
here to protect ourselves
|
||||
*/
|
||||
return CSN_SUCCESS;
|
||||
- } else if (time_diff > 0) {
|
||||
- time_t ts_before = CSN_CALC_TSTAMP(gen);
|
||||
- time_t ts_after = 0;
|
||||
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
- time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
- slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
- "gen state before %08lx%04x:%ld:%ld:%ld\n",
|
||||
- new_time, gen->state.seq_num,
|
||||
- gen->state.sampled_time,
|
||||
- gen->state.local_offset,
|
||||
- gen->state.remote_offset);
|
||||
- }
|
||||
-
|
||||
- gen->state.sampled_time = cur_time;
|
||||
- if (time_diff > gen->state.local_offset)
|
||||
- gen->state.local_offset = 0;
|
||||
- else
|
||||
- gen->state.local_offset = gen->state.local_offset - time_diff;
|
||||
-
|
||||
- /* only reset the seq_num if the new timestamp part of the CSN
|
||||
- is going to be greater than the old one - if they are the
|
||||
- same after the above adjustment (which can happen if
|
||||
- csngen_adjust_time has to store the offset in the
|
||||
- local_offset field) we must not allow the CSN to regress or
|
||||
- generate duplicate numbers */
|
||||
- ts_after = CSN_CALC_TSTAMP(gen);
|
||||
- if (ts_after > ts_before) {
|
||||
- gen->state.seq_num = 0; /* only reset if new time > old time */
|
||||
- }
|
||||
-
|
||||
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
- time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
- slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
- "gen state after %08lx%04x:%ld:%ld:%ld\n",
|
||||
- new_time, gen->state.seq_num,
|
||||
- gen->state.sampled_time,
|
||||
- gen->state.local_offset,
|
||||
- gen->state.remote_offset);
|
||||
- }
|
||||
- return CSN_SUCCESS;
|
||||
- } else /* time was turned back */
|
||||
- {
|
||||
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
- time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
- slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
- "gen state back before %08lx%04x:%ld:%ld:%ld\n",
|
||||
- new_time, gen->state.seq_num,
|
||||
- gen->state.sampled_time,
|
||||
- gen->state.local_offset,
|
||||
- gen->state.remote_offset);
|
||||
- }
|
||||
+ }
|
||||
+ if (labs(time_diff) > TIME_DIFF_WARNING_DELAY) {
|
||||
+ /* We had a jump larger than a day */
|
||||
+ slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn",
|
||||
+ "Detected large jump in CSN time. Delta: %ld (current time: %ld vs previous time: %ld)\n",
|
||||
+ time_diff, cur_time, gen->state.sampled_time);
|
||||
+ }
|
||||
+ if (!ignore_time_skew && (gen->state.local_offset - time_diff > CSN_MAX_TIME_ADJUST)) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "_csngen_adjust_local_time",
|
||||
+ "Adjustment limit exceeded; value - %ld, limit - %d\n",
|
||||
+ gen->state.local_offset - time_diff, CSN_MAX_TIME_ADJUST);
|
||||
+ return CSN_LIMIT_EXCEEDED;
|
||||
+ }
|
||||
|
||||
- if (!ignore_time_skew && (labs(time_diff) > CSN_MAX_TIME_ADJUST)) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, "_csngen_adjust_local_time",
|
||||
- "Adjustment limit exceeded; value - %ld, limit - %d\n",
|
||||
- labs(time_diff), CSN_MAX_TIME_ADJUST);
|
||||
- return CSN_LIMIT_EXCEEDED;
|
||||
- }
|
||||
+ time_t ts_before = CSN_CALC_TSTAMP(gen);
|
||||
+ time_t ts_after = 0;
|
||||
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
+ time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
+ slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
+ "gen state before %08lx%04x:%ld:%ld:%ld\n",
|
||||
+ new_time, gen->state.seq_num,
|
||||
+ gen->state.sampled_time,
|
||||
+ gen->state.local_offset,
|
||||
+ gen->state.remote_offset);
|
||||
+ }
|
||||
|
||||
- gen->state.sampled_time = cur_time;
|
||||
- gen->state.local_offset = MAX_VAL(gen->state.local_offset, labs(time_diff));
|
||||
- gen->state.seq_num = 0;
|
||||
+ gen->state.sampled_time = cur_time;
|
||||
+ gen->state.local_offset = MAX_VAL(0, gen->state.local_offset - time_diff);
|
||||
+ /* new local_offset = MAX_VAL(0, old sample_time + old local_offset - cur_time)
|
||||
+ * ==> new local_offset >= 0 and
|
||||
+ * new local_offset + cur_time >= old sample_time + old local_offset
|
||||
+ * ==> new local_offset + cur_time + remote_offset >=
|
||||
+ * sample_time + old local_offset + remote_offset
|
||||
+ * ==> CSN_CALC_TSTAMP(new gen) >= CSN_CALC_TSTAMP(old gen)
|
||||
+ */
|
||||
|
||||
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
- time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
- slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
- "gen state back after %08lx%04x:%ld:%ld:%ld\n",
|
||||
- new_time, gen->state.seq_num,
|
||||
- gen->state.sampled_time,
|
||||
- gen->state.local_offset,
|
||||
- gen->state.remote_offset);
|
||||
- }
|
||||
+ /* only reset the seq_num if the new timestamp part of the CSN
|
||||
+ is going to be greater than the old one - if they are the
|
||||
+ same after the above adjustment (which can happen if
|
||||
+ csngen_adjust_time has to store the offset in the
|
||||
+ local_offset field) we must not allow the CSN to regress or
|
||||
+ generate duplicate numbers */
|
||||
+ ts_after = CSN_CALC_TSTAMP(gen);
|
||||
+ PR_ASSERT(ts_after >= ts_before);
|
||||
+ if (ts_after > ts_before) {
|
||||
+ gen->state.seq_num = 0; /* only reset if new time > old time */
|
||||
+ }
|
||||
|
||||
- return CSN_SUCCESS;
|
||||
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
|
||||
+ time_t new_time = CSN_CALC_TSTAMP(gen);
|
||||
+ slapi_log_err(SLAPI_LOG_REPL, "_csngen_adjust_local_time",
|
||||
+ "gen state after %08lx%04x:%ld:%ld:%ld\n",
|
||||
+ new_time, gen->state.seq_num,
|
||||
+ gen->state.sampled_time,
|
||||
+ gen->state.local_offset,
|
||||
+ gen->state.remote_offset);
|
||||
}
|
||||
+ return CSN_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -799,7 +783,7 @@ _csngen_remote_tester_main(void *data)
|
||||
"Failed to adjust generator's time; csn error - %d\n", rc);
|
||||
}
|
||||
|
||||
- csngen_dump_state(gen);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_INFO);
|
||||
}
|
||||
csn_free(&csn);
|
||||
|
||||
@@ -825,8 +809,83 @@ _csngen_local_tester_main(void *data)
|
||||
/*
|
||||
* g_sampled_time -= slapi_rand () % 100;
|
||||
*/
|
||||
- csngen_dump_state(gen);
|
||||
+ csngen_dump_state(gen, SLAPI_LOG_INFO);
|
||||
}
|
||||
|
||||
PR_AtomicDecrement(&s_thread_count);
|
||||
}
|
||||
+
|
||||
+int _csngen_tester_state;
|
||||
+int _csngen_tester_state_rid;
|
||||
+
|
||||
+static int
|
||||
+_mynoise(int time, int len, double height)
|
||||
+{
|
||||
+ if (((time/len) % 2) == 0) {
|
||||
+ return -height + 2 * height * ( time % len ) / (len-1);
|
||||
+ } else {
|
||||
+ return height - 2 * height * ( time % len ) / (len-1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int32_t _csngen_tester_gettime(struct timespec *tp)
|
||||
+{
|
||||
+ int vtime = _csngen_tester_state ;
|
||||
+ tp->tv_sec = 0x1000000 + vtime + 2 * _csngen_tester_state_rid;
|
||||
+ if (_csngen_tester_state_rid == 3) {
|
||||
+ /* tp->tv_sec += _mynoise(vtime, 10, 1.5); */
|
||||
+ tp->tv_sec += _mynoise(vtime, 30, 15);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Mimic a fully meshed multi suplier topology */
|
||||
+void csngen_multi_suppliers_test(void)
|
||||
+{
|
||||
+#define NB_TEST_MASTERS 6
|
||||
+#define NB_TEST_STATES 500
|
||||
+ CSNGen *gen[NB_TEST_MASTERS];
|
||||
+ struct timespec now = {0};
|
||||
+ CSN *last_csn = NULL;
|
||||
+ CSN *csn = NULL;
|
||||
+ int i,j,rc;
|
||||
+
|
||||
+ _csngen_tester_gettime(&now);
|
||||
+
|
||||
+ for (i=0; i< NB_TEST_MASTERS; i++) {
|
||||
+ gen[i] = csngen_new(i+1, NULL);
|
||||
+ gen[i]->gettime = _csngen_tester_gettime;
|
||||
+ gen[i]->state.sampled_time = now.tv_sec;
|
||||
+ }
|
||||
+
|
||||
+ for (_csngen_tester_state=0; _csngen_tester_state < NB_TEST_STATES; _csngen_tester_state++) {
|
||||
+ for (i=0; i< NB_TEST_MASTERS; i++) {
|
||||
+ _csngen_tester_state_rid = i+1;
|
||||
+ rc = csngen_new_csn(gen[i], &csn, PR_FALSE);
|
||||
+ if (rc) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ csngen_dump_state(gen[i], SLAPI_LOG_INFO);
|
||||
+
|
||||
+ if (csn_compare(csn, last_csn) <= 0) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "csngen_multi_suppliers_test",
|
||||
+ "CSN generated in disorder state=%d rid=%d\n", _csngen_tester_state, _csngen_tester_state_rid);
|
||||
+ _csngen_tester_state = NB_TEST_STATES;
|
||||
+ break;
|
||||
+ }
|
||||
+ last_csn = csn;
|
||||
+
|
||||
+ for (j=0; j< NB_TEST_MASTERS; j++) {
|
||||
+ if (i==j) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ _csngen_tester_state_rid = j+1;
|
||||
+ rc = csngen_adjust_time(gen[j], csn);
|
||||
+ if (rc) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
|
||||
index 56765fdfb..59c5ec9ab 100644
|
||||
--- a/ldap/servers/slapd/slapi-plugin.h
|
||||
+++ b/ldap/servers/slapd/slapi-plugin.h
|
||||
@@ -6762,8 +6762,17 @@ time_t slapi_current_time(void) __attribute__((deprecated));
|
||||
*
|
||||
* \param tp - a timespec struct where the system time is set
|
||||
* \return result code, upon success tp is set to the system time
|
||||
+ * as a clock in UTC timezone. This clock adjusts with ntp steps,
|
||||
+ * and should NOT be used for timer information.
|
||||
*/
|
||||
int32_t slapi_clock_gettime(struct timespec *tp);
|
||||
+/*
|
||||
+ * slapi_clock_gettime should have better been called
|
||||
+ * slapi_clock_utc_gettime but sice the function pre-existed
|
||||
+ * we are just adding an alias (to avoid risking to break
|
||||
+ * some custom plugins)
|
||||
+ */
|
||||
+#define slapi_clock_utc_gettime slapi_clock_gettime
|
||||
|
||||
/**
|
||||
* Returns the current system time as a hr clock relative to uptime
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,27 @@
|
||||
From be7c2b82958e91ce08775bf6b5da3c311d3b00e5 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 20 Feb 2023 16:14:05 +0100
|
||||
Subject: [PATCH 2/2] Issue 5647 - Fix unused variable warning from previous
|
||||
commit (#5670)
|
||||
|
||||
* issue 5647 - memory leak in audit log when adding entries
|
||||
* Issue 5647 - Fix unused variable warning from previous commit
|
||||
---
|
||||
ldap/servers/slapd/auditlog.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c
|
||||
index 3128e0497..0597ecc6f 100644
|
||||
--- a/ldap/servers/slapd/auditlog.c
|
||||
+++ b/ldap/servers/slapd/auditlog.c
|
||||
@@ -254,7 +254,6 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
} else {
|
||||
/* Return all attributes */
|
||||
for (; entry_attr; entry_attr = entry_attr->a_next) {
|
||||
- Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
char *attr = NULL;
|
||||
|
||||
slapi_attr_get_type(entry_attr, &attr);
|
||||
--
|
||||
2.43.0
|
||||
|
@ -1,240 +0,0 @@
|
||||
From 957ffd53b041c19d27753a028e6f514dcc75dfbd Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 26 Oct 2021 15:51:24 -0700
|
||||
Subject: [PATCH 03/12] Issue 3584 - Fix PBKDF2_SHA256 hashing in FIPS mode
|
||||
(#4949)
|
||||
|
||||
Issue Description: Use PK11_Decrypt function to get hash data
|
||||
because PK11_ExtractKeyValue function is forbidden in FIPS mode.
|
||||
We can't extract keys while in FIPS mode. But we use PK11_ExtractKeyValue
|
||||
for hashes, and it's not forbidden.
|
||||
|
||||
We can't use OpenSSL's PBKDF2-SHA256 implementation right now because
|
||||
we need to support an upgrade procedure while in FIPS mode (update
|
||||
hash on bind). For that, we should fix existing PBKDF2 usage, and we can
|
||||
switch to OpenSSL's PBKDF2-SHA256 in the following versions.
|
||||
|
||||
Fix Description: Use PK11_Decrypt function to get the data.
|
||||
|
||||
Enable TLS on all CI test topologies while in FIPS because without
|
||||
that we don't set up the NSS database correctly.
|
||||
|
||||
Add PBKDF2-SHA256 (OpenSSL) to ldif templates, so the password scheme is
|
||||
discoverable by internal functions.
|
||||
|
||||
https://github.com/389ds/389-ds-base/issues/3584
|
||||
|
||||
Reviewed by: @progier389, @mreynolds389, @Firstyear, @tbordaz (Thanks!!)
|
||||
---
|
||||
.../healthcheck/health_security_test.py | 10 ---
|
||||
ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c | 62 ++++++++++++++++---
|
||||
ldap/servers/slapd/main.c | 12 ++++
|
||||
src/lib389/lib389/__init__.py | 4 ++
|
||||
src/lib389/lib389/topologies.py | 6 +-
|
||||
src/lib389/lib389/utils.py | 13 ++++
|
||||
6 files changed, 86 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_security_test.py b/dirsrvtests/tests/suites/healthcheck/health_security_test.py
|
||||
index 6c0d27aaa..c1dc7938c 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_security_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_security_test.py
|
||||
@@ -40,16 +40,6 @@ else:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
-def is_fips():
|
||||
- if os.path.exists('/proc/sys/crypto/fips_enabled'):
|
||||
- with open('/proc/sys/crypto/fips_enabled', 'r') as f:
|
||||
- state = f.readline().strip()
|
||||
- if state == '1':
|
||||
- return True
|
||||
- else:
|
||||
- return False
|
||||
-
|
||||
-
|
||||
def run_healthcheck_and_flush_log(topology, instance, searched_code, json, searched_code2=None):
|
||||
args = FakeArgs()
|
||||
args.instance = instance.serverid
|
||||
diff --git a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
index d310dc792..dcac4fcdd 100644
|
||||
--- a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
+++ b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
@@ -91,10 +91,11 @@ pbkdf2_sha256_extract(char *hash_in, SECItem *salt, uint32_t *iterations)
|
||||
SECStatus
|
||||
pbkdf2_sha256_hash(char *hash_out, size_t hash_out_len, SECItem *pwd, SECItem *salt, uint32_t iterations)
|
||||
{
|
||||
- SECItem *result = NULL;
|
||||
SECAlgorithmID *algid = NULL;
|
||||
PK11SlotInfo *slot = NULL;
|
||||
PK11SymKey *symkey = NULL;
|
||||
+ SECItem *wrapKeyData = NULL;
|
||||
+ SECStatus rv = SECFailure;
|
||||
|
||||
/* We assume that NSS is already started. */
|
||||
algid = PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA256, SEC_OID_HMAC_SHA256, hash_out_len, iterations, salt);
|
||||
@@ -104,7 +105,6 @@ pbkdf2_sha256_hash(char *hash_out, size_t hash_out_len, SECItem *pwd, SECItem *s
|
||||
slot = PK11_GetBestSlotMultiple(mechanism_array, 2, NULL);
|
||||
if (slot != NULL) {
|
||||
symkey = PK11_PBEKeyGen(slot, algid, pwd, PR_FALSE, NULL);
|
||||
- PK11_FreeSlot(slot);
|
||||
if (symkey == NULL) {
|
||||
/* We try to get the Error here but NSS has two or more error interfaces, and sometimes it uses none of them. */
|
||||
int32_t status = PORT_GetError();
|
||||
@@ -123,18 +123,60 @@ pbkdf2_sha256_hash(char *hash_out, size_t hash_out_len, SECItem *pwd, SECItem *s
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
- if (PK11_ExtractKeyValue(symkey) == SECSuccess) {
|
||||
- result = PK11_GetKeyData(symkey);
|
||||
- if (result != NULL && result->len <= hash_out_len) {
|
||||
- memcpy(hash_out, result->data, result->len);
|
||||
- PK11_FreeSymKey(symkey);
|
||||
+ /*
|
||||
+ * First, we need to generate a wrapped key for PK11_Decrypt call:
|
||||
+ * slot is the same slot we used in PK11_PBEKeyGen()
|
||||
+ * 256 bits / 8 bit per byte
|
||||
+ */
|
||||
+ PK11SymKey *wrapKey = PK11_KeyGen(slot, CKM_AES_ECB, NULL, 256/8, NULL);
|
||||
+ PK11_FreeSlot(slot);
|
||||
+ if (wrapKey == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "pbkdf2_sha256_hash", "Unable to generate a wrapped key.\n");
|
||||
+ return SECFailure;
|
||||
+ }
|
||||
+
|
||||
+ wrapKeyData = (SECItem *)PORT_Alloc(sizeof(SECItem));
|
||||
+ /* Align the wrapped key with 32 bytes. */
|
||||
+ wrapKeyData->len = (PK11_GetKeyLength(symkey) + 31) & ~31;
|
||||
+ /* Allocate the aligned space for pkc5PBE key plus AESKey block */
|
||||
+ wrapKeyData->data = (unsigned char *)slapi_ch_calloc(wrapKeyData->len, sizeof(unsigned char));
|
||||
+
|
||||
+ /* Get symkey wrapped with wrapKey - required for PK11_Decrypt call */
|
||||
+ rv = PK11_WrapSymKey(CKM_AES_ECB, NULL, wrapKey, symkey, wrapKeyData);
|
||||
+ if (rv != SECSuccess) {
|
||||
+ PK11_FreeSymKey(symkey);
|
||||
+ PK11_FreeSymKey(wrapKey);
|
||||
+ SECITEM_FreeItem(wrapKeyData, PR_TRUE);
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "pbkdf2_sha256_hash", "Unable to wrap the symkey. (%d)\n", rv);
|
||||
+ return SECFailure;
|
||||
+ }
|
||||
+
|
||||
+ /* Allocate the space for our result */
|
||||
+ void *result = (char *)slapi_ch_calloc(wrapKeyData->len, sizeof(char));
|
||||
+ unsigned int result_len = 0;
|
||||
+
|
||||
+ /* User wrapKey to decrypt the wrapped contents.
|
||||
+ * result is the hash that we need;
|
||||
+ * result_len is the actual lengh of the data;
|
||||
+ * has_out_len is the maximum (the space we allocted for hash_out)
|
||||
+ */
|
||||
+ rv = PK11_Decrypt(wrapKey, CKM_AES_ECB, NULL, result, &result_len, hash_out_len, wrapKeyData->data, wrapKeyData->len);
|
||||
+ PK11_FreeSymKey(symkey);
|
||||
+ PK11_FreeSymKey(wrapKey);
|
||||
+ SECITEM_FreeItem(wrapKeyData, PR_TRUE);
|
||||
+
|
||||
+ if (rv == SECSuccess) {
|
||||
+ if (result != NULL && result_len <= hash_out_len) {
|
||||
+ memcpy(hash_out, result, result_len);
|
||||
+ slapi_ch_free((void **)&result);
|
||||
} else {
|
||||
- PK11_FreeSymKey(symkey);
|
||||
- slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to retrieve (get) hash output.\n");
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "pbkdf2_sha256_hash", "Unable to retrieve (get) hash output.\n");
|
||||
+ slapi_ch_free((void **)&result);
|
||||
return SECFailure;
|
||||
}
|
||||
} else {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to extract hash output.\n");
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "pbkdf2_sha256_hash", "Unable to extract hash output. (%d)\n", rv);
|
||||
+ slapi_ch_free((void **)&result);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
|
||||
index 61ed40b7d..04d0494f8 100644
|
||||
--- a/ldap/servers/slapd/main.c
|
||||
+++ b/ldap/servers/slapd/main.c
|
||||
@@ -2895,9 +2895,21 @@ slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_por
|
||||
* is enabled or not. We use NSS for random number generation and
|
||||
* other things even if we are not going to accept SSL connections.
|
||||
* We also need NSS for attribute encryption/decryption on import and export.
|
||||
+ *
|
||||
+ * It's important to remember that while in FIPS mode the administrator should always enable
|
||||
+ * the security, otherwise we don't call slapd_pk11_authenticate which is a requirement for FIPS mode
|
||||
*/
|
||||
+ PRBool isFIPS = slapd_pk11_isFIPS();
|
||||
int init_ssl = config_get_security();
|
||||
|
||||
+ if (isFIPS && !init_ssl) {
|
||||
+ slapi_log_err(SLAPI_LOG_WARNING, "slapd_do_all_nss_ssl_init",
|
||||
+ "ERROR: TLS is not enabled, and the machine is in FIPS mode. "
|
||||
+ "Some functionality won't work correctly (for example, "
|
||||
+ "users with PBKDF2_SHA256 password scheme won't be able to log in). "
|
||||
+ "It's highly advisable to enable TLS on this instance.\n");
|
||||
+ }
|
||||
+
|
||||
if (slapd_exemode == SLAPD_EXEMODE_SLAPD) {
|
||||
init_ssl = init_ssl && (0 != s_port) && (s_port <= LDAP_PORT_MAX);
|
||||
} else {
|
||||
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
|
||||
index 29ee5245a..e0299c5b4 100644
|
||||
--- a/src/lib389/lib389/__init__.py
|
||||
+++ b/src/lib389/lib389/__init__.py
|
||||
@@ -1588,6 +1588,10 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
:param post_open: Open the server connection after restart.
|
||||
:type post_open: bool
|
||||
"""
|
||||
+ if self.config.get_attr_val_utf8_l("nsslapd-security") == 'on':
|
||||
+ self.restart(post_open=post_open)
|
||||
+ return
|
||||
+
|
||||
# If it doesn't exist, create a cadb.
|
||||
ssca = NssSsl(dbpath=self.get_ssca_dir())
|
||||
if not ssca._db_exists():
|
||||
diff --git a/src/lib389/lib389/topologies.py b/src/lib389/lib389/topologies.py
|
||||
index e9969f524..e7d56582d 100644
|
||||
--- a/src/lib389/lib389/topologies.py
|
||||
+++ b/src/lib389/lib389/topologies.py
|
||||
@@ -15,7 +15,7 @@ import socket
|
||||
import pytest
|
||||
|
||||
from lib389 import DirSrv
|
||||
-from lib389.utils import generate_ds_params
|
||||
+from lib389.utils import generate_ds_params, is_fips
|
||||
from lib389.mit_krb5 import MitKrb5
|
||||
from lib389.saslmap import SaslMappings
|
||||
from lib389.replica import ReplicationManager, Replicas
|
||||
@@ -108,6 +108,10 @@ def _create_instances(topo_dict, suffix):
|
||||
if role == ReplicaRole.HUB:
|
||||
hs[instance.serverid] = instance
|
||||
instances.update(hs)
|
||||
+ # We should always enable TLS while in FIPS mode because otherwise NSS database won't be
|
||||
+ # configured in a FIPS compliant way
|
||||
+ if is_fips():
|
||||
+ instance.enable_tls()
|
||||
log.info("Instance with parameters {} was created.".format(args_instance))
|
||||
|
||||
if "standalone1" in instances and len(instances) == 1:
|
||||
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
|
||||
index b270784ce..5ba0c6676 100644
|
||||
--- a/src/lib389/lib389/utils.py
|
||||
+++ b/src/lib389/lib389/utils.py
|
||||
@@ -1430,3 +1430,16 @@ def is_valid_hostname(hostname):
|
||||
hostname = hostname[:-1] # strip exactly one dot from the right, if present
|
||||
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
||||
return all(allowed.match(x) for x in hostname.split("."))
|
||||
+
|
||||
+
|
||||
+def is_fips():
|
||||
+ if os.path.exists('/proc/sys/crypto/fips_enabled'):
|
||||
+ with open('/proc/sys/crypto/fips_enabled', 'r') as f:
|
||||
+ state = f.readline().strip()
|
||||
+ if state == '1':
|
||||
+ return True
|
||||
+ else:
|
||||
+ return False
|
||||
+ else:
|
||||
+ return False
|
||||
+
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,147 @@
|
||||
From 692c4cec6cc5c0086cf58f83bcfa690c766c9887 Mon Sep 17 00:00:00 2001
|
||||
From: Thierry Bordaz <tbordaz@redhat.com>
|
||||
Date: Fri, 2 Feb 2024 14:14:28 +0100
|
||||
Subject: [PATCH] Issue 5407 - sync_repl crashes if enabled while dynamic
|
||||
plugin is enabled (#5411)
|
||||
|
||||
Bug description:
|
||||
When dynamic plugin is enabled, if a MOD enables sync_repl plugin
|
||||
then sync_repl init function registers the postop callback
|
||||
that will be called for the MOD itself while the preop
|
||||
has not been called.
|
||||
postop expects preop to be called and so primary operation
|
||||
to be set. When it is not set it crashes
|
||||
|
||||
Fix description:
|
||||
If the primary operation is not set, just return
|
||||
|
||||
relates: #5407
|
||||
---
|
||||
.../suites/syncrepl_plugin/basic_test.py | 68 +++++++++++++++++++
|
||||
ldap/servers/plugins/sync/sync_persist.c | 23 ++++++-
|
||||
2 files changed, 90 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
index eb3770b78..cdf35eeaa 100644
|
||||
--- a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
@@ -592,6 +592,74 @@ def test_sync_repl_cenotaph(topo_m2, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
+def test_sync_repl_dynamic_plugin(topology, request):
|
||||
+ """Test sync_repl with dynamic plugin
|
||||
+
|
||||
+ :id: d4f84913-c18a-459f-8525-110f610ca9e6
|
||||
+ :setup: install a standalone instance
|
||||
+ :steps:
|
||||
+ 1. reset instance to standard (no retroCL, no sync_repl, no dynamic plugin)
|
||||
+ 2. Enable dynamic plugin
|
||||
+ 3. Enable retroCL/content_sync
|
||||
+ 4. Establish a sync_repl req
|
||||
+ :expectedresults:
|
||||
+ 1. Should succeeds
|
||||
+ 2. Should succeeds
|
||||
+ 3. Should succeeds
|
||||
+ 4. Should succeeds
|
||||
+ """
|
||||
+
|
||||
+ # Reset the instance in a default config
|
||||
+ # Disable content sync plugin
|
||||
+ topology.standalone.plugins.disable(name=PLUGIN_REPL_SYNC)
|
||||
+
|
||||
+ # Disable retro changelog
|
||||
+ topology.standalone.plugins.disable(name=PLUGIN_RETRO_CHANGELOG)
|
||||
+
|
||||
+ # Disable dynamic plugins
|
||||
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', b'off')])
|
||||
+ topology.standalone.restart()
|
||||
+
|
||||
+ # Now start the test
|
||||
+ # Enable dynamic plugins
|
||||
+ try:
|
||||
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', b'on')])
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.error('Failed to enable dynamic plugin! {}'.format(e.args[0]['desc']))
|
||||
+ assert False
|
||||
+
|
||||
+ # Enable retro changelog
|
||||
+ topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG)
|
||||
+
|
||||
+ # Enbale content sync plugin
|
||||
+ topology.standalone.plugins.enable(name=PLUGIN_REPL_SYNC)
|
||||
+
|
||||
+ # create a sync repl client and wait 5 seconds to be sure it is running
|
||||
+ sync_repl = Sync_persist(topology.standalone)
|
||||
+ sync_repl.start()
|
||||
+ time.sleep(5)
|
||||
+
|
||||
+ # create users
|
||||
+ users = UserAccounts(topology.standalone, DEFAULT_SUFFIX)
|
||||
+ users_set = []
|
||||
+ for i in range(10001, 10004):
|
||||
+ users_set.append(users.create_test_user(uid=i))
|
||||
+
|
||||
+ time.sleep(10)
|
||||
+ # delete users, that automember/memberof will generate nested updates
|
||||
+ for user in users_set:
|
||||
+ user.delete()
|
||||
+ # stop the server to get the sync_repl result set (exit from while loop).
|
||||
+ # Only way I found to acheive that.
|
||||
+ # and wait a bit to let sync_repl thread time to set its result before fetching it.
|
||||
+ topology.standalone.stop()
|
||||
+ sync_repl.get_result()
|
||||
+ sync_repl.join()
|
||||
+ log.info('test_sync_repl_dynamic_plugin: PASS\n')
|
||||
+
|
||||
+ # Success
|
||||
+ log.info('Test complete')
|
||||
+
|
||||
def test_sync_repl_invalid_cookie(topology, request):
|
||||
"""Test sync_repl with invalid cookie
|
||||
|
||||
diff --git a/ldap/servers/plugins/sync/sync_persist.c b/ldap/servers/plugins/sync/sync_persist.c
|
||||
index d2210b64c..283607361 100644
|
||||
--- a/ldap/servers/plugins/sync/sync_persist.c
|
||||
+++ b/ldap/servers/plugins/sync/sync_persist.c
|
||||
@@ -156,6 +156,17 @@ ignore_op_pl(Slapi_PBlock *pb)
|
||||
* This is the same for ident
|
||||
*/
|
||||
prim_op = get_thread_primary_op();
|
||||
+ if (prim_op == NULL) {
|
||||
+ /* This can happen if the PRE_OP (sync_update_persist_betxn_pre_op) was not called.
|
||||
+ * The only known case it happens is with dynamic plugin enabled and an
|
||||
+ * update that enable the sync_repl plugin. In such case sync_repl registers
|
||||
+ * the postop (sync_update_persist_op) that is called while the preop was not called
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM,
|
||||
+ "ignore_op_pl - Operation without primary op set (0x%lx)\n",
|
||||
+ (ulong) op);
|
||||
+ return;
|
||||
+ }
|
||||
ident = sync_persist_get_operation_extension(pb);
|
||||
|
||||
if (ident) {
|
||||
@@ -232,8 +243,18 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
|
||||
|
||||
|
||||
prim_op = get_thread_primary_op();
|
||||
+ if (prim_op == NULL) {
|
||||
+ /* This can happen if the PRE_OP (sync_update_persist_betxn_pre_op) was not called.
|
||||
+ * The only known case it happens is with dynamic plugin enabled and an
|
||||
+ * update that enable the sync_repl plugin. In such case sync_repl registers
|
||||
+ * the postop (sync_update_persist_op) that is called while the preop was not called
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM,
|
||||
+ "sync_update_persist_op - Operation without primary op set (0x%lx)\n",
|
||||
+ (ulong) pb_op);
|
||||
+ return;
|
||||
+ }
|
||||
ident = sync_persist_get_operation_extension(pb);
|
||||
- PR_ASSERT(prim_op);
|
||||
|
||||
if ((ident == NULL) && operation_is_flag_set(pb_op, OP_FLAG_NOOP)) {
|
||||
/* This happens for URP (add cenotaph, fixup rename, tombstone resurrect)
|
||||
--
|
||||
2.43.0
|
||||
|
@ -1,114 +0,0 @@
|
||||
From d037688c072c4cb84fbf9b2a6cb24927f7950605 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 20 Oct 2021 10:04:06 -0400
|
||||
Subject: [PATCH 04/12] Issue 4956 - Automember allows invalid regex, and does
|
||||
not log proper error
|
||||
|
||||
Bug Description: The server was detecting an invalid automember
|
||||
regex, but it did not reject it, and it did not
|
||||
log which regex rule was invalid.
|
||||
|
||||
Fix Description: By properly rejecting the invalid regex will also
|
||||
trigger the proper error logging to occur.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4956
|
||||
|
||||
Reviewed by: tbordaz & spichugi(Thanks!!)
|
||||
---
|
||||
.../automember_plugin/configuration_test.py | 49 +++++++++++++++++--
|
||||
ldap/servers/plugins/automember/automember.c | 1 +
|
||||
2 files changed, 46 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/automember_plugin/configuration_test.py b/dirsrvtests/tests/suites/automember_plugin/configuration_test.py
|
||||
index 0f9cc49dc..4a6b596db 100644
|
||||
--- a/dirsrvtests/tests/suites/automember_plugin/configuration_test.py
|
||||
+++ b/dirsrvtests/tests/suites/automember_plugin/configuration_test.py
|
||||
@@ -1,21 +1,20 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2019 Red Hat, Inc.
|
||||
+# Copyright (C) 2021 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# License: GPL (version 3 or any later version).
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
|
||||
+import ldap
|
||||
import os
|
||||
import pytest
|
||||
-
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinitions, MemberOfPlugin
|
||||
-import ldap
|
||||
+from lib389._constants import DEFAULT_SUFFIX
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
-
|
||||
@pytest.mark.bz834056
|
||||
def test_configuration(topo):
|
||||
"""
|
||||
@@ -52,6 +51,48 @@ def test_configuration(topo):
|
||||
'"cn=SuffDef1,ou=autouserGroups,cn=config" '
|
||||
'can not be a child of the plugin config area "cn=config"')
|
||||
|
||||
+def test_invalid_regex(topo):
|
||||
+ """Test invalid regex is properly reportedin the error log
|
||||
+
|
||||
+ :id: a6d89f84-ec76-4871-be96-411d051800b1
|
||||
+ :setup: Standalone Instance
|
||||
+ :steps:
|
||||
+ 1. Setup automember
|
||||
+ 2. Add invalid regex
|
||||
+ 3. Error log reports useful message
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ """
|
||||
+ REGEX_DN = "cn=regex1,cn=testregex,cn=auto membership plugin,cn=plugins,cn=config"
|
||||
+ REGEX_VALUE = "cn=*invalid*"
|
||||
+ REGEX_ESC_VALUE = "cn=\\*invalid\\*"
|
||||
+ GROUP_DN = "cn=demo_group,ou=groups," + DEFAULT_SUFFIX
|
||||
+
|
||||
+ AutoMembershipPlugin(topo.standalone).remove_all("nsslapd-pluginConfigArea")
|
||||
+ automemberplugin = AutoMembershipPlugin(topo.standalone)
|
||||
+
|
||||
+ automember_prop = {
|
||||
+ 'cn': 'testRegex',
|
||||
+ 'autoMemberScope': 'ou=People,' + DEFAULT_SUFFIX,
|
||||
+ 'autoMemberFilter': 'objectclass=*',
|
||||
+ 'autoMemberDefaultGroup': GROUP_DN,
|
||||
+ 'autoMemberGroupingAttr': 'member:dn',
|
||||
+ }
|
||||
+ automember_defs = AutoMembershipDefinitions(topo.standalone, "cn=Auto Membership Plugin,cn=plugins,cn=config")
|
||||
+ automember_def = automember_defs.create(properties=automember_prop)
|
||||
+ automember_def.add_regex_rule("regex1", GROUP_DN, include_regex=[REGEX_VALUE])
|
||||
+
|
||||
+ automemberplugin.enable()
|
||||
+ topo.standalone.restart()
|
||||
+
|
||||
+ # Check errors log for invalid message
|
||||
+ ERR_STR1 = "automember_parse_regex_rule - Unable to parse regex rule"
|
||||
+ ERR_STR2 = f"Skipping invalid inclusive regex rule in rule entry \"{REGEX_DN}\" \\(rule = \"{REGEX_ESC_VALUE}\"\\)"
|
||||
+ assert topo.standalone.searchErrorsLog(ERR_STR1)
|
||||
+ assert topo.standalone.searchErrorsLog(ERR_STR2)
|
||||
+
|
||||
|
||||
if __name__ == "__main__":
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
|
||||
index 39350ad53..b92b89bd5 100644
|
||||
--- a/ldap/servers/plugins/automember/automember.c
|
||||
+++ b/ldap/servers/plugins/automember/automember.c
|
||||
@@ -1217,6 +1217,7 @@ automember_parse_regex_rule(char *rule_string)
|
||||
"automember_parse_regex_rule - Unable to parse "
|
||||
"regex rule (invalid regex). Error \"%s\".\n",
|
||||
recomp_result ? recomp_result : "unknown");
|
||||
+ goto bail;
|
||||
}
|
||||
|
||||
/* Validation has passed, so create the regex rule struct and fill it in.
|
||||
--
|
||||
2.31.1
|
||||
|
840
SOURCES/0004-Issue-5547-automember-plugin-improvements.patch
Normal file
840
SOURCES/0004-Issue-5547-automember-plugin-improvements.patch
Normal file
@ -0,0 +1,840 @@
|
||||
From 8dc61a176323f0d41df730abd715ccff3034c2be Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Sun, 27 Nov 2022 09:37:19 -0500
|
||||
Subject: [PATCH] Issue 5547 - automember plugin improvements
|
||||
|
||||
Description:
|
||||
|
||||
Rebuild task has the following improvements:
|
||||
|
||||
- Only one task allowed at a time
|
||||
- Do not cleanup previous members by default. Add new CLI option to intentionally
|
||||
cleanup memberships before rebuilding from scratch.
|
||||
- Add better task logging to show fixup progress
|
||||
|
||||
To prevent automember from being called in a nested be_txn loop thread storage is
|
||||
used to check and skip these loops.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/5547
|
||||
|
||||
Reviewed by: spichugi(Thanks!)
|
||||
---
|
||||
.../automember_plugin/automember_mod_test.py | 43 +++-
|
||||
ldap/servers/plugins/automember/automember.c | 232 ++++++++++++++----
|
||||
ldap/servers/slapd/back-ldbm/ldbm_add.c | 11 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 10 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 11 +-
|
||||
.../lib389/cli_conf/plugins/automember.py | 10 +-
|
||||
src/lib389/lib389/plugins.py | 7 +-
|
||||
src/lib389/lib389/tasks.py | 9 +-
|
||||
8 files changed, 250 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py b/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
index 8d25384bf..7a0ed3275 100644
|
||||
--- a/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
+++ b/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
@@ -5,12 +5,13 @@
|
||||
# License: GPL (version 3 or any later version).
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
+import ldap
|
||||
import logging
|
||||
import pytest
|
||||
import os
|
||||
+import time
|
||||
from lib389.utils import ds_is_older
|
||||
-from lib389._constants import *
|
||||
+from lib389._constants import DEFAULT_SUFFIX
|
||||
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinitions
|
||||
from lib389.idm.user import UserAccounts
|
||||
from lib389.idm.group import Groups
|
||||
@@ -41,6 +42,11 @@ def automember_fixture(topo, request):
|
||||
user_accts = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
user = user_accts.create_test_user()
|
||||
|
||||
+ # Create extra users
|
||||
+ users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in range(0, 100):
|
||||
+ users.create_test_user(uid=i)
|
||||
+
|
||||
# Create automember definitions and regex rules
|
||||
automember_prop = {
|
||||
'cn': 'testgroup_definition',
|
||||
@@ -59,7 +65,7 @@ def automember_fixture(topo, request):
|
||||
automemberplugin.enable()
|
||||
topo.standalone.restart()
|
||||
|
||||
- return (user, groups)
|
||||
+ return user, groups
|
||||
|
||||
|
||||
def test_mods(automember_fixture, topo):
|
||||
@@ -72,19 +78,21 @@ def test_mods(automember_fixture, topo):
|
||||
2. Update user that should add it to group[1]
|
||||
3. Update user that should add it to group[2]
|
||||
4. Update user that should add it to group[0]
|
||||
- 5. Test rebuild task correctly moves user to group[1]
|
||||
+ 5. Test rebuild task adds user to group[1]
|
||||
+ 6. Test rebuild task cleanups groups and only adds it to group[1]
|
||||
:expectedresults:
|
||||
1. Success
|
||||
2. Success
|
||||
3. Success
|
||||
4. Success
|
||||
5. Success
|
||||
+ 6. Success
|
||||
"""
|
||||
(user, groups) = automember_fixture
|
||||
|
||||
# Update user which should go into group[0]
|
||||
user.replace('cn', 'whatever')
|
||||
- groups[0].is_member(user.dn)
|
||||
+ assert groups[0].is_member(user.dn)
|
||||
if groups[1].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -92,7 +100,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user0 which should go into group[1]
|
||||
user.replace('cn', 'mark')
|
||||
- groups[1].is_member(user.dn)
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -100,7 +108,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user which should go into group[2]
|
||||
user.replace('cn', 'simon')
|
||||
- groups[2].is_member(user.dn)
|
||||
+ assert groups[2].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[1].is_member(user.dn):
|
||||
@@ -108,7 +116,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user which should go back into group[0] (full circle)
|
||||
user.replace('cn', 'whatever')
|
||||
- groups[0].is_member(user.dn)
|
||||
+ assert groups[0].is_member(user.dn)
|
||||
if groups[1].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -128,12 +136,24 @@ def test_mods(automember_fixture, topo):
|
||||
automemberplugin.enable()
|
||||
topo.standalone.restart()
|
||||
|
||||
- # Run rebuild task
|
||||
+ # Run rebuild task (no cleanup)
|
||||
task = automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=posixaccount")
|
||||
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
+ # test only one fixup task is allowed at a time
|
||||
+ automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=top")
|
||||
task.wait()
|
||||
|
||||
- # Test membership
|
||||
- groups[1].is_member(user.dn)
|
||||
+ # Test membership (user should still be in groups[0])
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
+ if not groups[0].is_member(user.dn):
|
||||
+ assert False
|
||||
+
|
||||
+ # Run rebuild task with cleanup
|
||||
+ task = automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=posixaccount", cleanup=True)
|
||||
+ task.wait()
|
||||
+
|
||||
+ # Test membership (user should only be in groups[1])
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -148,4 +168,3 @@ if __name__ == '__main__':
|
||||
# -s for DEBUG mode
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main(["-s", CURRENT_FILE])
|
||||
-
|
||||
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
|
||||
index 3494d0343..419adb052 100644
|
||||
--- a/ldap/servers/plugins/automember/automember.c
|
||||
+++ b/ldap/servers/plugins/automember/automember.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2011 Red Hat, Inc.
|
||||
+ * Copyright (C) 2022 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -14,7 +14,7 @@
|
||||
* Auto Membership Plug-in
|
||||
*/
|
||||
#include "automember.h"
|
||||
-
|
||||
+#include <pthread.h>
|
||||
|
||||
/*
|
||||
* Plug-in globals
|
||||
@@ -22,7 +22,9 @@
|
||||
static PRCList *g_automember_config = NULL;
|
||||
static Slapi_RWLock *g_automember_config_lock = NULL;
|
||||
static uint64_t abort_rebuild_task = 0;
|
||||
-
|
||||
+static pthread_key_t td_automem_block_nested;
|
||||
+static PRBool fixup_running = PR_FALSE;
|
||||
+static PRLock *fixup_lock = NULL;
|
||||
static void *_PluginID = NULL;
|
||||
static Slapi_DN *_PluginDN = NULL;
|
||||
static Slapi_DN *_ConfigAreaDN = NULL;
|
||||
@@ -93,9 +95,43 @@ static void automember_task_export_destructor(Slapi_Task *task);
|
||||
static void automember_task_map_destructor(Slapi_Task *task);
|
||||
|
||||
#define DEFAULT_FILE_MODE PR_IRUSR | PR_IWUSR
|
||||
+#define FIXUP_PROGRESS_LIMIT 1000
|
||||
static uint64_t plugin_do_modify = 0;
|
||||
static uint64_t plugin_is_betxn = 0;
|
||||
|
||||
+/* automember_plugin fixup task and add operations should block other be_txn
|
||||
+ * plugins from calling automember_post_op_mod() */
|
||||
+static int32_t
|
||||
+slapi_td_block_nested_post_op(void)
|
||||
+{
|
||||
+ int32_t val = 12345;
|
||||
+
|
||||
+ if (pthread_setspecific(td_automem_block_nested, (void *)&val) != 0) {
|
||||
+ return PR_FAILURE;
|
||||
+ }
|
||||
+ return PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int32_t
|
||||
+slapi_td_unblock_nested_post_op(void)
|
||||
+{
|
||||
+ if (pthread_setspecific(td_automem_block_nested, NULL) != 0) {
|
||||
+ return PR_FAILURE;
|
||||
+ }
|
||||
+ return PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int32_t
|
||||
+slapi_td_is_post_op_nested(void)
|
||||
+{
|
||||
+ int32_t *value = pthread_getspecific(td_automem_block_nested);
|
||||
+
|
||||
+ if (value == NULL) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Config cache locking functions
|
||||
*/
|
||||
@@ -317,6 +353,14 @@ automember_start(Slapi_PBlock *pb)
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ if (fixup_lock == NULL) {
|
||||
+ if ((fixup_lock = PR_NewLock()) == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_start - Failed to create fixup lock.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Get the plug-in target dn from the system
|
||||
* and store it for future use. */
|
||||
@@ -360,6 +404,11 @@ automember_start(Slapi_PBlock *pb)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (pthread_key_create(&td_automem_block_nested, NULL) != 0) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_start - pthread_key_create failed\n");
|
||||
+ }
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_start - ready for service\n");
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
@@ -394,6 +443,8 @@ automember_close(Slapi_PBlock *pb __attribute__((unused)))
|
||||
slapi_sdn_free(&_ConfigAreaDN);
|
||||
slapi_destroy_rwlock(g_automember_config_lock);
|
||||
g_automember_config_lock = NULL;
|
||||
+ PR_DestroyLock(fixup_lock);
|
||||
+ fixup_lock = NULL;
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"<-- automember_close\n");
|
||||
@@ -1619,7 +1670,6 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
-
|
||||
/*
|
||||
* automember_update_member_value()
|
||||
*
|
||||
@@ -1634,7 +1684,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
|
||||
LDAPMod *mods[2];
|
||||
char *vals[2];
|
||||
char *member_value = NULL;
|
||||
- int rc = 0;
|
||||
+ int rc = LDAP_SUCCESS;
|
||||
Slapi_DN *group_sdn;
|
||||
|
||||
/* First thing check that the group still exists */
|
||||
@@ -1653,7 +1703,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
|
||||
"automember_update_member_value - group (default or target) can not be retrieved (%s) err=%d\n",
|
||||
group_dn, rc);
|
||||
}
|
||||
- return rc;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
/* If grouping_value is dn, we need to fetch the dn instead. */
|
||||
@@ -1879,6 +1929,13 @@ automember_mod_post_op(Slapi_PBlock *pb)
|
||||
PRCList *list = NULL;
|
||||
int rc = SLAPI_PLUGIN_SUCCESS;
|
||||
|
||||
+ if (slapi_td_is_post_op_nested()) {
|
||||
+ /* don't process op twice in the same thread */
|
||||
+ return rc;
|
||||
+ } else {
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ }
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"--> automember_mod_post_op\n");
|
||||
|
||||
@@ -2005,6 +2062,7 @@ automember_mod_post_op(Slapi_PBlock *pb)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"<-- automember_mod_post_op (%d)\n", rc);
|
||||
@@ -2024,6 +2082,13 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"--> automember_add_post_op\n");
|
||||
|
||||
+ if (slapi_td_is_post_op_nested()) {
|
||||
+ /* don't process op twice in the same thread */
|
||||
+ return rc;
|
||||
+ } else {
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ }
|
||||
+
|
||||
/* Reload config if a config entry was added. */
|
||||
if ((sdn = automember_get_sdn(pb))) {
|
||||
if (automember_dn_is_config(sdn)) {
|
||||
@@ -2039,7 +2104,7 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
|
||||
/* If replication, just bail. */
|
||||
if (automember_isrepl(pb)) {
|
||||
- return SLAPI_PLUGIN_SUCCESS;
|
||||
+ goto bail;
|
||||
}
|
||||
|
||||
/* Get the newly added entry. */
|
||||
@@ -2052,7 +2117,7 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
tombstone);
|
||||
slapi_value_free(&tombstone);
|
||||
if (is_tombstone) {
|
||||
- return SLAPI_PLUGIN_SUCCESS;
|
||||
+ goto bail;
|
||||
}
|
||||
|
||||
/* Check if a config entry applies
|
||||
@@ -2063,21 +2128,19 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
list = PR_LIST_HEAD(g_automember_config);
|
||||
while (list != g_automember_config) {
|
||||
config = (struct configEntry *)list;
|
||||
-
|
||||
/* Does the entry meet scope and filter requirements? */
|
||||
if (slapi_dn_issuffix(slapi_sdn_get_dn(sdn), config->scope) &&
|
||||
- (slapi_filter_test_simple(e, config->filter) == 0)) {
|
||||
+ (slapi_filter_test_simple(e, config->filter) == 0))
|
||||
+ {
|
||||
/* Find out what membership changes are needed and make them. */
|
||||
if (automember_update_membership(config, e, NULL) == SLAPI_PLUGIN_FAILURE) {
|
||||
rc = SLAPI_PLUGIN_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
-
|
||||
list = PR_NEXT_LINK(list);
|
||||
}
|
||||
}
|
||||
-
|
||||
automember_config_unlock();
|
||||
} else {
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
@@ -2098,6 +2161,7 @@ bail:
|
||||
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &result);
|
||||
slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, &errtxt);
|
||||
}
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2138,6 +2202,7 @@ typedef struct _task_data
|
||||
Slapi_DN *base_dn;
|
||||
char *bind_dn;
|
||||
int scope;
|
||||
+ PRBool cleanup;
|
||||
} task_data;
|
||||
|
||||
static void
|
||||
@@ -2270,6 +2335,7 @@ automember_task_abort_thread(void *arg)
|
||||
* basedn: dc=example,dc=com
|
||||
* filter: (uid=*)
|
||||
* scope: sub
|
||||
+ * cleanup: yes/on (default is off)
|
||||
*
|
||||
* basedn and filter are required. If scope is omitted, the default is sub
|
||||
*/
|
||||
@@ -2284,9 +2350,22 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
const char *base_dn;
|
||||
const char *filter;
|
||||
const char *scope;
|
||||
+ const char *cleanup_str;
|
||||
+ PRBool cleanup = PR_FALSE;
|
||||
|
||||
*returncode = LDAP_SUCCESS;
|
||||
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ if (fixup_running) {
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_task_add - there is already a fixup task running\n");
|
||||
+ rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+
|
||||
/*
|
||||
* Grab the task params
|
||||
*/
|
||||
@@ -2300,6 +2379,12 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
goto out;
|
||||
}
|
||||
+ if ((cleanup_str = slapi_entry_attr_get_ref(e, "cleanup"))) {
|
||||
+ if (strcasecmp(cleanup_str, "yes") == 0 || strcasecmp(cleanup_str, "on")) {
|
||||
+ cleanup = PR_TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
scope = slapi_fetch_attr(e, "scope", "sub");
|
||||
/*
|
||||
* setup our task data
|
||||
@@ -2315,6 +2400,7 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
|
||||
mytaskdata->base_dn = slapi_sdn_new_dn_byval(base_dn);
|
||||
mytaskdata->filter_str = slapi_ch_strdup(filter);
|
||||
+ mytaskdata->cleanup = cleanup;
|
||||
|
||||
if (scope) {
|
||||
if (strcasecmp(scope, "sub") == 0) {
|
||||
@@ -2334,6 +2420,9 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
|
||||
slapi_task_set_destructor_fn(task, automember_task_destructor);
|
||||
slapi_task_set_data(task, mytaskdata);
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_TRUE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
/*
|
||||
* Start the task as a separate thread
|
||||
*/
|
||||
@@ -2345,6 +2434,9 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
"automember_task_add - Unable to create task thread!\n");
|
||||
*returncode = LDAP_OPERATIONS_ERROR;
|
||||
slapi_task_finish(task, *returncode);
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_FALSE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
} else {
|
||||
rv = SLAPI_DSE_CALLBACK_OK;
|
||||
@@ -2372,6 +2464,9 @@ automember_rebuild_task_thread(void *arg)
|
||||
PRCList *list = NULL;
|
||||
PRCList *include_list = NULL;
|
||||
int result = 0;
|
||||
+ int64_t fixup_progress_count = 0;
|
||||
+ int64_t fixup_progress_elapsed = 0;
|
||||
+ int64_t fixup_start_time = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* Reset abort flag */
|
||||
@@ -2380,6 +2475,7 @@ automember_rebuild_task_thread(void *arg)
|
||||
if (!task) {
|
||||
return; /* no task */
|
||||
}
|
||||
+
|
||||
slapi_task_inc_refcount(task);
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_rebuild_task_thread - Refcount incremented.\n");
|
||||
@@ -2393,9 +2489,11 @@ automember_rebuild_task_thread(void *arg)
|
||||
slapi_task_log_status(task, "Automember rebuild task starting (base dn: (%s) filter (%s)...",
|
||||
slapi_sdn_get_dn(td->base_dn), td->filter_str);
|
||||
/*
|
||||
- * Set the bind dn in the local thread data
|
||||
+ * Set the bind dn in the local thread data, and block post op mods
|
||||
*/
|
||||
slapi_td_set_dn(slapi_ch_strdup(td->bind_dn));
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ fixup_start_time = slapi_current_rel_time_t();
|
||||
/*
|
||||
* Take the config lock now and search the database
|
||||
*/
|
||||
@@ -2426,6 +2524,21 @@ automember_rebuild_task_thread(void *arg)
|
||||
* Loop over the entries
|
||||
*/
|
||||
for (i = 0; entries && (entries[i] != NULL); i++) {
|
||||
+ fixup_progress_count++;
|
||||
+ if (fixup_progress_count % FIXUP_PROGRESS_LIMIT == 0 ) {
|
||||
+ slapi_task_log_notice(task,
|
||||
+ "Processed %ld entries in %ld seconds (+%ld seconds)",
|
||||
+ fixup_progress_count,
|
||||
+ slapi_current_rel_time_t() - fixup_start_time,
|
||||
+ slapi_current_rel_time_t() - fixup_progress_elapsed);
|
||||
+ slapi_task_log_status(task,
|
||||
+ "Processed %ld entries in %ld seconds (+%ld seconds)",
|
||||
+ fixup_progress_count,
|
||||
+ slapi_current_rel_time_t() - fixup_start_time,
|
||||
+ slapi_current_rel_time_t() - fixup_progress_elapsed);
|
||||
+ slapi_task_inc_progress(task);
|
||||
+ fixup_progress_elapsed = slapi_current_rel_time_t();
|
||||
+ }
|
||||
if (slapi_atomic_load_64(&abort_rebuild_task, __ATOMIC_ACQUIRE) == 1) {
|
||||
/* The task was aborted */
|
||||
slapi_task_log_notice(task, "Automember rebuild task was intentionally aborted");
|
||||
@@ -2443,48 +2556,66 @@ automember_rebuild_task_thread(void *arg)
|
||||
if (slapi_dn_issuffix(slapi_entry_get_dn(entries[i]), config->scope) &&
|
||||
(slapi_filter_test_simple(entries[i], config->filter) == 0))
|
||||
{
|
||||
- /* First clear out all the defaults groups */
|
||||
- for (size_t ii = 0; config->default_groups && config->default_groups[ii]; ii++) {
|
||||
- if ((result = automember_update_member_value(entries[i], config->default_groups[ii],
|
||||
- config->grouping_attr, config->grouping_value, NULL, DEL_MEMBER)))
|
||||
- {
|
||||
- slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from default group (%s) error (%d)",
|
||||
- config->default_groups[ii], result);
|
||||
- slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from default group (%s) error (%d)",
|
||||
- config->default_groups[ii], result);
|
||||
- slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
- "automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
- config->default_groups[ii], result);
|
||||
- goto out;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* Then clear out the non-default group */
|
||||
- if (config->inclusive_rules && !PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
|
||||
- include_list = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
|
||||
- while (include_list != (PRCList *)config->inclusive_rules) {
|
||||
- struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)include_list;
|
||||
- if ((result = automember_update_member_value(entries[i], slapi_sdn_get_dn(curr_rule->target_group_dn),
|
||||
- config->grouping_attr, config->grouping_value, NULL, DEL_MEMBER)))
|
||||
+ if (td->cleanup) {
|
||||
+
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Cleaning up groups (config %s)\n",
|
||||
+ config->dn);
|
||||
+ /* First clear out all the defaults groups */
|
||||
+ for (size_t ii = 0; config->default_groups && config->default_groups[ii]; ii++) {
|
||||
+ if ((result = automember_update_member_value(entries[i],
|
||||
+ config->default_groups[ii],
|
||||
+ config->grouping_attr,
|
||||
+ config->grouping_value,
|
||||
+ NULL, DEL_MEMBER)))
|
||||
{
|
||||
slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from group (%s) error (%d)",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ "member from default group (%s) error (%d)",
|
||||
+ config->default_groups[ii], result);
|
||||
slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from group (%s) error (%d)",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ "member from default group (%s) error (%d)",
|
||||
+ config->default_groups[ii], result);
|
||||
slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ config->default_groups[ii], result);
|
||||
goto out;
|
||||
}
|
||||
- include_list = PR_NEXT_LINK(include_list);
|
||||
}
|
||||
+
|
||||
+ /* Then clear out the non-default group */
|
||||
+ if (config->inclusive_rules && !PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
|
||||
+ include_list = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
|
||||
+ while (include_list != (PRCList *)config->inclusive_rules) {
|
||||
+ struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)include_list;
|
||||
+ if ((result = automember_update_member_value(entries[i],
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn),
|
||||
+ config->grouping_attr,
|
||||
+ config->grouping_value,
|
||||
+ NULL, DEL_MEMBER)))
|
||||
+ {
|
||||
+ slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
+ "member from group (%s) error (%d)",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
+ "member from group (%s) error (%d)",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ include_list = PR_NEXT_LINK(include_list);
|
||||
+ }
|
||||
+ }
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Finished cleaning up groups (config %s)\n",
|
||||
+ config->dn);
|
||||
}
|
||||
|
||||
/* Update the memberships for this entries */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Updating membership (config %s)\n",
|
||||
+ config->dn);
|
||||
if (slapi_is_shutting_down() ||
|
||||
automember_update_membership(config, entries[i], NULL) == SLAPI_PLUGIN_FAILURE)
|
||||
{
|
||||
@@ -2508,15 +2639,22 @@ out:
|
||||
slapi_task_log_notice(task, "Automember rebuild task aborted. Error (%d)", result);
|
||||
slapi_task_log_status(task, "Automember rebuild task aborted. Error (%d)", result);
|
||||
} else {
|
||||
- slapi_task_log_notice(task, "Automember rebuild task finished. Processed (%d) entries.", (int32_t)i);
|
||||
- slapi_task_log_status(task, "Automember rebuild task finished. Processed (%d) entries.", (int32_t)i);
|
||||
+ slapi_task_log_notice(task, "Automember rebuild task finished. Processed (%ld) entries in %ld seconds",
|
||||
+ (int64_t)i, slapi_current_rel_time_t() - fixup_start_time);
|
||||
+ slapi_task_log_status(task, "Automember rebuild task finished. Processed (%ld) entries in %ld seconds",
|
||||
+ (int64_t)i, slapi_current_rel_time_t() - fixup_start_time);
|
||||
}
|
||||
slapi_task_inc_progress(task);
|
||||
slapi_task_finish(task, result);
|
||||
slapi_task_dec_refcount(task);
|
||||
slapi_atomic_store_64(&abort_rebuild_task, 0, __ATOMIC_RELEASE);
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_FALSE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
- "automember_rebuild_task_thread - Refcount decremented.\n");
|
||||
+ "automember_rebuild_task_thread - task finished, refcount decremented.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
index ba2d73a84..ce4c314a1 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2022 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1264,10 +1264,6 @@ ldbm_back_add(Slapi_PBlock *pb)
|
||||
goto common_return;
|
||||
|
||||
error_return:
|
||||
- /* Revert the caches if this is the parent operation */
|
||||
- if (parent_op && betxn_callback_fails) {
|
||||
- revert_cache(inst, &parent_time);
|
||||
- }
|
||||
if (addingentry_id_assigned) {
|
||||
next_id_return(be, addingentry->ep_id);
|
||||
}
|
||||
@@ -1376,6 +1372,11 @@ diskfull_return:
|
||||
if (!not_an_error) {
|
||||
rc = SLAPI_FAIL_GENERAL;
|
||||
}
|
||||
+
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
}
|
||||
|
||||
common_return:
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
index de23190c3..27f0ac58a 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
@@ -1407,11 +1407,6 @@ commit_return:
|
||||
goto common_return;
|
||||
|
||||
error_return:
|
||||
- /* Revert the caches if this is the parent operation */
|
||||
- if (parent_op && betxn_callback_fails) {
|
||||
- revert_cache(inst, &parent_time);
|
||||
- }
|
||||
-
|
||||
if (tombstone) {
|
||||
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
|
||||
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
|
||||
@@ -1496,6 +1491,11 @@ error_return:
|
||||
conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
|
||||
}
|
||||
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
+
|
||||
common_return:
|
||||
if (orig_entry) {
|
||||
/* NOTE: #define SLAPI_DELETE_BEPREOP_ENTRY SLAPI_ENTRY_PRE_OP */
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
index 537369055..64b293001 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2022 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1043,11 +1043,6 @@ ldbm_back_modify(Slapi_PBlock *pb)
|
||||
goto common_return;
|
||||
|
||||
error_return:
|
||||
- /* Revert the caches if this is the parent operation */
|
||||
- if (parent_op && betxn_callback_fails) {
|
||||
- revert_cache(inst, &parent_time);
|
||||
- }
|
||||
-
|
||||
if (postentry != NULL) {
|
||||
slapi_entry_free(postentry);
|
||||
postentry = NULL;
|
||||
@@ -1103,6 +1098,10 @@ error_return:
|
||||
if (!not_an_error) {
|
||||
rc = SLAPI_FAIL_GENERAL;
|
||||
}
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* if ec is in cache, remove it, then add back e if we still have it */
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugins/automember.py b/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
index 15b00c633..568586ad8 100644
|
||||
--- a/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
+++ b/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
@@ -155,7 +155,7 @@ def fixup(inst, basedn, log, args):
|
||||
log.info('Attempting to add task entry... This will fail if Automembership plug-in is not enabled.')
|
||||
if not plugin.status():
|
||||
log.error("'%s' is disabled. Rebuild membership task can't be executed" % plugin.rdn)
|
||||
- fixup_task = plugin.fixup(args.DN, args.filter)
|
||||
+ fixup_task = plugin.fixup(args.DN, args.filter, args.cleanup)
|
||||
if args.wait:
|
||||
log.info(f'Waiting for fixup task "{fixup_task.dn}" to complete. You can safely exit by pressing Control C ...')
|
||||
fixup_task.wait(timeout=args.timeout)
|
||||
@@ -225,8 +225,8 @@ def create_parser(subparsers):
|
||||
subcommands = automember.add_subparsers(help='action')
|
||||
add_generic_plugin_parsers(subcommands, AutoMembershipPlugin)
|
||||
|
||||
- list = subcommands.add_parser('list', help='List Automembership definitions or regex rules.')
|
||||
- subcommands_list = list.add_subparsers(help='action')
|
||||
+ automember_list = subcommands.add_parser('list', help='List Automembership definitions or regex rules.')
|
||||
+ subcommands_list = automember_list.add_subparsers(help='action')
|
||||
list_definitions = subcommands_list.add_parser('definitions', help='Lists Automembership definitions.')
|
||||
list_definitions.set_defaults(func=definition_list)
|
||||
list_regexes = subcommands_list.add_parser('regexes', help='List Automembership regex rules.')
|
||||
@@ -269,6 +269,8 @@ def create_parser(subparsers):
|
||||
fixup_task.add_argument('-f', '--filter', required=True, help='Sets the LDAP filter for entries to fix up')
|
||||
fixup_task.add_argument('-s', '--scope', required=True, choices=['sub', 'base', 'one'], type=str.lower,
|
||||
help='Sets the LDAP search scope for entries to fix up')
|
||||
+ fixup_task.add_argument('--cleanup', action='store_true',
|
||||
+ help="Clean up previous group memberships before rebuilding")
|
||||
fixup_task.add_argument('--wait', action='store_true',
|
||||
help="Wait for the task to finish, this could take a long time")
|
||||
fixup_task.add_argument('--timeout', default=0, type=int,
|
||||
@@ -279,7 +281,7 @@ def create_parser(subparsers):
|
||||
fixup_status.add_argument('--dn', help="The task entry's DN")
|
||||
fixup_status.add_argument('--show-log', action='store_true', help="Display the task log")
|
||||
fixup_status.add_argument('--watch', action='store_true',
|
||||
- help="Watch the task's status and wait for it to finish")
|
||||
+ help="Watch the task's status and wait for it to finish")
|
||||
|
||||
abort_fixup = subcommands.add_parser('abort-fixup', help='Abort the rebuild membership task.')
|
||||
abort_fixup.set_defaults(func=abort)
|
||||
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
|
||||
index 52691a44c..a1ad0a45b 100644
|
||||
--- a/src/lib389/lib389/plugins.py
|
||||
+++ b/src/lib389/lib389/plugins.py
|
||||
@@ -1141,13 +1141,15 @@ class AutoMembershipPlugin(Plugin):
|
||||
def __init__(self, instance, dn="cn=Auto Membership Plugin,cn=plugins,cn=config"):
|
||||
super(AutoMembershipPlugin, self).__init__(instance, dn)
|
||||
|
||||
- def fixup(self, basedn, _filter=None):
|
||||
+ def fixup(self, basedn, _filter=None, cleanup=False):
|
||||
"""Create an automember rebuild membership task
|
||||
|
||||
:param basedn: Basedn to fix up
|
||||
:type basedn: str
|
||||
:param _filter: a filter for entries to fix up
|
||||
:type _filter: str
|
||||
+ :param cleanup: cleanup old group memberships
|
||||
+ :type cleanup: boolean
|
||||
|
||||
:returns: an instance of Task(DSLdapObject)
|
||||
"""
|
||||
@@ -1156,6 +1158,9 @@ class AutoMembershipPlugin(Plugin):
|
||||
task_properties = {'basedn': basedn}
|
||||
if _filter is not None:
|
||||
task_properties['filter'] = _filter
|
||||
+ if cleanup:
|
||||
+ task_properties['cleanup'] = "yes"
|
||||
+
|
||||
task.create(properties=task_properties)
|
||||
|
||||
return task
|
||||
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
|
||||
index 1a16bbb83..193805780 100644
|
||||
--- a/src/lib389/lib389/tasks.py
|
||||
+++ b/src/lib389/lib389/tasks.py
|
||||
@@ -1006,12 +1006,13 @@ class Tasks(object):
|
||||
return exitCode
|
||||
|
||||
def automemberRebuild(self, suffix=DEFAULT_SUFFIX, scope='sub',
|
||||
- filterstr='objectclass=top', args=None):
|
||||
+ filterstr='objectclass=top', cleanup=False, args=None):
|
||||
'''
|
||||
- @param suffix - The suffix the task should examine - defualt is
|
||||
+ @param suffix - The suffix the task should examine - default is
|
||||
"dc=example,dc=com"
|
||||
@param scope - The scope of the search to find entries
|
||||
- @param fitlerstr - THe search filter to find entries
|
||||
+ @param fitlerstr - The search filter to find entries
|
||||
+ @param cleanup - reset/clear the old group mmeberships prior to rebuilding
|
||||
@param args - is a dictionary that contains modifier of the task
|
||||
wait: True/[False] - If True, waits for the completion of
|
||||
the task before to return
|
||||
@@ -1027,6 +1028,8 @@ class Tasks(object):
|
||||
entry.setValues('basedn', suffix)
|
||||
entry.setValues('filter', filterstr)
|
||||
entry.setValues('scope', scope)
|
||||
+ if cleanup:
|
||||
+ entry.setValues('cleanup', 'yes')
|
||||
|
||||
# start the task and possibly wait for task completion
|
||||
try:
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,83 @@
|
||||
From 9319d5b022918f14cacb00e3faef85a6ab730a26 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 27 Feb 2024 16:30:47 -0800
|
||||
Subject: [PATCH] Issue 3527 - Support HAProxy and Instance on the same machine
|
||||
configuration (#6107)
|
||||
|
||||
Description: Improve how we handle HAProxy connections to work better when
|
||||
the DS and HAProxy are on the same machine.
|
||||
Ensure the client and header destination IPs are checked against the trusted IP list.
|
||||
|
||||
Additionally, this change will also allow configuration having
|
||||
HAProxy is listening on a different subnet than the one used to forward the request.
|
||||
|
||||
Related: https://github.com/389ds/389-ds-base/issues/3527
|
||||
|
||||
Reviewed by: @progier389, @jchapma (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/connection.c | 35 +++++++++++++++++++++++++--------
|
||||
1 file changed, 27 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
||||
index d28a39bf7..10a8cc577 100644
|
||||
--- a/ldap/servers/slapd/connection.c
|
||||
+++ b/ldap/servers/slapd/connection.c
|
||||
@@ -1187,6 +1187,8 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
|
||||
char str_ip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
char str_haproxy_ip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
char str_haproxy_destip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
+ int trusted_matches_ip_found = 0;
|
||||
+ int trusted_matches_destip_found = 0;
|
||||
struct berval **bvals = NULL;
|
||||
int proxy_connection = 0;
|
||||
|
||||
@@ -1245,21 +1247,38 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
|
||||
normalize_IPv4(conn->cin_addr, buf_ip, sizeof(buf_ip), str_ip, sizeof(str_ip));
|
||||
normalize_IPv4(&pr_netaddr_dest, buf_haproxy_destip, sizeof(buf_haproxy_destip),
|
||||
str_haproxy_destip, sizeof(str_haproxy_destip));
|
||||
+ size_t ip_len = strlen(buf_ip);
|
||||
+ size_t destip_len = strlen(buf_haproxy_destip);
|
||||
|
||||
/* Now, reset RC and set it to 0 only if a match is found */
|
||||
haproxy_rc = -1;
|
||||
|
||||
- /* Allow only:
|
||||
- * Trusted IP == Original Client IP == HAProxy Header Destination IP */
|
||||
+ /*
|
||||
+ * We need to allow a configuration where DS instance and HAProxy are on the same machine.
|
||||
+ * In this case, we need to check if
|
||||
+ * the HAProxy client IP (which will be a loopback address) matches one of the the trusted IP addresses,
|
||||
+ * while still checking that
|
||||
+ * the HAProxy header destination IP address matches one of the trusted IP addresses.
|
||||
+ * Additionally, this change will also allow configuration having
|
||||
+ * HAProxy listening on a different subnet than one used to forward the request.
|
||||
+ */
|
||||
for (size_t i = 0; bvals[i] != NULL; ++i) {
|
||||
- if ((strlen(bvals[i]->bv_val) == strlen(buf_ip)) &&
|
||||
- (strlen(bvals[i]->bv_val) == strlen(buf_haproxy_destip)) &&
|
||||
- (strncasecmp(bvals[i]->bv_val, buf_ip, strlen(buf_ip)) == 0) &&
|
||||
- (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, strlen(buf_haproxy_destip)) == 0)) {
|
||||
- haproxy_rc = 0;
|
||||
- break;
|
||||
+ size_t bval_len = strlen(bvals[i]->bv_val);
|
||||
+
|
||||
+ /* Check if the Client IP (HAProxy's machine IP) address matches the trusted IP address */
|
||||
+ if (!trusted_matches_ip_found) {
|
||||
+ trusted_matches_ip_found = (bval_len == ip_len) && (strncasecmp(bvals[i]->bv_val, buf_ip, ip_len) == 0);
|
||||
+ }
|
||||
+ /* Check if the HAProxy header destination IP address matches the trusted IP address */
|
||||
+ if (!trusted_matches_destip_found) {
|
||||
+ trusted_matches_destip_found = (bval_len == destip_len) && (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, destip_len) == 0);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (trusted_matches_ip_found && trusted_matches_destip_found) {
|
||||
+ haproxy_rc = 0;
|
||||
+ }
|
||||
+
|
||||
if (haproxy_rc == -1) {
|
||||
slapi_log_err(SLAPI_LOG_CONNS, "connection_read_operation", "HAProxy header received from unknown source.\n");
|
||||
disconnect_server_nomutex(conn, conn->c_connid, -1, SLAPD_DISCONNECT_PROXY_UNKNOWN, EPROTO);
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,245 +0,0 @@
|
||||
From 9c08a053938eb28821fad7d0850c046ef2ed44c4 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 9 Dec 2020 16:16:30 -0500
|
||||
Subject: [PATCH 05/12] Issue 4092 - systemd-tmpfiles warnings
|
||||
|
||||
Bug Description:
|
||||
|
||||
systemd-tmpfiles warns about legacy paths in our tmpfiles configs.
|
||||
Using /var/run also introduces a race condition, see the following
|
||||
issue https://pagure.io/389-ds-base/issue/47429
|
||||
|
||||
Fix Description:
|
||||
|
||||
Instead of using @localstatedir@/run use @localrundir@ which was
|
||||
introduced in #850.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/766
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/4092
|
||||
|
||||
Reviewed by: vashirov & firstyear(Thanks!)
|
||||
---
|
||||
Makefile.am | 4 ++--
|
||||
configure.ac | 10 ++++++++--
|
||||
dirsrvtests/tests/suites/basic/basic_test.py | 3 ++-
|
||||
ldap/admin/src/defaults.inf.in | 8 ++++----
|
||||
ldap/servers/snmp/main.c | 8 ++++----
|
||||
src/lib389/lib389/__init__.py | 3 +++
|
||||
src/lib389/lib389/instance/options.py | 7 ++++++-
|
||||
src/lib389/lib389/instance/remove.py | 13 ++++++++-----
|
||||
src/lib389/lib389/instance/setup.py | 10 ++++++++--
|
||||
9 files changed, 45 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
index 36434cf17..fc5a6a7d1 100644
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -141,8 +141,8 @@ PATH_DEFINES = -DLOCALSTATEDIR="\"$(localstatedir)\"" -DSYSCONFDIR="\"$(sysconfd
|
||||
-DLIBDIR="\"$(libdir)\"" -DBINDIR="\"$(bindir)\"" \
|
||||
-DDATADIR="\"$(datadir)\"" -DDOCDIR="\"$(docdir)\"" \
|
||||
-DSBINDIR="\"$(sbindir)\"" -DPLUGINDIR="\"$(serverplugindir)\"" \
|
||||
- -DTEMPLATEDIR="\"$(sampledatadir)\"" -DSYSTEMSCHEMADIR="\"$(systemschemadir)\""
|
||||
-
|
||||
+ -DTEMPLATEDIR="\"$(sampledatadir)\"" -DSYSTEMSCHEMADIR="\"$(systemschemadir)\"" \
|
||||
+ -DLOCALRUNDIR="\"$(localrundir)\""
|
||||
# Now that we have all our defines in place, setup the CPPFLAGS
|
||||
|
||||
# These flags are the "must have" for all components
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 61bf35e4a..9845beb7d 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -418,7 +418,14 @@ fi
|
||||
|
||||
m4_include(m4/fhs.m4)
|
||||
|
||||
-localrundir='/run'
|
||||
+# /run directory path
|
||||
+AC_ARG_WITH([localrundir],
|
||||
+ AS_HELP_STRING([--with-localrundir=DIR],
|
||||
+ [Runtime data directory]),
|
||||
+ [localrundir=$with_localrundir],
|
||||
+ [localrundir="/run"])
|
||||
+AC_SUBST([localrundir])
|
||||
+
|
||||
cockpitdir=/389-console
|
||||
|
||||
# installation paths - by default, we store everything
|
||||
@@ -899,7 +906,6 @@ AC_SUBST(ldaplib_defs)
|
||||
AC_SUBST(ldaptool_bindir)
|
||||
AC_SUBST(ldaptool_opts)
|
||||
AC_SUBST(plainldif_opts)
|
||||
-AC_SUBST(localrundir)
|
||||
|
||||
AC_SUBST(brand)
|
||||
AC_SUBST(capbrand)
|
||||
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
|
||||
index 41726f073..7e80c443b 100644
|
||||
--- a/dirsrvtests/tests/suites/basic/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
|
||||
@@ -901,7 +901,8 @@ def test_basic_ldapagent(topology_st, import_example_ldif):
|
||||
# Remember, this is *forking*
|
||||
check_output([os.path.join(topology_st.standalone.get_sbin_dir(), 'ldap-agent'), config_file])
|
||||
# First kill any previous agents ....
|
||||
- pidpath = os.path.join(var_dir, 'run/ldap-agent.pid')
|
||||
+ run_dir = topology_st.standalone.get_run_dir()
|
||||
+ pidpath = os.path.join(run_dir, 'ldap-agent.pid')
|
||||
pid = None
|
||||
with open(pidpath, 'r') as pf:
|
||||
pid = pf.readlines()[0].strip()
|
||||
diff --git a/ldap/admin/src/defaults.inf.in b/ldap/admin/src/defaults.inf.in
|
||||
index d5f504591..e02248b89 100644
|
||||
--- a/ldap/admin/src/defaults.inf.in
|
||||
+++ b/ldap/admin/src/defaults.inf.in
|
||||
@@ -35,12 +35,12 @@ sysconf_dir = @sysconfdir@
|
||||
initconfig_dir = @initconfigdir@
|
||||
config_dir = @instconfigdir@/slapd-{instance_name}
|
||||
local_state_dir = @localstatedir@
|
||||
-run_dir = @localstatedir@/run/dirsrv
|
||||
+run_dir = @localrundir@
|
||||
# This is the expected location of ldapi.
|
||||
-ldapi = @localstatedir@/run/slapd-{instance_name}.socket
|
||||
+ldapi = @localrundir@/slapd-{instance_name}.socket
|
||||
+pid_file = @localrundir@/slapd-{instance_name}.pid
|
||||
ldapi_listen = on
|
||||
ldapi_autobind = on
|
||||
-pid_file = @localstatedir@/run/dirsrv/slapd-{instance_name}.pid
|
||||
inst_dir = @serverdir@/slapd-{instance_name}
|
||||
plugin_dir = @serverplugindir@
|
||||
system_schema_dir = @systemschemadir@
|
||||
@@ -54,7 +54,7 @@ root_dn = cn=Directory Manager
|
||||
schema_dir = @instconfigdir@/slapd-{instance_name}/schema
|
||||
cert_dir = @instconfigdir@/slapd-{instance_name}
|
||||
|
||||
-lock_dir = @localstatedir@/lock/dirsrv/slapd-{instance_name}
|
||||
+lock_dir = @localrundir@/lock/dirsrv/slapd-{instance_name}
|
||||
log_dir = @localstatedir@/log/dirsrv/slapd-{instance_name}
|
||||
access_log = @localstatedir@/log/dirsrv/slapd-{instance_name}/access
|
||||
audit_log = @localstatedir@/log/dirsrv/slapd-{instance_name}/audit
|
||||
diff --git a/ldap/servers/snmp/main.c b/ldap/servers/snmp/main.c
|
||||
index 88a4d532a..e6271a8a9 100644
|
||||
--- a/ldap/servers/snmp/main.c
|
||||
+++ b/ldap/servers/snmp/main.c
|
||||
@@ -287,14 +287,14 @@ load_config(char *conf_path)
|
||||
}
|
||||
|
||||
/* set pidfile path */
|
||||
- if ((pidfile = malloc(strlen(LOCALSTATEDIR) + strlen("/run/") +
|
||||
+ if ((pidfile = malloc(strlen(LOCALRUNDIR) + strlen("/") +
|
||||
strlen(LDAP_AGENT_PIDFILE) + 1)) != NULL) {
|
||||
- strncpy(pidfile, LOCALSTATEDIR, strlen(LOCALSTATEDIR) + 1);
|
||||
+ strncpy(pidfile, LOCALRUNDIR, strlen(LOCALRUNDIR) + 1);
|
||||
/* The above will likely not be NULL terminated, but we need to
|
||||
* be sure that we're properly NULL terminated for the below
|
||||
* strcat() to work properly. */
|
||||
- pidfile[strlen(LOCALSTATEDIR)] = (char)0;
|
||||
- strcat(pidfile, "/run/");
|
||||
+ pidfile[strlen(LOCALRUNDIR)] = (char)0;
|
||||
+ strcat(pidfile, "/");
|
||||
strcat(pidfile, LDAP_AGENT_PIDFILE);
|
||||
} else {
|
||||
printf("ldap-agent: malloc error processing config file\n");
|
||||
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
|
||||
index e0299c5b4..2a0b83913 100644
|
||||
--- a/src/lib389/lib389/__init__.py
|
||||
+++ b/src/lib389/lib389/__init__.py
|
||||
@@ -1709,6 +1709,9 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
def get_bin_dir(self):
|
||||
return self.ds_paths.bin_dir
|
||||
|
||||
+ def get_run_dir(self):
|
||||
+ return self.ds_paths.run_dir
|
||||
+
|
||||
def get_plugin_dir(self):
|
||||
return self.ds_paths.plugin_dir
|
||||
|
||||
diff --git a/src/lib389/lib389/instance/options.py b/src/lib389/lib389/instance/options.py
|
||||
index 4e083618c..d5b95e6df 100644
|
||||
--- a/src/lib389/lib389/instance/options.py
|
||||
+++ b/src/lib389/lib389/instance/options.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2019 Red Hat, Inc.
|
||||
+# Copyright (C) 2021 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# License: GPL (version 3 or any later version).
|
||||
@@ -32,6 +32,7 @@ format_keys = [
|
||||
'backup_dir',
|
||||
'db_dir',
|
||||
'db_home_dir',
|
||||
+ 'ldapi',
|
||||
'ldif_dir',
|
||||
'lock_dir',
|
||||
'log_dir',
|
||||
@@ -233,6 +234,10 @@ class Slapd2Base(Options2):
|
||||
self._helptext['local_state_dir'] = "Sets the location of Directory Server variable data. Only set this parameter in a development environment."
|
||||
self._advanced['local_state_dir'] = True
|
||||
|
||||
+ self._options['ldapi'] = ds_paths.ldapi
|
||||
+ self._type['ldapi'] = str
|
||||
+ self._helptext['ldapi'] = "Sets the location of socket interface of the Directory Server."
|
||||
+
|
||||
self._options['lib_dir'] = ds_paths.lib_dir
|
||||
self._type['lib_dir'] = str
|
||||
self._helptext['lib_dir'] = "Sets the location of Directory Server shared libraries. Only set this parameter in a development environment."
|
||||
diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py
|
||||
index d7bb48ce0..1a35ddc07 100644
|
||||
--- a/src/lib389/lib389/instance/remove.py
|
||||
+++ b/src/lib389/lib389/instance/remove.py
|
||||
@@ -78,13 +78,16 @@ def remove_ds_instance(dirsrv, force=False):
|
||||
|
||||
_log.debug("Found instance marker at %s! Proceeding to remove ..." % dse_ldif_path)
|
||||
|
||||
- # Stop the instance (if running) and now we know it really does exist
|
||||
- # and hopefully have permission to access it ...
|
||||
- _log.debug("Stopping instance %s" % dirsrv.serverid)
|
||||
- dirsrv.stop()
|
||||
-
|
||||
### ANY NEW REMOVAL ACTION MUST BE BELOW THIS LINE!!!
|
||||
|
||||
+ # Remove LDAPI socket file
|
||||
+ ldapi_path = os.path.join(dirsrv.ds_paths.run_dir, "slapd-%s.socket" % dirsrv.serverid)
|
||||
+ if os.path.exists(ldapi_path):
|
||||
+ try:
|
||||
+ os.remove(ldapi_path)
|
||||
+ except OSError as e:
|
||||
+ _log.debug(f"Failed to remove LDAPI socket ({ldapi_path}) Error: {str(e)}")
|
||||
+
|
||||
# Remove these paths:
|
||||
# for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
|
||||
# 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
|
||||
diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py
|
||||
index ab7a2da85..57e7a9fd4 100644
|
||||
--- a/src/lib389/lib389/instance/setup.py
|
||||
+++ b/src/lib389/lib389/instance/setup.py
|
||||
@@ -732,7 +732,10 @@ class SetupDs(object):
|
||||
dse += line.replace('%', '{', 1).replace('%', '}', 1)
|
||||
|
||||
with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:
|
||||
- ldapi_path = os.path.join(slapd['local_state_dir'], "run/slapd-%s.socket" % slapd['instance_name'])
|
||||
+ if os.path.exists(os.path.dirname(slapd['ldapi'])):
|
||||
+ ldapi_path = slapd['ldapi']
|
||||
+ else:
|
||||
+ ldapi_path = os.path.join(slapd['run_dir'], "slapd-%s.socket" % slapd['instance_name'])
|
||||
dse_fmt = dse.format(
|
||||
schema_dir=slapd['schema_dir'],
|
||||
lock_dir=slapd['lock_dir'],
|
||||
@@ -902,10 +905,13 @@ class SetupDs(object):
|
||||
self.log.info("Perform SELinux labeling ...")
|
||||
selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
|
||||
'ldif_dir', 'lock_dir', 'log_dir', 'db_home_dir',
|
||||
- 'run_dir', 'schema_dir', 'tmp_dir')
|
||||
+ 'schema_dir', 'tmp_dir')
|
||||
for path in selinux_paths:
|
||||
selinux_restorecon(slapd[path])
|
||||
|
||||
+ # Don't run restorecon on the entire /run directory
|
||||
+ selinux_restorecon(slapd['run_dir'] + '/dirsrv')
|
||||
+
|
||||
selinux_label_port(slapd['port'])
|
||||
|
||||
# Start the server
|
||||
--
|
||||
2.31.1
|
||||
|
108
SOURCES/0006-CVE-2024-2199.patch
Normal file
108
SOURCES/0006-CVE-2024-2199.patch
Normal file
@ -0,0 +1,108 @@
|
||||
From 016a2b6bd3e27cbff36609824a75b020dfd24823 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Wed, 1 May 2024 15:01:33 +0100
|
||||
Subject: [PATCH] CVE-2024-2199
|
||||
|
||||
---
|
||||
.../tests/suites/password/password_test.py | 56 +++++++++++++++++++
|
||||
ldap/servers/slapd/modify.c | 8 ++-
|
||||
2 files changed, 62 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/password_test.py b/dirsrvtests/tests/suites/password/password_test.py
|
||||
index 38079476a..b3ff08904 100644
|
||||
--- a/dirsrvtests/tests/suites/password/password_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/password_test.py
|
||||
@@ -65,6 +65,62 @@ def test_password_delete_specific_password(topology_st):
|
||||
log.info('test_password_delete_specific_password: PASSED')
|
||||
|
||||
|
||||
+def test_password_modify_non_utf8(topology_st):
|
||||
+ """Attempt a modify of the userPassword attribute with
|
||||
+ an invalid non utf8 value
|
||||
+
|
||||
+ :id: a31af9d5-d665-42b9-8d6e-fea3d0837d36
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Add a user if it doesnt exist and set its password
|
||||
+ 2. Verify password with a bind
|
||||
+ 3. Modify userPassword attr with invalid value
|
||||
+ 4. Attempt a bind with invalid password value
|
||||
+ 5. Verify original password with a bind
|
||||
+ :expectedresults:
|
||||
+ 1. The user with userPassword should be added successfully
|
||||
+ 2. Operation should be successful
|
||||
+ 3. Server returns ldap.UNWILLING_TO_PERFORM
|
||||
+ 4. Server returns ldap.INVALID_CREDENTIALS
|
||||
+ 5. Operation should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info('Running test_password_modify_non_utf8...')
|
||||
+
|
||||
+ # Create user and set password
|
||||
+ standalone = topology_st.standalone
|
||||
+ users = UserAccounts(standalone, DEFAULT_SUFFIX)
|
||||
+ if not users.exists(TEST_USER_PROPERTIES['uid'][0]):
|
||||
+ user = users.create(properties=TEST_USER_PROPERTIES)
|
||||
+ else:
|
||||
+ user = users.get(TEST_USER_PROPERTIES['uid'][0])
|
||||
+ user.set('userpassword', PASSWORD)
|
||||
+
|
||||
+ # Verify password
|
||||
+ try:
|
||||
+ user.bind(PASSWORD)
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
|
||||
+ assert False
|
||||
+
|
||||
+ # Modify userPassword with an invalid value
|
||||
+ password = b'tes\x82t-password' # A non UTF-8 encoded password
|
||||
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
+ user.replace('userpassword', password)
|
||||
+
|
||||
+ # Verify a bind fails with invalid pasword
|
||||
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
||||
+ user.bind(password)
|
||||
+
|
||||
+ # Verify we can still bind with original password
|
||||
+ try:
|
||||
+ user.bind(PASSWORD)
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
|
||||
+ assert False
|
||||
+
|
||||
+ log.info('test_password_modify_non_utf8: PASSED')
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
||||
index 5ca78539c..669bb104c 100644
|
||||
--- a/ldap/servers/slapd/modify.c
|
||||
+++ b/ldap/servers/slapd/modify.c
|
||||
@@ -765,8 +765,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
|
||||
* flagged - leave mod attributes alone */
|
||||
if (!repl_op && !skip_modified_attrs && lastmod) {
|
||||
modify_update_last_modified_attr(pb, &smods);
|
||||
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, slapi_mods_get_ldapmods_byref(&smods));
|
||||
}
|
||||
|
||||
+
|
||||
if (0 == slapi_mods_get_num_mods(&smods)) {
|
||||
/* nothing to do - no mods - this is not an error - just
|
||||
send back LDAP_SUCCESS */
|
||||
@@ -933,8 +935,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
|
||||
|
||||
/* encode password */
|
||||
if (pw_encodevals_ext(pb, sdn, va)) {
|
||||
- slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s.\n", slapi_entry_get_dn_const(e));
|
||||
- send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to store attribute \"userPassword\" correctly\n", 0, NULL);
|
||||
+ slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s, "
|
||||
+ "check value is utf8 string.\n", slapi_entry_get_dn_const(e));
|
||||
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to hash \"userPassword\" attribute, "
|
||||
+ "check value is utf8 string.\n", 0, NULL);
|
||||
valuearray_free(&va);
|
||||
goto free_and_return;
|
||||
}
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,113 +0,0 @@
|
||||
From b4a3b88faeafa6aa197d88ee84e4b2dbadd37ace Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 1 Nov 2021 10:42:27 -0400
|
||||
Subject: [PATCH 06/12] Issue 4973 - installer changes permissions on /run
|
||||
|
||||
Description: There was a regression when we switched over to using /run
|
||||
that caused the installer to try and create /run which
|
||||
caused the ownership to change. Fixed this by changing
|
||||
the "run_dir" to /run/dirsrv
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4973
|
||||
|
||||
Reviewed by: jchapman(Thanks!)
|
||||
---
|
||||
ldap/admin/src/defaults.inf.in | 2 +-
|
||||
src/lib389/lib389/instance/remove.py | 10 +---------
|
||||
src/lib389/lib389/instance/setup.py | 13 +++----------
|
||||
3 files changed, 5 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/ldap/admin/src/defaults.inf.in b/ldap/admin/src/defaults.inf.in
|
||||
index e02248b89..92b93d695 100644
|
||||
--- a/ldap/admin/src/defaults.inf.in
|
||||
+++ b/ldap/admin/src/defaults.inf.in
|
||||
@@ -35,7 +35,7 @@ sysconf_dir = @sysconfdir@
|
||||
initconfig_dir = @initconfigdir@
|
||||
config_dir = @instconfigdir@/slapd-{instance_name}
|
||||
local_state_dir = @localstatedir@
|
||||
-run_dir = @localrundir@
|
||||
+run_dir = @localrundir@/dirsrv
|
||||
# This is the expected location of ldapi.
|
||||
ldapi = @localrundir@/slapd-{instance_name}.socket
|
||||
pid_file = @localrundir@/slapd-{instance_name}.pid
|
||||
diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py
|
||||
index 1a35ddc07..e96db3896 100644
|
||||
--- a/src/lib389/lib389/instance/remove.py
|
||||
+++ b/src/lib389/lib389/instance/remove.py
|
||||
@@ -52,9 +52,9 @@ def remove_ds_instance(dirsrv, force=False):
|
||||
remove_paths['ldif_dir'] = dirsrv.ds_paths.ldif_dir
|
||||
remove_paths['lock_dir'] = dirsrv.ds_paths.lock_dir
|
||||
remove_paths['log_dir'] = dirsrv.ds_paths.log_dir
|
||||
- # remove_paths['run_dir'] = dirsrv.ds_paths.run_dir
|
||||
remove_paths['inst_dir'] = dirsrv.ds_paths.inst_dir
|
||||
remove_paths['etc_sysconfig'] = "%s/sysconfig/dirsrv-%s" % (dirsrv.ds_paths.sysconf_dir, dirsrv.serverid)
|
||||
+ remove_paths['ldapi'] = dirsrv.ds_paths.ldapi
|
||||
|
||||
tmpfiles_d_path = dirsrv.ds_paths.tmpfiles_d + "/dirsrv-" + dirsrv.serverid + ".conf"
|
||||
|
||||
@@ -80,14 +80,6 @@ def remove_ds_instance(dirsrv, force=False):
|
||||
|
||||
### ANY NEW REMOVAL ACTION MUST BE BELOW THIS LINE!!!
|
||||
|
||||
- # Remove LDAPI socket file
|
||||
- ldapi_path = os.path.join(dirsrv.ds_paths.run_dir, "slapd-%s.socket" % dirsrv.serverid)
|
||||
- if os.path.exists(ldapi_path):
|
||||
- try:
|
||||
- os.remove(ldapi_path)
|
||||
- except OSError as e:
|
||||
- _log.debug(f"Failed to remove LDAPI socket ({ldapi_path}) Error: {str(e)}")
|
||||
-
|
||||
# Remove these paths:
|
||||
# for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
|
||||
# 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
|
||||
diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py
|
||||
index 57e7a9fd4..be6854af8 100644
|
||||
--- a/src/lib389/lib389/instance/setup.py
|
||||
+++ b/src/lib389/lib389/instance/setup.py
|
||||
@@ -732,10 +732,6 @@ class SetupDs(object):
|
||||
dse += line.replace('%', '{', 1).replace('%', '}', 1)
|
||||
|
||||
with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:
|
||||
- if os.path.exists(os.path.dirname(slapd['ldapi'])):
|
||||
- ldapi_path = slapd['ldapi']
|
||||
- else:
|
||||
- ldapi_path = os.path.join(slapd['run_dir'], "slapd-%s.socket" % slapd['instance_name'])
|
||||
dse_fmt = dse.format(
|
||||
schema_dir=slapd['schema_dir'],
|
||||
lock_dir=slapd['lock_dir'],
|
||||
@@ -759,7 +755,7 @@ class SetupDs(object):
|
||||
db_dir=slapd['db_dir'],
|
||||
db_home_dir=slapd['db_home_dir'],
|
||||
ldapi_enabled="on",
|
||||
- ldapi=ldapi_path,
|
||||
+ ldapi=slapd['ldapi'],
|
||||
ldapi_autobind="on",
|
||||
)
|
||||
file_dse.write(dse_fmt)
|
||||
@@ -861,7 +857,7 @@ class SetupDs(object):
|
||||
SER_ROOT_PW: self._raw_secure_password,
|
||||
SER_DEPLOYED_DIR: slapd['prefix'],
|
||||
SER_LDAPI_ENABLED: 'on',
|
||||
- SER_LDAPI_SOCKET: ldapi_path,
|
||||
+ SER_LDAPI_SOCKET: slapd['ldapi'],
|
||||
SER_LDAPI_AUTOBIND: 'on'
|
||||
}
|
||||
|
||||
@@ -905,13 +901,10 @@ class SetupDs(object):
|
||||
self.log.info("Perform SELinux labeling ...")
|
||||
selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
|
||||
'ldif_dir', 'lock_dir', 'log_dir', 'db_home_dir',
|
||||
- 'schema_dir', 'tmp_dir')
|
||||
+ 'run_dir', 'schema_dir', 'tmp_dir')
|
||||
for path in selinux_paths:
|
||||
selinux_restorecon(slapd[path])
|
||||
|
||||
- # Don't run restorecon on the entire /run directory
|
||||
- selinux_restorecon(slapd['run_dir'] + '/dirsrv')
|
||||
-
|
||||
selinux_label_port(slapd['port'])
|
||||
|
||||
# Start the server
|
||||
--
|
||||
2.31.1
|
||||
|
213
SOURCES/0007-CVE-2024-3657.patch
Normal file
213
SOURCES/0007-CVE-2024-3657.patch
Normal file
@ -0,0 +1,213 @@
|
||||
From d5bbe52fbe84a7d3b5938bf82d5c4af15061a8e2 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre Rogier <progier@redhat.com>
|
||||
Date: Wed, 17 Apr 2024 18:18:04 +0200
|
||||
Subject: [PATCH] CVE-2024-3657
|
||||
|
||||
---
|
||||
.../tests/suites/filter/large_filter_test.py | 34 +++++-
|
||||
ldap/servers/slapd/back-ldbm/index.c | 111 ++++++++++--------
|
||||
2 files changed, 92 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/filter/large_filter_test.py b/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
index ecc7bf979..40526bb16 100644
|
||||
--- a/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
+++ b/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
@@ -13,19 +13,29 @@ verify and testing Filter from a search
|
||||
|
||||
import os
|
||||
import pytest
|
||||
+import ldap
|
||||
|
||||
-from lib389._constants import PW_DM
|
||||
+from lib389._constants import PW_DM, DEFAULT_SUFFIX, ErrorLog
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.user import UserAccounts, UserAccount
|
||||
from lib389.idm.account import Accounts
|
||||
from lib389.backend import Backends
|
||||
from lib389.idm.domain import Domain
|
||||
+from lib389.utils import get_ldapurl_from_serverid
|
||||
|
||||
SUFFIX = 'dc=anuj,dc=com'
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
|
||||
+def open_new_ldapi_conn(dsinstance):
|
||||
+ ldapurl, certdir = get_ldapurl_from_serverid(dsinstance)
|
||||
+ assert 'ldapi://' in ldapurl
|
||||
+ conn = ldap.initialize(ldapurl)
|
||||
+ conn.sasl_interactive_bind_s("", ldap.sasl.external())
|
||||
+ return conn
|
||||
+
|
||||
+
|
||||
@pytest.fixture(scope="module")
|
||||
def _create_entries(request, topo):
|
||||
"""
|
||||
@@ -160,6 +170,28 @@ def test_large_filter(topo, _create_entries, real_value):
|
||||
assert len(Accounts(conn, SUFFIX).filter(real_value)) == 3
|
||||
|
||||
|
||||
+def test_long_filter_value(topo):
|
||||
+ """Exercise large eq filter with dn syntax attributes
|
||||
+
|
||||
+ :id: b069ef72-fcc3-11ee-981c-482ae39447e5
|
||||
+ :setup: Standalone
|
||||
+ :steps:
|
||||
+ 1. Try to pass filter rules as per the condition.
|
||||
+ :expectedresults:
|
||||
+ 1. Pass
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ conn = open_new_ldapi_conn(inst.serverid)
|
||||
+ inst.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.TRACE,ErrorLog.SEARCH_FILTER))
|
||||
+ filter_value = "a\x1Edmin" * 1025
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ filter_value = "aAdmin" * 1025
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ filter_value = "*"
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ inst.config.loglevel(vals=(ErrorLog.DEFAULT,))
|
||||
+
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main("-s -v %s" % CURRENT_FILE)
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
|
||||
index 410db23d1..30fa09ebb 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/index.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/index.c
|
||||
@@ -71,6 +71,32 @@ typedef struct _index_buffer_handle index_buffer_handle;
|
||||
#define INDEX_BUFFER_FLAG_SERIALIZE 1
|
||||
#define INDEX_BUFFER_FLAG_STATS 2
|
||||
|
||||
+/*
|
||||
+ * space needed to encode a byte:
|
||||
+ * 0x00-0x31 and 0x7f-0xff requires 3 bytes: \xx
|
||||
+ * 0x22 and 0x5C requires 2 bytes: \" and \\
|
||||
+ * other requires 1 byte: c
|
||||
+ */
|
||||
+static char encode_size[] = {
|
||||
+ /* 0x00 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x20 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
|
||||
+ /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
|
||||
+ /* 0x80 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x90 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xA0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xB0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xC0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xD0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xE0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xF0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* Index buffering functions */
|
||||
|
||||
static int
|
||||
@@ -799,65 +825,46 @@ index_add_mods(
|
||||
|
||||
/*
|
||||
* Convert a 'struct berval' into a displayable ASCII string
|
||||
+ * returns the printable string
|
||||
*/
|
||||
-
|
||||
-#define SPECIAL(c) (c < 32 || c > 126 || c == '\\' || c == '"')
|
||||
-
|
||||
const char *
|
||||
encode(const struct berval *data, char buf[BUFSIZ])
|
||||
{
|
||||
- char *s;
|
||||
- char *last;
|
||||
- if (data == NULL || data->bv_len == 0)
|
||||
- return "";
|
||||
- last = data->bv_val + data->bv_len - 1;
|
||||
- for (s = data->bv_val; s < last; ++s) {
|
||||
- if (SPECIAL(*s)) {
|
||||
- char *first = data->bv_val;
|
||||
- char *bufNext = buf;
|
||||
- size_t bufSpace = BUFSIZ - 4;
|
||||
- while (1) {
|
||||
- /* printf ("%lu bytes ASCII\n", (unsigned long)(s - first)); */
|
||||
- if (bufSpace < (size_t)(s - first))
|
||||
- s = first + bufSpace - 1;
|
||||
- if (s != first) {
|
||||
- memcpy(bufNext, first, s - first);
|
||||
- bufNext += (s - first);
|
||||
- bufSpace -= (s - first);
|
||||
- }
|
||||
- do {
|
||||
- if (bufSpace) {
|
||||
- *bufNext++ = '\\';
|
||||
- --bufSpace;
|
||||
- }
|
||||
- if (bufSpace < 2) {
|
||||
- memcpy(bufNext, "..", 2);
|
||||
- bufNext += 2;
|
||||
- goto bail;
|
||||
- }
|
||||
- if (*s == '\\' || *s == '"') {
|
||||
- *bufNext++ = *s;
|
||||
- --bufSpace;
|
||||
- } else {
|
||||
- sprintf(bufNext, "%02x", (unsigned)*(unsigned char *)s);
|
||||
- bufNext += 2;
|
||||
- bufSpace -= 2;
|
||||
- }
|
||||
- } while (++s <= last && SPECIAL(*s));
|
||||
- if (s > last)
|
||||
- break;
|
||||
- first = s;
|
||||
- while (!SPECIAL(*s) && s <= last)
|
||||
- ++s;
|
||||
- }
|
||||
- bail:
|
||||
- *bufNext = '\0';
|
||||
- /* printf ("%lu chars in buffer\n", (unsigned long)(bufNext - buf)); */
|
||||
+ if (!data || !data->bv_val) {
|
||||
+ strcpy(buf, "<NULL>");
|
||||
+ return buf;
|
||||
+ }
|
||||
+ char *endbuff = &buf[BUFSIZ-4]; /* Reserve space to append "...\0" */
|
||||
+ char *ptout = buf;
|
||||
+ unsigned char *ptin = (unsigned char*) data->bv_val;
|
||||
+ unsigned char *endptin = ptin+data->bv_len;
|
||||
+
|
||||
+ while (ptin < endptin) {
|
||||
+ if (ptout >= endbuff) {
|
||||
+ /*
|
||||
+ * BUFSIZ(8K) > SLAPI_LOG_BUFSIZ(2K) so the error log message will be
|
||||
+ * truncated anyway. So there is no real interrest to test if the original
|
||||
+ * data contains no special characters and return it as is.
|
||||
+ */
|
||||
+ strcpy(endbuff, "...");
|
||||
return buf;
|
||||
}
|
||||
+ switch (encode_size[*ptin]) {
|
||||
+ case 1:
|
||||
+ *ptout++ = *ptin++;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ *ptout++ = '\\';
|
||||
+ *ptout++ = *ptin++;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ sprintf(ptout, "\\%02x", *ptin++);
|
||||
+ ptout += 3;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- /* printf ("%lu bytes, all ASCII\n", (unsigned long)(s - data->bv_val)); */
|
||||
- return data->bv_val;
|
||||
+ *ptout = 0;
|
||||
+ return buf;
|
||||
}
|
||||
|
||||
static const char *
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,70 +0,0 @@
|
||||
From c26c463ac92682dcf01ddbdc11cc1109b183eb0a Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 1 Nov 2021 16:04:28 -0400
|
||||
Subject: [PATCH 07/12] Issue 4973 - update snmp to use /run/dirsrv for PID
|
||||
file
|
||||
|
||||
Description: Previously SNMP would write the agent PID file directly
|
||||
under /run (or /var/run), but this broke a CI test after
|
||||
updating lib389/defaults.inf to use /run/dirsrv.
|
||||
|
||||
Instead of hacking the CI test, I changed the path
|
||||
snmp uses to: /run/dirsrv/ Which is where it
|
||||
should really be written anyway.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4973
|
||||
|
||||
Reviewed by: vashirov(Thanks!)
|
||||
---
|
||||
ldap/servers/snmp/main.c | 4 ++--
|
||||
wrappers/systemd-snmp.service.in | 6 +++---
|
||||
2 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/snmp/main.c b/ldap/servers/snmp/main.c
|
||||
index e6271a8a9..d8eb918f6 100644
|
||||
--- a/ldap/servers/snmp/main.c
|
||||
+++ b/ldap/servers/snmp/main.c
|
||||
@@ -287,14 +287,14 @@ load_config(char *conf_path)
|
||||
}
|
||||
|
||||
/* set pidfile path */
|
||||
- if ((pidfile = malloc(strlen(LOCALRUNDIR) + strlen("/") +
|
||||
+ if ((pidfile = malloc(strlen(LOCALRUNDIR) + strlen("/dirsrv/") +
|
||||
strlen(LDAP_AGENT_PIDFILE) + 1)) != NULL) {
|
||||
strncpy(pidfile, LOCALRUNDIR, strlen(LOCALRUNDIR) + 1);
|
||||
/* The above will likely not be NULL terminated, but we need to
|
||||
* be sure that we're properly NULL terminated for the below
|
||||
* strcat() to work properly. */
|
||||
pidfile[strlen(LOCALRUNDIR)] = (char)0;
|
||||
- strcat(pidfile, "/");
|
||||
+ strcat(pidfile, "/dirsrv/");
|
||||
strcat(pidfile, LDAP_AGENT_PIDFILE);
|
||||
} else {
|
||||
printf("ldap-agent: malloc error processing config file\n");
|
||||
diff --git a/wrappers/systemd-snmp.service.in b/wrappers/systemd-snmp.service.in
|
||||
index 477bc623d..f18766cb4 100644
|
||||
--- a/wrappers/systemd-snmp.service.in
|
||||
+++ b/wrappers/systemd-snmp.service.in
|
||||
@@ -1,7 +1,7 @@
|
||||
# do not edit this file in /lib/systemd/system - instead do the following:
|
||||
# cp /lib/systemd/system/dirsrv-snmp.service /etc/systemd/system/
|
||||
# edit /etc/systemd/system/dirsrv-snmp.service
|
||||
-# systemctl daemon-reload
|
||||
+# systemctl daemon-reload
|
||||
# systemctl (re)start dirsrv-snmp.service
|
||||
[Unit]
|
||||
Description=@capbrand@ Directory Server SNMP Subagent.
|
||||
@@ -9,8 +9,8 @@ After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
-PIDFile=/run/ldap-agent.pid
|
||||
-ExecStart=@sbindir@/ldap-agent @configdir@/ldap-agent.conf
|
||||
+PIDFile=/run/dirsrv/ldap-agent.pid
|
||||
+ExecStart=@sbindir@/ldap-agent @configdir@/ldap-agent.conf
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,70 +0,0 @@
|
||||
From 88d6ceb18e17c5a18bafb5092ae0c22241b212df Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 1 Nov 2021 14:01:11 -0400
|
||||
Subject: [PATCH 08/12] Issue 4978 - make installer robust
|
||||
|
||||
Description: When run in a container the server can fail to start
|
||||
because the installer sets the db_home_dir to /dev/shm,
|
||||
but in containers the default size of /dev/shm is too
|
||||
small for libdb. We should detect if we are in a
|
||||
container and not set db_home_dir to /dev/shm.
|
||||
|
||||
During instance removal, if an instance was not properly
|
||||
created then it can not be removed either. Make the
|
||||
uninstall more robust to accept some errors and continue
|
||||
removing the instance.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4978
|
||||
|
||||
Reviewed by: firstyear & tbordaz(Thanks!)
|
||||
---
|
||||
src/lib389/lib389/instance/setup.py | 9 +++++++++
|
||||
src/lib389/lib389/utils.py | 5 ++++-
|
||||
2 files changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py
|
||||
index be6854af8..7b0147cf9 100644
|
||||
--- a/src/lib389/lib389/instance/setup.py
|
||||
+++ b/src/lib389/lib389/instance/setup.py
|
||||
@@ -731,6 +731,15 @@ class SetupDs(object):
|
||||
for line in template_dse.readlines():
|
||||
dse += line.replace('%', '{', 1).replace('%', '}', 1)
|
||||
|
||||
+ # Check if we are in a container, if so don't use /dev/shm for the db home dir
|
||||
+ # as containers typically don't allocate enough space for dev/shm and we don't
|
||||
+ # want to unexpectedly break the server after an upgrade
|
||||
+ container_result = subprocess.run(["systemd-detect-virt", "-c"], capture_output=True)
|
||||
+ if container_result.returncode == 0:
|
||||
+ # In a container, set the db_home_dir to the db path
|
||||
+ self.log.debug("Container detected setting db home directory to db directory.")
|
||||
+ slapd['db_home_dir'] = slapd['db_dir']
|
||||
+
|
||||
with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:
|
||||
dse_fmt = dse.format(
|
||||
schema_dir=slapd['schema_dir'],
|
||||
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
|
||||
index 5ba0c6676..c63b4d0ee 100644
|
||||
--- a/src/lib389/lib389/utils.py
|
||||
+++ b/src/lib389/lib389/utils.py
|
||||
@@ -266,6 +266,8 @@ def selinux_label_port(port, remove_label=False):
|
||||
:type remove_label: boolean
|
||||
:raises: ValueError: Error message
|
||||
"""
|
||||
+ if port is None:
|
||||
+ return
|
||||
try:
|
||||
import selinux
|
||||
except ImportError:
|
||||
@@ -662,7 +664,8 @@ def isLocalHost(host_name):
|
||||
Uses gethostbyname()
|
||||
"""
|
||||
# first see if this is a "well known" local hostname
|
||||
- if host_name == 'localhost' or \
|
||||
+ if host_name is None or \
|
||||
+ host_name == 'localhost' or \
|
||||
host_name == 'localhost.localdomain' or \
|
||||
host_name == socket.gethostname():
|
||||
return True
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,143 @@
|
||||
From 6e5f03d5872129963106024f53765234a282406c Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Fri, 16 Feb 2024 11:13:16 +0000
|
||||
Subject: [PATCH] Issue 6096 - Improve connection timeout error logging (#6097)
|
||||
|
||||
Bug description: When a paged result search is run with a time limit,
|
||||
if the time limit is exceed the server closes the connection with
|
||||
closed IO timeout (nsslapd-ioblocktimeout) - T2. This error message
|
||||
is incorrect as the reason the connection has been closed was because
|
||||
the specified time limit on a paged result search has been exceeded.
|
||||
|
||||
Fix description: Correct error message
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6096
|
||||
|
||||
Reviewed by: @tbordaz (Thank you)
|
||||
---
|
||||
ldap/admin/src/logconv.pl | 24 ++++++++++++++++++-
|
||||
ldap/servers/slapd/daemon.c | 4 ++--
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 1 +
|
||||
ldap/servers/slapd/disconnect_errors.h | 2 +-
|
||||
4 files changed, 27 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl
|
||||
index 7698c383a..2a933c4a3 100755
|
||||
--- a/ldap/admin/src/logconv.pl
|
||||
+++ b/ldap/admin/src/logconv.pl
|
||||
@@ -267,7 +267,7 @@ my $optimeAvg = 0;
|
||||
my %cipher = ();
|
||||
my @removefiles = ();
|
||||
|
||||
-my @conncodes = qw(A1 B1 B4 T1 T2 B2 B3 R1 P1 P2 U1);
|
||||
+my @conncodes = qw(A1 B1 B4 T1 T2 T3 B2 B3 R1 P1 P2 U1);
|
||||
my %conn = ();
|
||||
map {$conn{$_} = $_} @conncodes;
|
||||
|
||||
@@ -355,6 +355,7 @@ $connmsg{"B1"} = "Bad Ber Tag Encountered";
|
||||
$connmsg{"B4"} = "Server failed to flush data (response) back to Client";
|
||||
$connmsg{"T1"} = "Idle Timeout Exceeded";
|
||||
$connmsg{"T2"} = "IO Block Timeout Exceeded or NTSSL Timeout";
|
||||
+$connmsg{"T3"} = "Paged Search Time Limit Exceeded";
|
||||
$connmsg{"B2"} = "Ber Too Big";
|
||||
$connmsg{"B3"} = "Ber Peek";
|
||||
$connmsg{"R1"} = "Revents";
|
||||
@@ -1723,6 +1724,10 @@ if ($usage =~ /j/i || $verb eq "yes"){
|
||||
print "\n $recCount. You have some coonections that are being closed by the ioblocktimeout setting. You may want to increase the ioblocktimeout.\n";
|
||||
$recCount++;
|
||||
}
|
||||
+ if (defined($conncount->{"T3"}) and $conncount->{"T3"} > 0){
|
||||
+ print "\n $recCount. You have some connections that are being closed because a paged result search limit has been exceeded. You may want to increase the search time limit.\n";
|
||||
+ $recCount++;
|
||||
+ }
|
||||
# compare binds to unbinds, if the difference is more than 30% of the binds, then report a issue
|
||||
if (($bindCount - $unbindCount) > ($bindCount*.3)){
|
||||
print "\n $recCount. You have a significant difference between binds and unbinds. You may want to investigate this difference.\n";
|
||||
@@ -2366,6 +2371,7 @@ sub parseLineNormal
|
||||
$brokenPipeCount++;
|
||||
if (m/- T1/){ $hashes->{rc}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{rc}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{rc}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{rc}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{rc}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{rc}->{"B4"}++; }
|
||||
@@ -2381,6 +2387,7 @@ sub parseLineNormal
|
||||
$connResetByPeerCount++;
|
||||
if (m/- T1/){ $hashes->{src}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{src}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{src}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{src}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{src}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{src}->{"B4"}++; }
|
||||
@@ -2396,6 +2403,7 @@ sub parseLineNormal
|
||||
$resourceUnavailCount++;
|
||||
if (m/- T1/){ $hashes->{rsrc}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{rsrc}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{rsrc}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{rsrc}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{rsrc}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{rsrc}->{"B4"}++; }
|
||||
@@ -2494,6 +2502,20 @@ sub parseLineNormal
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (m/- T3/){
|
||||
+ if ($_ =~ /conn= *([0-9A-Z]+)/i) {
|
||||
+ $exc = "no";
|
||||
+ $ip = getIPfromConn($1, $serverRestartCount);
|
||||
+ for (my $xxx = 0; $xxx < $#excludeIP; $xxx++){
|
||||
+ if ($ip eq $excludeIP[$xxx]){$exc = "yes";}
|
||||
+ }
|
||||
+ if ($exc ne "yes"){
|
||||
+ $hashes->{T3}->{$ip}++;
|
||||
+ $hashes->{conncount}->{"T3"}++;
|
||||
+ $connCodeCount++;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
if (m/- B2/){
|
||||
if ($_ =~ /conn= *([0-9A-Z]+)/i) {
|
||||
$exc = "no";
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index 5a48aa66f..bb80dae36 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -1599,9 +1599,9 @@ setup_pr_read_pds(Connection_Table *ct)
|
||||
int add_fd = 1;
|
||||
/* check timeout for PAGED RESULTS */
|
||||
if (pagedresults_is_timedout_nolock(c)) {
|
||||
- /* Exceeded the timelimit; disconnect the client */
|
||||
+ /* Exceeded the paged search timelimit; disconnect the client */
|
||||
disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
- SLAPD_DISCONNECT_IO_TIMEOUT,
|
||||
+ SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT,
|
||||
0);
|
||||
connection_table_move_connection_out_of_active_list(ct,
|
||||
c);
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index f7a31d728..c2d9e283b 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -27,6 +27,7 @@ ER2(SLAPD_DISCONNECT_BER_FLUSH, "B4")
|
||||
ER2(SLAPD_DISCONNECT_IDLE_TIMEOUT, "T1")
|
||||
ER2(SLAPD_DISCONNECT_REVENTS, "R1")
|
||||
ER2(SLAPD_DISCONNECT_IO_TIMEOUT, "T2")
|
||||
+ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
ER2(SLAPD_DISCONNECT_PLUGIN, "P1")
|
||||
ER2(SLAPD_DISCONNECT_UNBIND, "U1")
|
||||
ER2(SLAPD_DISCONNECT_POLL, "P2")
|
||||
diff --git a/ldap/servers/slapd/disconnect_errors.h b/ldap/servers/slapd/disconnect_errors.h
|
||||
index a0484f1c2..e118f674c 100644
|
||||
--- a/ldap/servers/slapd/disconnect_errors.h
|
||||
+++ b/ldap/servers/slapd/disconnect_errors.h
|
||||
@@ -35,6 +35,6 @@
|
||||
#define SLAPD_DISCONNECT_SASL_FAIL SLAPD_DISCONNECT_ERROR_BASE + 12
|
||||
#define SLAPD_DISCONNECT_PROXY_INVALID_HEADER SLAPD_DISCONNECT_ERROR_BASE + 13
|
||||
#define SLAPD_DISCONNECT_PROXY_UNKNOWN SLAPD_DISCONNECT_ERROR_BASE + 14
|
||||
-
|
||||
+#define SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT SLAPD_DISCONNECT_ERROR_BASE + 15
|
||||
|
||||
#endif /* __DISCONNECT_ERRORS_H_ */
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,468 +0,0 @@
|
||||
From 2ae2f53756b6f13e2816bb30812740cb7ad97403 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Fri, 5 Nov 2021 09:56:43 +0100
|
||||
Subject: [PATCH 09/12] Issue 4972 - gecos with IA5 introduces a compatibility
|
||||
issue with previous (#4981)
|
||||
|
||||
releases where it was DirectoryString
|
||||
|
||||
Bug description:
|
||||
For years 'gecos' was DirectoryString (UTF8), with #50933 it was restricted to IA5 (ascii)
|
||||
https://github.com/389ds/389-ds-base/commit/0683bcde1b667b6d0ca6e8d1ef605f17c51ea2f7#
|
||||
|
||||
IA5 definition conforms rfc2307 but is a problem for existing deployments
|
||||
where entries can have 'gecos' attribute value with UTF8.
|
||||
|
||||
Fix description:
|
||||
Revert the definition to of 'gecos' being Directory String
|
||||
|
||||
Additional fix to make test_replica_backup_and_restore more
|
||||
robust to CI
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4972
|
||||
|
||||
Reviewed by: William Brown, Pierre Rogier, James Chapman (Thanks !)
|
||||
|
||||
Platforms tested: F34
|
||||
---
|
||||
.../tests/suites/schema/schema_test.py | 398 +++++++++++++++++-
|
||||
ldap/schema/10rfc2307compat.ldif | 6 +-
|
||||
2 files changed, 400 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/schema/schema_test.py b/dirsrvtests/tests/suites/schema/schema_test.py
|
||||
index d590624b6..5d62b8d59 100644
|
||||
--- a/dirsrvtests/tests/suites/schema/schema_test.py
|
||||
+++ b/dirsrvtests/tests/suites/schema/schema_test.py
|
||||
@@ -18,8 +18,12 @@ import pytest
|
||||
import six
|
||||
from ldap.cidict import cidict
|
||||
from ldap.schema import SubSchema
|
||||
+from lib389.schema import SchemaLegacy
|
||||
from lib389._constants import *
|
||||
-from lib389.topologies import topology_st
|
||||
+from lib389.topologies import topology_st, topology_m2 as topo_m2
|
||||
+from lib389.idm.user import UserAccounts, UserAccount
|
||||
+from lib389.replica import ReplicationManager
|
||||
+from lib389.utils import ensure_bytes
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
@@ -165,6 +169,398 @@ def test_schema_comparewithfiles(topology_st):
|
||||
|
||||
log.info('test_schema_comparewithfiles: PASSED')
|
||||
|
||||
+def test_gecos_directoryString(topology_st):
|
||||
+ """Check that gecos supports directoryString value
|
||||
+
|
||||
+ :id: aee422bb-6299-4124-b5cd-d7393dac19d3
|
||||
+
|
||||
+ :setup: Standalone instance
|
||||
+
|
||||
+ :steps:
|
||||
+ 1. Add a common user
|
||||
+ 2. replace gecos with a direstoryString value
|
||||
+
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ """
|
||||
+
|
||||
+ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
|
||||
+
|
||||
+ user_properties = {
|
||||
+ 'uid': 'testuser',
|
||||
+ 'cn' : 'testuser',
|
||||
+ 'sn' : 'user',
|
||||
+ 'uidNumber' : '1000',
|
||||
+ 'gidNumber' : '2000',
|
||||
+ 'homeDirectory' : '/home/testuser',
|
||||
+ }
|
||||
+ testuser = users.create(properties=user_properties)
|
||||
+
|
||||
+ # Add a gecos UTF value
|
||||
+ testuser.replace('gecos', 'Hélène')
|
||||
+
|
||||
+def test_gecos_mixed_definition_topo(topo_m2, request):
|
||||
+ """Check that replication is still working if schema contains
|
||||
+ definitions that does not conform with a replicated entry
|
||||
+
|
||||
+ :id: d5940e71-d18a-4b71-aaf7-b9185361fffe
|
||||
+ :setup: Two suppliers replication setup
|
||||
+ :steps:
|
||||
+ 1. Create a testuser on M1
|
||||
+ 2 Stop M1 and M2
|
||||
+ 3 Change gecos def on M2 to be IA5
|
||||
+ 4 Update testuser with gecos directoryString value
|
||||
+ 5 Check replication is still working
|
||||
+ :expectedresults:
|
||||
+ 1. success
|
||||
+ 2. success
|
||||
+ 3. success
|
||||
+ 4. success
|
||||
+ 5. success
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
+ m1 = topo_m2.ms["supplier1"]
|
||||
+ m2 = topo_m2.ms["supplier2"]
|
||||
+
|
||||
+
|
||||
+ # create a test user
|
||||
+ testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
|
||||
+ testuser = UserAccount(m1, testuser_dn)
|
||||
+ try:
|
||||
+ testuser.create(properties={
|
||||
+ 'uid': 'testuser',
|
||||
+ 'cn': 'testuser',
|
||||
+ 'sn': 'testuser',
|
||||
+ 'uidNumber' : '1000',
|
||||
+ 'gidNumber' : '2000',
|
||||
+ 'homeDirectory' : '/home/testuser',
|
||||
+ })
|
||||
+ except ldap.ALREADY_EXISTS:
|
||||
+ pass
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # Stop suppliers to update the schema
|
||||
+ m1.stop()
|
||||
+ m2.stop()
|
||||
+
|
||||
+ # on M1: gecos is DirectoryString (default)
|
||||
+ # on M2: gecos is IA5
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
|
||||
+ "'gecos' DESC 'The GECOS field; the common name' " +
|
||||
+ "EQUALITY caseIgnoreIA5Match " +
|
||||
+ "SUBSTR caseIgnoreIA5SubstringsMatch " +
|
||||
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
|
||||
+ "SINGLE-VALUE )\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+
|
||||
+ # start the instances
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+
|
||||
+ # Check that gecos is IA5 on M2
|
||||
+ schema = SchemaLegacy(m2)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
|
||||
+
|
||||
+
|
||||
+ # Add a gecos UTF value on M1
|
||||
+ testuser.replace('gecos', 'Hélène')
|
||||
+
|
||||
+ # Check replication is still working
|
||||
+ testuser.replace('displayName', 'ascii value')
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+ testuser_m2 = UserAccount(m2, testuser_dn)
|
||||
+ assert testuser_m2.exists()
|
||||
+ assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
|
||||
+
|
||||
+ def fin():
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+ testuser.delete()
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # on M2 restore a default 99user.ldif
|
||||
+ m2.stop()
|
||||
+ os.remove(m2.schemadir + "/99user.ldif")
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+ m2.start()
|
||||
+ m1.start()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+def test_gecos_directoryString_wins_M1(topo_m2, request):
|
||||
+ """Check that if inital syntax are IA5(M2) and DirectoryString(M1)
|
||||
+ Then directoryString wins when nsSchemaCSN M1 is the greatest
|
||||
+
|
||||
+ :id: ad119fa5-7671-45c8-b2ef-0b28ffb68fdb
|
||||
+ :setup: Two suppliers replication setup
|
||||
+ :steps:
|
||||
+ 1. Create a testuser on M1
|
||||
+ 2 Stop M1 and M2
|
||||
+ 3 Change gecos def on M2 to be IA5
|
||||
+ 4 Start M1 and M2
|
||||
+ 5 Update M1 schema so that M1 has greatest nsSchemaCSN
|
||||
+ 6 Update testuser with gecos directoryString value
|
||||
+ 7 Check replication is still working
|
||||
+ 8 Check gecos is DirectoryString on M1 and M2
|
||||
+ :expectedresults:
|
||||
+ 1. success
|
||||
+ 2. success
|
||||
+ 3. success
|
||||
+ 4. success
|
||||
+ 5. success
|
||||
+ 6. success
|
||||
+ 7. success
|
||||
+ 8. success
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
+ m1 = topo_m2.ms["supplier1"]
|
||||
+ m2 = topo_m2.ms["supplier2"]
|
||||
+
|
||||
+
|
||||
+ # create a test user
|
||||
+ testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
|
||||
+ testuser = UserAccount(m1, testuser_dn)
|
||||
+ try:
|
||||
+ testuser.create(properties={
|
||||
+ 'uid': 'testuser',
|
||||
+ 'cn': 'testuser',
|
||||
+ 'sn': 'testuser',
|
||||
+ 'uidNumber' : '1000',
|
||||
+ 'gidNumber' : '2000',
|
||||
+ 'homeDirectory' : '/home/testuser',
|
||||
+ })
|
||||
+ except ldap.ALREADY_EXISTS:
|
||||
+ pass
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # Stop suppliers to update the schema
|
||||
+ m1.stop()
|
||||
+ m2.stop()
|
||||
+
|
||||
+ # on M1: gecos is DirectoryString (default)
|
||||
+ # on M2: gecos is IA5
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
|
||||
+ "'gecos' DESC 'The GECOS field; the common name' " +
|
||||
+ "EQUALITY caseIgnoreIA5Match " +
|
||||
+ "SUBSTR caseIgnoreIA5SubstringsMatch " +
|
||||
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
|
||||
+ "SINGLE-VALUE )\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+
|
||||
+ # start the instances
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+
|
||||
+ # Check that gecos is IA5 on M2
|
||||
+ schema = SchemaLegacy(m2)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
|
||||
+
|
||||
+
|
||||
+ # update M1 schema to increase its nsschemaCSN
|
||||
+ new_at = "( dummy-oid NAME 'dummy' DESC 'dummy attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )"
|
||||
+ m1.schema.add_schema('attributetypes', ensure_bytes(new_at))
|
||||
+
|
||||
+ # Add a gecos UTF value on M1
|
||||
+ testuser.replace('gecos', 'Hélène')
|
||||
+
|
||||
+ # Check replication is still working
|
||||
+ testuser.replace('displayName', 'ascii value')
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+ testuser_m2 = UserAccount(m2, testuser_dn)
|
||||
+ assert testuser_m2.exists()
|
||||
+ assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
|
||||
+
|
||||
+ # Check that gecos is DirectoryString on M1
|
||||
+ schema = SchemaLegacy(m1)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
|
||||
+
|
||||
+ # Check that gecos is DirectoryString on M2
|
||||
+ schema = SchemaLegacy(m2)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
|
||||
+
|
||||
+ def fin():
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+ testuser.delete()
|
||||
+ m1.schema.del_schema('attributetypes', ensure_bytes(new_at))
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # on M2 restore a default 99user.ldif
|
||||
+ m2.stop()
|
||||
+ os.remove(m2.schemadir + "/99user.ldif")
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+ m2.start()
|
||||
+ m1.start()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+def test_gecos_directoryString_wins_M2(topo_m2, request):
|
||||
+ """Check that if inital syntax are IA5(M2) and DirectoryString(M1)
|
||||
+ Then directoryString wins when nsSchemaCSN M2 is the greatest
|
||||
+
|
||||
+ :id: 2da7f1b1-f86d-4072-a940-ba56d4bc8348
|
||||
+ :setup: Two suppliers replication setup
|
||||
+ :steps:
|
||||
+ 1. Create a testuser on M1
|
||||
+ 2 Stop M1 and M2
|
||||
+ 3 Change gecos def on M2 to be IA5
|
||||
+ 4 Start M1 and M2
|
||||
+ 5 Update M2 schema so that M2 has greatest nsSchemaCSN
|
||||
+ 6 Update testuser on M2 and trigger replication to M1
|
||||
+ 7 Update testuser on M2 with gecos directoryString value
|
||||
+ 8 Check replication is still working
|
||||
+ 9 Check gecos is DirectoryString on M1 and M2
|
||||
+ :expectedresults:
|
||||
+ 1. success
|
||||
+ 2. success
|
||||
+ 3. success
|
||||
+ 4. success
|
||||
+ 5. success
|
||||
+ 6. success
|
||||
+ 7. success
|
||||
+ 8. success
|
||||
+ 9. success
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
+ m1 = topo_m2.ms["supplier1"]
|
||||
+ m2 = topo_m2.ms["supplier2"]
|
||||
+
|
||||
+
|
||||
+ # create a test user
|
||||
+ testuser_dn = 'uid={},{}'.format('testuser', DEFAULT_SUFFIX)
|
||||
+ testuser = UserAccount(m1, testuser_dn)
|
||||
+ try:
|
||||
+ testuser.create(properties={
|
||||
+ 'uid': 'testuser',
|
||||
+ 'cn': 'testuser',
|
||||
+ 'sn': 'testuser',
|
||||
+ 'uidNumber' : '1000',
|
||||
+ 'gidNumber' : '2000',
|
||||
+ 'homeDirectory' : '/home/testuser',
|
||||
+ })
|
||||
+ except ldap.ALREADY_EXISTS:
|
||||
+ pass
|
||||
+ testuser.replace('displayName', 'to trigger replication M1-> M2')
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # Stop suppliers to update the schema
|
||||
+ m1.stop()
|
||||
+ m2.stop()
|
||||
+
|
||||
+ # on M1: gecos is DirectoryString (default)
|
||||
+ # on M2: gecos is IA5
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ schema_file.write("attributetypes: ( 1.3.6.1.1.1.1.2 NAME " +
|
||||
+ "'gecos' DESC 'The GECOS field; the common name' " +
|
||||
+ "EQUALITY caseIgnoreIA5Match " +
|
||||
+ "SUBSTR caseIgnoreIA5SubstringsMatch " +
|
||||
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
|
||||
+ "SINGLE-VALUE )\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+
|
||||
+ # start the instances
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+
|
||||
+ # Check that gecos is IA5 on M2
|
||||
+ schema = SchemaLegacy(m2)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.26"
|
||||
+
|
||||
+ # update M2 schema to increase its nsschemaCSN
|
||||
+ new_at = "( dummy-oid NAME 'dummy' DESC 'dummy attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )"
|
||||
+ m2.schema.add_schema('attributetypes', ensure_bytes(new_at))
|
||||
+
|
||||
+ # update just to trigger replication M2->M1
|
||||
+ # and update of M2 schema
|
||||
+ testuser_m2 = UserAccount(m2, testuser_dn)
|
||||
+ testuser_m2.replace('displayName', 'to trigger replication M2-> M1')
|
||||
+
|
||||
+ # Add a gecos UTF value on M1
|
||||
+ testuser.replace('gecos', 'Hélène')
|
||||
+
|
||||
+ # Check replication is still working
|
||||
+ testuser.replace('displayName', 'ascii value')
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+ assert testuser_m2.exists()
|
||||
+ assert testuser_m2.get_attr_val_utf8('displayName') == 'ascii value'
|
||||
+
|
||||
+ # Check that gecos is DirectoryString on M1
|
||||
+ schema = SchemaLegacy(m1)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
|
||||
+
|
||||
+ # Check that gecos is DirectoryString on M2
|
||||
+ schema = SchemaLegacy(m2)
|
||||
+ attributetypes = schema.query_attributetype('gecos')
|
||||
+ assert attributetypes[0].syntax == "1.3.6.1.4.1.1466.115.121.1.15"
|
||||
+
|
||||
+ def fin():
|
||||
+ m1.start()
|
||||
+ m2.start()
|
||||
+ testuser.delete()
|
||||
+ m1.schema.del_schema('attributetypes', ensure_bytes(new_at))
|
||||
+ repl.wait_for_replication(m1, m2)
|
||||
+
|
||||
+ # on M2 restore a default 99user.ldif
|
||||
+ m2.stop()
|
||||
+ os.remove(m2.schemadir + "/99user.ldif")
|
||||
+ schema_filename = (m2.schemadir + "/99user.ldif")
|
||||
+ try:
|
||||
+ with open(schema_filename, 'w') as schema_file:
|
||||
+ schema_file.write("dn: cn=schema\n")
|
||||
+ os.chmod(schema_filename, 0o777)
|
||||
+ except OSError as e:
|
||||
+ log.fatal("Failed to update schema file: " +
|
||||
+ "{} Error: {}".format(schema_filename, str(e)))
|
||||
+ m2.start()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
diff --git a/ldap/schema/10rfc2307compat.ldif b/ldap/schema/10rfc2307compat.ldif
|
||||
index 8ba72e1e3..998b8983b 100644
|
||||
--- a/ldap/schema/10rfc2307compat.ldif
|
||||
+++ b/ldap/schema/10rfc2307compat.ldif
|
||||
@@ -21,9 +21,9 @@ attributeTypes: (
|
||||
attributeTypes: (
|
||||
1.3.6.1.1.1.1.2 NAME 'gecos'
|
||||
DESC 'The GECOS field; the common name'
|
||||
- EQUALITY caseIgnoreIA5Match
|
||||
- SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
+ EQUALITY caseIgnoreMatch
|
||||
+ SUBSTR caseIgnoreSubstringsMatch
|
||||
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE
|
||||
)
|
||||
attributeTypes: (
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,44 @@
|
||||
From a112394af3a20787755029804684d57a9c3ffa9a Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Wed, 21 Feb 2024 12:43:03 +0000
|
||||
Subject: [PATCH] Issue 6103 - New connection timeout error breaks errormap
|
||||
(#6104)
|
||||
|
||||
Bug description: A recent addition to the connection disconnect error
|
||||
messaging, conflicts with how errormap.c maps error codes/strings.
|
||||
|
||||
Fix description: errormap expects error codes/strings to be in ascending
|
||||
order. Moved the new error code to the bottom of the list.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6103
|
||||
|
||||
Reviewed by: @droideck. @progier389 (Thank you)
|
||||
---
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index c2d9e283b..f603a08ce 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -14,7 +14,8 @@
|
||||
/* disconnect_error_strings.h
|
||||
*
|
||||
* Strings describing the errors used in logging the reason a connection
|
||||
- * was closed.
|
||||
+ * was closed. Ensure definitions are in the same order as the error codes
|
||||
+ * defined in disconnect_errors.h
|
||||
*/
|
||||
#ifndef __DISCONNECT_ERROR_STRINGS_H_
|
||||
#define __DISCONNECT_ERROR_STRINGS_H_
|
||||
@@ -35,6 +36,6 @@ ER2(SLAPD_DISCONNECT_NTSSL_TIMEOUT, "T2")
|
||||
ER2(SLAPD_DISCONNECT_SASL_FAIL, "S1")
|
||||
ER2(SLAPD_DISCONNECT_PROXY_INVALID_HEADER, "P3")
|
||||
ER2(SLAPD_DISCONNECT_PROXY_UNKNOWN, "P4")
|
||||
-
|
||||
+ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
|
||||
#endif /* __DISCONNECT_ERROR_STRINGS_H_ */
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 3909877f12e50556e844bc20e72870a4fa905ada Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Tue, 9 Nov 2021 12:55:28 +0000
|
||||
Subject: [PATCH 10/12] Issue 4997 - Function declaration compiler error on
|
||||
1.4.3
|
||||
|
||||
Bug description: Building the server on the 1.4.3 branch generates a
|
||||
compiler error due to a typo in function declaration.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/4997
|
||||
|
||||
Reviewed by: @jchapman (one line commit rule)
|
||||
---
|
||||
ldap/servers/slapd/slapi-private.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
|
||||
index 570765e47..d6d74e8a7 100644
|
||||
--- a/ldap/servers/slapd/slapi-private.h
|
||||
+++ b/ldap/servers/slapd/slapi-private.h
|
||||
@@ -273,7 +273,7 @@ void *csngen_register_callbacks(CSNGen *gen, GenCSNFn genFn, void *genArg, Abort
|
||||
void csngen_unregister_callbacks(CSNGen *gen, void *cookie);
|
||||
|
||||
/* debugging function */
|
||||
-void csngen_dump_state(const CSNGen *gen);
|
||||
+void csngen_dump_state(const CSNGen *gen, int severity);
|
||||
|
||||
/* this function tests csn generator */
|
||||
void csngen_test(void);
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,30 @@
|
||||
From edd9abc8901604dde1d739d87ca2906734d53dd3 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 13 Jun 2024 13:35:09 +0200
|
||||
Subject: [PATCH] Issue 6103 - New connection timeout error breaks errormap
|
||||
|
||||
Description:
|
||||
Remove duplicate SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT error code.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6103
|
||||
|
||||
Reviewed by: @tbordaz (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index f603a08ce..d49cc79a2 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -28,7 +28,6 @@ ER2(SLAPD_DISCONNECT_BER_FLUSH, "B4")
|
||||
ER2(SLAPD_DISCONNECT_IDLE_TIMEOUT, "T1")
|
||||
ER2(SLAPD_DISCONNECT_REVENTS, "R1")
|
||||
ER2(SLAPD_DISCONNECT_IO_TIMEOUT, "T2")
|
||||
-ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
ER2(SLAPD_DISCONNECT_PLUGIN, "P1")
|
||||
ER2(SLAPD_DISCONNECT_UNBIND, "U1")
|
||||
ER2(SLAPD_DISCONNECT_POLL, "P2")
|
||||
--
|
||||
2.45.0
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 60d570e52465b58167301f64792f5f85cbc85e20 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 10 Nov 2021 08:53:45 -0500
|
||||
Subject: [PATCH 11/12] Issue 4978 - use more portable python command for
|
||||
checking containers
|
||||
|
||||
Description: During the installation check for containers use arguments
|
||||
for subprocess.run() that work on all versions of python
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/4978
|
||||
|
||||
Reviewed by: mreynolds(one line commit rule)
|
||||
---
|
||||
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 7b0147cf9..b23d2deb8 100644
|
||||
--- a/src/lib389/lib389/instance/setup.py
|
||||
+++ b/src/lib389/lib389/instance/setup.py
|
||||
@@ -734,7 +734,7 @@ class SetupDs(object):
|
||||
# Check if we are in a container, if so don't use /dev/shm for the db home dir
|
||||
# as containers typically don't allocate enough space for dev/shm and we don't
|
||||
# want to unexpectedly break the server after an upgrade
|
||||
- container_result = subprocess.run(["systemd-detect-virt", "-c"], capture_output=True)
|
||||
+ container_result = subprocess.run(["systemd-detect-virt", "-c"], stdout=subprocess.PIPE)
|
||||
if container_result.returncode == 0:
|
||||
# In a container, set the db_home_dir to the db path
|
||||
self.log.debug("Container detected setting db home directory to db directory.")
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,220 @@
|
||||
From 8cf981c00ae18d3efaeb10819282cd991621e9a2 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 22 May 2024 11:29:05 +0200
|
||||
Subject: [PATCH] Issue 6172 - RFE: improve the performance of evaluation of
|
||||
filter component when tested against a large valueset (like group members)
|
||||
(#6173)
|
||||
|
||||
Bug description:
|
||||
Before returning an entry (to a SRCH) the server checks that the entry matches the SRCH filter.
|
||||
If a filter component (equality) is testing the value (ava) against a
|
||||
large valueset (like uniquemember values), it takes a long time because
|
||||
of the large number of values and required normalization of the values.
|
||||
This can be improved taking benefit of sorted valueset. Those sorted
|
||||
valueset were created to improve updates of large valueset (groups) but
|
||||
at that time not implemented in SRCH path.
|
||||
|
||||
Fix description:
|
||||
In case of LDAP_FILTER_EQUALITY component, the server can get
|
||||
benefit of the sorted valuearray.
|
||||
To limit the risk of regression, we use the sorted valuearray
|
||||
only for the DN syntax attribute. Indeed the sorted valuearray was
|
||||
designed for those type of attribute.
|
||||
With those two limitations, there is no need of a toggle and
|
||||
the call to plugin_call_syntax_filter_ava can be replaced by
|
||||
a call to slapi_valueset_find.
|
||||
In both cases, sorted valueset and plugin_call_syntax_filter_ava, ava and
|
||||
values are normalized.
|
||||
In sorted valueset, the values have been normalized to insert the index
|
||||
in the sorted array and then comparison is done on normalized values.
|
||||
In plugin_call_syntax_filter_ava, all values in valuearray (of valueset) are normalized
|
||||
before comparison.
|
||||
|
||||
relates: #6172
|
||||
|
||||
Reviewed by: Pierre Rogier, Simon Pichugin (Big Thanks !!!)
|
||||
---
|
||||
.../tests/suites/filter/filter_test.py | 125 ++++++++++++++++++
|
||||
ldap/servers/slapd/filterentry.c | 22 ++-
|
||||
2 files changed, 146 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/filter/filter_test.py b/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
index d6bfa5a3b..4baaf04a7 100644
|
||||
--- a/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
+++ b/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
@@ -9,7 +9,11 @@
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
+import time
|
||||
+from lib389.dirsrv_log import DirsrvAccessLog
|
||||
from lib389.tasks import *
|
||||
+from lib389.backend import Backends, Backend
|
||||
+from lib389.dbgen import dbgen_users, dbgen_groups
|
||||
from lib389.topologies import topology_st
|
||||
from lib389._constants import PASSWORD, DEFAULT_SUFFIX, DN_DM, SUFFIX
|
||||
from lib389.utils import *
|
||||
@@ -304,6 +308,127 @@ def test_extended_search(topology_st):
|
||||
ents = topology_st.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, myfilter)
|
||||
assert len(ents) == 1
|
||||
|
||||
+def test_match_large_valueset(topology_st):
|
||||
+ """Test that when returning a big number of entries
|
||||
+ and that we need to match the filter from a large valueset
|
||||
+ we get benefit to use the sorted valueset
|
||||
+
|
||||
+ :id: 7db5aa88-50e0-4c31-85dd-1d2072cb674c
|
||||
+
|
||||
+ :setup: Standalone instance
|
||||
+
|
||||
+ :steps:
|
||||
+ 1. Create a users and groups backends and tune them
|
||||
+ 2. Generate a test ldif (2k users and 1K groups with all users)
|
||||
+ 3. Import test ldif file using Offline import (ldif2db).
|
||||
+ 4. Prim the 'groups' entrycache with a "fast" search
|
||||
+ 5. Search the 'groups' with a difficult matching value
|
||||
+ 6. check that etime from step 5 is less than a second
|
||||
+
|
||||
+ :expectedresults:
|
||||
+ 1. Create a users and groups backends should PASS
|
||||
+ 2. Generate LDIF should PASS.
|
||||
+ 3. Offline import should PASS.
|
||||
+ 4. Priming should PASS.
|
||||
+ 5. Performance search should PASS.
|
||||
+ 6. Etime of performance search should PASS.
|
||||
+ """
|
||||
+
|
||||
+ log.info('Running test_match_large_valueset...')
|
||||
+ #
|
||||
+ # Test online/offline LDIF imports
|
||||
+ #
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.start()
|
||||
+ backends = Backends(inst)
|
||||
+ users_suffix = "ou=users,%s" % DEFAULT_SUFFIX
|
||||
+ users_backend = 'users'
|
||||
+ users_ldif = 'users_import.ldif'
|
||||
+ groups_suffix = "ou=groups,%s" % DEFAULT_SUFFIX
|
||||
+ groups_backend = 'groups'
|
||||
+ groups_ldif = 'groups_import.ldif'
|
||||
+ groups_entrycache = '200000000'
|
||||
+ users_number = 2000
|
||||
+ groups_number = 1000
|
||||
+
|
||||
+
|
||||
+ # For priming the cache we just want to be fast
|
||||
+ # taking the first value in the valueset is good
|
||||
+ # whether the valueset is sorted or not
|
||||
+ priming_user_rdn = "user0001"
|
||||
+
|
||||
+ # For performance testing, this is important to use
|
||||
+ # user1000 rather then user0001
|
||||
+ # Because user0001 is the first value in the valueset
|
||||
+ # whether we use the sorted valuearray or non sorted
|
||||
+ # valuearray the performance will be similar.
|
||||
+ # With middle value user1000, the performance boost of
|
||||
+ # the sorted valuearray will make the difference.
|
||||
+ perf_user_rdn = "user1000"
|
||||
+
|
||||
+ # Step 1. Prepare the backends and tune the groups entrycache
|
||||
+ try:
|
||||
+ be_users = backends.create(properties={'parent': DEFAULT_SUFFIX, 'nsslapd-suffix': users_suffix, 'name': users_backend})
|
||||
+ be_groups = backends.create(properties={'parent': DEFAULT_SUFFIX, 'nsslapd-suffix': groups_suffix, 'name': groups_backend})
|
||||
+
|
||||
+ # set the entry cache to 200Mb as the 1K groups of 2K users require at least 170Mb
|
||||
+ be_groups.replace('nsslapd-cachememsize', groups_entrycache)
|
||||
+ except:
|
||||
+ raise
|
||||
+
|
||||
+ # Step 2. Generate a test ldif (10k users entries)
|
||||
+ log.info("Generating users LDIF...")
|
||||
+ ldif_dir = inst.get_ldif_dir()
|
||||
+ users_import_ldif = "%s/%s" % (ldif_dir, users_ldif)
|
||||
+ groups_import_ldif = "%s/%s" % (ldif_dir, groups_ldif)
|
||||
+ dbgen_users(inst, users_number, users_import_ldif, suffix=users_suffix, generic=True, parent=users_suffix)
|
||||
+
|
||||
+ # Generate a test ldif (800 groups with 10k members) that fit in 700Mb entry cache
|
||||
+ props = {
|
||||
+ "name": "group",
|
||||
+ "suffix": groups_suffix,
|
||||
+ "parent": groups_suffix,
|
||||
+ "number": groups_number,
|
||||
+ "numMembers": users_number,
|
||||
+ "createMembers": False,
|
||||
+ "memberParent": users_suffix,
|
||||
+ "membershipAttr": "uniquemember",
|
||||
+ }
|
||||
+ dbgen_groups(inst, groups_import_ldif, props)
|
||||
+
|
||||
+ # Step 3. Do the both offline imports
|
||||
+ inst.stop()
|
||||
+ if not inst.ldif2db(users_backend, None, None, None, users_import_ldif):
|
||||
+ log.fatal('test_basic_import_export: Offline users import failed')
|
||||
+ assert False
|
||||
+ if not inst.ldif2db(groups_backend, None, None, None, groups_import_ldif):
|
||||
+ log.fatal('test_basic_import_export: Offline groups import failed')
|
||||
+ assert False
|
||||
+ inst.start()
|
||||
+
|
||||
+ # Step 4. first prime the cache
|
||||
+ # Just request the 'DN'. We are interested by the time of matching not by the time of transfert
|
||||
+ entries = topology_st.standalone.search_s(groups_suffix, ldap.SCOPE_SUBTREE, "(&(objectclass=groupOfUniqueNames)(uniquemember=uid=%s,%s))" % (priming_user_rdn, users_suffix), ['dn'])
|
||||
+ assert len(entries) == groups_number
|
||||
+
|
||||
+ # Step 5. Now do the real performance checking it should take less than a second
|
||||
+ # Just request the 'DN'. We are interested by the time of matching not by the time of transfert
|
||||
+ search_start = time.time()
|
||||
+ entries = topology_st.standalone.search_s(groups_suffix, ldap.SCOPE_SUBTREE, "(&(objectclass=groupOfUniqueNames)(uniquemember=uid=%s,%s))" % (perf_user_rdn, users_suffix), ['dn'])
|
||||
+ duration = time.time() - search_start
|
||||
+ log.info("Duration of the search was %f", duration)
|
||||
+
|
||||
+ # Step 6. Gather the etime from the access log
|
||||
+ inst.stop()
|
||||
+ access_log = DirsrvAccessLog(inst)
|
||||
+ search_result = access_log.match(".*RESULT err=0 tag=101 nentries=%s.*" % groups_number)
|
||||
+ log.info("Found patterns are %s", search_result[0])
|
||||
+ log.info("Found patterns are %s", search_result[1])
|
||||
+ etime = float(search_result[1].split('etime=')[1])
|
||||
+ log.info("Duration of the search from access log was %f", etime)
|
||||
+ assert len(entries) == groups_number
|
||||
+ assert (etime < 1)
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/filterentry.c b/ldap/servers/slapd/filterentry.c
|
||||
index fd8fdda9f..cae5c7edc 100644
|
||||
--- a/ldap/servers/slapd/filterentry.c
|
||||
+++ b/ldap/servers/slapd/filterentry.c
|
||||
@@ -296,7 +296,27 @@ test_ava_filter(
|
||||
rc = -1;
|
||||
for (; a != NULL; a = a->a_next) {
|
||||
if (slapi_attr_type_cmp(ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE) == 0) {
|
||||
- rc = plugin_call_syntax_filter_ava(a, ftype, ava);
|
||||
+ if ((ftype == LDAP_FILTER_EQUALITY) &&
|
||||
+ (slapi_attr_is_dn_syntax_type(a->a_type))) {
|
||||
+ /* This path is for a performance improvement */
|
||||
+
|
||||
+ /* In case of equality filter we can get benefit of the
|
||||
+ * sorted valuearray (from valueset).
|
||||
+ * This improvement is limited to DN syntax attributes for
|
||||
+ * which the sorted valueset was designed.
|
||||
+ */
|
||||
+ Slapi_Value *sval = NULL;
|
||||
+ sval = slapi_value_new_berval(&ava->ava_value);
|
||||
+ if (slapi_valueset_find((const Slapi_Attr *)a, &a->a_present_values, sval)) {
|
||||
+ rc = 0;
|
||||
+ }
|
||||
+ slapi_value_free(&sval);
|
||||
+ } else {
|
||||
+ /* When sorted valuearray optimization cannot be used
|
||||
+ * lets filter the value according to its syntax
|
||||
+ */
|
||||
+ rc = plugin_call_syntax_filter_ava(a, ftype, ava);
|
||||
+ }
|
||||
if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,31 +0,0 @@
|
||||
From 2c6653edef793d46815e6df607e55d68e14fe232 Mon Sep 17 00:00:00 2001
|
||||
From: spike <spike@fedoraproject.org>
|
||||
Date: Fri, 5 Nov 2021 13:56:41 +0100
|
||||
Subject: [PATCH 12/12] Issue 4959 - Invalid /etc/hosts setup can cause
|
||||
isLocalHost to fail.
|
||||
|
||||
Description: Use local_simple_allocate in dsctl so that isLocal is always set properly
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/4959
|
||||
|
||||
Reviewed by: @droideck (Thanks!)
|
||||
---
|
||||
src/lib389/cli/dsctl | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl
|
||||
index b6c42b5cc..d2ea6cd29 100755
|
||||
--- a/src/lib389/cli/dsctl
|
||||
+++ b/src/lib389/cli/dsctl
|
||||
@@ -135,7 +135,7 @@ if __name__ == '__main__':
|
||||
log.error("Unable to access instance information. Are you running as the correct user? (usually dirsrv or root)")
|
||||
sys.exit(1)
|
||||
|
||||
- inst.allocate(insts[0])
|
||||
+ inst.local_simple_allocate(insts[0]['server-id'])
|
||||
log.debug('Instance allocated')
|
||||
|
||||
try:
|
||||
--
|
||||
2.31.1
|
||||
|
163
SOURCES/0012-Security-fix-for-CVE-2024-5953.patch
Normal file
163
SOURCES/0012-Security-fix-for-CVE-2024-5953.patch
Normal file
@ -0,0 +1,163 @@
|
||||
From 57051154bafaf50b83fc27dadbd89a49fd1c8c36 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre Rogier <progier@redhat.com>
|
||||
Date: Fri, 14 Jun 2024 13:27:10 +0200
|
||||
Subject: [PATCH] Security fix for CVE-2024-5953
|
||||
|
||||
Description:
|
||||
A denial of service vulnerability was found in the 389 Directory Server.
|
||||
This issue may allow an authenticated user to cause a server denial
|
||||
of service while attempting to log in with a user with a malformed hash
|
||||
in their password.
|
||||
|
||||
Fix Description:
|
||||
To prevent buffer overflow when a bind request is processed, the bind fails
|
||||
if the hash size is not coherent without even attempting to process further
|
||||
the hashed password.
|
||||
|
||||
References:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2024-5953
|
||||
- https://access.redhat.com/security/cve/CVE-2024-5953
|
||||
- https://bugzilla.redhat.com/show_bug.cgi?id=2292104
|
||||
---
|
||||
.../tests/suites/password/regression_test.py | 54 ++++++++++++++++++-
|
||||
ldap/servers/plugins/pwdstorage/md5_pwd.c | 9 +++-
|
||||
ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c | 6 +++
|
||||
3 files changed, 66 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/regression_test.py b/dirsrvtests/tests/suites/password/regression_test.py
|
||||
index 8f1facb6d..1fa581643 100644
|
||||
--- a/dirsrvtests/tests/suites/password/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/regression_test.py
|
||||
@@ -7,12 +7,14 @@
|
||||
#
|
||||
import pytest
|
||||
import time
|
||||
+import glob
|
||||
+import base64
|
||||
from lib389._constants import PASSWORD, DN_DM, DEFAULT_SUFFIX
|
||||
from lib389._constants import SUFFIX, PASSWORD, DN_DM, DN_CONFIG, PLUGIN_RETRO_CHANGELOG, DEFAULT_SUFFIX, DEFAULT_CHANGELOG_DB
|
||||
from lib389 import Entry
|
||||
from lib389.topologies import topology_m1 as topo_supplier
|
||||
-from lib389.idm.user import UserAccounts
|
||||
-from lib389.utils import ldap, os, logging, ensure_bytes, ds_is_newer
|
||||
+from lib389.idm.user import UserAccounts, UserAccount
|
||||
+from lib389.utils import ldap, os, logging, ensure_bytes, ds_is_newer, ds_supports_new_changelog
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
|
||||
@@ -39,6 +41,13 @@ TEST_PASSWORDS += ['CNpwtest1ZZZZ', 'ZZZZZCNpwtest1',
|
||||
TEST_PASSWORDS2 = (
|
||||
'CN12pwtest31', 'SN3pwtest231', 'UID1pwtest123', 'MAIL2pwtest12@redhat.com', '2GN1pwtest123', 'People123')
|
||||
|
||||
+SUPPORTED_SCHEMES = (
|
||||
+ "{SHA}", "{SSHA}", "{SHA256}", "{SSHA256}",
|
||||
+ "{SHA384}", "{SSHA384}", "{SHA512}", "{SSHA512}",
|
||||
+ "{crypt}", "{NS-MTA-MD5}", "{clear}", "{MD5}",
|
||||
+ "{SMD5}", "{PBKDF2_SHA256}", "{PBKDF2_SHA512}",
|
||||
+ "{GOST_YESCRYPT}", "{PBKDF2-SHA256}", "{PBKDF2-SHA512}" )
|
||||
+
|
||||
def _check_unhashed_userpw(inst, user_dn, is_present=False):
|
||||
"""Check if unhashed#user#password attribute is present or not in the changelog"""
|
||||
unhashed_pwd_attribute = 'unhashed#user#password'
|
||||
@@ -319,6 +328,47 @@ def test_unhashed_pw_switch(topo_supplier):
|
||||
# Add debugging steps(if any)...
|
||||
pass
|
||||
|
||||
+@pytest.mark.parametrize("scheme", SUPPORTED_SCHEMES )
|
||||
+def test_long_hashed_password(topo, create_user, scheme):
|
||||
+ """Check that hashed password with very long value does not cause trouble
|
||||
+
|
||||
+ :id: 252a1f76-114b-11ef-8a7a-482ae39447e5
|
||||
+ :setup: standalone Instance
|
||||
+ :parametrized: yes
|
||||
+ :steps:
|
||||
+ 1. Add a test user user
|
||||
+ 2. Set a long password with requested scheme
|
||||
+ 3. Bind on that user using a wrong password
|
||||
+ 4. Check that instance is still alive
|
||||
+ 5. Remove the added user
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Should get ldap.INVALID_CREDENTIALS exception
|
||||
+ 4. Success
|
||||
+ 5. Success
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ # Make sure that server is started as this test may crash it
|
||||
+ inst.start()
|
||||
+ # Adding Test user (It may already exists if previous test failed)
|
||||
+ user2 = UserAccount(inst, dn='uid=test_user_1002,ou=People,dc=example,dc=com')
|
||||
+ if not user2.exists():
|
||||
+ user2 = users.create_test_user(uid=1002, gid=2002)
|
||||
+ # Setting hashed password
|
||||
+ passwd = 'A'*4000
|
||||
+ hashed_passwd = scheme.encode('utf-8') + base64.b64encode(passwd.encode('utf-8'))
|
||||
+ user2.replace('userpassword', hashed_passwd)
|
||||
+ # Bind on that user using a wrong password
|
||||
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
||||
+ conn = user2.bind(PASSWORD)
|
||||
+ # Check that instance is still alive
|
||||
+ assert inst.status()
|
||||
+ # Remove the added user
|
||||
+ user2.delete()
|
||||
+
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
diff --git a/ldap/servers/plugins/pwdstorage/md5_pwd.c b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
index 1e2cf58e7..b9a48d5ca 100644
|
||||
--- a/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
+++ b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
@@ -37,6 +37,7 @@ md5_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
unsigned char hash_out[MD5_HASH_LEN];
|
||||
unsigned char b2a_out[MD5_HASH_LEN * 2]; /* conservative */
|
||||
SECItem binary_item;
|
||||
+ size_t dbpwd_len = strlen(dbpwd);
|
||||
|
||||
ctx = PK11_CreateDigestContext(SEC_OID_MD5);
|
||||
if (ctx == NULL) {
|
||||
@@ -45,6 +46,12 @@ md5_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
goto loser;
|
||||
}
|
||||
|
||||
+ if (dbpwd_len >= sizeof b2a_out) {
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
|
||||
+ "The hashed password stored in the user entry is longer than any valid md5 hash");
|
||||
+ goto loser;
|
||||
+ }
|
||||
+
|
||||
/* create the hash */
|
||||
PK11_DigestBegin(ctx);
|
||||
PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
|
||||
@@ -57,7 +64,7 @@ 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, dbpwd_len);
|
||||
} else {
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
|
||||
"Could not base64 encode hashed value for password compare");
|
||||
diff --git a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
index dcac4fcdd..82b8c9501 100644
|
||||
--- a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
+++ b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
@@ -255,6 +255,12 @@ pbkdf2_sha256_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
passItem.data = (unsigned char *)userpwd;
|
||||
passItem.len = strlen(userpwd);
|
||||
|
||||
+ if (pwdstorage_base64_decode_len(dbpwd, dbpwd_len) > sizeof dbhash) {
|
||||
+ /* Hashed value is too long and cannot match any value generated by pbkdf2_sha256_hash */
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to base64 decode dbpwd value. (hashed value is too long)\n");
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
/* Decode the DBpwd to bytes from b64 */
|
||||
if (PL_Base64Decode(dbpwd, dbpwd_len, dbhash) == NULL) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to base64 decode dbpwd value\n");
|
||||
--
|
||||
2.46.0
|
||||
|
@ -1,105 +0,0 @@
|
||||
From d000349089eb15b3476ec302f4279f118336290e Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 16 Dec 2021 16:13:08 -0500
|
||||
Subject: [PATCH 1/2] CVE-2021-4091 (BZ#2030367) double-free of the virtual
|
||||
attribute context in persistent search
|
||||
|
||||
description:
|
||||
A search is processed by a worker using a private pblock.
|
||||
If the search is persistent, the worker spawn a thread
|
||||
and kind of duplicate its private pblock so that the spawn
|
||||
thread continue to process the persistent search.
|
||||
Then worker ends the initial search, reinit (free) its private pblock,
|
||||
and returns monitoring the wait_queue.
|
||||
When the persistent search completes, it frees the duplicated
|
||||
pblock.
|
||||
The problem is that private pblock and duplicated pblock
|
||||
are referring to a same structure (pb_vattr_context).
|
||||
That lead to a double free
|
||||
|
||||
Fix:
|
||||
When cloning the pblock (slapi_pblock_clone) make sure
|
||||
to transfert the references inside the original (private)
|
||||
pblock to the target (cloned) one
|
||||
That includes pb_vattr_context pointer.
|
||||
|
||||
Reviewed by: Mark Reynolds, James Chapman, Pierre Rogier (Thanks !)
|
||||
---
|
||||
ldap/servers/slapd/connection.c | 8 +++++---
|
||||
ldap/servers/slapd/pblock.c | 14 ++++++++++++--
|
||||
2 files changed, 17 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
||||
index e0c1a52d2..fc7ed9c4a 100644
|
||||
--- a/ldap/servers/slapd/connection.c
|
||||
+++ b/ldap/servers/slapd/connection.c
|
||||
@@ -1823,9 +1823,11 @@ connection_threadmain()
|
||||
pthread_mutex_unlock(&(conn->c_mutex));
|
||||
}
|
||||
/* ps_add makes a shallow copy of the pb - so we
|
||||
- * can't free it or init it here - just set operation to NULL.
|
||||
- * ps_send_results will call connection_remove_operation_ext to free it
|
||||
- */
|
||||
+ * can't free it or init it here - just set operation to NULL.
|
||||
+ * ps_send_results will call connection_remove_operation_ext to free it
|
||||
+ * The connection_thread private pblock ('pb') has be cloned and should only
|
||||
+ * be reinit (slapi_pblock_init)
|
||||
+ */
|
||||
slapi_pblock_set(pb, SLAPI_OPERATION, NULL);
|
||||
slapi_pblock_init(pb);
|
||||
} else {
|
||||
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
|
||||
index a64986aeb..c78d1250f 100644
|
||||
--- a/ldap/servers/slapd/pblock.c
|
||||
+++ b/ldap/servers/slapd/pblock.c
|
||||
@@ -292,6 +292,12 @@ _pblock_assert_pb_deprecated(Slapi_PBlock *pblock)
|
||||
}
|
||||
}
|
||||
|
||||
+/* It clones the pblock
|
||||
+ * the content of the source pblock is transfered
|
||||
+ * to the target pblock (returned)
|
||||
+ * The source pblock should not be used for any operation
|
||||
+ * it needs to be reinit (slapi_pblock_init)
|
||||
+ */
|
||||
Slapi_PBlock *
|
||||
slapi_pblock_clone(Slapi_PBlock *pb)
|
||||
{
|
||||
@@ -312,28 +318,32 @@ slapi_pblock_clone(Slapi_PBlock *pb)
|
||||
if (pb->pb_task != NULL) {
|
||||
_pblock_assert_pb_task(new_pb);
|
||||
*(new_pb->pb_task) = *(pb->pb_task);
|
||||
+ memset(pb->pb_task, 0, sizeof(slapi_pblock_task));
|
||||
}
|
||||
if (pb->pb_mr != NULL) {
|
||||
_pblock_assert_pb_mr(new_pb);
|
||||
*(new_pb->pb_mr) = *(pb->pb_mr);
|
||||
+ memset(pb->pb_mr, 0, sizeof(slapi_pblock_matching_rule));
|
||||
}
|
||||
if (pb->pb_misc != NULL) {
|
||||
_pblock_assert_pb_misc(new_pb);
|
||||
*(new_pb->pb_misc) = *(pb->pb_misc);
|
||||
+ memset(pb->pb_misc, 0, sizeof(slapi_pblock_misc));
|
||||
}
|
||||
if (pb->pb_intop != NULL) {
|
||||
_pblock_assert_pb_intop(new_pb);
|
||||
*(new_pb->pb_intop) = *(pb->pb_intop);
|
||||
- /* set pwdpolicy to NULL so this clone allocates its own policy */
|
||||
- new_pb->pb_intop->pwdpolicy = NULL;
|
||||
+ memset(pb->pb_intop, 0, sizeof(slapi_pblock_intop));
|
||||
}
|
||||
if (pb->pb_intplugin != NULL) {
|
||||
_pblock_assert_pb_intplugin(new_pb);
|
||||
*(new_pb->pb_intplugin) = *(pb->pb_intplugin);
|
||||
+ memset(pb->pb_intplugin, 0,sizeof(slapi_pblock_intplugin));
|
||||
}
|
||||
if (pb->pb_deprecated != NULL) {
|
||||
_pblock_assert_pb_deprecated(new_pb);
|
||||
*(new_pb->pb_deprecated) = *(pb->pb_deprecated);
|
||||
+ memset(pb->pb_deprecated, 0, sizeof(slapi_pblock_deprecated));
|
||||
}
|
||||
#ifdef PBLOCK_ANALYTICS
|
||||
new_pb->analytics = NULL;
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,102 +0,0 @@
|
||||
From 03ca5111a8de602ecef9ad33206ba593b242d0df Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Fri, 21 Jan 2022 10:15:35 -0500
|
||||
Subject: [PATCH 1/2] Issue 5127 - run restorecon on /dev/shm at server startup
|
||||
|
||||
Description:
|
||||
|
||||
Update the systemd service file to execute a script that runs
|
||||
restorecon on the DB home directory. This addresses issues with
|
||||
backup/restore, reboot, and FS restore issues that can happen when
|
||||
/dev/shm is missing or created outside of dscreate.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/5127
|
||||
|
||||
Reviewed by: progier & viktor (Thanks!!)
|
||||
---
|
||||
Makefile.am | 2 +-
|
||||
rpm/389-ds-base.spec.in | 1 +
|
||||
wrappers/ds_selinux_restorecon.sh.in | 33 ++++++++++++++++++++++++++++
|
||||
wrappers/systemd.template.service.in | 1 +
|
||||
4 files changed, 36 insertions(+), 1 deletion(-)
|
||||
create mode 100644 wrappers/ds_selinux_restorecon.sh.in
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
index fc5a6a7d1..d6ad273c3 100644
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -775,7 +775,7 @@ libexec_SCRIPTS += ldap/admin/src/scripts/ds_selinux_enabled \
|
||||
ldap/admin/src/scripts/ds_selinux_port_query
|
||||
endif
|
||||
if SYSTEMD
|
||||
-libexec_SCRIPTS += wrappers/ds_systemd_ask_password_acl
|
||||
+libexec_SCRIPTS += wrappers/ds_systemd_ask_password_acl wrappers/ds_selinux_restorecon.sh
|
||||
endif
|
||||
|
||||
install-data-hook:
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index d80de8422..6c0d95abd 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -623,6 +623,7 @@ exit 0
|
||||
%{_sbindir}/ns-slapd
|
||||
%{_mandir}/man8/ns-slapd.8.gz
|
||||
%{_libexecdir}/%{pkgname}/ds_systemd_ask_password_acl
|
||||
+%{_libexecdir}/%{pkgname}/ds_selinux_restorecon.sh
|
||||
%{_mandir}/man5/99user.ldif.5.gz
|
||||
%{_mandir}/man5/certmap.conf.5.gz
|
||||
%{_mandir}/man5/slapd-collations.conf.5.gz
|
||||
diff --git a/wrappers/ds_selinux_restorecon.sh.in b/wrappers/ds_selinux_restorecon.sh.in
|
||||
new file mode 100644
|
||||
index 000000000..063347de3
|
||||
--- /dev/null
|
||||
+++ b/wrappers/ds_selinux_restorecon.sh.in
|
||||
@@ -0,0 +1,33 @@
|
||||
+#!/bin/sh
|
||||
+# BEGIN COPYRIGHT BLOCK
|
||||
+# Copyright (C) 2022 Red Hat, Inc.
|
||||
+#
|
||||
+# All rights reserved.
|
||||
+#
|
||||
+# License: GPL (version 3 or any later version).
|
||||
+# See LICENSE for details.
|
||||
+# END COPYRIGHT BLOCK
|
||||
+
|
||||
+# Make sure we have the path to the dse.ldif
|
||||
+if [ -z $1 ]
|
||||
+then
|
||||
+ echo "usage: ${0} /etc/dirsrv/slapd-<instance>/dse.ldif"
|
||||
+ exit 0
|
||||
+fi
|
||||
+
|
||||
+if ! command -v restorecon &> /dev/null
|
||||
+then
|
||||
+ # restorecon is not available
|
||||
+ exit 0
|
||||
+fi
|
||||
+
|
||||
+# Grep the db_home_dir out of the config file
|
||||
+DS_HOME_DIR=`grep 'nsslapd-db-home-directory: ' $1 | awk '{print $2}'`
|
||||
+if [ -z "$DS_HOME_DIR" ]
|
||||
+then
|
||||
+ # No DB home set, that's ok
|
||||
+ exit 0
|
||||
+fi
|
||||
+
|
||||
+# Now run restorecon
|
||||
+restorecon ${DS_HOME_DIR}
|
||||
diff --git a/wrappers/systemd.template.service.in b/wrappers/systemd.template.service.in
|
||||
index a8c21a9be..4485e0ec0 100644
|
||||
--- a/wrappers/systemd.template.service.in
|
||||
+++ b/wrappers/systemd.template.service.in
|
||||
@@ -14,6 +14,7 @@ EnvironmentFile=-@initconfigdir@/@package_name@
|
||||
EnvironmentFile=-@initconfigdir@/@package_name@-%i
|
||||
PIDFile=/run/@package_name@/slapd-%i.pid
|
||||
ExecStartPre=@libexecdir@/ds_systemd_ask_password_acl @instconfigdir@/slapd-%i/dse.ldif
|
||||
+ExecStartPre=@libexecdir@/ds_selinux_restorecon.sh @instconfigdir@/slapd-%i/dse.ldif
|
||||
ExecStart=@sbindir@/ns-slapd -D @instconfigdir@/slapd-%i -i /run/@package_name@/slapd-%i.pid
|
||||
PrivateTmp=on
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 0ed471bae52bb0debd23336cbc5f3f1d400cbbc9 Mon Sep 17 00:00:00 2001
|
||||
From: Adam Williamson <awilliam@redhat.com>
|
||||
Date: Thu, 27 Jan 2022 11:07:26 -0800
|
||||
Subject: [PATCH] Issue 5127 - ds_selinux_restorecon.sh: always exit 0
|
||||
|
||||
Description:
|
||||
|
||||
We don't want to error out and give up on starting the service
|
||||
if the restorecon fails - it might just be that the directory
|
||||
doesn't exist and doesn't need restoring. Issue identified and
|
||||
fix suggested by Simon Farnsworth
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/5127
|
||||
|
||||
Reviewed by: adamw & mreynolds
|
||||
---
|
||||
wrappers/ds_selinux_restorecon.sh.in | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/wrappers/ds_selinux_restorecon.sh.in b/wrappers/ds_selinux_restorecon.sh.in
|
||||
index 063347de3..2d7386233 100644
|
||||
--- a/wrappers/ds_selinux_restorecon.sh.in
|
||||
+++ b/wrappers/ds_selinux_restorecon.sh.in
|
||||
@@ -29,5 +29,6 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
-# Now run restorecon
|
||||
-restorecon ${DS_HOME_DIR}
|
||||
+# Now run restorecon, but don't die if it fails (could be that the
|
||||
+# directory doesn't exist)
|
||||
+restorecon ${DS_HOME_DIR} || :
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,262 +0,0 @@
|
||||
From 93588ea455aff691bdfbf59cdef4df8fcedb69f2 Mon Sep 17 00:00:00 2001
|
||||
From: Firstyear <william@blackhats.net.au>
|
||||
Date: Thu, 19 Aug 2021 10:46:00 +1000
|
||||
Subject: [PATCH 1/2] Issue 4775 - Add entryuuid CLI and Fixup (#4776)
|
||||
|
||||
Bug Description: EntryUUID when added was missing it's CLI
|
||||
and helpers for fixups.
|
||||
|
||||
Fix Description: Add the CLI elements.
|
||||
|
||||
fixes: https://github.com/389ds/389-ds-base/issues/4775
|
||||
|
||||
Author: William Brown <william@blackhats.net.au>
|
||||
|
||||
Review by: @mreynolds389 (thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_conf/plugin.py | 6 ++-
|
||||
.../lib389/cli_conf/plugins/entryuuid.py | 39 ++++++++++++++
|
||||
src/plugins/entryuuid/src/lib.rs | 54 ++++++++-----------
|
||||
3 files changed, 65 insertions(+), 34 deletions(-)
|
||||
create mode 100644 src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
|
||||
index 560c57f9b..7c0cf2c80 100644
|
||||
--- a/src/lib389/lib389/cli_conf/plugin.py
|
||||
+++ b/src/lib389/lib389/cli_conf/plugin.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2018 Red Hat, Inc.
|
||||
+# Copyright (C) 2022 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# License: GPL (version 3 or any later version).
|
||||
@@ -27,6 +27,8 @@ from lib389.cli_conf.plugins import passthroughauth as cli_passthroughauth
|
||||
from lib389.cli_conf.plugins import retrochangelog as cli_retrochangelog
|
||||
from lib389.cli_conf.plugins import automember as cli_automember
|
||||
from lib389.cli_conf.plugins import posix_winsync as cli_posix_winsync
|
||||
+from lib389.cli_conf.plugins import contentsync as cli_contentsync
|
||||
+from lib389.cli_conf.plugins import entryuuid as cli_entryuuid
|
||||
|
||||
SINGULAR = Plugin
|
||||
MANY = Plugins
|
||||
@@ -113,6 +115,8 @@ def create_parser(subparsers):
|
||||
cli_passthroughauth.create_parser(subcommands)
|
||||
cli_retrochangelog.create_parser(subcommands)
|
||||
cli_posix_winsync.create_parser(subcommands)
|
||||
+ cli_contentsync.create_parser(subcommands)
|
||||
+ cli_entryuuid.create_parser(subcommands)
|
||||
|
||||
list_parser = subcommands.add_parser('list', help="List current configured (enabled and disabled) plugins")
|
||||
list_parser.set_defaults(func=plugin_list)
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugins/entryuuid.py b/src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||
new file mode 100644
|
||||
index 000000000..6c86bff4b
|
||||
--- /dev/null
|
||||
+++ b/src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||
@@ -0,0 +1,39 @@
|
||||
+# --- BEGIN COPYRIGHT BLOCK ---
|
||||
+# Copyright (C) 2021 William Brown <william@blackhats.net.au>
|
||||
+# All rights reserved.
|
||||
+#
|
||||
+# License: GPL (version 3 or any later version).
|
||||
+# See LICENSE for details.
|
||||
+# --- END COPYRIGHT BLOCK ---
|
||||
+
|
||||
+import ldap
|
||||
+from lib389.plugins import EntryUUIDPlugin
|
||||
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, generic_object_add
|
||||
+
|
||||
+def do_fixup(inst, basedn, log, args):
|
||||
+ plugin = EntryUUIDPlugin(inst)
|
||||
+ log.info('Attempting to add task entry...')
|
||||
+ if not plugin.status():
|
||||
+ log.error("'%s' is disabled. Fix up task can't be executed" % plugin.rdn)
|
||||
+ return
|
||||
+ fixup_task = plugin.fixup(args.DN, args.filter)
|
||||
+ fixup_task.wait()
|
||||
+ exitcode = fixup_task.get_exit_code()
|
||||
+ if exitcode != 0:
|
||||
+ log.error('EntryUUID fixup task has failed. Please, check the error log for more - %s' % exitcode)
|
||||
+ else:
|
||||
+ log.info('Successfully added task entry')
|
||||
+
|
||||
+def create_parser(subparsers):
|
||||
+ referint = subparsers.add_parser('entryuuid', help='Manage and configure EntryUUID plugin')
|
||||
+ subcommands = referint.add_subparsers(help='action')
|
||||
+
|
||||
+ add_generic_plugin_parsers(subcommands, EntryUUIDPlugin)
|
||||
+
|
||||
+ fixup = subcommands.add_parser('fixup', help='Run the fix-up task for EntryUUID plugin')
|
||||
+ fixup.set_defaults(func=do_fixup)
|
||||
+ fixup.add_argument('DN', help="Base DN that contains entries to fix up")
|
||||
+ fixup.add_argument('-f', '--filter',
|
||||
+ help='Filter for entries to fix up.\n If omitted, all entries under base DN'
|
||||
+ 'will have their EntryUUID attribute regenerated if not present.')
|
||||
+
|
||||
diff --git a/src/plugins/entryuuid/src/lib.rs b/src/plugins/entryuuid/src/lib.rs
|
||||
index da9f0c239..29a9f1258 100644
|
||||
--- a/src/plugins/entryuuid/src/lib.rs
|
||||
+++ b/src/plugins/entryuuid/src/lib.rs
|
||||
@@ -33,7 +33,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||
// 🚧 safety barrier 🚧
|
||||
if e.contains_attr("entryUUID") {
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"assign_uuid -> entryUUID exists, skipping dn {}",
|
||||
sdn.to_dn_string()
|
||||
);
|
||||
@@ -47,7 +47,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||
if sdn.is_below_suffix(&*config_sdn) || sdn.is_below_suffix(&*schema_sdn) {
|
||||
// We don't need to assign to these suffixes.
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"assign_uuid -> not assigning to {:?} as part of system suffix",
|
||||
sdn.to_dn_string()
|
||||
);
|
||||
@@ -57,7 +57,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||
// Generate a new Uuid.
|
||||
let u: Uuid = Uuid::new_v4();
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"assign_uuid -> assigning {:?} to dn {}",
|
||||
u,
|
||||
sdn.to_dn_string()
|
||||
@@ -78,13 +78,13 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
fn betxn_pre_add(pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||
if pb.get_is_replicated_operation() {
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"betxn_pre_add -> replicated operation, will not change"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
- log_error!(ErrorLevel::Trace, "betxn_pre_add -> start");
|
||||
+ log_error!(ErrorLevel::Plugin, "betxn_pre_add -> start");
|
||||
|
||||
let mut e = pb.get_op_add_entryref().map_err(|_| PluginError::Pblock)?;
|
||||
assign_uuid(&mut e);
|
||||
@@ -105,7 +105,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
.first()
|
||||
.ok_or_else(|| {
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"task_validate basedn error -> empty value array?"
|
||||
);
|
||||
LDAPError::Operation
|
||||
@@ -113,7 +113,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.map_err(|e| {
|
||||
- log_error!(ErrorLevel::Trace, "task_validate basedn error -> {:?}", e);
|
||||
+ log_error!(ErrorLevel::Plugin, "task_validate basedn error -> {:?}", e);
|
||||
LDAPError::Operation
|
||||
})?,
|
||||
None => return Err(LDAPError::ObjectClassViolation),
|
||||
@@ -124,7 +124,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
.first()
|
||||
.ok_or_else(|| {
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"task_validate filter error -> empty value array?"
|
||||
);
|
||||
LDAPError::Operation
|
||||
@@ -132,7 +132,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.map_err(|e| {
|
||||
- log_error!(ErrorLevel::Trace, "task_validate filter error -> {:?}", e);
|
||||
+ log_error!(ErrorLevel::Plugin, "task_validate filter error -> {:?}", e);
|
||||
LDAPError::Operation
|
||||
})?,
|
||||
None => {
|
||||
@@ -144,17 +144,11 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
// Error if the first filter is empty?
|
||||
|
||||
// Now, to make things faster, we wrap the filter in a exclude term.
|
||||
-
|
||||
- // 2021 - #4877 because we allow entryuuid to be strings, on import these may
|
||||
- // be invalid. As a result, we DO need to allow the fixup to check the entryuuid
|
||||
- // value is correct, so we can not exclude these during the search.
|
||||
- /*
|
||||
let raw_filter = if !raw_filter.starts_with('(') && !raw_filter.ends_with('(') {
|
||||
format!("(&({})(!(entryuuid=*)))", raw_filter)
|
||||
} else {
|
||||
format!("(&{}(!(entryuuid=*)))", raw_filter)
|
||||
};
|
||||
- */
|
||||
|
||||
Ok(FixupData { basedn, raw_filter })
|
||||
}
|
||||
@@ -165,7 +159,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
|
||||
fn task_handler(_task: &Task, data: Self::TaskData) -> Result<Self::TaskData, PluginError> {
|
||||
log_error!(
|
||||
- ErrorLevel::Trace,
|
||||
+ ErrorLevel::Plugin,
|
||||
"task_handler -> start thread with -> {:?}",
|
||||
data
|
||||
);
|
||||
@@ -205,12 +199,12 @@ impl SlapiPlugin3 for EntryUuid {
|
||||
}
|
||||
|
||||
fn start(_pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||
- log_error!(ErrorLevel::Trace, "plugin start");
|
||||
+ log_error!(ErrorLevel::Plugin, "plugin start");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(_pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||
- log_error!(ErrorLevel::Trace, "plugin close");
|
||||
+ log_error!(ErrorLevel::Plugin, "plugin close");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -219,20 +213,14 @@ pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError
|
||||
/* Supply a modification to the entry. */
|
||||
let sdn = e.get_sdnref();
|
||||
|
||||
- /* Check that entryuuid doesn't already exist, and is valid */
|
||||
- if let Some(valueset) = e.get_attr("entryUUID") {
|
||||
- if valueset.iter().all(|v| {
|
||||
- let u: Result<Uuid, _> = (&v).try_into();
|
||||
- u.is_ok()
|
||||
- }) {
|
||||
- // All values were valid uuid, move on!
|
||||
- log_error!(
|
||||
- ErrorLevel::Plugin,
|
||||
- "skipping fixup for -> {}",
|
||||
- sdn.to_dn_string()
|
||||
- );
|
||||
- return Ok(());
|
||||
- }
|
||||
+ /* Sanity check that entryuuid doesn't already exist */
|
||||
+ if e.contains_attr("entryUUID") {
|
||||
+ log_error!(
|
||||
+ ErrorLevel::Plugin,
|
||||
+ "skipping fixup for -> {}",
|
||||
+ sdn.to_dn_string()
|
||||
+ );
|
||||
+ return Ok(());
|
||||
}
|
||||
|
||||
// Setup the modifications
|
||||
@@ -248,7 +236,7 @@ pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError
|
||||
|
||||
match lmod.execute() {
|
||||
Ok(_) => {
|
||||
- log_error!(ErrorLevel::Trace, "fixed-up -> {}", sdn.to_dn_string());
|
||||
+ log_error!(ErrorLevel::Plugin, "fixed-up -> {}", sdn.to_dn_string());
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
--
|
||||
2.34.1
|
||||
|
@ -1,42 +0,0 @@
|
||||
From 525f2307fa3e2d0ae55c8c922e6f7220a1e5bd1b Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 3 Feb 2022 16:51:38 -0500
|
||||
Subject: [PATCH] Issue 4775 - Fix cherry-pick error
|
||||
|
||||
Bug Description: EntryUUID when added was missing it's CLI
|
||||
and helpers for fixups.
|
||||
|
||||
Fix Description: Add the CLI elements.
|
||||
|
||||
fixes: https://github.com/389ds/389-ds-base/issues/4775
|
||||
|
||||
Author: William Brown <william@blackhats.net.au>
|
||||
|
||||
Review by: @mreynolds389 (thanks!)
|
||||
---
|
||||
src/lib389/lib389/cli_conf/plugin.py | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
|
||||
index 7c0cf2c80..fb0ef3077 100644
|
||||
--- a/src/lib389/lib389/cli_conf/plugin.py
|
||||
+++ b/src/lib389/lib389/cli_conf/plugin.py
|
||||
@@ -27,7 +27,6 @@ from lib389.cli_conf.plugins import passthroughauth as cli_passthroughauth
|
||||
from lib389.cli_conf.plugins import retrochangelog as cli_retrochangelog
|
||||
from lib389.cli_conf.plugins import automember as cli_automember
|
||||
from lib389.cli_conf.plugins import posix_winsync as cli_posix_winsync
|
||||
-from lib389.cli_conf.plugins import contentsync as cli_contentsync
|
||||
from lib389.cli_conf.plugins import entryuuid as cli_entryuuid
|
||||
|
||||
SINGULAR = Plugin
|
||||
@@ -115,7 +114,6 @@ def create_parser(subparsers):
|
||||
cli_passthroughauth.create_parser(subcommands)
|
||||
cli_retrochangelog.create_parser(subcommands)
|
||||
cli_posix_winsync.create_parser(subcommands)
|
||||
- cli_contentsync.create_parser(subcommands)
|
||||
cli_entryuuid.create_parser(subcommands)
|
||||
|
||||
list_parser = subcommands.add_parser('list', help="List current configured (enabled and disabled) plugins")
|
||||
--
|
||||
2.34.1
|
||||
|
@ -1,108 +0,0 @@
|
||||
From ad7573252147770c66ff3761add0f04fc8fa6f6c Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 3 Mar 2022 16:29:41 -0500
|
||||
Subject: [PATCH 1/2] Issue 5221 - User with expired password can still login
|
||||
with full privledges
|
||||
|
||||
Bug Description:
|
||||
|
||||
A user with an expired password can still login and perform operations
|
||||
with its typical access perimssions. But an expired password means the
|
||||
account should be considered anonymous.
|
||||
|
||||
Fix Description:
|
||||
|
||||
Clear the bind credentials if the password is expired
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/5221
|
||||
|
||||
Reviewed by: progier(Thanks!)
|
||||
---
|
||||
.../suites/password/pw_expired_access_test.py | 62 +++++++++++++++++++
|
||||
ldap/servers/slapd/pw_mgmt.c | 1 +
|
||||
2 files changed, 63 insertions(+)
|
||||
create mode 100644 dirsrvtests/tests/suites/password/pw_expired_access_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pw_expired_access_test.py b/dirsrvtests/tests/suites/password/pw_expired_access_test.py
|
||||
new file mode 100644
|
||||
index 000000000..fb0afb190
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/password/pw_expired_access_test.py
|
||||
@@ -0,0 +1,62 @@
|
||||
+import ldap
|
||||
+import logging
|
||||
+import pytest
|
||||
+import os
|
||||
+import time
|
||||
+from lib389._constants import DEFAULT_SUFFIX, PASSWORD
|
||||
+from lib389.idm.domain import Domain
|
||||
+from lib389.idm.user import UserAccounts
|
||||
+from lib389.topologies import topology_st as topo
|
||||
+
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+def test_expired_user_has_no_privledge(topo):
|
||||
+ """Specify a test case purpose or name here
|
||||
+
|
||||
+ :id: 3df86b45-9929-414b-9bf6-06c25301d207
|
||||
+ :setup: Standalone Instance
|
||||
+ :steps:
|
||||
+ 1. Set short password expiration time
|
||||
+ 2. Add user and wait for expiration time to run out
|
||||
+ 3. Set one aci that allows authenticated users full access
|
||||
+ 4. Bind as user (password should be expired)
|
||||
+ 5. Attempt modify
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Success
|
||||
+ 5. Success
|
||||
+ """
|
||||
+
|
||||
+ # Configured password epxiration
|
||||
+ topo.standalone.config.replace_many(('passwordexp', 'on'), ('passwordmaxage', '1'))
|
||||
+
|
||||
+ # Set aci
|
||||
+ suffix = Domain(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ ACI_TEXT = '(targetattr="*")(version 3.0; acl "test aci"; allow (all) (userdn="ldap:///all");)'
|
||||
+ suffix.replace('aci', ACI_TEXT)
|
||||
+
|
||||
+ # Add user
|
||||
+ user = UserAccounts(topo.standalone, DEFAULT_SUFFIX, rdn=None).create_test_user()
|
||||
+ user.replace('userpassword', PASSWORD)
|
||||
+ time.sleep(2)
|
||||
+
|
||||
+ # Bind as user with expired password. Need to use raw ldap calls because
|
||||
+ # lib389 will close the connection when an error 49 is encountered.
|
||||
+ ldap_object = ldap.initialize(topo.standalone.toLDAPURL())
|
||||
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
||||
+ res_type, res_data, res_msgid, res_ctrls = ldap_object.simple_bind_s(
|
||||
+ user.dn, PASSWORD)
|
||||
+
|
||||
+ # Try modify
|
||||
+ with pytest.raises(ldap.INSUFFICIENT_ACCESS):
|
||||
+ modlist = [ (ldap.MOD_REPLACE, 'description', b'Should not work!') ]
|
||||
+ ldap_object.modify_ext_s(DEFAULT_SUFFIX, modlist)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ # Run isolated
|
||||
+ # -s for DEBUG mode
|
||||
+ CURRENT_FILE = os.path.realpath(__file__)
|
||||
+ pytest.main(["-s", CURRENT_FILE])
|
||||
diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
|
||||
index 59b90dfa6..b67c2c8c0 100644
|
||||
--- a/ldap/servers/slapd/pw_mgmt.c
|
||||
+++ b/ldap/servers/slapd/pw_mgmt.c
|
||||
@@ -208,6 +208,7 @@ skip:
|
||||
slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED);
|
||||
}
|
||||
slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
|
||||
+ bind_credentials_clear(pb_conn, PR_FALSE, PR_TRUE);
|
||||
slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
|
||||
"password expired!", 0, NULL);
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From c7f4542fade3d06c8725d0c2976d81f5206719c4 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 30 Mar 2022 18:07:23 +0200
|
||||
Subject: [PATCH 2/2] Issue 5242- Craft message may crash the server (#5243)
|
||||
|
||||
Bug description:
|
||||
A craft request can result in DoS
|
||||
|
||||
Fix description:
|
||||
If the server fails to decode the ber value
|
||||
then return an Error
|
||||
|
||||
relates: 5242
|
||||
|
||||
Reviewed by: Pierre Rogier, Mark Reynolds (thanks !)
|
||||
|
||||
Platforms tested: F34
|
||||
---
|
||||
ldap/servers/slapd/filter.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/filter.c b/ldap/servers/slapd/filter.c
|
||||
index d671c87ff..52fd95750 100644
|
||||
--- a/ldap/servers/slapd/filter.c
|
||||
+++ b/ldap/servers/slapd/filter.c
|
||||
@@ -647,8 +647,14 @@ get_extensible_filter(BerElement *ber, mr_filter_t *mrf)
|
||||
}
|
||||
}
|
||||
|
||||
- if ((tag != LBER_ERROR) && (len != -1)) {
|
||||
- goto parsing_error;
|
||||
+ if (tag == LBER_ERROR) {
|
||||
+ if (len == -1) {
|
||||
+ /* means that the ber sequence ended without LBER_END_OF_SEQORSET tag
|
||||
+ * and it is considered as valid to ensure compatibility with open ldap.
|
||||
+ */
|
||||
+ } else {
|
||||
+ goto parsing_error;
|
||||
+ }
|
||||
}
|
||||
|
||||
slapi_log_err(SLAPI_LOG_FILTER, "get_extensible_filter", "<= %i\n", rc);
|
||||
--
|
||||
2.31.1
|
||||
|
933
SOURCES/Cargo-1.4.3.39-1.lock
Normal file
933
SOURCES/Cargo-1.4.3.39-1.lock
Normal file
@ -0,0 +1,933 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags 1.3.2",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concread"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcc9816f5ac93ebd51c37f7f9a6bf2b40dfcd42978ad2aea5d542016e9244cf6"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"crossbeam",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"lru",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "entryuuid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"paste",
|
||||
"slapi_r_plugin",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "entryuuid_syntax"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"paste",
|
||||
"slapi_r_plugin",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "fernet"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93804560e638370a8be6d59ce71ed803e55e230abdbf42598e666b41adda9b1f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"getrandom",
|
||||
"openssl",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "librnsslapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"libc",
|
||||
"slapd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librslapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"concread",
|
||||
"libc",
|
||||
"slapd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
||||
dependencies = [
|
||||
"paste-impl",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste-impl"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwdchan"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cc",
|
||||
"libc",
|
||||
"openssl",
|
||||
"paste",
|
||||
"slapi_r_plugin",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsds"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fernet",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slapi_r_plugin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"paste",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.4.1",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.35.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
565
SOURCES/Cargo.lock
generated
565
SOURCES/Cargo.lock
generated
@ -1,565 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "entryuuid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"paste",
|
||||
"slapi_r_plugin",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "entryuuid_syntax"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"paste",
|
||||
"slapi_r_plugin",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fernet"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93804560e638370a8be6d59ce71ed803e55e230abdbf42598e666b41adda9b1f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"getrandom",
|
||||
"openssl",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce"
|
||||
|
||||
[[package]]
|
||||
name = "librnsslapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"libc",
|
||||
"slapd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librslapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"libc",
|
||||
"slapd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
||||
dependencies = [
|
||||
"paste-impl",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste-impl"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsds"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slapd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fernet",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slapi_r_plugin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"paste",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
@ -25,7 +25,7 @@ ExcludeArch: i686
|
||||
|
||||
%if %{bundle_jemalloc}
|
||||
%global jemalloc_name jemalloc
|
||||
%global jemalloc_ver 5.2.1
|
||||
%global jemalloc_ver 5.3.0
|
||||
%global __provides_exclude ^libjemalloc\\.so.*$
|
||||
%endif
|
||||
|
||||
@ -47,9 +47,9 @@ ExcludeArch: i686
|
||||
|
||||
Summary: 389 Directory Server (base)
|
||||
Name: 389-ds-base
|
||||
Version: 1.4.3.28
|
||||
Release: %{?relprefix}7%{?prerel}%{?dist}
|
||||
License: GPLv3+
|
||||
Version: 1.4.3.39
|
||||
Release: %{?relprefix}8%{?prerel}%{?dist}
|
||||
License: GPLv3+ and (ASL 2.0 or MIT)
|
||||
URL: https://www.port389.org
|
||||
Group: System Environment/Daemons
|
||||
Conflicts: selinux-policy-base < 3.9.8
|
||||
@ -58,74 +58,116 @@ Obsoletes: %{name} <= 1.4.0.9
|
||||
Provides: ldif2ldbm >= 0
|
||||
|
||||
##### Bundled cargo crates list - START #####
|
||||
Provides: bundled(crate(ansi_term)) = 0.11.0
|
||||
Provides: bundled(crate(addr2line)) = 0.21.0
|
||||
Provides: bundled(crate(adler)) = 1.0.2
|
||||
Provides: bundled(crate(ahash)) = 0.7.7
|
||||
Provides: bundled(crate(ansi_term)) = 0.12.1
|
||||
Provides: bundled(crate(atty)) = 0.2.14
|
||||
Provides: bundled(crate(autocfg)) = 1.0.1
|
||||
Provides: bundled(crate(base64)) = 0.13.0
|
||||
Provides: bundled(crate(autocfg)) = 1.1.0
|
||||
Provides: bundled(crate(backtrace)) = 0.3.69
|
||||
Provides: bundled(crate(base64)) = 0.13.1
|
||||
Provides: bundled(crate(bitflags)) = 1.3.2
|
||||
Provides: bundled(crate(byteorder)) = 1.4.3
|
||||
Provides: bundled(crate(bitflags)) = 2.4.1
|
||||
Provides: bundled(crate(byteorder)) = 1.5.0
|
||||
Provides: bundled(crate(cbindgen)) = 0.9.1
|
||||
Provides: bundled(crate(cc)) = 1.0.71
|
||||
Provides: bundled(crate(cc)) = 1.0.83
|
||||
Provides: bundled(crate(cfg-if)) = 1.0.0
|
||||
Provides: bundled(crate(clap)) = 2.33.3
|
||||
Provides: bundled(crate(clap)) = 2.34.0
|
||||
Provides: bundled(crate(concread)) = 0.2.21
|
||||
Provides: bundled(crate(crossbeam)) = 0.8.4
|
||||
Provides: bundled(crate(crossbeam-channel)) = 0.5.11
|
||||
Provides: bundled(crate(crossbeam-deque)) = 0.8.5
|
||||
Provides: bundled(crate(crossbeam-epoch)) = 0.9.18
|
||||
Provides: bundled(crate(crossbeam-queue)) = 0.3.11
|
||||
Provides: bundled(crate(crossbeam-utils)) = 0.8.19
|
||||
Provides: bundled(crate(entryuuid)) = 0.1.0
|
||||
Provides: bundled(crate(entryuuid_syntax)) = 0.1.0
|
||||
Provides: bundled(crate(errno)) = 0.3.8
|
||||
Provides: bundled(crate(fastrand)) = 2.0.1
|
||||
Provides: bundled(crate(fernet)) = 0.1.4
|
||||
Provides: bundled(crate(foreign-types)) = 0.3.2
|
||||
Provides: bundled(crate(foreign-types-shared)) = 0.1.1
|
||||
Provides: bundled(crate(getrandom)) = 0.2.3
|
||||
Provides: bundled(crate(getrandom)) = 0.2.12
|
||||
Provides: bundled(crate(gimli)) = 0.28.1
|
||||
Provides: bundled(crate(hashbrown)) = 0.12.3
|
||||
Provides: bundled(crate(hermit-abi)) = 0.1.19
|
||||
Provides: bundled(crate(itoa)) = 0.4.8
|
||||
Provides: bundled(crate(jobserver)) = 0.1.24
|
||||
Provides: bundled(crate(lazy_static)) = 1.4.0
|
||||
Provides: bundled(crate(libc)) = 0.2.104
|
||||
Provides: bundled(crate(instant)) = 0.1.12
|
||||
Provides: bundled(crate(itoa)) = 1.0.10
|
||||
Provides: bundled(crate(jobserver)) = 0.1.27
|
||||
Provides: bundled(crate(libc)) = 0.2.152
|
||||
Provides: bundled(crate(librnsslapd)) = 0.1.0
|
||||
Provides: bundled(crate(librslapd)) = 0.1.0
|
||||
Provides: bundled(crate(log)) = 0.4.14
|
||||
Provides: bundled(crate(once_cell)) = 1.8.0
|
||||
Provides: bundled(crate(openssl)) = 0.10.36
|
||||
Provides: bundled(crate(openssl-sys)) = 0.9.67
|
||||
Provides: bundled(crate(linux-raw-sys)) = 0.4.12
|
||||
Provides: bundled(crate(lock_api)) = 0.4.11
|
||||
Provides: bundled(crate(log)) = 0.4.20
|
||||
Provides: bundled(crate(lru)) = 0.7.8
|
||||
Provides: bundled(crate(memchr)) = 2.7.1
|
||||
Provides: bundled(crate(miniz_oxide)) = 0.7.1
|
||||
Provides: bundled(crate(object)) = 0.32.2
|
||||
Provides: bundled(crate(once_cell)) = 1.19.0
|
||||
Provides: bundled(crate(openssl)) = 0.10.62
|
||||
Provides: bundled(crate(openssl-macros)) = 0.1.1
|
||||
Provides: bundled(crate(openssl-sys)) = 0.9.98
|
||||
Provides: bundled(crate(parking_lot)) = 0.11.2
|
||||
Provides: bundled(crate(parking_lot_core)) = 0.8.6
|
||||
Provides: bundled(crate(paste)) = 0.1.18
|
||||
Provides: bundled(crate(paste-impl)) = 0.1.18
|
||||
Provides: bundled(crate(pkg-config)) = 0.3.20
|
||||
Provides: bundled(crate(ppv-lite86)) = 0.2.14
|
||||
Provides: bundled(crate(proc-macro-hack)) = 0.5.19
|
||||
Provides: bundled(crate(proc-macro2)) = 1.0.30
|
||||
Provides: bundled(crate(quote)) = 1.0.10
|
||||
Provides: bundled(crate(rand)) = 0.8.4
|
||||
Provides: bundled(crate(pin-project-lite)) = 0.2.13
|
||||
Provides: bundled(crate(pkg-config)) = 0.3.28
|
||||
Provides: bundled(crate(ppv-lite86)) = 0.2.17
|
||||
Provides: bundled(crate(proc-macro-hack)) = 0.5.20+deprecated
|
||||
Provides: bundled(crate(proc-macro2)) = 1.0.76
|
||||
Provides: bundled(crate(pwdchan)) = 0.1.0
|
||||
Provides: bundled(crate(quote)) = 1.0.35
|
||||
Provides: bundled(crate(rand)) = 0.8.5
|
||||
Provides: bundled(crate(rand_chacha)) = 0.3.1
|
||||
Provides: bundled(crate(rand_core)) = 0.6.3
|
||||
Provides: bundled(crate(rand_hc)) = 0.3.1
|
||||
Provides: bundled(crate(redox_syscall)) = 0.2.10
|
||||
Provides: bundled(crate(remove_dir_all)) = 0.5.3
|
||||
Provides: bundled(crate(rand_core)) = 0.6.4
|
||||
Provides: bundled(crate(redox_syscall)) = 0.2.16
|
||||
Provides: bundled(crate(redox_syscall)) = 0.4.1
|
||||
Provides: bundled(crate(rsds)) = 0.1.0
|
||||
Provides: bundled(crate(ryu)) = 1.0.5
|
||||
Provides: bundled(crate(serde)) = 1.0.130
|
||||
Provides: bundled(crate(serde_derive)) = 1.0.130
|
||||
Provides: bundled(crate(serde_json)) = 1.0.68
|
||||
Provides: bundled(crate(rustc-demangle)) = 0.1.23
|
||||
Provides: bundled(crate(rustix)) = 0.38.30
|
||||
Provides: bundled(crate(ryu)) = 1.0.16
|
||||
Provides: bundled(crate(scopeguard)) = 1.2.0
|
||||
Provides: bundled(crate(serde)) = 1.0.195
|
||||
Provides: bundled(crate(serde_derive)) = 1.0.195
|
||||
Provides: bundled(crate(serde_json)) = 1.0.111
|
||||
Provides: bundled(crate(slapd)) = 0.1.0
|
||||
Provides: bundled(crate(slapi_r_plugin)) = 0.1.0
|
||||
Provides: bundled(crate(smallvec)) = 1.12.0
|
||||
Provides: bundled(crate(strsim)) = 0.8.0
|
||||
Provides: bundled(crate(syn)) = 1.0.80
|
||||
Provides: bundled(crate(synstructure)) = 0.12.6
|
||||
Provides: bundled(crate(tempfile)) = 3.2.0
|
||||
Provides: bundled(crate(syn)) = 1.0.109
|
||||
Provides: bundled(crate(syn)) = 2.0.48
|
||||
Provides: bundled(crate(tempfile)) = 3.9.0
|
||||
Provides: bundled(crate(textwrap)) = 0.11.0
|
||||
Provides: bundled(crate(toml)) = 0.5.8
|
||||
Provides: bundled(crate(unicode-width)) = 0.1.9
|
||||
Provides: bundled(crate(unicode-xid)) = 0.2.2
|
||||
Provides: bundled(crate(tokio)) = 1.35.1
|
||||
Provides: bundled(crate(tokio-macros)) = 2.2.0
|
||||
Provides: bundled(crate(toml)) = 0.5.11
|
||||
Provides: bundled(crate(unicode-ident)) = 1.0.12
|
||||
Provides: bundled(crate(unicode-width)) = 0.1.11
|
||||
Provides: bundled(crate(uuid)) = 0.8.2
|
||||
Provides: bundled(crate(vcpkg)) = 0.2.15
|
||||
Provides: bundled(crate(vec_map)) = 0.8.2
|
||||
Provides: bundled(crate(wasi)) = 0.10.2+wasi_snapshot_preview1
|
||||
Provides: bundled(crate(version_check)) = 0.9.4
|
||||
Provides: bundled(crate(wasi)) = 0.11.0+wasi_snapshot_preview1
|
||||
Provides: bundled(crate(winapi)) = 0.3.9
|
||||
Provides: bundled(crate(winapi-i686-pc-windows-gnu)) = 0.4.0
|
||||
Provides: bundled(crate(winapi-x86_64-pc-windows-gnu)) = 0.4.0
|
||||
Provides: bundled(crate(zeroize)) = 1.4.2
|
||||
Provides: bundled(crate(zeroize_derive)) = 1.2.0
|
||||
Provides: bundled(crate(windows-sys)) = 0.52.0
|
||||
Provides: bundled(crate(windows-targets)) = 0.52.0
|
||||
Provides: bundled(crate(windows_aarch64_gnullvm)) = 0.52.0
|
||||
Provides: bundled(crate(windows_aarch64_msvc)) = 0.52.0
|
||||
Provides: bundled(crate(windows_i686_gnu)) = 0.52.0
|
||||
Provides: bundled(crate(windows_i686_msvc)) = 0.52.0
|
||||
Provides: bundled(crate(windows_x86_64_gnu)) = 0.52.0
|
||||
Provides: bundled(crate(windows_x86_64_gnullvm)) = 0.52.0
|
||||
Provides: bundled(crate(windows_x86_64_msvc)) = 0.52.0
|
||||
Provides: bundled(crate(zeroize)) = 1.7.0
|
||||
Provides: bundled(crate(zeroize_derive)) = 1.4.2
|
||||
##### Bundled cargo crates list - END #####
|
||||
|
||||
BuildRequires: nspr-devel
|
||||
BuildRequires: nss-devel >= 3.34
|
||||
BuildRequires: nspr-devel >= 4.32
|
||||
BuildRequires: nss-devel >= 3.67.0-7
|
||||
BuildRequires: perl-generators
|
||||
BuildRequires: openldap-devel
|
||||
BuildRequires: libdb-devel
|
||||
@ -185,6 +227,7 @@ BuildRequires: python%{python3_pkgversion}-argcomplete
|
||||
BuildRequires: python%{python3_pkgversion}-argparse-manpage
|
||||
BuildRequires: python%{python3_pkgversion}-policycoreutils
|
||||
BuildRequires: python%{python3_pkgversion}-libselinux
|
||||
BuildRequires: python%{python3_pkgversion}-cryptography
|
||||
|
||||
# For cockpit
|
||||
BuildRequires: rsync
|
||||
@ -207,7 +250,8 @@ Requires: python%{python3_pkgversion}-ldap
|
||||
# this is needed to setup SSL if you are not using the
|
||||
# administration server package
|
||||
Requires: nss-tools
|
||||
Requires: nss >= 3.34
|
||||
Requires: nspr >= 4.32
|
||||
Requires: nss >= 3.67.0-7
|
||||
|
||||
# these are not found by the auto-dependency method
|
||||
# they are required to support the mandatory LDAP SASL mechs
|
||||
@ -246,28 +290,21 @@ Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download
|
||||
%endif
|
||||
%if %{use_rust}
|
||||
Source4: vendor-%{version}-1.tar.gz
|
||||
Source5: Cargo.lock
|
||||
Source5: Cargo-%{version}-1.lock
|
||||
%endif
|
||||
|
||||
Patch01: 0001-Issue-4678-RFE-automatique-disable-of-virtual-attrib.patch
|
||||
Patch02: 0002-Issue-4943-Fix-csn-generator-to-limit-time-skew-drif.patch
|
||||
Patch03: 0003-Issue-3584-Fix-PBKDF2_SHA256-hashing-in-FIPS-mode-49.patch
|
||||
Patch04: 0004-Issue-4956-Automember-allows-invalid-regex-and-does-.patch
|
||||
Patch05: 0005-Issue-4092-systemd-tmpfiles-warnings.patch
|
||||
Patch06: 0006-Issue-4973-installer-changes-permissions-on-run.patch
|
||||
Patch07: 0007-Issue-4973-update-snmp-to-use-run-dirsrv-for-PID-fil.patch
|
||||
Patch08: 0008-Issue-4978-make-installer-robust.patch
|
||||
Patch09: 0009-Issue-4972-gecos-with-IA5-introduces-a-compatibility.patch
|
||||
Patch10: 0010-Issue-4997-Function-declaration-compiler-error-on-1..patch
|
||||
Patch11: 0011-Issue-4978-use-more-portable-python-command-for-chec.patch
|
||||
Patch12: 0012-Issue-4959-Invalid-etc-hosts-setup-can-cause-isLocal.patch
|
||||
Patch13: 0013-CVE-2021-4091-BZ-2030367-double-free-of-the-virtual-.patch
|
||||
Patch14: 0014-Issue-5127-run-restorecon-on-dev-shm-at-server-start.patch
|
||||
Patch15: 0015-Issue-5127-ds_selinux_restorecon.sh-always-exit-0.patch
|
||||
Patch16: 0016-Issue-4775-Add-entryuuid-CLI-and-Fixup-4776.patch
|
||||
Patch17: 0017-Issue-4775-Fix-cherry-pick-error.patch
|
||||
Patch18: 0018-Issue-5221-User-with-expired-password-can-still-logi.patch
|
||||
Patch19: 0019-Issue-5242-Craft-message-may-crash-the-server-5243.patch
|
||||
Patch01: 0001-issue-5647-covscan-memory-leak-in-audit-log-when-add.patch
|
||||
Patch02: 0002-Issue-5647-Fix-unused-variable-warning-from-previous.patch
|
||||
Patch03: 0003-Issue-5407-sync_repl-crashes-if-enabled-while-dynami.patch
|
||||
Patch04: 0004-Issue-5547-automember-plugin-improvements.patch
|
||||
Patch05: 0005-Issue-3527-Support-HAProxy-and-Instance-on-the-same-.patch
|
||||
Patch06: 0006-CVE-2024-2199.patch
|
||||
Patch07: 0007-CVE-2024-3657.patch
|
||||
Patch08: 0008-Issue-6096-Improve-connection-timeout-error-logging-.patch
|
||||
Patch09: 0009-Issue-6103-New-connection-timeout-error-breaks-error.patch
|
||||
Patch10: 0010-Issue-6103-New-connection-timeout-error-breaks-error.patch
|
||||
Patch11: 0011-Issue-6172-RFE-improve-the-performance-of-evaluation.patch
|
||||
Patch12: 0012-Security-fix-for-CVE-2024-5953.patch
|
||||
|
||||
%description
|
||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||
@ -281,8 +318,8 @@ Please see http://seclists.org/oss-sec/2016/q1/363 for more information.
|
||||
%package libs
|
||||
Summary: Core libraries for 389 Directory Server
|
||||
Group: System Environment/Daemons
|
||||
BuildRequires: nspr-devel
|
||||
BuildRequires: nss-devel >= 3.34
|
||||
BuildRequires: nspr-devel >= 4.32
|
||||
BuildRequires: nss-devel >= 3.67.0-7
|
||||
BuildRequires: openldap-devel
|
||||
BuildRequires: libdb-devel
|
||||
BuildRequires: cyrus-sasl-devel
|
||||
@ -335,8 +372,8 @@ Summary: Development libraries for 389 Directory Server
|
||||
Group: Development/Libraries
|
||||
Requires: %{name}-libs = %{version}-%{release}
|
||||
Requires: pkgconfig
|
||||
Requires: nspr-devel
|
||||
Requires: nss-devel >= 3.34
|
||||
Requires: nspr-devel >= 4.32
|
||||
Requires: nss-devel >= 3.67.0-7
|
||||
Requires: openldap-devel
|
||||
Requires: libtalloc
|
||||
Requires: libevent
|
||||
@ -363,6 +400,7 @@ SNMP Agent for the 389 Directory Server base package.
|
||||
Summary: A library for accessing, testing, and configuring the 389 Directory Server
|
||||
BuildArch: noarch
|
||||
Group: Development/Libraries
|
||||
Requires: 389-ds-base
|
||||
Requires: openssl
|
||||
Requires: iproute
|
||||
Requires: platform-python
|
||||
@ -376,6 +414,7 @@ Requires: python%{python3_pkgversion}-argcomplete
|
||||
Requires: python%{python3_pkgversion}-libselinux
|
||||
Requires: python%{python3_pkgversion}-setuptools
|
||||
Requires: python%{python3_pkgversion}-distro
|
||||
Requires: python%{python3_pkgversion}-cryptography
|
||||
%{?python_provide:%python_provide python%{python3_pkgversion}-lib389}
|
||||
|
||||
%description -n python%{python3_pkgversion}-lib389
|
||||
@ -396,7 +435,7 @@ A cockpit UI Plugin for configuring and administering the 389 Directory Server
|
||||
%autosetup -p1 -v -n %{name}-%{version}%{?prerel}
|
||||
%if %{use_rust}
|
||||
tar xvzf %{SOURCE4}
|
||||
cp %{SOURCE5} src/
|
||||
cp %{SOURCE5} src/Cargo.lock
|
||||
%endif
|
||||
%if %{bundle_jemalloc}
|
||||
%setup -q -n %{name}-%{version}%{?prerel} -T -D -b 3
|
||||
@ -887,47 +926,77 @@ exit 0
|
||||
%doc README.md
|
||||
|
||||
%changelog
|
||||
* Thu May 19 2022 Thierry Bordaz <tbordaz@redhat.com> - 1.4.3.28-7
|
||||
- Bump version to 1.4.3.28-7
|
||||
- Resolves: Bug 2081008 - CVE-2022-0996 389-ds:1.4/389-ds-base: expired password was still allowed to access the database
|
||||
- Resolves: Bug 2081014 - CVE-2022-0918 389-ds:1.4/389-ds-base: sending crafted message could result in DoS
|
||||
* Mon Sep 09 2024 Viktor Ashirov <vashirov@redhat.com> - 1.4.3.39-8
|
||||
- Bump version to 1.4.3.39-8
|
||||
- Resolves: RHEL-40943 - CVE-2024-5953 389-ds:1.4/389-ds-base: Malformed userPassword hash may cause Denial of Service [rhel-8.10.z]
|
||||
- Resolves: RHEL-58069 - perf search result investigation for many large static groups and members [rhel-8.10.0.z]
|
||||
|
||||
* Thu Feb 3 2022 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-6
|
||||
- Bump version to 1.4.3.28-6
|
||||
- Resolves: Bug 2047171 - Based on 1944494 (RFC 4530 entryUUID attribute) - plugin entryuuid failing
|
||||
* Thu Jun 13 2024 Viktor Ashirov <vashirov@redhat.com> - 1.4.3.39-7
|
||||
- Bump version to 1.4.3.39-7
|
||||
- Resolves: RHEL-16277 - LDAP connections are closed with code T2 before the IO block timeout is reached. [rhel-8.10.0.z]
|
||||
|
||||
* Fri Jan 28 2022 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-5
|
||||
- Bump version to 1.4.3.28-5
|
||||
- Resolves: Bug 2045223 - ipa-restore command is failing when restore after uninstalling the server (aprt 2)
|
||||
* Thu Jun 13 2024 Viktor Ashirov <vashirov@redhat.com> - 1.4.3.39-6
|
||||
- Bump version to 1.4.3.39-6
|
||||
- Resolves: RHEL-16277 - LDAP connections are closed with code T2 before the IO block timeout is reached. [rhel-8.10.0.z]
|
||||
|
||||
* Tue Jan 25 2022 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-4
|
||||
- Bump version to 1.4.3.28-4
|
||||
- Resolves: Bug 2045223 - ipa-restore command is failing when restore after uninstalling the server
|
||||
* Tue Jun 11 2024 Viktor Ashirov <vashirov@redhat.com> - 1.4.3.39-5
|
||||
- Bump version to 1.4.3.39-5
|
||||
- Resolves: RHEL-16277 - LDAP connections are closed with code T2 before the IO block timeout is reached. [rhel-8.10.0.z]
|
||||
|
||||
* Thu Nov 18 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-3
|
||||
- Bump version to 1.4.3.28-3
|
||||
- Resolves: Bug 2030367 - EMBARGOED CVE-2021-4091 389-ds:1.4/389-ds-base: double-free of the virtual attribute context in persistent search
|
||||
- Resolves: Bug 2033398 - PBKDF2 hashing does not work in FIPS mode
|
||||
* Thu Jun 06 2024 James Chapman <jachapma@redhat.com> - 1.4.3.39-4
|
||||
- Bump version to 1.4.3.39-4
|
||||
- Resolves: RHEL-34818 - redhat-ds:11/389-ds-base: Malformed userPassword may cause crash at do_modify in slapd/modify.c
|
||||
- Resolves: RHEL-34824 - redhat-ds:11/389-ds-base: potential denial of service via specially crafted kerberos AS-REQ request
|
||||
|
||||
* Thu Nov 18 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-2
|
||||
- Bump version to 1.4.3.28-2
|
||||
- Resolves: Bug 2024695 - DB corruption "_entryrdn_insert_key - Same DN (dn: nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff,<SUFFIX>) is already in the entryrdn file"
|
||||
- Resolves: Bug 1859210 - systemd-tmpfiles warnings
|
||||
- Resolves: Bug 1913199 - IPA server (389ds) is very slow in execution of some searches (`&(memberOf=...)(objectClass=ipaHost)` in particular)
|
||||
- Resolves: Bug 1974236 - automatique disable of virtual attribute checking
|
||||
- Resolves: Bug 1976882 - logconv.pl -j: Use of uninitialized value $first in numeric gt (>)
|
||||
- Resolves: Bug 1981281 - ipa user-add fails with "gecos: value invalid per syntax: Invalid syntax"
|
||||
- Resolves: Bug 2015998 - Log the Auto Member invalid regex rules in the LDAP errors log
|
||||
* Thu Mar 14 2024 Simon Pichugin <spichugi@redhat.com> - 1.4.3.39-3
|
||||
- Bump version to 1.4.3.39-3
|
||||
- Resolves: RHEL-19240 - RFE Add PROXY protocol support to 389-ds-base via confiuration item - similar to Postfix
|
||||
|
||||
* Thu Oct 21 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.28-1
|
||||
- Bump version to 1.4.3.28-1
|
||||
- Resolves: Bug 2016014 - rebase RHEL 8.6 with 389-ds-base-1.4.3
|
||||
- Resolves: Bug 1990002 - monitor displays wrong date for connection
|
||||
- Resolves: Bug 1950335 - upgrade password hash on bind also causes passwordExpirationtime to be updated
|
||||
- Resolves: Bug 1916292 - Indexing a single backend actually processes all configured backends
|
||||
- Resolves: Bug 1780842 - [RFE] set db home directory to /dev/shm by default
|
||||
- Resolves: Bug 2000975 - Retro Changelog does not trim changes
|
||||
* Mon Feb 05 2024 Thierry Bordaz <tbordaz@redhat.com> - 1.4.3.39-2
|
||||
- Bump version to 1.4.3.39-2
|
||||
- Resolves: RHEL-23209 - CVE-2024-1062 389-ds:1.4/389-ds-base: a heap overflow leading to denail-of-servce while writing a value larger than 256 chars (in log_entry_attr)
|
||||
- Resolves: RHEL-5390 - schema-compat-plugin expensive with automember rebuild
|
||||
- Resolves: RHEL-5135 - crash in sync_update_persist_op() of content sync plugin
|
||||
|
||||
* Tue Jan 16 2024 Simon Pichugin <spichugi@redhat.com> - 1.4.3.39-1
|
||||
- Bump version to 1.4.3.39-1
|
||||
- Resolves: RHEL-19028 - Rebase 389-ds-base in RHEL 8.10 to 1.4.3.39
|
||||
- Resolves: RHEL-19240 - [RFE] Add PROXY protocol support to 389-ds-base
|
||||
- Resolves: RHEL-5143 - SELinux labeling for dirsrv files seen during ipa install/uninstall should be moved to DEBUG.
|
||||
- Resolves: RHEL-5107 - bdb_start - Detected Disorderly Shutdown directory server is not starting
|
||||
- Resolves: RHEL-16338 - ns-slapd crash in slapi_attr_basetype
|
||||
- Resolves: RHEL-14025 - After an upgrade the LDAP server won't start if nsslapd-conntablesize is present in the dse.ldif file.
|
||||
|
||||
|
||||
* Fri Dec 08 2023 James Chapman <jachapma@redhat.com> - 1.4.3.38-1
|
||||
- Bump version to 1.4.3.38-1
|
||||
- Resolves: RHEL-19028 - Rebase 389-ds-base in RHEL 8.10 to 1.4.3.38
|
||||
|
||||
* Wed Aug 16 2023 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.37-1
|
||||
- Bump versionto 1.4.3.37-1
|
||||
- Resolves: rhbz#2224505 - Paged search impacts performance
|
||||
- Resolves: rhbz#2220890 - healthcheck tool needs to be updates for new default password storage scheme
|
||||
- Resolves: rhbz#2218235 - python3-lib389: Python tarfile extraction needs change to avoid a warning
|
||||
- Resolves: rhbz#2210491 - dtablesize being set to soft maxfiledescriptor limit causing massive slowdown in large enviroments.
|
||||
- Resolves: rhbz#2149967 - SELinux labeling for dirsrv files seen during ipa install/uninstall should be moved to DEBUG
|
||||
|
||||
* Tue Jul 11 2023 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.36-2
|
||||
- Bump version to 1.4.3.36-2
|
||||
- Resolves: rhbz#2220890 - healthcheck tool needs to be updates for new default password storage scheme
|
||||
|
||||
* Wed Jun 14 2023 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.36-1
|
||||
- Bump version to 1.4.3.36-1
|
||||
- Resolves: rhbz#2188628 - Rebase 389-ds-base in RHEL 8.9 to 1.4.3.36
|
||||
|
||||
* Mon May 22 2023 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.35-1
|
||||
- Bump version to 1.4.3.35-1
|
||||
- Resolves: rhbz#2188628 - Rebase 389-ds-base in RHEL 8.9 to 1.4.3.35
|
||||
|
||||
* Tue Nov 15 2022 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.32-1
|
||||
- Bump version to 1.4.3.32-1
|
||||
- Resolves: Bug 2098138 - broken nsslapd-subtree-rename-switch option in rhds11
|
||||
- Resolves: Bug 2119063 - entryuuid fixup tasks fails because entryUUID is not mutable
|
||||
- Resolves: Bug 2136610 - [RFE] Add 'cn' attribute to IPA audit logs
|
||||
- Resolves: Bug 2142638 - pam mutex lock causing high etimes, affecting red hat internal sso
|
||||
- Resolves: Bug 2096795 - [RFE] Support ECDSA private keys for TLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user