ldap/servers
by Ludwig Krispenz
ldap/servers/plugins/dna/dna.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 32aa1721054c2e024108fea9ed48a39b2e99a8df
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Mon Oct 6 17:12:42 2014 +0200
Ticket 47918 - result of dna_dn_is_shared_config is incorrectly used
Bug Description: dna_load_shared_servers() is called for all entries,
except the config entries
Fix Description: revert the logic of the result of dna_dn_is_shared_config()
https://fedorahosted.org/389/ticket/47918
Reviewed by: Mark, Thanks
diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c
index b42150a..bc280a4 100644
--- a/ldap/servers/plugins/dna/dna.c
+++ b/ldap/servers/plugins/dna/dna.c
@@ -4163,7 +4163,7 @@ static int dna_config_check_post_op(Slapi_PBlock * pb)
if (dna_dn_is_config(dn)) {
dna_load_plugin_config(pb, 0);
}
- if(dna_dn_is_shared_config(pb, dn) == 0){
+ if(dna_dn_is_shared_config(pb, dn)){
dna_load_shared_servers();
}
}
9 years, 6 months
admserv/cgi-src40
by Noriko Hosoi
admserv/cgi-src40/admpw.c | 5 -
admserv/cgi-src40/sec-activate.c | 111 ++++++++++++++++++++++++++-------------
2 files changed, 75 insertions(+), 41 deletions(-)
New commits:
commit c9b6de5743e2fd7c965a1b8e99c3942b6734aed7
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Sat Oct 4 21:53:29 2014 -0700
Ticket #47493 - Configuration Tab does not work with FIPS mode enabled
Bug Description: Admin Server CGI sec-activate retrieves attribute
values of
dn: cn=encryption,cn=configuration,cn=admin-serv-ID,cn=389 Administration
Server,cn=Server Group,cn=FQDN,ou=DOMAIN,o=NetscapeRoot
and return them to the client such as Console. The CGI sec-activate
was supposed to get the knowledge if the FIPS mode is enabled or not,
and return ciphers FIPS compliant, but the code was missing.
In this patch, the code is added to check if it is FIPS mode or not
and if it is, return just FIPS friendly ciphers in this patch.
Plus unnecessary temp buffer and copies from temp to temp_return were
removed.
https://fedorahosted.org/389/ticket/47493
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/admserv/cgi-src40/admpw.c b/admserv/cgi-src40/admpw.c
index e695881..1e24423 100644
--- a/admserv/cgi-src40/admpw.c
+++ b/admserv/cgi-src40/admpw.c
@@ -50,11 +50,6 @@
#include <pk11pqg.h>
#include <base64.h>
-/* NSS - for password hashing */
-#include <pk11func.h>
-#include <pk11pqg.h>
-#include <base64.h>
-
#include "libadminutil/resource.h"
#include "libadminutil/admutil.h"
#include "libadminutil/distadm.h"
diff --git a/admserv/cgi-src40/sec-activate.c b/admserv/cgi-src40/sec-activate.c
index 6ae70ed..08568ca 100644
--- a/admserv/cgi-src40/sec-activate.c
+++ b/admserv/cgi-src40/sec-activate.c
@@ -38,6 +38,10 @@
extern "C" {
#endif
+#include <string.h>
+#include "nspr.h"
+#include "pk11func.h"
+
#include "cert.h"
#include "key.h"
#include "certdb.h"
@@ -213,18 +217,46 @@ int get_cert_nickname(char *buf, size_t bufsize) {
}
return -1;
}
+
+void
+drop_non_fips(char *val)
+{
+ char *p = NULL;
+ char *endp = NULL;
+ if (!val) {
+ return;
+ }
+ p = PL_strchr(val, '+');
+ while (p) {
+ endp = PL_strchr(p, ',');
+ if (endp) {
+ *endp = '\0';
+ /* E.g., p = "+rsa_rc2_40_md5" or p = "+fips_3des_sha" */
+ if (!PL_strcasestr(p, "fips")) {
+ *p = '-';
+ }
+ *endp = ',';
+ p = PL_strchr(endp+1, '+');
+ } else {
+ break;
+ }
+ }
+}
+
/*
* int GetSSLFamilyAttributes
* Reads all LDAP entries relating to cipher family information.
* Returns return_string, a string of all information found, and
* 0 on success, -1 on failure.
*/
-int GetSSLFamilyAttributes(PsetHndl pset, char **return_string) {
-
+int
+GetSSLFamilyAttributes(PsetHndl pset, char **return_string)
+{
AttrNameList family_list;
int errorCode;
char temp_return[5000];
- char temp[1000];
+ char *tmpp = NULL;
+ size_t tmplen = 0;
char **family;
char family_attribute[1024];
@@ -233,6 +265,7 @@ int GetSSLFamilyAttributes(PsetHndl pset, char **return_string) {
char *val;
char *family_name;
+ PRBool isfips = PR_FALSE;
*return_string = NULL;
strcpy(temp_return, "");
@@ -240,11 +273,9 @@ int GetSSLFamilyAttributes(PsetHndl pset, char **return_string) {
val = psetGetAttrSingleValue(pset,
"configuration.nsServerSecurity",
&errorCode);
- if(val)
- PR_snprintf(temp, sizeof(temp), "security=%s\n", val);
- else
- PR_snprintf(temp, sizeof(temp), "security=off\n");
- PL_strcatn(temp_return, sizeof(temp_return), temp);
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "security=%s\n", val?val:"off");
if((family_list = psetGetChildren(pset, "configuration.Encryption", &errorCode))) {
@@ -276,67 +307,75 @@ int GetSSLFamilyAttributes(PsetHndl pset, char **return_string) {
family_name = strrchr(*family, '.');
family_name++;
- PR_snprintf(temp, sizeof(temp), "familyList=%s\n", family_name);
- PL_strcatn(temp_return, sizeof(temp_return), temp);
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "familyList=%s\n", family_name);
- PR_snprintf(temp, sizeof(temp), "%s-activated=%s\n", family_name, val);
- PL_strcatn(temp_return, sizeof(temp_return), temp);
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "%s-activated=%s\n", family_name, val);
- PR_snprintf(temp, sizeof(temp), "%s-token=%s\n", family_name, token);
- PL_strcatn(temp_return, sizeof(temp_return), temp);
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "%s-token=%s\n", family_name, token);
- PR_snprintf(temp, sizeof(temp), "%s-cert=%s\n", family_name, personality);
- PL_strcatn(temp_return, sizeof(temp_return), temp);
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "%s-cert=%s\n", family_name, personality);
}
}
PL_strcatn(temp_return, sizeof(temp_return), "familyList=NULL\n");
/* get cipher preferences */
+ isfips = PK11_IsFIPS();
val = NULL;
val = psetGetAttrSingleValue(pset,
"configuration.encryption.nsSSL2",
&errorCode);
- PL_strcatn(temp_return, sizeof(temp_return), "ssl2-activated=");
- if(val)
- PL_strcatn(temp_return, sizeof(temp_return), val);
- PL_strcatn(temp_return, sizeof(temp_return), "\n");
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "ssl2-activated=%s\n", val?val:"");
val = NULL;
val = psetGetAttrSingleValue(pset,
"configuration.encryption.nsSSL2Ciphers",
&errorCode);
- PL_strcatn(temp_return, sizeof(temp_return), "ssl2=");
- if(val)
- PL_strcatn(temp_return, sizeof(temp_return), val);
- PL_strcatn(temp_return, sizeof(temp_return), "\n");
+ /* If is fips, don't allow ciphers without "fips" */
+ if (isfips) {
+ drop_non_fips(val);
+ }
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "ssl2=%s\n", val?val:"");
val = NULL;
val = psetGetAttrSingleValue(pset,
"configuration.encryption.nsSSL3",
&errorCode);
- PL_strcatn(temp_return, sizeof(temp_return), "ssl3-activated=");
- if(val)
- PL_strcatn(temp_return, sizeof(temp_return), val);
- PL_strcatn(temp_return, sizeof(temp_return), "\n");
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "ssl3-activated=%s\n", val?val:"");
val = NULL;
val = psetGetAttrSingleValue(pset,
"configuration.encryption.nsSSL3Ciphers",
&errorCode);
- PL_strcatn(temp_return, sizeof(temp_return), "ssl3=");
- if(val)
- PL_strcatn(temp_return, sizeof(temp_return), val);
- PL_strcatn(temp_return, sizeof(temp_return), "\n");
+ /* If is fips, don't allow ciphers without "fips" */
+ if (isfips) {
+ drop_non_fips(val);
+ }
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "ssl3=%s\n", val?val:"");
val = NULL;
val = psetGetAttrSingleValue(pset,
"configuration.encryption.nsSSLClientAuth",
&errorCode);
- PL_strcatn(temp_return, sizeof(temp_return), "clientauth=");
- if(val)
- PL_strcatn(temp_return, sizeof(temp_return), val);
- PL_strcatn(temp_return, sizeof(temp_return), "\n");
+ tmplen = strlen(temp_return);
+ tmpp = temp_return + tmplen;
+ PR_snprintf(tmpp, sizeof(temp_return) - tmplen, "clientauth=%s\n", val?val:"");
*return_string = PORT_Strdup(temp_return);
return 0;
9 years, 6 months
Branch '389-ds-base-1.2.11' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47900_test.py | 398 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/libglobs.c | 2
ldap/servers/slapd/pw.c | 18 +
3 files changed, 415 insertions(+), 3 deletions(-)
New commits:
commit ed6f09b278431967f9e8f1ca0ccb7484dc07f189
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Oct 2 10:17:13 2014 -0400
Ticket 47900 - Server fails to start if password admin is set
Bug Description: The server will crash at startup if the password admin is set.
Fix Description: When creating a password policy for the pblock, which we do
for add and modifiy operations, make sure the server is fully
up and running before searching backends for password admins.
Also, allow passwordAdminDN to be deleted from the cn=config.
https://fedorahosted.org/389/ticket/47900
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 4711de687174d6e5dd7b2c04782b62dc1cb90a6e)
diff --git a/dirsrvtests/tickets/ticket47900_test.py b/dirsrvtests/tickets/ticket47900_test.py
new file mode 100644
index 0000000..4e6f5d7
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47900_test.py
@@ -0,0 +1,398 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+ADMIN_NAME = 'passwd_admin'
+ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
+ADMIN_PWD = 'adminPassword_1'
+ENTRY_NAME = 'Joe Schmo'
+ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
+INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47900(topology):
+ """
+ Test that password administrators/root DN can
+ bypass password syntax/policy.
+
+ We need to test how passwords are modified in
+ existing entries, and when adding new entries.
+
+ Create the Password Admin entry, but do not set
+ it as an admin yet. Use the entry to verify invalid
+ passwords are caught. Then activate the password
+ admin and make sure it can bypass password policy.
+ """
+
+ # Prepare the Password Administator
+ entry = Entry(ADMIN_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ADMIN_NAME)
+ entry.setValues('cn', ADMIN_NAME)
+ entry.setValues('userpassword', ADMIN_PWD)
+
+ topology.standalone.log.info("Creating Password Administator entry %s..." % ADMIN_DN)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Unexpected result ' + e.message['desc'])
+ assert False
+ topology.standalone.log.error("Failed to add Password Administator %s, error: %s "
+ % (ADMIN_DN, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info("Configuring password policy...")
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinTokenLength' , '1'),
+ (ldap.MOD_REPLACE, 'passwordExp' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinDigits' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinSpecials' , '1')])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed configure password policy: ' + e.message['desc'])
+ assert False
+
+ #
+ # Add an aci to allow everyone all access (just makes things easier)
+ #
+ topology.standalone.log.info("Add aci to allow password admin to add/update entries...")
+
+ ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
+ ACI_TARGETATTR = "(targetattr = *)"
+ ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
+ ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
+ ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ try:
+ topology.standalone.modify_s(SUFFIX, mod)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add aci for password admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Bind as the Password Admin
+ #
+ topology.standalone.log.info("Bind as the Password Administator (before activating)...")
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Setup our test entry, and test password policy is working
+ #
+ entry = Entry(ENTRY_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ENTRY_NAME)
+ entry.setValues('cn', ENTRY_NAME)
+
+ #
+ # Start by attempting to add an entry with an invalid password
+ #
+ topology.standalone.log.info("Attempt to add entries with invalid passwords, these adds should fail...")
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Add failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an entry " +
+ "with an invalid password (%s)" % (passwd))
+ assert False
+
+
+ #
+ # Now activate a password administator, bind as root dn to do the config
+ # update, then rebind as the password admin
+ #
+ topology.standalone.log.info("Activate the Password Administator...")
+
+ # Bind as Root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Start adding entries with invalid passwords, delete the entry after each pass.
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info('Succesfully added entry (%s)' % ENTRY_DN)
+
+ # Delete entry for the next pass
+ try:
+ topology.standalone.delete_s(ENTRY_DN)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to delete entry: %s' % (e.message['desc']))
+ assert False
+
+
+ #
+ # Add the entry for the next round of testing (modify password)
+ #
+ entry.setValues('userpassword', ADMIN_PWD)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with valid password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ #
+ # Deactivate the password admin and make sure invalid password updates fail
+ #
+ topology.standalone.log.info("Deactivate Password Administator and try invalid password updates...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to remove password admin from config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make invalid password updates that should fail
+ #
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Password update failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an invalid password (%s)"
+ % (passwd))
+ assert False
+
+ #
+ # Now activate a password administator
+ #
+ topology.standalone.log.info("Activate Password Administator and try updates again...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make the same password updates, but this time they should succeed
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Password update failed unexpectedly: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+ topology.standalone.log.info('Password update succeeded (%s)' % passwd)
+ #
+ # Test passed
+ #
+ topology.standalone.log.info('Test 47900 Passed.')
+
+
+def test_ticket47900_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47900(topo)
+
+if __name__ == '__main__':
+ run_isolated()
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index b2cb8e2..63093e1 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1446,7 +1446,7 @@ FrontendConfig_init () {
init_entryusn_global = cfg->entryusn_global = LDAP_OFF;
cfg->entryusn_import_init = slapi_ch_strdup(ENTRYUSN_IMPORT_INIT);
- cfg->allowed_to_delete_attrs = slapi_ch_strdup("nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
+ cfg->allowed_to_delete_attrs = slapi_ch_strdup("passwordadmindn nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
cfg->default_naming_context = NULL; /* store normalized dn */
init_disk_monitoring = cfg->disk_monitoring = LDAP_OFF;
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 3a1e4a1..94fc08e 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1643,13 +1643,27 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
slapdFrontendConfig_t *slapdFrontendConfig;
int optype = -1;
- slapdFrontendConfig = getFrontendConfig();
- pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+ /* If we already allocated a pw policy, return it */
+ if(pb && pb->pwdpolicy){
+ return pb->pwdpolicy;
+ }
+
+ if (g_get_active_threadcnt() == 0){
+ /*
+ * If the server is starting up the thread count will be zero, so
+ * we should not proceed, because not all the backends have been
+ * initialized yet.
+ */
+ return NULL;
+ }
if (pb) {
slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
}
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
/* If we're doing an add, COS does not apply yet so we check
parents for the pwdpolicysubentry. We look only for virtual
9 years, 6 months
Branch '389-ds-base-1.3.1' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47900_test.py | 398 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/libglobs.c | 2
ldap/servers/slapd/pw.c | 13 -
3 files changed, 410 insertions(+), 3 deletions(-)
New commits:
commit 46051b42d3917ff0c899b8480b5374429441f89e
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Oct 2 10:17:13 2014 -0400
Ticket 47900 - Server fails to start if password admin is set
Bug Description: The server will crash at startup if the password admin is set.
Fix Description: When creating a password policy for the pblock, which we do
for add and modifiy operations, make sure the server is fully
up and running before searching backends for password admins.
Also, allow passwordAdminDN to be deleted from the cn=config.
https://fedorahosted.org/389/ticket/47900
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 4711de687174d6e5dd7b2c04782b62dc1cb90a6e)
diff --git a/dirsrvtests/tickets/ticket47900_test.py b/dirsrvtests/tickets/ticket47900_test.py
new file mode 100644
index 0000000..4e6f5d7
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47900_test.py
@@ -0,0 +1,398 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+ADMIN_NAME = 'passwd_admin'
+ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
+ADMIN_PWD = 'adminPassword_1'
+ENTRY_NAME = 'Joe Schmo'
+ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
+INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47900(topology):
+ """
+ Test that password administrators/root DN can
+ bypass password syntax/policy.
+
+ We need to test how passwords are modified in
+ existing entries, and when adding new entries.
+
+ Create the Password Admin entry, but do not set
+ it as an admin yet. Use the entry to verify invalid
+ passwords are caught. Then activate the password
+ admin and make sure it can bypass password policy.
+ """
+
+ # Prepare the Password Administator
+ entry = Entry(ADMIN_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ADMIN_NAME)
+ entry.setValues('cn', ADMIN_NAME)
+ entry.setValues('userpassword', ADMIN_PWD)
+
+ topology.standalone.log.info("Creating Password Administator entry %s..." % ADMIN_DN)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Unexpected result ' + e.message['desc'])
+ assert False
+ topology.standalone.log.error("Failed to add Password Administator %s, error: %s "
+ % (ADMIN_DN, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info("Configuring password policy...")
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinTokenLength' , '1'),
+ (ldap.MOD_REPLACE, 'passwordExp' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinDigits' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinSpecials' , '1')])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed configure password policy: ' + e.message['desc'])
+ assert False
+
+ #
+ # Add an aci to allow everyone all access (just makes things easier)
+ #
+ topology.standalone.log.info("Add aci to allow password admin to add/update entries...")
+
+ ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
+ ACI_TARGETATTR = "(targetattr = *)"
+ ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
+ ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
+ ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ try:
+ topology.standalone.modify_s(SUFFIX, mod)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add aci for password admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Bind as the Password Admin
+ #
+ topology.standalone.log.info("Bind as the Password Administator (before activating)...")
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Setup our test entry, and test password policy is working
+ #
+ entry = Entry(ENTRY_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ENTRY_NAME)
+ entry.setValues('cn', ENTRY_NAME)
+
+ #
+ # Start by attempting to add an entry with an invalid password
+ #
+ topology.standalone.log.info("Attempt to add entries with invalid passwords, these adds should fail...")
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Add failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an entry " +
+ "with an invalid password (%s)" % (passwd))
+ assert False
+
+
+ #
+ # Now activate a password administator, bind as root dn to do the config
+ # update, then rebind as the password admin
+ #
+ topology.standalone.log.info("Activate the Password Administator...")
+
+ # Bind as Root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Start adding entries with invalid passwords, delete the entry after each pass.
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info('Succesfully added entry (%s)' % ENTRY_DN)
+
+ # Delete entry for the next pass
+ try:
+ topology.standalone.delete_s(ENTRY_DN)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to delete entry: %s' % (e.message['desc']))
+ assert False
+
+
+ #
+ # Add the entry for the next round of testing (modify password)
+ #
+ entry.setValues('userpassword', ADMIN_PWD)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with valid password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ #
+ # Deactivate the password admin and make sure invalid password updates fail
+ #
+ topology.standalone.log.info("Deactivate Password Administator and try invalid password updates...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to remove password admin from config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make invalid password updates that should fail
+ #
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Password update failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an invalid password (%s)"
+ % (passwd))
+ assert False
+
+ #
+ # Now activate a password administator
+ #
+ topology.standalone.log.info("Activate Password Administator and try updates again...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make the same password updates, but this time they should succeed
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Password update failed unexpectedly: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+ topology.standalone.log.info('Password update succeeded (%s)' % passwd)
+ #
+ # Test passed
+ #
+ topology.standalone.log.info('Test 47900 Passed.')
+
+
+def test_ticket47900_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47900(topo)
+
+if __name__ == '__main__':
+ run_isolated()
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index ca31ab9..8d48af8 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1503,7 +1503,7 @@ FrontendConfig_init () {
init_entryusn_global = cfg->entryusn_global = LDAP_OFF;
cfg->entryusn_import_init = slapi_ch_strdup(ENTRYUSN_IMPORT_INIT);
- cfg->allowed_to_delete_attrs = slapi_ch_strdup("nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
+ cfg->allowed_to_delete_attrs = slapi_ch_strdup("passwordadmindn nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
cfg->default_naming_context = NULL; /* store normalized dn */
cfg->allowed_sasl_mechs = NULL;
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 94ececb..7b803dd 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1620,13 +1620,22 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
return pb->pwdpolicy;
}
- slapdFrontendConfig = getFrontendConfig();
- pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+ if (g_get_active_threadcnt() == 0){
+ /*
+ * If the server is starting up the thread count will be zero, so
+ * we should not proceed, because not all the backends have been
+ * initialized yet.
+ */
+ return NULL;
+ }
if (pb) {
slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
}
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
/* If we're doing an add, COS does not apply yet so we check
parents for the pwdpolicysubentry. We look only for virtual
9 years, 6 months
Branch '389-ds-base-1.3.2' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47900_test.py | 398 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/libglobs.c | 2
ldap/servers/slapd/pw.c | 13 -
3 files changed, 410 insertions(+), 3 deletions(-)
New commits:
commit f9eed02496e41426bdd3ba054bff04b4bf9825d5
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Oct 2 10:17:13 2014 -0400
Ticket 47900 - Server fails to start if password admin is set
Bug Description: The server will crash at startup if the password admin is set.
Fix Description: When creating a password policy for the pblock, which we do
for add and modifiy operations, make sure the server is fully
up and running before searching backends for password admins.
Also, allow passwordAdminDN to be deleted from the cn=config.
https://fedorahosted.org/389/ticket/47900
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 4711de687174d6e5dd7b2c04782b62dc1cb90a6e)
diff --git a/dirsrvtests/tickets/ticket47900_test.py b/dirsrvtests/tickets/ticket47900_test.py
new file mode 100644
index 0000000..4e6f5d7
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47900_test.py
@@ -0,0 +1,398 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+ADMIN_NAME = 'passwd_admin'
+ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
+ADMIN_PWD = 'adminPassword_1'
+ENTRY_NAME = 'Joe Schmo'
+ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
+INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47900(topology):
+ """
+ Test that password administrators/root DN can
+ bypass password syntax/policy.
+
+ We need to test how passwords are modified in
+ existing entries, and when adding new entries.
+
+ Create the Password Admin entry, but do not set
+ it as an admin yet. Use the entry to verify invalid
+ passwords are caught. Then activate the password
+ admin and make sure it can bypass password policy.
+ """
+
+ # Prepare the Password Administator
+ entry = Entry(ADMIN_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ADMIN_NAME)
+ entry.setValues('cn', ADMIN_NAME)
+ entry.setValues('userpassword', ADMIN_PWD)
+
+ topology.standalone.log.info("Creating Password Administator entry %s..." % ADMIN_DN)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Unexpected result ' + e.message['desc'])
+ assert False
+ topology.standalone.log.error("Failed to add Password Administator %s, error: %s "
+ % (ADMIN_DN, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info("Configuring password policy...")
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinTokenLength' , '1'),
+ (ldap.MOD_REPLACE, 'passwordExp' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinDigits' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinSpecials' , '1')])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed configure password policy: ' + e.message['desc'])
+ assert False
+
+ #
+ # Add an aci to allow everyone all access (just makes things easier)
+ #
+ topology.standalone.log.info("Add aci to allow password admin to add/update entries...")
+
+ ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
+ ACI_TARGETATTR = "(targetattr = *)"
+ ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
+ ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
+ ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ try:
+ topology.standalone.modify_s(SUFFIX, mod)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add aci for password admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Bind as the Password Admin
+ #
+ topology.standalone.log.info("Bind as the Password Administator (before activating)...")
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Setup our test entry, and test password policy is working
+ #
+ entry = Entry(ENTRY_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ENTRY_NAME)
+ entry.setValues('cn', ENTRY_NAME)
+
+ #
+ # Start by attempting to add an entry with an invalid password
+ #
+ topology.standalone.log.info("Attempt to add entries with invalid passwords, these adds should fail...")
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Add failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an entry " +
+ "with an invalid password (%s)" % (passwd))
+ assert False
+
+
+ #
+ # Now activate a password administator, bind as root dn to do the config
+ # update, then rebind as the password admin
+ #
+ topology.standalone.log.info("Activate the Password Administator...")
+
+ # Bind as Root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Start adding entries with invalid passwords, delete the entry after each pass.
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info('Succesfully added entry (%s)' % ENTRY_DN)
+
+ # Delete entry for the next pass
+ try:
+ topology.standalone.delete_s(ENTRY_DN)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to delete entry: %s' % (e.message['desc']))
+ assert False
+
+
+ #
+ # Add the entry for the next round of testing (modify password)
+ #
+ entry.setValues('userpassword', ADMIN_PWD)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with valid password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ #
+ # Deactivate the password admin and make sure invalid password updates fail
+ #
+ topology.standalone.log.info("Deactivate Password Administator and try invalid password updates...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to remove password admin from config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make invalid password updates that should fail
+ #
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Password update failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an invalid password (%s)"
+ % (passwd))
+ assert False
+
+ #
+ # Now activate a password administator
+ #
+ topology.standalone.log.info("Activate Password Administator and try updates again...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make the same password updates, but this time they should succeed
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Password update failed unexpectedly: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+ topology.standalone.log.info('Password update succeeded (%s)' % passwd)
+ #
+ # Test passed
+ #
+ topology.standalone.log.info('Test 47900 Passed.')
+
+
+def test_ticket47900_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47900(topo)
+
+if __name__ == '__main__':
+ run_isolated()
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 691b6f5..1ce1fea 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1535,7 +1535,7 @@ FrontendConfig_init () {
init_entryusn_global = cfg->entryusn_global = LDAP_OFF;
cfg->entryusn_import_init = slapi_ch_strdup(ENTRYUSN_IMPORT_INIT);
- cfg->allowed_to_delete_attrs = slapi_ch_strdup("nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
+ cfg->allowed_to_delete_attrs = slapi_ch_strdup("passwordadmindn nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
cfg->default_naming_context = NULL; /* store normalized dn */
cfg->allowed_sasl_mechs = NULL;
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index a4d2dc6..9c541c5 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1629,13 +1629,22 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
return pb->pwdpolicy;
}
- slapdFrontendConfig = getFrontendConfig();
- pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+ if (g_get_active_threadcnt() == 0){
+ /*
+ * If the server is starting up the thread count will be zero, so
+ * we should not proceed, because not all the backends have been
+ * initialized yet.
+ */
+ return NULL;
+ }
if (pb) {
slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
}
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
/* If we're doing an add, COS does not apply yet so we check
parents for the pwdpolicysubentry. We look only for virtual
9 years, 6 months
Branch '389-ds-base-1.3.3' - dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47900_test.py | 398 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/libglobs.c | 2
ldap/servers/slapd/pw.c | 13 -
3 files changed, 410 insertions(+), 3 deletions(-)
New commits:
commit 1bf510c11c2041e09cb991af79ce44523040281e
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Oct 2 10:17:13 2014 -0400
Ticket 47900 - Server fails to start if password admin is set
Bug Description: The server will crash at startup if the password admin is set.
Fix Description: When creating a password policy for the pblock, which we do
for add and modifiy operations, make sure the server is fully
up and running before searching backends for password admins.
Also, allow passwordAdminDN to be deleted from the cn=config.
https://fedorahosted.org/389/ticket/47900
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit 4711de687174d6e5dd7b2c04782b62dc1cb90a6e)
diff --git a/dirsrvtests/tickets/ticket47900_test.py b/dirsrvtests/tickets/ticket47900_test.py
new file mode 100644
index 0000000..4e6f5d7
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47900_test.py
@@ -0,0 +1,398 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+ADMIN_NAME = 'passwd_admin'
+ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
+ADMIN_PWD = 'adminPassword_1'
+ENTRY_NAME = 'Joe Schmo'
+ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
+INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47900(topology):
+ """
+ Test that password administrators/root DN can
+ bypass password syntax/policy.
+
+ We need to test how passwords are modified in
+ existing entries, and when adding new entries.
+
+ Create the Password Admin entry, but do not set
+ it as an admin yet. Use the entry to verify invalid
+ passwords are caught. Then activate the password
+ admin and make sure it can bypass password policy.
+ """
+
+ # Prepare the Password Administator
+ entry = Entry(ADMIN_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ADMIN_NAME)
+ entry.setValues('cn', ADMIN_NAME)
+ entry.setValues('userpassword', ADMIN_PWD)
+
+ topology.standalone.log.info("Creating Password Administator entry %s..." % ADMIN_DN)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Unexpected result ' + e.message['desc'])
+ assert False
+ topology.standalone.log.error("Failed to add Password Administator %s, error: %s "
+ % (ADMIN_DN, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info("Configuring password policy...")
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinTokenLength' , '1'),
+ (ldap.MOD_REPLACE, 'passwordExp' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinDigits' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinSpecials' , '1')])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed configure password policy: ' + e.message['desc'])
+ assert False
+
+ #
+ # Add an aci to allow everyone all access (just makes things easier)
+ #
+ topology.standalone.log.info("Add aci to allow password admin to add/update entries...")
+
+ ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
+ ACI_TARGETATTR = "(targetattr = *)"
+ ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
+ ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
+ ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ try:
+ topology.standalone.modify_s(SUFFIX, mod)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add aci for password admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Bind as the Password Admin
+ #
+ topology.standalone.log.info("Bind as the Password Administator (before activating)...")
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Setup our test entry, and test password policy is working
+ #
+ entry = Entry(ENTRY_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ENTRY_NAME)
+ entry.setValues('cn', ENTRY_NAME)
+
+ #
+ # Start by attempting to add an entry with an invalid password
+ #
+ topology.standalone.log.info("Attempt to add entries with invalid passwords, these adds should fail...")
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Add failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an entry " +
+ "with an invalid password (%s)" % (passwd))
+ assert False
+
+
+ #
+ # Now activate a password administator, bind as root dn to do the config
+ # update, then rebind as the password admin
+ #
+ topology.standalone.log.info("Activate the Password Administator...")
+
+ # Bind as Root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Start adding entries with invalid passwords, delete the entry after each pass.
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info('Succesfully added entry (%s)' % ENTRY_DN)
+
+ # Delete entry for the next pass
+ try:
+ topology.standalone.delete_s(ENTRY_DN)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to delete entry: %s' % (e.message['desc']))
+ assert False
+
+
+ #
+ # Add the entry for the next round of testing (modify password)
+ #
+ entry.setValues('userpassword', ADMIN_PWD)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with valid password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ #
+ # Deactivate the password admin and make sure invalid password updates fail
+ #
+ topology.standalone.log.info("Deactivate Password Administator and try invalid password updates...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to remove password admin from config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make invalid password updates that should fail
+ #
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Password update failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an invalid password (%s)"
+ % (passwd))
+ assert False
+
+ #
+ # Now activate a password administator
+ #
+ topology.standalone.log.info("Activate Password Administator and try updates again...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make the same password updates, but this time they should succeed
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Password update failed unexpectedly: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+ topology.standalone.log.info('Password update succeeded (%s)' % passwd)
+ #
+ # Test passed
+ #
+ topology.standalone.log.info('Test 47900 Passed.')
+
+
+def test_ticket47900_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47900(topo)
+
+if __name__ == '__main__':
+ run_isolated()
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index b437112..0e2a202 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1546,7 +1546,7 @@ FrontendConfig_init () {
init_entryusn_global = cfg->entryusn_global = LDAP_OFF;
cfg->entryusn_import_init = slapi_ch_strdup(ENTRYUSN_IMPORT_INIT);
- cfg->allowed_to_delete_attrs = slapi_ch_strdup("nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
+ cfg->allowed_to_delete_attrs = slapi_ch_strdup("passwordadmindn nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
cfg->default_naming_context = NULL; /* store normalized dn */
cfg->allowed_sasl_mechs = NULL;
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index a4d2dc6..9c541c5 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1629,13 +1629,22 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
return pb->pwdpolicy;
}
- slapdFrontendConfig = getFrontendConfig();
- pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+ if (g_get_active_threadcnt() == 0){
+ /*
+ * If the server is starting up the thread count will be zero, so
+ * we should not proceed, because not all the backends have been
+ * initialized yet.
+ */
+ return NULL;
+ }
if (pb) {
slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
}
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
/* If we're doing an add, COS does not apply yet so we check
parents for the pwdpolicysubentry. We look only for virtual
9 years, 6 months
dirsrvtests/tickets ldap/servers
by Mark Reynolds
dirsrvtests/tickets/ticket47900_test.py | 398 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/libglobs.c | 2
ldap/servers/slapd/pw.c | 13 -
3 files changed, 410 insertions(+), 3 deletions(-)
New commits:
commit 4711de687174d6e5dd7b2c04782b62dc1cb90a6e
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Thu Oct 2 10:17:13 2014 -0400
Ticket 47900 - Server fails to start if password admin is set
Bug Description: The server will crash at startup if the password admin is set.
Fix Description: When creating a password policy for the pblock, which we do
for add and modifiy operations, make sure the server is fully
up and running before searching backends for password admins.
Also, allow passwordAdminDN to be deleted from the cn=config.
https://fedorahosted.org/389/ticket/47900
Reviewed by: nhosoi(Thanks!)
diff --git a/dirsrvtests/tickets/ticket47900_test.py b/dirsrvtests/tickets/ticket47900_test.py
new file mode 100644
index 0000000..4e6f5d7
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47900_test.py
@@ -0,0 +1,398 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+ADMIN_NAME = 'passwd_admin'
+ADMIN_DN = 'cn=%s,%s' % (ADMIN_NAME, SUFFIX)
+ADMIN_PWD = 'adminPassword_1'
+ENTRY_NAME = 'Joe Schmo'
+ENTRY_DN = 'cn=%s,%s' % (ENTRY_NAME, SUFFIX)
+INVALID_PWDS = ('2_Short', 'No_Number', 'N0Special', '{SSHA}bBy8UdtPZwu8uZna9QOYG3Pr41RpIRVDl8wddw==')
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=10)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=10)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ #
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47900(topology):
+ """
+ Test that password administrators/root DN can
+ bypass password syntax/policy.
+
+ We need to test how passwords are modified in
+ existing entries, and when adding new entries.
+
+ Create the Password Admin entry, but do not set
+ it as an admin yet. Use the entry to verify invalid
+ passwords are caught. Then activate the password
+ admin and make sure it can bypass password policy.
+ """
+
+ # Prepare the Password Administator
+ entry = Entry(ADMIN_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ADMIN_NAME)
+ entry.setValues('cn', ADMIN_NAME)
+ entry.setValues('userpassword', ADMIN_PWD)
+
+ topology.standalone.log.info("Creating Password Administator entry %s..." % ADMIN_DN)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Unexpected result ' + e.message['desc'])
+ assert False
+ topology.standalone.log.error("Failed to add Password Administator %s, error: %s "
+ % (ADMIN_DN, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info("Configuring password policy...")
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinTokenLength' , '1'),
+ (ldap.MOD_REPLACE, 'passwordExp' , 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinDigits' , '1'),
+ (ldap.MOD_REPLACE, 'passwordMinSpecials' , '1')])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed configure password policy: ' + e.message['desc'])
+ assert False
+
+ #
+ # Add an aci to allow everyone all access (just makes things easier)
+ #
+ topology.standalone.log.info("Add aci to allow password admin to add/update entries...")
+
+ ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX
+ ACI_TARGETATTR = "(targetattr = *)"
+ ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) "
+ ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)"
+ ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ try:
+ topology.standalone.modify_s(SUFFIX, mod)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add aci for password admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Bind as the Password Admin
+ #
+ topology.standalone.log.info("Bind as the Password Administator (before activating)...")
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Setup our test entry, and test password policy is working
+ #
+ entry = Entry(ENTRY_DN)
+ entry.setValues('objectclass', 'top', 'person')
+ entry.setValues('sn', ENTRY_NAME)
+ entry.setValues('cn', ENTRY_NAME)
+
+ #
+ # Start by attempting to add an entry with an invalid password
+ #
+ topology.standalone.log.info("Attempt to add entries with invalid passwords, these adds should fail...")
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Add failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an entry " +
+ "with an invalid password (%s)" % (passwd))
+ assert False
+
+
+ #
+ # Now activate a password administator, bind as root dn to do the config
+ # update, then rebind as the password admin
+ #
+ topology.standalone.log.info("Activate the Password Administator...")
+
+ # Bind as Root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Start adding entries with invalid passwords, delete the entry after each pass.
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ topology.standalone.log.info("Create a regular user entry %s with password (%s)..." % (ENTRY_DN, passwd))
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ topology.standalone.log.info('Succesfully added entry (%s)' % ENTRY_DN)
+
+ # Delete entry for the next pass
+ try:
+ topology.standalone.delete_s(ENTRY_DN)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to delete entry: %s' % (e.message['desc']))
+ assert False
+
+
+ #
+ # Add the entry for the next round of testing (modify password)
+ #
+ entry.setValues('userpassword', ADMIN_PWD)
+ try:
+ topology.standalone.add_s(entry)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add entry with valid password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+
+ #
+ # Deactivate the password admin and make sure invalid password updates fail
+ #
+ topology.standalone.log.info("Deactivate Password Administator and try invalid password updates...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_DELETE, 'passwordAdminDN', None)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to remove password admin from config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make invalid password updates that should fail
+ #
+ for passwd in INVALID_PWDS:
+ failed_as_expected = False
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ # We failed as expected
+ failed_as_expected = True
+ topology.standalone.log.info('Password update failed as expected: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+
+ if not failed_as_expected:
+ topology.standalone.log.error("We were incorrectly able to add an invalid password (%s)"
+ % (passwd))
+ assert False
+
+ #
+ # Now activate a password administator
+ #
+ topology.standalone.log.info("Activate Password Administator and try updates again...")
+
+ # Bind as root DN
+ try:
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Root DN failed to authenticate: ' + e.message['desc'])
+ assert False
+
+ # Update config
+ try:
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordAdminDN', ADMIN_DN)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to add password admin to config: ' + e.message['desc'])
+ assert False
+
+ # Bind as Password Admin
+ try:
+ topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD)
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Failed to bind as the Password Admin: ' + e.message['desc'])
+ assert False
+
+ #
+ # Make the same password updates, but this time they should succeed
+ #
+ for passwd in INVALID_PWDS:
+ entry.setValues('userpassword', passwd)
+ try:
+ topology.standalone.modify_s(ENTRY_DN, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ topology.standalone.log.error('Password update failed unexpectedly: password (%s) result (%s)'
+ % (passwd, e.message['desc']))
+ assert False
+ topology.standalone.log.info('Password update succeeded (%s)' % passwd)
+ #
+ # Test passed
+ #
+ topology.standalone.log.info('Test 47900 Passed.')
+
+
+def test_ticket47900_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47900(topo)
+
+if __name__ == '__main__':
+ run_isolated()
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index b437112..0e2a202 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -1546,7 +1546,7 @@ FrontendConfig_init () {
init_entryusn_global = cfg->entryusn_global = LDAP_OFF;
cfg->entryusn_import_init = slapi_ch_strdup(ENTRYUSN_IMPORT_INIT);
- cfg->allowed_to_delete_attrs = slapi_ch_strdup("nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
+ cfg->allowed_to_delete_attrs = slapi_ch_strdup("passwordadmindn nsslapd-listenhost nsslapd-securelistenhost nsslapd-defaultnamingcontext");
cfg->default_naming_context = NULL; /* store normalized dn */
cfg->allowed_sasl_mechs = NULL;
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index a4d2dc6..9c541c5 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -1629,13 +1629,22 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
return pb->pwdpolicy;
}
- slapdFrontendConfig = getFrontendConfig();
- pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+ if (g_get_active_threadcnt() == 0){
+ /*
+ * If the server is starting up the thread count will be zero, so
+ * we should not proceed, because not all the backends have been
+ * initialized yet.
+ */
+ return NULL;
+ }
if (pb) {
slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
}
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
/* If we're doing an add, COS does not apply yet so we check
parents for the pwdpolicysubentry. We look only for virtual
9 years, 6 months
Branch '389-ds-base-1.3.3' - ldap/servers
by Noriko Hosoi
ldap/servers/plugins/acl/acl.c | 10 +++++-----
ldap/servers/plugins/acl/aclparse.c | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
New commits:
commit 5353f9fd97518074b77698bf13d95325aeb667d9
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed Oct 1 14:06:06 2014 -0700
Ticket #47892 - coverity defects found in 1.3.3.x
Description: fixing compiler warnings reported by covscan on 1.3.3.4.
https://fedorahosted.org/389/ticket/47892#comment:8
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit afc8b06f9e9cc045906d6d6fb64fe5d5f9d7c3d5)
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
index f8b854c..fe863c8 100644
--- a/ldap/servers/plugins/acl/acl.c
+++ b/ldap/servers/plugins/acl/acl.c
@@ -2475,13 +2475,13 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *
int done;
- if (aclpb->aclpb_access & SLAPI_ACL_ADD &&
- aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
+ if ((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
+ (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
attrFilterArray = aci->targetAttrAddFilters;
- } else if (aclpb->aclpb_access & SLAPI_ACL_DELETE &&
- aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) {
+ } else if ((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
+ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) {
attrFilterArray = aci->targetAttrDelFilters;
@@ -2490,7 +2490,7 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *
attr_matched = ACL_TRUE;
num_attrs = 0;
- while (attrFilterArray[num_attrs] && attr_matched) {
+ while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) {
attrFilter = attrFilterArray[num_attrs];
/*
diff --git a/ldap/servers/plugins/acl/aclparse.c b/ldap/servers/plugins/acl/aclparse.c
index ae4f2d5..ea64fa7 100644
--- a/ldap/servers/plugins/acl/aclparse.c
+++ b/ldap/servers/plugins/acl/aclparse.c
@@ -256,7 +256,7 @@ __aclp__parse_aci(char *str, aci_t *aci_item, char **errbuf)
int targetattrfilterslen = strlen(aci_targetattrfilters);
int target_to_len = strlen(aci_target_to);
int target_from_len = strlen(aci_target_from);
- PRBool is_target_to;
+ PRBool is_target_to = PR_FALSE;
__acl_strip_leading_space( &str );
9 years, 6 months
ldap/servers
by Noriko Hosoi
ldap/servers/plugins/acl/acl.c | 10 +++++-----
ldap/servers/plugins/acl/aclparse.c | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
New commits:
commit afc8b06f9e9cc045906d6d6fb64fe5d5f9d7c3d5
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed Oct 1 14:06:06 2014 -0700
Ticket #47892 - coverity defects found in 1.3.3.x
Description: fixing compiler warnings reported by covscan on 1.3.3.4.
https://fedorahosted.org/389/ticket/47892#comment:8
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
index f8b854c..fe863c8 100644
--- a/ldap/servers/plugins/acl/acl.c
+++ b/ldap/servers/plugins/acl/acl.c
@@ -2475,13 +2475,13 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *
int done;
- if (aclpb->aclpb_access & SLAPI_ACL_ADD &&
- aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
+ if ((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
+ (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
attrFilterArray = aci->targetAttrAddFilters;
- } else if (aclpb->aclpb_access & SLAPI_ACL_DELETE &&
- aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) {
+ } else if ((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
+ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) {
attrFilterArray = aci->targetAttrDelFilters;
@@ -2490,7 +2490,7 @@ acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *
attr_matched = ACL_TRUE;
num_attrs = 0;
- while (attrFilterArray[num_attrs] && attr_matched) {
+ while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) {
attrFilter = attrFilterArray[num_attrs];
/*
diff --git a/ldap/servers/plugins/acl/aclparse.c b/ldap/servers/plugins/acl/aclparse.c
index ae4f2d5..ea64fa7 100644
--- a/ldap/servers/plugins/acl/aclparse.c
+++ b/ldap/servers/plugins/acl/aclparse.c
@@ -256,7 +256,7 @@ __aclp__parse_aci(char *str, aci_t *aci_item, char **errbuf)
int targetattrfilterslen = strlen(aci_targetattrfilters);
int target_to_len = strlen(aci_target_to);
int target_from_len = strlen(aci_target_from);
- PRBool is_target_to;
+ PRBool is_target_to = PR_FALSE;
__acl_strip_leading_space( &str );
9 years, 6 months
Branch '389-ds-base-1.3.1' - 4 commits - ldap/servers
by Noriko Hosoi
ldap/servers/plugins/replication/cl5_api.c | 31 +-
ldap/servers/plugins/replication/urp.c | 3
ldap/servers/plugins/replication/urp.h | 2
ldap/servers/plugins/replication/urp_glue.c | 2
ldap/servers/plugins/replication/urp_tombstone.c | 59 ++--
ldap/servers/slapd/add.c | 2
ldap/servers/slapd/back-ldbm/back-ldbm.h | 3
ldap/servers/slapd/back-ldbm/cache.c | 316 +++++++++++++++--------
ldap/servers/slapd/back-ldbm/ldbm_add.c | 110 ++++----
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 202 ++++++++------
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 90 +++---
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 191 ++++++-------
ldap/servers/slapd/back-ldbm/parents.c | 4
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 6
ldap/servers/slapd/bind.c | 13
ldap/servers/slapd/dn.c | 6
ldap/servers/slapd/rdn.c | 22 +
ldap/servers/slapd/slapi-plugin.h | 4
18 files changed, 636 insertions(+), 430 deletions(-)
New commits:
commit 154abc975af643ebecc70750eddf5921e2befc12
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Sep 22 14:34:58 2014 -0700
Ticket #47750 - Creating a glue fails if one above level is a conflict or missing
Description: Poring changes made to 1.2.11 branch to newer versions.
1) Enabiling cache lock in cache_is_in_cache and cache_has_otherref.
2) Removing unused field new_entry_in_cache from "struct _modify_context".
(cherry picked from commit 5ae13072330e9a769a5949b2e8a91085b38ac4e1)
(cherry picked from commit ef766784ed7d09aa81e82316b621e8490a368dc6)
(cherry picked from commit 6ca4422d1a585c30b92045cff4d38f1c7edf72c7)
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index 7213a9e..a74a9db 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -694,7 +694,6 @@ typedef struct _import_subcount_stuff import_subcount_stuff;
/* Handy structures for modify operations */
struct _modify_context {
- int new_entry_in_cache;
struct backentry *old_entry;
struct backentry *new_entry;
Slapi_Mods *smods;
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index a98cf0c..4746204 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -1506,10 +1506,12 @@ int cache_add_tentative(struct cache *cache, struct backentry *e,
{
return entrycache_add_int(cache, e, ENTRY_STATE_CREATING, alt);
}
+
void cache_lock(struct cache *cache)
{
PR_EnterMonitor(cache->c_mutex);
}
+
void cache_unlock(struct cache *cache)
{
PR_ExitMonitor(cache->c_mutex);
@@ -2095,9 +2097,9 @@ cache_has_otherref(struct cache *cache, void *ptr)
return hasref;
}
bep = (struct backcommon *)ptr;
- /* slows down too much? PR_Lock(cache->c_mutex); */
+ cache_lock(cache);
hasref = bep->ep_refcnt;
- /* PR_Unlock(cache->c_mutex); */
+ cache_unlock(cache);
return (hasref>1)?1:0;
}
@@ -2111,8 +2113,8 @@ cache_is_in_cache(struct cache *cache, void *ptr)
return in_cache;
}
bep = (struct backcommon *)ptr;
- /* slows down too much? PR_Lock(cache->c_mutex); */
+ cache_lock(cache);
in_cache = (bep->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE))?0:1;
- /* PR_Unlock(cache->c_mutex); */
+ cache_unlock(cache);
return in_cache;
}
commit 44b66b4ceabc78c21ba48a7fe153915663dbc749
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Tue Sep 9 12:45:58 2014 -0700
Ticket #47748 - Simultaneous adding a user and binding as the user could fail in the password policy check
Description: commit 4fc53e1a63222d0ff67c30a59f2cff4b535f90a8 fix for
Ticket #47748 introduced a bug: "Simple bind hangs after enabling
password policy".
In do_bind, slapi_check_account_lock and need_new_pw overwrote the
return code from backend bind which is used later. This patch fixes
it not to override the return code.
https://fedorahosted.org/389/ticket/47748
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit 4f11606b02419c8ccdb319b8040e683af9109d1b)
(cherry picked from commit 8c82941c0f2b0b5d7fa698a1ca3e4f26245cf85a)
(cherry picked from commit 5b6d60ec4d3d93d1d69f6a071ce135a06f4c8cfd)
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
index 58a4e13..bc4aa24 100644
--- a/ldap/servers/slapd/bind.c
+++ b/ldap/servers/slapd/bind.c
@@ -769,6 +769,7 @@ do_bind( Slapi_PBlock *pb )
}
if ( rc == SLAPI_BIND_SUCCESS ) {
+ int myrc = 0;
if (!auto_bind) {
/*
* There could be a race that bind_target_entry was not added
@@ -779,9 +780,9 @@ do_bind( Slapi_PBlock *pb )
if (!bind_target_entry) {
bind_target_entry = get_entry(pb, slapi_sdn_get_ndn(sdn));
if (bind_target_entry) {
- rc = slapi_check_account_lock(pb, bind_target_entry,
+ myrc = slapi_check_account_lock(pb, bind_target_entry,
pw_response_requested, 1, 1);
- if (1 == rc) { /* account is locked */
+ if (1 == myrc) { /* account is locked */
goto account_locked;
}
} else {
@@ -795,8 +796,8 @@ do_bind( Slapi_PBlock *pb )
if (!slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
/* check if need new password before sending
the bind success result */
- rc = need_new_pw(pb, &t, bind_target_entry, pw_response_requested);
- switch (rc) {
+ myrc = need_new_pw(pb, &t, bind_target_entry, pw_response_requested);
+ switch (myrc) {
case 1:
(void)slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
break;
@@ -811,8 +812,8 @@ do_bind( Slapi_PBlock *pb )
if (auth_response_requested) {
slapi_add_auth_response_control(pb, slapi_sdn_get_ndn(sdn));
}
- if (-1 == rc) {
- /* neeed_new_pw failed; need_new_pw already send_ldap_result in it. */
+ if (-1 == myrc) {
+ /* need_new_pw failed; need_new_pw already send_ldap_result in it. */
goto free_and_return;
}
} else { /* anonymous */
commit 891d03a3d36fc46d3851eeaf2582bd3575fd5823
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Tue Aug 19 14:42:52 2014 -0700
Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
Bug Description: Test case to verify the problem crashed the server.
Fix Description:
1. Clean up entry cache related code
1-1. Changing cache log reentrant to avoid self deadlock.
1-2. Introducing cache_is_in_cache to get rid of local variables in
ldap_back_{add,delete,modify,modrdn}.
2. ldap_back_{add,delete,modify,modrdn}
2-1. As described in 1-2, removed [a-z]*_in_cache local variables.
2-2. In the deadlock retry loop, entries were duplicated by backentry_
dup after CACHE_REMOVE'd and CACHE_RETURN'ed. At the moment, the
entry could be already freed. Changed to create a duplicated
entry before calling CACHE_REMOVE and CACHE_RETURN.
3. _cl5NewDBFile (replication/cl5_api.c): When a leftover semaphore is
found, _cl5NewDBFile removes it and creates it, but it rarely fails
to delete and it causes the server restart fail. Adding a message
to remove such a leftover semaphore by ipcrm.
https://fedorahosted.org/389/ticket/47834
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit 6333936da2c4287e96b36fecc24a4c62da5a8ea2)
(cherry picked from commit d9c8b1fe47e8ce708fa3cbeddbefa1916f1bf669)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index abcc39a..4ab0eb0 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -5697,7 +5697,7 @@ static int _cl5DBOpenFileByReplicaName (const char *replName, const char *replGe
if (checkDups)
{
PR_Lock (s_cl5Desc.fileLock);
- file_name = _cl5MakeFileName (replName, replGen);
+ file_name = _cl5MakeFileName (replName, replGen);
tmpObj = objset_find (s_cl5Desc.dbFiles, _cl5CompareDBFile, file_name);
slapi_ch_free((void **)&file_name);
if (tmpObj) /* this file already exist */
@@ -5772,10 +5772,10 @@ done:;
if (checkDups)
{
- PR_Unlock (s_cl5Desc.fileLock);
- }
+ PR_Unlock (s_cl5Desc.fileLock);
+ }
- return rc;
+ return rc;
}
/* adds file to the db file list */
@@ -5939,7 +5939,14 @@ out:
* and re-create it.
*/
if (PR_GetError() == PR_FILE_EXISTS_ERROR) {
+ PRErrorCode prerr;
PR_DeleteSemaphore((*dbFile)->semaName);
+ prerr = PR_GetError();
+ if (PR_SUCCESS != prerr) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: PR_DeleteSemaphore: %s; NSPR error - %d\n",
+ (*dbFile)->semaName ? (*dbFile)->semaName : "(nil)", prerr);
+ }
(*dbFile)->sema = PR_OpenSemaphore((*dbFile)->semaName,
PR_SEM_CREATE | PR_SEM_EXCL, 0666,
s_cl5Desc.dbConfig.maxConcurrentWrites );
@@ -5949,9 +5956,19 @@ out:
* we should just error out. */
if ((*dbFile)->sema == NULL )
{
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "_cl5NewDBFile: failed to create semaphore %s; NSPR error - %d\n",
- (*dbFile)->semaName ? (*dbFile)->semaName : "(nil)", PR_GetError());
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_EXISTS_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: PR_OpenSemaphore: %s; sema: 0x%p, NSPR error - %d\n",
+ (*dbFile)->semaName ? (*dbFile)->semaName : "(nil)", (*dbFile)->sema, prerr);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ " : Leftover semaphores may exist. "
+ "Run \"ipcs -s\", and remove them with \"ipcrm -s <SEMID>\" if any\n");
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: failed to create semaphore %s; NSPR error - %d\n",
+ (*dbFile)->semaName ? (*dbFile)->semaName : "(nil)", prerr);
+ }
rc = CL5_SYSTEM_ERROR;
goto done;
}
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index 8aa9825..7213a9e 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -403,7 +403,7 @@ struct cache {
Slapi_Counter *c_tries;
struct backcommon *c_lruhead; /* add entries here */
struct backcommon *c_lrutail; /* remove entries here */
- PRLock *c_mutex; /* lock for cache operations */
+ PRMonitor *c_mutex; /* lock for cache operations */
PRLock *c_emutexalloc_mutex;
};
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index 0732415..a98cf0c 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -544,10 +544,9 @@ int cache_init(struct cache *cache, size_t maxsize, long maxentries, int type)
cache->c_lruhead = cache->c_lrutail = NULL;
cache_make_hashes(cache, type);
- if (((cache->c_mutex = PR_NewLock()) == NULL) ||
- ((cache->c_emutexalloc_mutex = PR_NewLock()) == NULL)) {
- LDAPDebug(LDAP_DEBUG_ANY, "ldbm: cache_init: PR_NewLock failed\n",
- 0, 0, 0);
+ if (((cache->c_mutex = PR_NewMonitor()) == NULL) ||
+ ((cache->c_emutexalloc_mutex = PR_NewLock()) == NULL)) {
+ LDAPDebug0Args(LDAP_DEBUG_ANY, "ldbm: cache_init: PR_NewMonitor failed\n");
return 0;
}
LDAPDebug(LDAP_DEBUG_TRACE, "<= cache_init\n", 0, 0, 0);
@@ -634,13 +633,13 @@ static void entrycache_clear_int(struct cache *cache)
void cache_clear(struct cache *cache, int type)
{
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (CACHE_TYPE_ENTRY == type) {
entrycache_clear_int(cache);
} else if (CACHE_TYPE_DN == type) {
dncache_clear_int(cache);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
static void erase_cache(struct cache *cache, int type)
@@ -664,7 +663,7 @@ void cache_destroy_please(struct cache *cache, int type)
slapi_counter_destroy(&cache->c_cursize);
slapi_counter_destroy(&cache->c_hits);
slapi_counter_destroy(&cache->c_tries);
- PR_DestroyLock(cache->c_mutex);
+ PR_DestroyMonitor(cache->c_mutex);
PR_DestroyLock(cache->c_emutexalloc_mutex);
}
@@ -688,7 +687,7 @@ static void entrycache_set_max_size(struct cache *cache, size_t bytes)
"WARNING -- Minimum cache size is %lu -- rounding up\n",
MINCACHESIZE, 0, 0);
}
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
cache->c_maxsize = bytes;
LOG("entry cache size set to %lu\n", bytes, 0, 0);
/* check for full cache, and clear out if necessary */
@@ -707,7 +706,7 @@ static void entrycache_set_max_size(struct cache *cache, size_t bytes)
erase_cache(cache, CACHE_TYPE_ENTRY);
cache_make_hashes(cache, CACHE_TYPE_ENTRY);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
if (! dblayer_is_cachesize_sane(&bytes)) {
LDAPDebug(LDAP_DEBUG_ANY,
"WARNING -- Possible CONFIGURATION ERROR -- cachesize "
@@ -725,7 +724,7 @@ void cache_set_max_entries(struct cache *cache, long entries)
* was given in # entries instead of memory footprint. hopefully,
* we can eventually drop this.
*/
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
cache->c_maxentries = entries;
if (entries >= 0) {
LOG("entry cache entry-limit set to %lu\n", entries, 0, 0);
@@ -736,7 +735,7 @@ void cache_set_max_entries(struct cache *cache, long entries)
/* check for full cache, and clear out if necessary */
if (CACHE_FULL(cache))
eflush = entrycache_flush(cache);
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
while (eflush)
{
eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
@@ -749,9 +748,9 @@ size_t cache_get_max_size(struct cache *cache)
{
size_t n = 0;
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
n = cache->c_maxsize;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return n;
}
@@ -759,9 +758,9 @@ long cache_get_max_entries(struct cache *cache)
{
long n;
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
n = cache->c_maxentries;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return n;
}
@@ -787,14 +786,14 @@ void cache_get_stats(struct cache *cache, PRUint64 *hits, PRUint64 *tries,
long *nentries, long *maxentries,
size_t *size, size_t *maxsize)
{
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (hits) *hits = slapi_counter_get_value(cache->c_hits);
if (tries) *tries = slapi_counter_get_value(cache->c_tries);
if (nentries) *nentries = cache->c_curentries;
if (maxentries) *maxentries = cache->c_maxentries;
if (size) *size = slapi_counter_get_value(cache->c_cursize);
if (maxsize) *maxsize = cache->c_maxsize;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
void cache_debug_hash(struct cache *cache, char **out)
@@ -805,7 +804,7 @@ void cache_debug_hash(struct cache *cache, char **out)
Hashtable *ht = NULL;
char *name = "unknown";
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
*out = (char *)slapi_ch_malloc(1024);
**out = 0;
@@ -841,7 +840,7 @@ void cache_debug_hash(struct cache *cache, char **out)
sprintf(*out + strlen(*out), "%d[%d] ", j, slot_stats[j]);
slapi_ch_free((void **)&slot_stats);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
@@ -947,14 +946,14 @@ int cache_remove(struct cache *cache, void *ptr)
}
e = (struct backcommon *)ptr;
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (CACHE_TYPE_ENTRY == e->ep_type) {
ASSERT(e->ep_refcnt > 0);
ret = entrycache_remove_int(cache, (struct backentry *)e);
} else if (CACHE_TYPE_DN == e->ep_type) {
ret = dncache_remove_int(cache, (struct backdn *)e);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return ret;
}
@@ -1014,7 +1013,7 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
#endif
newndn = slapi_sdn_get_ndn(backentry_get_sdn(newe));
entry_size = cache_entry_size(newe);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
/*
* First, remove the old entry from all the hashtables.
@@ -1034,7 +1033,7 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
}
/* If fails, we have to make sure the both entires are removed from the cache,
* otherwise, we have no idea what's left in the cache or not... */
- if (!entry_same_dn(newe, (void *)oldndn) && (newe->ep_state & ENTRY_STATE_NOTINCACHE) == 0) {
+ if (cache_is_in_cache(cache, newe)) {
/* if we're doing a modrdn or turning an entry to a tombstone,
* the new entry can be in the dn table already, so we need to remove that too.
*/
@@ -1042,6 +1041,7 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
{
slapi_counter_subtract(cache->c_cursize, newe->ep_size);
cache->c_curentries--;
+ newe->ep_refcnt--;
LOG("entry cache replace remove entry size %lu\n", newe->ep_size, 0, 0);
}
}
@@ -1064,7 +1064,7 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
LOG("entry cache replace (%s): cache index tables out of sync - found dn [%d] id [%d]\n",
oldndn, found_in_dn, found_in_id);
#endif
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
}
@@ -1073,32 +1073,32 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
* tested enough that we believe it works.)
*/
if (!add_hash(cache->c_dntable, (void *)newndn, strlen(newndn), newe, (void **)&alte)) {
- LOG("entry cache replace (%s): can't add to dn table (returned %s)\n",
- newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
- PR_Unlock(cache->c_mutex);
- return 1;
+ LOG("entry cache replace (%s): can't add to dn table (returned %s)\n",
+ newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
+ cache_lock(cache);
+ return 1;
}
if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, (void **)&alte)) {
- LOG("entry cache replace (%s): can't add to id table (returned %s)\n",
- newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
- if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
- LOG("entry cache replace: failed to remove dn table\n", 0, 0, 0);
- }
- PR_Unlock(cache->c_mutex);
- return 1;
+ LOG("entry cache replace (%s): can't add to id table (returned %s)\n",
+ newndn, alte?slapi_entry_get_dn(alte->ep_entry):"none", 0);
+ if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
+ LOG("entry cache replace: failed to remove dn table\n", 0, 0, 0);
+ }
+ cache_unlock(cache);
+ return 1;
}
#ifdef UUIDCACHE_ON
if (newuuid && !add_hash(cache->c_uuidtable, (void *)newuuid, strlen(newuuid),
newe, NULL)) {
- LOG("entry cache replace: can't add uuid\n", 0, 0, 0);
- if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
- LOG("entry cache replace: failed to remove dn table(uuid cache)\n", 0, 0, 0);
- }
- if(remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID)) == 0){
- LOG("entry cache replace: failed to remove id table(uuid cache)\n", 0, 0, 0);
- }
- PR_Unlock(cache->c_mutex);
- return 1;
+ LOG("entry cache replace: can't add uuid\n", 0, 0, 0);
+ if(remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)) == 0){
+ LOG("entry cache replace: failed to remove dn table(uuid cache)\n", 0, 0, 0);
+ }
+ if(remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID)) == 0){
+ LOG("entry cache replace: failed to remove id table(uuid cache)\n", 0, 0, 0);
+ }
+ cache_unlock(cache);
+ return 1;
}
#endif
/* adjust cache meta info */
@@ -1110,7 +1110,7 @@ static int entrycache_replace(struct cache *cache, struct backentry *olde,
slapi_counter_subtract(cache->c_cursize, olde->ep_size - newe->ep_size);
}
newe->ep_state = 0;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= entrycache_replace OK, cache size now %lu cache count now %ld\n",
slapi_counter_get_value(cache->c_cursize), cache->c_curentries, 0);
return 0;
@@ -1144,10 +1144,14 @@ entrycache_return(struct cache *cache, struct backentry **bep)
struct backentry *e;
e = *bep;
+ if (!e) {
+ LDAPDebug0Args(LDAP_DEBUG_ANY, "entrycache_return e is NULL\n");
+ return;
+ }
LOG("=> entrycache_return (%s) entry count: %d, entry in cache:%ld\n",
backentry_get_ndn(e), e->ep_refcnt, cache->c_curentries);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (e->ep_state & ENTRY_STATE_NOTINCACHE)
{
backentry_free(bep);
@@ -1166,7 +1170,7 @@ entrycache_return(struct cache *cache, struct backentry **bep)
}
}
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
while (eflush)
{
eflushtemp = BACK_LRU_NEXT(eflush, struct backentry *);
@@ -1185,22 +1189,22 @@ struct backentry *cache_find_dn(struct cache *cache, const char *dn, unsigned lo
LOG("=> cache_find_dn (%s)\n", dn, 0, 0);
/*entry normalized by caller (dn2entry.c) */
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (find_hash(cache->c_dntable, (void *)dn, ndnlen, (void **)&e)) {
/* need to check entry state */
if (e->ep_state != 0) {
/* entry is deleted or not fully created yet */
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= cache_find_dn (NOT FOUND)\n", 0, 0, 0);
return NULL;
}
if (e->ep_refcnt == 0)
lru_delete(cache, (void *)e);
e->ep_refcnt++;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
slapi_counter_increment(cache->c_hits);
} else {
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
slapi_counter_increment(cache->c_tries);
@@ -1216,22 +1220,22 @@ struct backentry *cache_find_id(struct cache *cache, ID id)
LOG("=> cache_find_id (%lu)\n", (u_long)id, 0, 0);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (find_hash(cache->c_idtable, &id, sizeof(ID), (void **)&e)) {
/* need to check entry state */
if (e->ep_state != 0) {
/* entry is deleted or not fully created yet */
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= cache_find_id (NOT FOUND)\n", 0, 0, 0);
return NULL;
}
if (e->ep_refcnt == 0)
lru_delete(cache, (void *)e);
e->ep_refcnt++;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
slapi_counter_increment(cache->c_hits);
} else {
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
slapi_counter_increment(cache->c_tries);
@@ -1247,22 +1251,22 @@ struct backentry *cache_find_uuid(struct cache *cache, const char *uuid)
LOG("=> cache_find_uuid (%s)\n", uuid, 0, 0);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (find_hash(cache->c_uuidtable, uuid, strlen(uuid), (void **)&e)) {
/* need to check entry state */
if (e->ep_state != 0) {
/* entry is deleted or not fully created yet */
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= cache_find_uuid (NOT FOUND)\n", 0, 0, 0);
return NULL;
}
if (e->ep_refcnt == 0)
lru_delete(cache, (void *)e);
e->ep_refcnt++;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
slapi_counter_increment(cache->c_hits);
} else {
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
slapi_counter_increment(cache->c_tries);
@@ -1299,7 +1303,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
entry_size = e->ep_size;
}
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (! add_hash(cache->c_dntable, (void *)ndn, strlen(ndn), e,
(void **)&my_alt)) {
LOG("entry \"%s\" already in dn cache\n", ndn, 0, 0);
@@ -1334,7 +1338,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
* to prevent that the caller accidentally thinks the existing
* entry is not the same one the caller has and releases it.
*/
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
}
@@ -1344,7 +1348,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
{
LOG("the entry %s is reserved (ep_state: 0x%x, state: 0x%x)\n", ndn, e->ep_state, state);
e->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return -1;
}
else if (state != 0)
@@ -1352,7 +1356,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
LOG("the entry %s already exists. cannot reserve it. (ep_state: 0x%x, state: 0x%x)\n",
ndn, e->ep_state, state);
e->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return -1;
}
else
@@ -1364,12 +1368,14 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
(*alt)->ep_refcnt++;
LOG("the entry %s already exists. returning existing entry %s (state: 0x%x)\n",
ndn, backentry_get_ndn(my_alt), state);
+ cache_unlock(cache);
+ return 1;
} else {
LOG("the entry %s already exists. Not returning existing entry %s (state: 0x%x)\n",
ndn, backentry_get_ndn(my_alt), state);
+ cache_unlock(cache);
+ return -1;
}
- PR_Unlock(cache->c_mutex);
- return 1;
}
}
}
@@ -1399,14 +1405,14 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
* fine (i think).
*/
LOG("<= entrycache_add_int (ignoring)\n", 0, 0, 0);
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 0;
}
if(remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)) == 0){
LOG("entrycache_add_int: failed to remove %s from dn table\n", 0, 0, 0);
}
e->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("entrycache_add_int: failed to add %s to cache (ep_state: %x, already_in: %d)\n",
ndn, e->ep_state, already_in);
return -1;
@@ -1425,7 +1431,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
LOG("entrycache_add_int: failed to remove id table(uuid cache)\n", 0, 0, 0);
}
e->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return -1;
}
}
@@ -1450,7 +1456,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
if (CACHE_FULL(cache))
eflush = entrycache_flush(cache);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
while (eflush)
{
@@ -1502,11 +1508,11 @@ int cache_add_tentative(struct cache *cache, struct backentry *e,
}
void cache_lock(struct cache *cache)
{
- PR_Lock(cache->c_mutex);
+ PR_EnterMonitor(cache->c_mutex);
}
void cache_unlock(struct cache *cache)
{
- PR_Unlock(cache->c_mutex);
+ PR_ExitMonitor(cache->c_mutex);
}
/* locks an entry so that it can be modified (you should have gotten the
@@ -1540,14 +1546,14 @@ int cache_lock_entry(struct cache *cache, struct backentry *e)
PR_EnterMonitor(e->ep_mutexp);
/* make sure entry hasn't been deleted now */
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (e->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE)) {
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
PR_ExitMonitor(e->ep_mutexp);
LOG("<= cache_lock_entry (DELETED)\n", 0, 0, 0);
return RETRY_CACHE_LOCK;
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= cache_lock_entry (FOUND)\n", 0, 0, 0);
return 0;
@@ -1613,7 +1619,7 @@ dncache_set_max_size(struct cache *cache, size_t bytes)
"WARNING -- Minimum cache size is %lu -- rounding up\n",
MINCACHESIZE, 0, 0);
}
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
cache->c_maxsize = bytes;
LOG("entry cache size set to %lu\n", bytes, 0, 0);
/* check for full cache, and clear out if necessary */
@@ -1633,7 +1639,7 @@ dncache_set_max_size(struct cache *cache, size_t bytes)
erase_cache(cache, CACHE_TYPE_DN);
cache_make_hashes(cache, CACHE_TYPE_DN);
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
if (! dblayer_is_cachesize_sane(&bytes)) {
LDAPDebug1Arg(LDAP_DEBUG_ANY,
"WARNING -- Possible CONFIGURATION ERROR -- cachesize "
@@ -1697,7 +1703,7 @@ dncache_return(struct cache *cache, struct backdn **bdn)
LOG("=> dncache_return (%s) reference count: %d, dn in cache:%ld\n",
slapi_sdn_get_dn((*bdn)->dn_sdn), (*bdn)->ep_refcnt, cache->c_curentries);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if ((*bdn)->ep_state & ENTRY_STATE_NOTINCACHE)
{
backdn_free(bdn);
@@ -1717,7 +1723,7 @@ dncache_return(struct cache *cache, struct backdn **bdn)
}
}
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
while (dnflush)
{
dnflushtemp = BACK_LRU_NEXT(dnflush, struct backdn *);
@@ -1738,22 +1744,22 @@ dncache_find_id(struct cache *cache, ID id)
LOG("=> dncache_find_id (%lu)\n", (u_long)id, 0, 0);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (find_hash(cache->c_idtable, &id, sizeof(ID), (void **)&bdn)) {
/* need to check entry state */
if (bdn->ep_state != 0) {
/* entry is deleted or not fully created yet */
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= dncache_find_id (NOT FOUND)\n", 0, 0, 0);
return NULL;
}
if (bdn->ep_refcnt == 0)
lru_delete(cache, (void *)bdn);
bdn->ep_refcnt++;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
slapi_counter_increment(cache->c_hits);
} else {
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
}
slapi_counter_increment(cache->c_tries);
@@ -1778,7 +1784,7 @@ dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
LOG("=> dncache_add_int( \"%s\", %ld )\n", slapi_sdn_get_dn(bdn->dn_sdn),
bdn->ep_id, 0);
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
if (! add_hash(cache->c_idtable, &(bdn->ep_id), sizeof(ID), bdn,
(void **)&my_alt)) {
@@ -1813,7 +1819,7 @@ dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
* to prevent that the caller accidentally thinks the existing
* entry is not the same one the caller has and releases it.
*/
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
}
@@ -1823,14 +1829,14 @@ dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
{
LOG("the entry is reserved\n", 0, 0, 0);
bdn->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return -1;
}
else if (state != 0)
{
LOG("the entry already exists. cannot reserve it.\n", 0, 0, 0);
bdn->ep_state |= ENTRY_STATE_NOTINCACHE;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return -1;
}
else
@@ -1841,7 +1847,7 @@ dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
lru_delete(cache, (void *)*alt);
(*alt)->ep_refcnt++;
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
}
@@ -1870,7 +1876,7 @@ dncache_add_int(struct cache *cache, struct backdn *bdn, int state,
dnflush = dncache_flush(cache);
}
}
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
while (dnflush)
{
@@ -1898,7 +1904,7 @@ dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn)
* where the entry isn't in all the table yet, so we don't care if any
* of these return errors.
*/
- PR_Lock(cache->c_mutex);
+ cache_lock(cache);
/*
* First, remove the old entry from the hashtable.
@@ -1910,7 +1916,7 @@ dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn)
found = remove_hash(cache->c_idtable, &(olddn->ep_id), sizeof(ID));
if (!found) {
LOG("dn cache replace: cache index tables out of sync\n", 0, 0, 0);
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
}
@@ -1921,7 +1927,7 @@ dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn)
*/
if (!add_hash(cache->c_idtable, &(newdn->ep_id), sizeof(ID), newdn, NULL)) {
LOG("dn cache replace: can't add id\n", 0, 0, 0);
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
return 1;
}
/* adjust cache meta info */
@@ -1936,7 +1942,7 @@ dncache_replace(struct cache *cache, struct backdn *olddn, struct backdn *newdn)
}
olddn->ep_state = ENTRY_STATE_DELETED;
newdn->ep_state = 0;
- PR_Unlock(cache->c_mutex);
+ cache_unlock(cache);
LOG("<= dncache_replace OK, cache size now %lu cache count now %ld\n",
slapi_counter_get_value(cache->c_cursize), cache->c_curentries, 0);
return 0;
@@ -2022,23 +2028,24 @@ dn_lru_verify(struct cache *cache, struct backdn *dn, int in)
#ifdef CACHE_DEBUG
void
-check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
+check_entry_cache(struct cache *cache, struct backentry *e)
{
Slapi_DN *sdn = slapi_entry_get_sdn(e->ep_entry);
struct backentry *debug_e = cache_find_dn(cache,
slapi_sdn_get_dn(sdn),
slapi_sdn_get_ndn_len(sdn));
+ in_cache = cache_is_in_cache(cache, (void *)e);
if (in_cache) {
if (debug_e) { /* e is in cache */
CACHE_RETURN(cache, &debug_e);
if ((e != debug_e) && !(e->ep_state & ENTRY_STATE_DELETED)) {
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_FATAL, "check_entry_cache",
"entry 0x%p is not in dn cache but 0x%p having the same dn %s is "
"although in_cache flag is set!!!\n",
e, debug_e, slapi_sdn_get_dn(sdn));
}
} else if (!(e->ep_state & ENTRY_STATE_DELETED)) {
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_FATAL, "check_entry_cache",
"%s (id %d) is not in dn cache although in_cache flag is set!!!\n",
slapi_sdn_get_dn(sdn), e->ep_id);
}
@@ -2046,13 +2053,13 @@ check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
if (debug_e) { /* e is in cache */
CACHE_RETURN(cache, &debug_e);
if ((e != debug_e) && !(e->ep_state & ENTRY_STATE_DELETED)) {
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_FATAL, "check_entry_cache",
"entry 0x%p is not in id cache but 0x%p having the same id %d is "
"although in_cache flag is set!!!\n",
e, debug_e, e->ep_id);
}
} else {
- slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_CACHE, "check_entry_cache",
"%s (id %d) is not in id cache although in_cache flag is set!!!\n",
slapi_sdn_get_dn(sdn), e->ep_id);
}
@@ -2060,7 +2067,7 @@ check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
if (debug_e) { /* e is in cache */
CACHE_RETURN(cache, &debug_e);
if (e == debug_e) {
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_FATAL, "check_entry_cache",
"%s (id %d) is in dn cache although in_cache flag is not set!!!\n",
slapi_sdn_get_dn(sdn), e->ep_id);
}
@@ -2069,7 +2076,7 @@ check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
if (debug_e) { /* e is in cache: bad */
CACHE_RETURN(cache, &debug_e);
if (e == debug_e) {
- slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_CACHE, "check_entry_cache",
"%s (id %d) is in id cache although in_cache flag is not set!!!\n",
slapi_sdn_get_dn(sdn), e->ep_id);
}
@@ -2077,3 +2084,35 @@ check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
}
}
#endif
+
+int
+cache_has_otherref(struct cache *cache, void *ptr)
+{
+ struct backcommon *bep;
+ int hasref = 0;
+
+ if (NULL == ptr) {
+ return hasref;
+ }
+ bep = (struct backcommon *)ptr;
+ /* slows down too much? PR_Lock(cache->c_mutex); */
+ hasref = bep->ep_refcnt;
+ /* PR_Unlock(cache->c_mutex); */
+ return (hasref>1)?1:0;
+}
+
+int
+cache_is_in_cache(struct cache *cache, void *ptr)
+{
+ struct backcommon *bep;
+ int in_cache = 0;
+
+ if (NULL == ptr) {
+ return in_cache;
+ }
+ bep = (struct backcommon *)ptr;
+ /* slows down too much? PR_Lock(cache->c_mutex); */
+ in_cache = (bep->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE))?0:1;
+ /* PR_Unlock(cache->c_mutex); */
+ return in_cache;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index 2d26e40..d92343e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -85,6 +85,7 @@ ldbm_back_add( Slapi_PBlock *pb )
struct backentry *addingentry = NULL;
struct backentry *parententry = NULL;
struct backentry *originalentry = NULL;
+ struct backentry *tmpentry = NULL;
ID pid;
int isroot;
char *errbuf= NULL;
@@ -104,8 +105,6 @@ ldbm_back_add( Slapi_PBlock *pb )
int ruv_c_init = 0;
int rc = 0;
int addingentry_id_assigned = 0;
- int addingentry_in_cache = 0;
- int tombstone_in_cache = 0;
Slapi_DN *sdn = NULL;
Slapi_DN parentsdn;
Slapi_Operation *operation;
@@ -222,34 +221,32 @@ ldbm_back_add( Slapi_PBlock *pb )
dblayer_txn_abort_ext(li, &txn, PR_FALSE);
noabort = 1;
slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
-
- if (addingentry_in_cache) {
+ /* must duplicate addingentry before returning it to cache,
+ * which could free the entry. */
+ if ( (tmpentry = backentry_dup( addingentry )) == NULL ) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (cache_is_in_cache(&inst->inst_cache, addingentry)) {
/* addingentry is in cache. Remove it once. */
retval = CACHE_REMOVE(&inst->inst_cache, addingentry);
if (retval) {
LDAPDebug1Arg(LDAP_DEBUG_CACHE, "ldbm_add: cache_remove %s failed.\n",
slapi_entry_get_dn_const(addingentry->ep_entry));
}
- CACHE_RETURN(&inst->inst_cache, &addingentry);
- } else {
- backentry_free(&addingentry);
}
+ CACHE_RETURN(&inst->inst_cache, &addingentry);
slapi_pblock_set( pb, SLAPI_ADD_ENTRY, originalentry->ep_entry );
addingentry = originalentry;
- if ( (originalentry = backentry_dup( addingentry )) == NULL ) {
- ldap_result_code= LDAP_OPERATIONS_ERROR;
+ originalentry = tmpentry;
+ tmpentry = NULL;
+ /* Adding the resetted addingentry to the cache. */
+ if (cache_add_tentative(&inst->inst_cache, addingentry, NULL) < 0) {
+ LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
+ slapi_entry_get_dn_const(addingentry->ep_entry));
+ ldap_result_code = LDAP_ALREADY_EXISTS;
goto error_return;
}
- if (addingentry_in_cache) {
- /* Adding the resetted addingentry to the cache. */
- if (cache_add_tentative(&inst->inst_cache, addingentry, NULL) != 0) {
- LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
- slapi_entry_get_dn_const(addingentry->ep_entry));
- ldap_result_code = LDAP_ALREADY_EXISTS;
- addingentry_in_cache = 0;
- goto error_return;
- }
- }
if (ruv_c_init) {
/* reset the ruv txn stuff */
modify_term(&ruv_c, be);
@@ -531,7 +528,6 @@ ldbm_back_add( Slapi_PBlock *pb )
ldap_result_code= -1;
goto error_return; /* error result sent by find_entry2modify() */
}
- tombstone_in_cache = 1;
addingentry = backentry_dup( tombstoneentry );
if ( addingentry==NULL )
@@ -788,14 +784,13 @@ ldbm_back_add( Slapi_PBlock *pb )
/* Tentatively add the entry to the cache. We do this after adding any
* operational attributes to ensure that the cache is sized correctly. */
- if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL )!= 0 )
+ if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL ) < 0 )
{
LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
slapi_entry_get_dn_const(addingentry->ep_entry));
ldap_result_code= LDAP_ALREADY_EXISTS;
goto error_return;
}
- addingentry_in_cache = 1;
/*
* Before we add the entry, find out if the syntax of the aci
@@ -830,7 +825,6 @@ ldbm_back_add( Slapi_PBlock *pb )
parent_found = 1;
parententry = NULL;
}
-
if ( (originalentry = backentry_dup(addingentry )) == NULL ) {
ldap_result_code= LDAP_OPERATIONS_ERROR;
goto error_return;
@@ -865,7 +859,7 @@ ldbm_back_add( Slapi_PBlock *pb )
goto error_return;
}
- retval = id2entry_add( be, addingentry, &txn );
+ retval = id2entry_add_ext(be, addingentry, &txn, 1, &myrc);
if (DB_LOCK_DEADLOCK == retval)
{
LDAPDebug( LDAP_DEBUG_ARGS, "add 1 DEADLOCK\n", 0, 0, 0 );
@@ -1085,10 +1079,6 @@ ldbm_back_add( Slapi_PBlock *pb )
retval = -1;
goto error_return;
}
- if (addingentry_in_cache) { /* decrease the refcnt added by tentative */
- CACHE_RETURN( &inst->inst_cache, &addingentry );
- }
- addingentry_in_cache = 1; /* reset it to make it sure... */
/*
* The tombstone was locked down in the cache... we can
* get rid of the entry in the cache now.
@@ -1103,9 +1093,6 @@ ldbm_back_add( Slapi_PBlock *pb )
CACHE_RETURN(&inst->inst_dncache, &bdn);
}
}
- cache_unlock_entry(&inst->inst_cache, tombstoneentry);
- CACHE_RETURN(&inst->inst_cache, &tombstoneentry);
- tombstone_in_cache = 0;
}
if (parent_found)
{
@@ -1173,21 +1160,18 @@ error_return:
}
if ( addingentry )
{
- if ( addingentry_in_cache )
- {
- if (inst) {
- CACHE_REMOVE(&inst->inst_cache, addingentry);
- /* tell frontend not to free this entry */
- slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
- }
+ if (inst && cache_is_in_cache(&inst->inst_cache, addingentry)) {
+ CACHE_REMOVE(&inst->inst_cache, addingentry);
+ /* tell frontend not to free this entry */
+ slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
}
- else
+ else if (!cache_has_otherref(&inst->inst_cache, addingentry))
{
if (!is_resurect_operation) { /* if resurect, tombstoneentry is dupped. */
backentry_clear_entry(addingentry); /* e is released in the frontend */
}
- backentry_free( &addingentry ); /* release the backend wrapper, here */
}
+ CACHE_RETURN( &inst->inst_cache, &addingentry );
}
if (rc == DB_RUNRECOVERY) {
dblayer_remember_disk_filled(li);
@@ -1240,12 +1224,6 @@ diskfull_return:
opreturn = -1;
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
}
- if (addingentry_in_cache && addingentry && inst) {
- CACHE_REMOVE(&inst->inst_cache, addingentry);
- /* tell frontend not to free this entry */
- slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
- }
-
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
}
@@ -1263,11 +1241,11 @@ diskfull_return:
common_return:
if (inst) {
- if(tombstone_in_cache && tombstoneentry) {
+ if (tombstoneentry && cache_is_in_cache(&inst->inst_cache, tombstoneentry)) {
cache_unlock_entry(&inst->inst_cache, tombstoneentry);
CACHE_RETURN(&inst->inst_cache, &tombstoneentry);
}
- if (addingentry_in_cache && addingentry) {
+ if (addingentry) {
if ((0 == retval) && entryrdn_get_switch()) { /* subtree-rename: on */
/* since adding the entry to the entry cache was successful,
* let's add the dn to dncache, if not yet done. */
@@ -1319,6 +1297,7 @@ common_return:
slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
}
backentry_free(&originalentry);
+ backentry_free(&tmpentry);
slapi_sdn_done(&parentsdn);
slapi_ch_free( (void**)&ldap_result_matcheddn );
slapi_ch_free( (void**)&errbuf );
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 13a78fa..90736b3 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -61,6 +61,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
struct backentry *e = NULL;
struct backentry *tombstone = NULL;
struct backentry *original_tombstone = NULL;
+ struct backentry *tmptombstone = NULL;
const char *dn = NULL;
back_txn txn;
back_txnid parent_txn;
@@ -88,8 +89,6 @@ ldbm_back_delete( Slapi_PBlock *pb )
int delete_tombstone_entry = 0; /* We must remove the given tombstone entry from the DB */
int create_tombstone_entry = 0; /* We perform a "regular" LDAP delete but since we use */
/* replication, we must create a new tombstone entry */
- int tombstone_in_cache = 0;
- int e_in_cache = 0;
int remove_e_from_cache = 0;
entry_address *addr;
int addordel_flags = 0; /* passed to index_addordel */
@@ -103,6 +102,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
int myrc = 0;
PRUint64 conn_id;
int op_id;
+ ID ep_id = 0;
+ ID tomb_ep_id = 0;
+
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
conn_id = 0; /* connection is NULL */
}
@@ -205,7 +207,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
*/
txn.back_txn_txn = NULL; /* ready to create the child transaction */
for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
- if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) {
+ if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) { /* retry_count > 0 */
Slapi_Entry *ent = NULL;
/* Don't release SERIAL LOCK */
@@ -226,25 +228,30 @@ ldbm_back_delete( Slapi_PBlock *pb )
/* reset tombstone entry */
if (original_tombstone) {
- if (tombstone_in_cache) {
- CACHE_REMOVE(&inst->inst_cache, tombstone);
- CACHE_RETURN(&inst->inst_cache, &tombstone);
- tombstone = NULL;
- tombstone_in_cache = 0;
- } else {
- backentry_free(&tombstone);
- }
- tombstone = original_tombstone;
- if ( (original_tombstone = backentry_dup( tombstone )) == NULL ) {
+ /* must duplicate tombstone before returning it to cache,
+ * which could free the entry. */
+ if ( (tmptombstone = backentry_dup( original_tombstone )) == NULL ) {
ldap_result_code= LDAP_OPERATIONS_ERROR;
goto error_return;
}
+ if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
+ CACHE_REMOVE(&inst->inst_cache, tombstone);
+ }
+ CACHE_RETURN(&inst->inst_cache, &tombstone);
+ if (tombstone) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "conn=%lu op=%d [retry: %d] tombstone %s is not freed!!! refcnt %d, state %d\n",
+ conn_id, op_id, retry_count, slapi_entry_get_dn(tombstone->ep_entry),
+ tombstone->ep_refcnt, tombstone->ep_state);
+ }
+ tombstone = original_tombstone;
+ original_tombstone = tmptombstone;
+ tmptombstone = NULL;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "conn=%lu op=%d [retry: %d] No original_tombstone for %s!!\n",
+ conn_id, op_id, retry_count, slapi_entry_get_dn(e->ep_entry));
}
- /* reset original entry in cache */
- if (!e_in_cache) {
- CACHE_ADD(&inst->inst_cache, e, NULL);
- e_in_cache = 1;
- }
if (ruv_c_init) {
/* reset the ruv txn stuff */
modify_term(&ruv_c, be);
@@ -252,8 +259,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
}
/* We're re-trying */
- LDAPDebug0Args(LDAP_DEBUG_BACKLDBM,
- "Delete Retrying Transaction\n");
+ LDAPDebug0Args(LDAP_DEBUG_BACKLDBM, "Delete Retrying Transaction\n");
#ifndef LDBM_NO_BACKOFF_DELAY
{
PRIntervalTime interval;
@@ -295,12 +301,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
LDAPDebug0Args(LDAP_DEBUG_BACKLDBM, "ldbm_back_delete: Deleting entry is already deleted.\n");
goto error_return; /* error result sent by find_entry2modify() */
}
- e_in_cache = 1; /* e is cached */
-
+ ep_id = e->ep_id;
retval = slapi_entry_has_children(e->ep_entry);
if (retval) {
ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
"conn=%lu op=%d Deleting entry %s has %d children.\n",
conn_id, op_id, slapi_entry_get_dn(e->ep_entry), retval);
retval = -1;
@@ -548,12 +553,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
op |= PARENTUPDATE_DELETE_TOMBSTONE;
}
retval = parent_update_on_childchange(&parent_modify_c, op, &haschildren);
- slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
- "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
- conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
-
/* The modify context now contains info needed later */
if (0 != retval) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
ldap_result_code= LDAP_OPERATIONS_ERROR;
slapi_sdn_done(&parentsdn);
retval = -1;
@@ -610,6 +614,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
parentuniqueid= slapi_entry_get_uniqueid(parent_modify_c.old_entry->ep_entry);
}
tombstone = backentry_dup( e );
+ tomb_ep_id = tombstone->ep_id;
slapi_entry_set_dn(tombstone->ep_entry,tombstone_dn); /* Consumes DN */
if (entryrdn_get_switch()) /* subtree-rename: on */
{
@@ -720,13 +725,10 @@ ldbm_back_delete( Slapi_PBlock *pb )
* entry is removed from the cache.
*/
retval = cache_add_tentative(&inst->inst_cache, tombstone, NULL);
- if (0 == retval) {
- tombstone_in_cache = 1;
- } else {
+ if (0 > retval) {
slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
"conn=%lu op=%d tombstone entry %s failed to add to the cache: %d\n",
conn_id, op_id, slapi_entry_get_dn(tombstone->ep_entry), retval);
- tombstone_in_cache = 0;
if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
DEL_SET_ERROR(ldap_result_code,
LDAP_OPERATIONS_ERROR, retry_count);
@@ -745,13 +747,6 @@ ldbm_back_delete( Slapi_PBlock *pb )
DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
goto error_return;
}
- if (tombstone_in_cache) {
- /* tombstone was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
- and/or id2entry_add - so it already had one refcount - cache_replace adds another refcount -
- drop the extra ref added by cache_replace */
- CACHE_RETURN( &inst->inst_cache, &tombstone );
- }
- tombstone_in_cache = 1;
}
else
{
@@ -1155,6 +1150,15 @@ ldbm_back_delete( Slapi_PBlock *pb )
retval = -1;
goto error_return;
}
+ if (create_tombstone_entry) {
+ retval = cache_replace(&inst->inst_cache, e, tombstone);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_CACHE, "ldbm_back_delete: cache_replace failed (%d): %s --> %s\n",
+ retval, slapi_entry_get_dn(e->ep_entry), slapi_entry_get_dn(tombstone->ep_entry));
+ retval= -1;
+ goto error_return;
+ }
+ }
if (create_tombstone_entry) {
retval = cache_replace(&inst->inst_cache, e, tombstone);
@@ -1205,22 +1209,26 @@ ldbm_back_delete( Slapi_PBlock *pb )
/* delete from cache and clean up */
if (e) {
- if (entryrdn_get_switch()) { /* subtree-rename: on */
+ if (cache_is_in_cache(&inst->inst_cache, e)) {
+ ep_id = e->ep_id; /* Otherwise, e might have been freed. */
+ CACHE_REMOVE(&inst->inst_cache, e);
+ }
+ cache_unlock_entry(&inst->inst_cache, e);
+ CACHE_RETURN(&inst->inst_cache, &e);
+ /*
+ * e is unlocked and no longer in cache.
+ * It could be freed at any moment.
+ */
+ e = NULL;
+
+ if (entryrdn_get_switch() && ep_id) { /* subtree-rename: on */
/* since the op was successful, delete the tombstone dn from the dn cache */
- struct backdn *bdn = dncache_find_id(&inst->inst_dncache, e->ep_id);
+ struct backdn *bdn = dncache_find_id(&inst->inst_dncache, ep_id);
if (bdn) { /* in the dncache, remove it. */
CACHE_REMOVE(&inst->inst_dncache, bdn);
CACHE_RETURN(&inst->inst_dncache, &bdn);
}
}
- if (e_in_cache) {
- CACHE_REMOVE(&inst->inst_cache, e);
- cache_unlock_entry(&inst->inst_cache, e);
- CACHE_RETURN(&inst->inst_cache, &e);
- } else {
- cache_unlock_entry(&inst->inst_cache, e);
- }
- e = NULL;
}
if (ruv_c_init) {
@@ -1250,43 +1258,23 @@ ldbm_back_delete( Slapi_PBlock *pb )
error_return:
if (tombstone) {
- if (entryrdn_get_switch()) { /* subtree-rename: on */
+ if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
+ tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
+ }
+ if (entryrdn_get_switch() && tomb_ep_id) { /* subtree-rename: on */
struct backdn *bdn = dncache_find_id(&inst->inst_dncache, tombstone->ep_id);
if (bdn) { /* already in the dncache. Delete it. */
CACHE_REMOVE(&inst->inst_dncache, bdn);
CACHE_RETURN(&inst->inst_dncache, &bdn);
}
}
-#ifdef CACHE_DEBUG
- check_entry_cache(&inst->inst_cache, tombstone, tombstone_in_cache);
-#endif
- if (tombstone_in_cache) { /* successfully replaced */
- CACHE_REMOVE( &inst->inst_cache, tombstone );
- CACHE_RETURN( &inst->inst_cache, &tombstone );
- tombstone = NULL;
- tombstone_in_cache = 0;
- } else {
- backentry_free( &tombstone );
- }
- }
- /* Need to return to cache after post op plugins are called */
- if (e) {
-#ifdef CACHE_DEBUG
- check_entry_cache(&inst->inst_cache, e, e_in_cache);
-#endif
- if (e_in_cache) {
- if (remove_e_from_cache) {
- /* The entry is already transformed to a tombstone. */
- CACHE_REMOVE( &inst->inst_cache, e );
- }
- cache_unlock_entry( &inst->inst_cache, e );
- CACHE_RETURN( &inst->inst_cache, &e );
- } else {
- cache_unlock_entry( &inst->inst_cache, e );
+ if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
+ CACHE_REMOVE(&inst->inst_cache, tombstone);
}
+ CACHE_RETURN( &inst->inst_cache, &tombstone );
+ tombstone = NULL;
}
-
if (retval == DB_RUNRECOVERY) {
dblayer_remember_disk_filled(li);
ldbm_nasty("Delete",79,retval);
@@ -1376,16 +1364,8 @@ common_return:
}
}
}
-#ifdef CACHE_DEBUG
- check_entry_cache(&inst->inst_cache, tombstone, tombstone_in_cache);
-#endif
- if (tombstone_in_cache) { /* successfully replaced */
- CACHE_RETURN( &inst->inst_cache, &tombstone );
- tombstone = NULL;
- tombstone_in_cache = 0;
- } else {
- backentry_free( &tombstone );
- }
+ CACHE_RETURN( &inst->inst_cache, &tombstone );
+ tombstone = NULL;
}
/* result code could be used in the bepost plugin functions. */
@@ -1397,8 +1377,14 @@ common_return:
if (!delete_tombstone_entry) {
plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
}
+<<<<<<< HEAD
if (e) {
if (e_in_cache) {
+=======
+ /* Need to return to cache after post op plugins are called */
+ if (e) {
+ if (cache_is_in_cache(&inst->inst_cache, e)) {
+>>>>>>> d9c8b1f... Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
if (remove_e_from_cache) {
/* The entry is already transformed to a tombstone. */
CACHE_REMOVE( &inst->inst_cache, e );
@@ -1406,7 +1392,11 @@ common_return:
}
cache_unlock_entry( &inst->inst_cache, e );
CACHE_RETURN( &inst->inst_cache, &e );
+<<<<<<< HEAD
/*
+=======
+ /*
+>>>>>>> d9c8b1f... Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
* e is unlocked and no longer in cache.
* It could be freed at any moment.
*/
@@ -1430,7 +1420,8 @@ diskfull_return:
}
slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
"conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p, in_cache=%d\n",
- conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, parent_modify_c.new_entry_in_cache);
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry,
+ cache_is_in_cache(&inst->inst_cache, parent_modify_c.new_entry));
myrc = modify_term(&parent_modify_c, be);
if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry)
{
@@ -1448,6 +1439,7 @@ diskfull_return:
slapi_pblock_set(pb, SLAPI_DELETE_EXISTING_ENTRY, NULL);
}
backentry_free(&original_tombstone);
+ backentry_free(&tmptombstone);
slapi_ch_free((void**)&errbuf);
slapi_sdn_done(&nscpEntrySDN);
slapi_ch_free_string(&e_uniqueid);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index da6a127..e6ccf20 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -65,7 +65,6 @@ void modify_init(modify_context *mc,struct backentry *old_entry)
PR_ASSERT(NULL == mc->new_entry);
mc->old_entry = old_entry;
- mc->new_entry_in_cache = 0;
mc->attr_encrypt = 1;
}
@@ -86,6 +85,9 @@ int modify_apply_mods_ignore_error(modify_context *mc, Slapi_Mods *smods, int er
ret = entry_apply_mods_ignore_error( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods), error);
}
mc->smods= smods;
+ if (error == ret) {
+ ret = LDAP_SUCCESS;
+ }
return ret;
}
@@ -96,16 +98,13 @@ int modify_term(modify_context *mc,struct backend *be)
slapi_mods_free(&mc->smods);
/* Unlock and return entries */
- if (NULL != mc->old_entry) {
+ if (mc->old_entry) {
cache_unlock_entry(&inst->inst_cache, mc->old_entry);
CACHE_RETURN( &(inst->inst_cache), &(mc->old_entry) );
mc->old_entry= NULL;
}
- if (mc->new_entry_in_cache) {
- CACHE_RETURN( &(inst->inst_cache), &(mc->new_entry) );
- } else {
- backentry_free(&(mc->new_entry));
- }
+
+ CACHE_RETURN(&(inst->inst_cache), &(mc->new_entry));
mc->new_entry= NULL;
return 0;
}
@@ -115,11 +114,9 @@ int modify_switch_entries(modify_context *mc,backend *be)
{
ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
int ret = 0;
- if (mc->old_entry!=NULL && mc->new_entry!=NULL) {
+ if (mc->old_entry && mc->new_entry) {
ret = cache_replace(&(inst->inst_cache), mc->old_entry, mc->new_entry);
- if (ret == 0) {
- mc->new_entry_in_cache = 1;
- } else {
+ if (ret) {
LDAPDebug(LDAP_DEBUG_CACHE, "modify_switch_entries: replacing %s with %s failed (%d)\n",
slapi_entry_get_dn(mc->old_entry->ep_entry),
slapi_entry_get_dn(mc->new_entry->ep_entry), ret);
@@ -140,13 +137,19 @@ modify_unswitch_entries(modify_context *mc,backend *be)
ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
int ret = 0;
- if (mc->old_entry && mc->new_entry && mc->new_entry_in_cache) {
+ if (mc->old_entry && mc->new_entry &&
+ cache_is_in_cache(&inst->inst_cache, mc->new_entry)) {
/* switch the entries, and reset the new, new, entry */
tmp_be = mc->new_entry;
mc->new_entry = mc->old_entry;
mc->new_entry->ep_state = 0;
- mc->new_entry->ep_refcnt = 0;
- mc->new_entry_in_cache = 0;
+ if (cache_has_otherref(&(inst->inst_cache), mc->new_entry)) {
+ /* some other thread refers the entry */
+ CACHE_RETURN(&(inst->inst_cache), &(mc->new_entry));
+ } else {
+ /* don't call CACHE_RETURN, that frees the entry! */
+ mc->new_entry->ep_refcnt = 0;
+ }
mc->old_entry = tmp_be;
ret = cache_replace(&(inst->inst_cache), mc->old_entry, mc->new_entry);
@@ -157,9 +160,7 @@ modify_unswitch_entries(modify_context *mc,backend *be)
* "old" one. modify_term() will then return the "new" entry.
*/
cache_unlock_entry(&inst->inst_cache, mc->new_entry);
- CACHE_RETURN( &(inst->inst_cache), &(mc->old_entry) );
- mc->new_entry_in_cache = 1;
- mc->old_entry = NULL;
+ cache_lock_entry(&inst->inst_cache, mc->old_entry);
} else {
LDAPDebug(LDAP_DEBUG_CACHE, "modify_unswitch_entries: replacing %s with %s failed (%d)\n",
slapi_entry_get_dn(mc->old_entry->ep_entry),
@@ -362,7 +363,8 @@ ldbm_back_modify( Slapi_PBlock *pb )
backend *be;
ldbm_instance *inst = NULL;
struct ldbminfo *li;
- struct backentry *e = NULL, *ec = NULL, *original_entry = NULL;
+ struct backentry *e = NULL, *ec = NULL;
+ struct backentry *original_entry = NULL, *tmpentry = NULL;
Slapi_Entry *postentry = NULL;
LDAPMod **mods = NULL;
LDAPMod **mods_original = NULL;
@@ -381,7 +383,6 @@ ldbm_back_modify( Slapi_PBlock *pb )
int rc = 0;
Slapi_Operation *operation;
entry_address *addr;
- int ec_in_cache = 0;
int is_fixup_operation= 0;
int is_ruv = 0; /* True if the current entry is RUV */
CSN *opcsn = NULL;
@@ -475,14 +476,22 @@ ldbm_back_modify( Slapi_PBlock *pb )
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
ldap_mods_free(mods, 1);
slapi_pblock_set(pb, SLAPI_MODIFY_MODS, copy_mods(mods_original));
- /* ec is not really added to the cache until cache_replace, so we
- don't have to worry about the cache here */
- backentry_free(&ec);
- slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, original_entry->ep_entry );
- ec = original_entry;
- if ( (original_entry = backentry_dup( ec )) == NULL ) {
- ldap_result_code= LDAP_OPERATIONS_ERROR;
- goto error_return;
+
+ /* reset ec set cache in id2entry_add_ext */
+ if (ec) {
+ /* must duplicate ec before returning it to cache,
+ * which could free the entry. */
+ if ( (tmpentry = backentry_dup( ec )) == NULL ) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (cache_is_in_cache(&inst->inst_cache, ec)) {
+ CACHE_REMOVE(&inst->inst_cache, ec);
+ }
+ CACHE_RETURN(&inst->inst_cache, &ec);
+ ec = original_entry;
+ original_entry = tmpentry;
+ tmpentry = NULL;
}
if (ruv_c_init) {
@@ -765,15 +774,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
goto error_return;
}
/* e uncached */
- /* we must return both e (which has been deleted) and new entry ec */
- /* cache_replace removes e from the caches */
+ /* we must return both e (which has been deleted) and new entry ec to cache */
+ /* cache_replace removes e from the cache hash tables */
cache_unlock_entry( &inst->inst_cache, e );
CACHE_RETURN( &inst->inst_cache, &e );
-
/* lock new entry in cache to prevent usage until we are complete */
cache_lock_entry( &inst->inst_cache, ec );
- ec_in_cache = 1;
-
postentry = slapi_entry_dup( ec->ep_entry );
slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
@@ -879,11 +885,11 @@ error_return:
}
/* if ec is in cache, remove it, then add back e if we still have it */
- if (inst && ec_in_cache) {
+ if (inst && cache_is_in_cache(&inst->inst_cache, ec)) {
CACHE_REMOVE( &inst->inst_cache, ec );
/* if ec was in cache, e was not - add back e */
if (e) {
- if (CACHE_ADD( &inst->inst_cache, e, NULL )) {
+ if (CACHE_ADD( &inst->inst_cache, e, NULL ) < 0) {
LDAPDebug1Arg(LDAP_DEBUG_CACHE, "ldbm_modify: CACHE_ADD %s failed\n",
slapi_entry_get_dn(e->ep_entry));
}
@@ -894,18 +900,15 @@ common_return:
slapi_mods_done(&smods);
if (inst) {
- if (ec_in_cache) {
- cache_unlock_entry( &inst->inst_cache, ec);
- CACHE_RETURN( &inst->inst_cache, &ec );
- } else {
- backentry_free(&ec);
+ if (cache_is_in_cache(&inst->inst_cache, ec)) {
+ cache_unlock_entry(&inst->inst_cache, ec);
+ } else if (e) {
/* if ec was not in cache, cache_replace was not done.
* i.e., e was not unlocked. */
- if (e) {
- cache_unlock_entry( &inst->inst_cache, e);
- CACHE_RETURN( &inst->inst_cache, &e);
- }
+ cache_unlock_entry(&inst->inst_cache, e);
+ CACHE_RETURN(&inst->inst_cache, &e);
}
+ CACHE_RETURN(&inst->inst_cache, &ec);
if (inst->inst_ref_count) {
slapi_counter_decrement(inst->inst_ref_count);
}
@@ -935,6 +938,7 @@ common_return:
/* free our backups */
ldap_mods_free(mods_original, 1);
backentry_free(&original_entry);
+ backentry_free(&tmpentry);
slapi_ch_free_string(&errbuf);
return rc;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 65880f9..1b297a4 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -50,7 +50,7 @@ static void moddn_unlock_and_return_entry(backend *be,struct backentry **targete
static int moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods_wsi, int is_repl_op);
static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns, int is_resurect_operation);
static int moddn_rename_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, IDList *children, Slapi_DN *dn_parentdn, Slapi_DN *dn_newsuperiordn, struct backentry *child_entries[]);
-static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3, int *e_in_cache, int *ec_in_cache);
+static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3);
static void mods_remove_nsuniqueid(Slapi_Mods *smods);
#define MOD_SET_ERROR(rc, error, count) \
@@ -67,8 +67,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
struct ldbminfo *li;
struct backentry *e= NULL;
struct backentry *ec= NULL;
- int ec_in_cache= 0;
- int e_in_cache= 0;
back_txn txn;
back_txnid parent_txn;
int retval = -1;
@@ -83,8 +81,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
struct backentry *parententry= NULL;
struct backentry *newparententry= NULL;
struct backentry *original_entry = NULL;
- struct backentry *original_parent = NULL;
- struct backentry *original_newparent = NULL;
+ struct backentry *tmpentry = NULL;
modify_context parent_modify_context = {0};
modify_context newparent_modify_context = {0};
modify_context ruv_c = {0};
@@ -270,29 +267,22 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
slapi_sdn_free(&dn_newsuperiordn);
slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, orig_dn_newsuperiordn);
orig_dn_newsuperiordn = slapi_sdn_dup(orig_dn_newsuperiordn);
-#ifdef CACHE_DEBUG
- check_entry_cache(&inst->inst_cache, ec, ec_in_cache);
-#endif
- if (ec_in_cache) {
- /* New entry 'ec' is in the entry cache.
- * Remove it from the cache . */
+ /* must duplicate ec before returning it to cache,
+ * which could free the entry. */
+ if ( (tmpentry = backentry_dup( ec )) == NULL ) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (cache_is_in_cache(&inst->inst_cache, ec)) {
CACHE_REMOVE(&inst->inst_cache, ec);
- CACHE_RETURN(&inst->inst_cache, &ec);
-#ifdef DEBUG_CACHE
- PR_ASSERT(ec == NULL);
-#endif
- ec_in_cache = 0;
- } else {
- backentry_free(&ec);
}
- /* make sure the original entry is back in the cache if it was removed */
- if (!e_in_cache) {
- if (CACHE_ADD(&inst->inst_cache, e, NULL)) {
+ CACHE_RETURN(&inst->inst_cache, &ec);
+ if (!cache_is_in_cache(&inst->inst_cache, e)) {
+ if (CACHE_ADD(&inst->inst_cache, e, NULL) < 0) {
LDAPDebug1Arg(LDAP_DEBUG_CACHE,
"ldbm_back_modrdn: CACHE_ADD %s to cache failed\n",
slapi_entry_get_dn_const(e->ep_entry));
}
- e_in_cache = 1;
}
slapi_pblock_get( pb, SLAPI_MODRDN_EXISTING_ENTRY, &ent );
if (ent && (ent != original_entry->ep_entry)) {
@@ -300,16 +290,13 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
slapi_pblock_set( pb, SLAPI_MODRDN_EXISTING_ENTRY, NULL );
}
ec = original_entry;
- if ( (original_entry = backentry_dup( ec )) == NULL ) {
- ldap_result_code= LDAP_OPERATIONS_ERROR;
- goto error_return;
- }
+ original_entry = tmpentry;
+ tmpentry = NULL;
slapi_pblock_set( pb, SLAPI_MODRDN_EXISTING_ENTRY, original_entry->ep_entry );
free_modrdn_existing_entry = 0; /* owned by original_entry now */
- if (!ec_in_cache) {
+ if (!cache_is_in_cache(&inst->inst_cache, ec)) {
/* Put the resetted entry 'ec' into the cache again. */
- if (cache_add_tentative( &inst->inst_cache, ec, NULL ) != 0) {
- ec_in_cache = 0; /* not in cache */
+ if (cache_add_tentative( &inst->inst_cache, ec, NULL ) < 0) {
/* allow modrdn even if the src dn and dest dn are identical */
if ( 0 != slapi_sdn_compare((const Slapi_DN *)&dn_newdn,
(const Slapi_DN *)sdn) ) {
@@ -321,8 +308,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
}
/* so if the old dn is the same as the new dn, the entry will not be cached
until it is replaced with cache_replace */
- } else {
- ec_in_cache = 1;
}
}
@@ -509,7 +494,6 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
ldap_result_code= -1;
goto error_return; /* error result sent by find_entry2modify() */
}
- e_in_cache = 1; /* e is in the cache and locked */
if (slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE) &&
!is_resurect_operation) {
ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
@@ -747,8 +731,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
}
/* create it in the cache - prevents others from creating it */
- if (( cache_add_tentative( &inst->inst_cache, ec, NULL ) != 0 ) ) {
- ec_in_cache = 0; /* not in cache */
+ if (( cache_add_tentative( &inst->inst_cache, ec, NULL ) < 0 ) ) {
/* allow modrdn even if the src dn and dest dn are identical */
if ( 0 != slapi_sdn_compare((const Slapi_DN *)&dn_newdn,
(const Slapi_DN *)sdn) ) {
@@ -764,46 +747,41 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
}
/* so if the old dn is the same as the new dn, the entry will not be cached
until it is replaced with cache_replace */
- } else {
- ec_in_cache = 1;
}
-
/* Build the list of modifications required to the existing entry */
+ slapi_mods_init(&smods_generated,4);
+ slapi_mods_init(&smods_generated_wsi,4);
+ ldap_result_code = moddn_newrdn_mods(pb, slapi_sdn_get_ndn(sdn),
+ ec, &smods_generated_wsi, is_replicated_operation);
+ if (ldap_result_code != LDAP_SUCCESS) {
+ if (ldap_result_code == LDAP_UNWILLING_TO_PERFORM)
+ ldap_result_message = "Modification of old rdn attribute type not allowed.";
+ goto error_return;
+ }
+ if (!entryrdn_get_switch()) /* subtree-rename: off */
{
- slapi_mods_init(&smods_generated,4);
- slapi_mods_init(&smods_generated_wsi,4);
- ldap_result_code = moddn_newrdn_mods(pb, slapi_sdn_get_ndn(sdn),
- ec, &smods_generated_wsi, is_replicated_operation);
- if (ldap_result_code != LDAP_SUCCESS) {
- if (ldap_result_code == LDAP_UNWILLING_TO_PERFORM)
- ldap_result_message = "Modification of old rdn attribute type not allowed.";
- goto error_return;
- }
- if (!entryrdn_get_switch()) /* subtree-rename: off */
- {
- /*
- * Remove the old entrydn index entry, and add the new one.
- */
- slapi_mods_add( &smods_generated, LDAP_MOD_DELETE, LDBM_ENTRYDN_STR,
- strlen(backentry_get_ndn(e)), backentry_get_ndn(e));
- slapi_mods_add( &smods_generated, LDAP_MOD_REPLACE, LDBM_ENTRYDN_STR,
- strlen(backentry_get_ndn(ec)), backentry_get_ndn(ec));
- }
-
/*
- * Update parentid if we have a new superior.
- */
- if(slapi_sdn_get_dn(dn_newsuperiordn)!=NULL) {
- char buf[40]; /* Enough for an ID */
-
- if (parententry != NULL) {
- sprintf( buf, "%lu", (u_long)parententry->ep_id );
- slapi_mods_add_string(&smods_generated, LDAP_MOD_DELETE, LDBM_PARENTID_STR, buf);
- }
- if (newparententry != NULL) {
- sprintf( buf, "%lu", (u_long)newparententry->ep_id );
- slapi_mods_add_string(&smods_generated, LDAP_MOD_REPLACE, LDBM_PARENTID_STR, buf);
- }
+ * Remove the old entrydn index entry, and add the new one.
+ */
+ slapi_mods_add( &smods_generated, LDAP_MOD_DELETE, LDBM_ENTRYDN_STR,
+ strlen(backentry_get_ndn(e)), backentry_get_ndn(e));
+ slapi_mods_add( &smods_generated, LDAP_MOD_REPLACE, LDBM_ENTRYDN_STR,
+ strlen(backentry_get_ndn(ec)), backentry_get_ndn(ec));
+ }
+
+ /*
+ * Update parentid if we have a new superior.
+ */
+ if(slapi_sdn_get_dn(dn_newsuperiordn)!=NULL) {
+ char buf[40]; /* Enough for an ID */
+
+ if (parententry != NULL) {
+ sprintf( buf, "%lu", (u_long)parententry->ep_id );
+ slapi_mods_add_string(&smods_generated, LDAP_MOD_DELETE, LDBM_PARENTID_STR, buf);
+ }
+ if (newparententry != NULL) {
+ sprintf( buf, "%lu", (u_long)newparententry->ep_id );
+ slapi_mods_add_string(&smods_generated, LDAP_MOD_REPLACE, LDBM_PARENTID_STR, buf);
}
}
@@ -1029,7 +1007,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
/*
* Update the indexes for the entry.
*/
- retval = modrdn_rename_entry_update_indexes(&txn, pb, li, e, &ec, &smods_generated, &smods_generated_wsi, &smods_operation_wsi, &e_in_cache, &ec_in_cache);
+ retval = modrdn_rename_entry_update_indexes(&txn, pb, li, e, &ec, &smods_generated, &smods_generated_wsi, &smods_operation_wsi);
if (DB_LOCK_DEADLOCK == retval)
{
/* Retry txn */
@@ -1472,19 +1450,13 @@ common_return:
}
/* remove the new entry from the cache if the op failed -
otherwise, leave it in */
-#ifdef CACHE_DEBUG
- check_entry_cache(&inst->inst_cache, ec, ec_in_cache);
-#endif
- if (ec_in_cache && ec && inst) {
- if (retval) {
+ if (ec && inst) {
+ if (retval && cache_is_in_cache(&inst->inst_cache, ec)) {
CACHE_REMOVE( &inst->inst_cache, ec );
}
CACHE_RETURN( &inst->inst_cache, &ec );
- } else {
- backentry_free( &ec );
}
ec = NULL;
- ec_in_cache = 0;
}
if (inst) {
@@ -1546,8 +1518,7 @@ common_return:
slapi_ch_free_string(&original_newrdn);
slapi_sdn_free(&orig_dn_newsuperiordn);
backentry_free(&original_entry);
- backentry_free(&original_parent);
- backentry_free(&original_newparent);
+ backentry_free(&tmpentry);
slapi_entry_free(original_targetentry);
slapi_ch_free((void**)&errbuf);
if (retval == 0 && opcsn != NULL && !is_fixup_operation)
@@ -1817,7 +1788,9 @@ mods_remove_nsuniqueid(Slapi_Mods *smods)
* mods contains the list of attribute change made.
*/
static int
-modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3, int *e_in_cache, int *ec_in_cache)
+modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li,
+ struct backentry *e, struct backentry **ec,
+ Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3)
{
backend *be;
ldbm_instance *inst;
@@ -1825,7 +1798,6 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
char *msg;
Slapi_Operation *operation;
int is_ruv = 0; /* True if the current entry is RUV */
- int orig_ec_in_cache = 0;
int cache_rc = 0;
slapi_pblock_get( pb, SLAPI_BACKEND, &be );
@@ -1833,7 +1805,6 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
inst = (ldbm_instance *) be->be_instance_info;
- orig_ec_in_cache = *ec_in_cache;
/*
* Update the ID to Entry index.
* Note that id2entry_add replaces the entry, so the Entry ID stays the same.
@@ -1855,7 +1826,6 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
LDAPDebug( LDAP_DEBUG_ANY, "modrdn_rename_entry_update_indexes: id2entry_add failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
goto error_return;
}
- *ec_in_cache = 1; /* id2entry_add adds to cache if not already in */
if(smods1!=NULL && slapi_mods_get_num_mods(smods1)>0)
{
/*
@@ -1943,13 +1913,6 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
retval= -1;
goto error_return;
}
- *e_in_cache = 0;
- if (orig_ec_in_cache) {
- /* ec was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
- and/or id2entry_add - so it already had one refcount - cache_replace adds another refcount -
- drop the extra ref added by cache_replace */
- CACHE_RETURN( &inst->inst_cache, ec );
- }
error_return:
return retval;
}
@@ -1984,9 +1947,6 @@ moddn_rename_child_entry(
int olddncomps= 0;
int need= 1; /* For the '\0' */
int i;
- int e_in_cache = 1;
- int ec_in_cache = 0;
-
olddn = slapi_entry_get_dn((*ec)->ep_entry);
if (NULL == olddn) {
return retval;
@@ -2048,8 +2008,7 @@ moddn_rename_child_entry(
* Update all the indexes.
*/
retval = modrdn_rename_entry_update_indexes(ptxn, pb, li, e, ec,
- smodsp, NULL, NULL,
- &e_in_cache, &ec_in_cache);
+ smodsp, NULL, NULL);
/* JCMREPL - Should the children get updated modifiersname and lastmodifiedtime? */
slapi_mods_done(&smods);
}
diff --git a/ldap/servers/slapd/back-ldbm/parents.c b/ldap/servers/slapd/back-ldbm/parents.c
index d375519..f55d527 100644
--- a/ldap/servers/slapd/back-ldbm/parents.c
+++ b/ldap/servers/slapd/back-ldbm/parents.c
@@ -126,11 +126,11 @@ parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
mod_op = LDAP_MOD_ADD;
} else if (PARENTUPDATE_DEL == op) {
if (!already_present) {
- /* This means that something is wrong---deleting a child but no subcount present on parent */
+ /* This means that there was a conflict. Before coming to this point,
+ * the entry to be deleted was deleted... */
LDAPDebug(LDAP_DEBUG_ANY, "Parent %s has no children. (op 0x%x, repl_op 0x%x)\n",
slapi_entry_get_dn(mc->old_entry->ep_entry), op, repl_op);
slapi_mods_free(&smods);
- PR_ASSERT(0);
return -1;
} else {
if (current_sub_count == 1) {
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 180ad4c..632502d 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -87,8 +87,11 @@ int cache_add_tentative(struct cache *cache, struct backentry *e,
int cache_lock_entry(struct cache *cache, struct backentry *e);
void cache_unlock_entry(struct cache *cache, struct backentry *e);
int cache_replace(struct cache *cache, void *oldptr, void *newptr);
+int cache_has_otherref(struct cache *cache, void *bep);
+int cache_is_in_cache(struct cache *cache, void *ptr);
+
#ifdef CACHE_DEBUG
-void check_entry_cache(struct cache *cache, struct backentry *e, int in_cache);
+void check_entry_cache(struct cache *cache, struct backentry *e);
#endif
Hashtable *new_hash(u_long size, u_long offset, HashFn hfn,
commit 112203f49844bdc47649a6305b64d00485193671
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Tue Jun 24 16:39:24 2014 -0700
Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
Bug description: tombstone_to_glue resolves parents recursively if
they are also a tombstone entry, which may change the DN of the
target entry, but the DN change was not adjusted.
Fix description: Added a new argument newparentdn to tombstone_to_
glue_resolve_parent to return the new parent DN if it has been updated.
If a new parent DN is returned, set it to the target DN.
This patch also adds a cache debugging function: check_entry_cache,
which is disabled by default (in #ifdef CACHE_DEBUG)
Note: this bug is a left over of ticket #47750.
https://fedorahosted.org/389/ticket/47834
Reviewed by rmeggins(a)redhat.com (Thank you, Rich!!)
(cherry picked from commit 708a56b8d524131362e2d71b7fbc2eb257075e14)
(cherry picked from commit 513788ce60ef4f3742bfdb5442a92887735367c9)
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
index d867274..c7d60e2 100644
--- a/ldap/servers/plugins/replication/urp.c
+++ b/ldap/servers/plugins/replication/urp.c
@@ -966,7 +966,8 @@ urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *ent
if(is_tombstone_entry(parententry)) /* The parent is a tombstone */
{
/* The parent entry must be resurected from the dead. */
- ldap_rc = tombstone_to_glue (pb, sessionid, parententry, parentdn, REASON_RESURRECT_ENTRY, opcsn);
+ /* parentdn retrieved from entry is not tombstone dn. */
+ ldap_rc = tombstone_to_glue (pb, sessionid, parententry, parentdn, REASON_RESURRECT_ENTRY, opcsn, NULL);
if ( ldap_rc != LDAP_SUCCESS )
{
ldap_rc= LDAP_OPERATIONS_ERROR;
diff --git a/ldap/servers/plugins/replication/urp.h b/ldap/servers/plugins/replication/urp.h
index 8afd7d1..678a2cc 100644
--- a/ldap/servers/plugins/replication/urp.h
+++ b/ldap/servers/plugins/replication/urp.h
@@ -79,6 +79,6 @@ PRBool get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn);
* urp_tombstone.c
*/
int is_tombstone_entry(const Slapi_Entry* entry);
-int tombstone_to_glue(Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn);
+int tombstone_to_glue(Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn, Slapi_DN **newparentdn);
int entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry );
PRBool get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn);
diff --git a/ldap/servers/plugins/replication/urp_glue.c b/ldap/servers/plugins/replication/urp_glue.c
index 199d4de..a13c0be 100644
--- a/ldap/servers/plugins/replication/urp_glue.c
+++ b/ldap/servers/plugins/replication/urp_glue.c
@@ -230,7 +230,7 @@ create_glue_entry ( Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char
slapi_pblock_get( pb, SLAPI_BACKEND, &backend );
slapi_sdn_get_backend_parent ( dn, superiordn, backend );
- slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(dn), 1/* skip nsuniqeid=..., in dn */);
+ slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(dn), SLAPI_RDN_SET_DN_SKIP_UNIQUEID);
while(!done)
{
diff --git a/ldap/servers/plugins/replication/urp_tombstone.c b/ldap/servers/plugins/replication/urp_tombstone.c
index 5a37ca8..db7fa00 100644
--- a/ldap/servers/plugins/replication/urp_tombstone.c
+++ b/ldap/servers/plugins/replication/urp_tombstone.c
@@ -87,17 +87,18 @@ tombstone_to_glue_resolve_parent (
char *sessionid,
const Slapi_DN *parentdn,
const char *parentuniqueid,
- CSN *opcsn)
+ CSN *opcsn,
+ Slapi_DN **newparentdn)
{
/* Let's have a look at the parent of this entry... */
if(!slapi_sdn_isempty(parentdn) && parentuniqueid!=NULL)
{
int op_result;
- Slapi_PBlock *newpb= slapi_pblock_new();
- slapi_search_internal_set_pb(
- newpb,
- slapi_sdn_get_dn(parentdn), /* JCM - This DN just identifies the backend to be searched. */
- LDAP_SCOPE_BASE,
+ Slapi_PBlock *newpb= slapi_pblock_new();
+ slapi_search_internal_set_pb(
+ newpb,
+ slapi_sdn_get_dn(parentdn), /* JCM - This DN just identifies the backend to be searched. */
+ LDAP_SCOPE_BASE,
"objectclass=*",
NULL, /*attrs*/
0, /*attrsonly*/
@@ -106,7 +107,7 @@ tombstone_to_glue_resolve_parent (
repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
0);
slapi_search_internal_pb(newpb);
- slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
switch(op_result)
{
case LDAP_SUCCESS:
@@ -118,7 +119,8 @@ tombstone_to_glue_resolve_parent (
{
if(is_tombstone_entry(entries[0]))
{
- tombstone_to_glue (pb, sessionid, entries[0], parentdn, REASON_RESURRECT_ENTRY, opcsn);
+ tombstone_to_glue(pb, sessionid, entries[0], parentdn,
+ REASON_RESURRECT_ENTRY, opcsn, newparentdn);
}
}
else
@@ -146,14 +148,16 @@ tombstone_to_glue (
Slapi_PBlock *pb,
char *sessionid,
Slapi_Entry *tombstoneentry,
- const Slapi_DN *tombstonedn,
+ const Slapi_DN *gluedn, /* does not start with uniqueid= */
const char *reason,
- CSN *opcsn)
+ CSN *opcsn,
+ Slapi_DN **newparentdn)
{
Slapi_DN *parentdn;
char *parentuniqueid;
const char *tombstoneuniqueid;
- Slapi_Entry *addingentry;
+ Slapi_Entry *addingentry = NULL;
+ Slapi_Entry *addingentry_bakup = NULL;
const char *addingdn;
int op_result;
int rdn_is_conflict = 0;
@@ -164,23 +168,35 @@ tombstone_to_glue (
* must attach the entry to the Operation
*/
-
/* Resurrect the parent entry first */
/* JCM - This DN calculation is odd. It could resolve to NULL
* which won't help us identify the correct backend to search.
*/
- is_suffix_dn_ext (pb, tombstonedn, &parentdn, 1 /* is_tombstone */);
- parentuniqueid= slapi_entry_attr_get_charptr (tombstoneentry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
- tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn);
+ is_suffix_dn_ext (pb, gluedn, &parentdn, 1 /* is_tombstone */);
+ parentuniqueid = slapi_entry_attr_get_charptr (tombstoneentry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
+ tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn, newparentdn);
/* Submit an Add operation to turn the tombstone entry into glue. */
/*
* The tombstone is stored with an invalid DN, we must fix this.
*/
addingentry = slapi_entry_dup(tombstoneentry);
- addingdn = slapi_sdn_get_dn(tombstonedn);
- slapi_entry_set_sdn(addingentry, tombstonedn);
+
+ if (newparentdn && *newparentdn && slapi_sdn_compare(parentdn, *newparentdn)) {
+ /* If the parents are resolved, the tombstone's DN is going to be different... */
+ /* Update DN in addingentry */
+ Slapi_RDN *rdn = slapi_rdn_new();
+ slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(gluedn), SLAPI_RDN_SET_DN_INCLUDE_UNIQUEID);
+ addingdn = slapi_moddn_get_newdn(slapi_entry_get_sdn(addingentry), slapi_rdn_get_rdn(rdn),
+ slapi_sdn_get_dn(*newparentdn));
+ slapi_rdn_free(&rdn);
+ slapi_sdn_init_normdn_passin(*newparentdn, addingdn); /* to return the new parentdn to the caller */
+ } else {
+ slapi_sdn_free(newparentdn); /* no change in parentdn; returning NULL */
+ addingdn = slapi_sdn_get_dn(gluedn);
+ }
+ slapi_sdn_set_normdn_byval(slapi_entry_get_sdn(addingentry), addingdn);
/* not just e_sdn, e_rsdn needs to be updated. */
slapi_rdn_set_all_dn(slapi_entry_get_srdn(addingentry), slapi_entry_get_dn_const(addingentry));
rdn_is_conflict = slapi_rdn_is_conflict(slapi_entry_get_srdn(addingentry));
@@ -198,6 +214,7 @@ tombstone_to_glue (
* tombstoneentry from DB/entry cache is duplicated and turned to be a glue.
* This addingentry is freed in op_shared_add.
*/
+ addingentry_bakup = slapi_entry_dup(addingentry);
op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, slapi_ch_strdup(parentuniqueid), opcsn, OP_FLAG_RESURECT_ENTRY);
if ((LDAP_ALREADY_EXISTS == op_result) && !rdn_is_conflict) {
/* conflict -- there's already the same named entry added.
@@ -207,7 +224,8 @@ tombstone_to_glue (
* */
char *conflictrdn = get_rdn_plus_uniqueid(sessionid, addingdn, tombstoneuniqueid);
if (conflictrdn) {
- addingentry = slapi_entry_dup(tombstoneentry);
+ addingentry = addingentry_bakup;
+ addingentry_bakup = NULL;
if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason)) {
/* Add the reason of turning it to glue - The backend code will use it*/
slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
@@ -223,15 +241,16 @@ tombstone_to_glue (
addingentry = NULL;
}
}
+ slapi_entry_free(addingentry_bakup);
slapi_ch_free_string(&parentuniqueid);
if (op_result == LDAP_SUCCESS)
{
- slapi_log_error (slapi_log_urp, repl_plugin_name,
+ slapi_log_error (/*slapi_log_urp*/SLAPI_LOG_FATAL, repl_plugin_name,
"%s: Resurrected tombstone %s to glue reason '%s'\n", sessionid, addingdn, reason);
}
else if (LDAP_ALREADY_EXISTS == op_result)
{
- slapi_log_error(slapi_log_urp, repl_plugin_name,
+ slapi_log_error(/*slapi_log_urp*/SLAPI_LOG_FATAL, repl_plugin_name,
"%s: No need to turn tombstone %s to glue; it was already resurrected.\n",
sessionid, addingdn);
op_result = LDAP_SUCCESS;
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index 2a89358..4559951 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -737,9 +737,9 @@ static void op_shared_add (Slapi_PBlock *pb)
if (be->be_add != NULL)
{
- rc = (*be->be_add)(pb);
/* backend may change this if errors and not consumed */
slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e);
+ rc = (*be->be_add)(pb);
slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
if (rc == 0)
{
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index 0309fcf..0732415 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -47,6 +47,7 @@
#ifdef DEBUG
#define LDAP_CACHE_DEBUG
/* #define LDAP_CACHE_DEBUG_LRU * causes slowdown */
+/* #define CACHE_DEBUG * causes slowdown */
#endif
/* cache can't get any smaller than this (in bytes) */
@@ -1341,14 +1342,14 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state,
{
if (my_alt->ep_state & ENTRY_STATE_CREATING)
{
- LOG("the entry %s is reserved (ep_state: 0x%x, state: 0x%x\n", ndn, e->ep_state, state);
+ LOG("the entry %s is reserved (ep_state: 0x%x, state: 0x%x)\n", ndn, e->ep_state, state);
e->ep_state |= ENTRY_STATE_NOTINCACHE;
PR_Unlock(cache->c_mutex);
return -1;
}
else if (state != 0)
{
- LOG("the entry %s already exists. cannot reserve it. (ep_state: 0x%x, state: 0x%x\n",
+ LOG("the entry %s already exists. cannot reserve it. (ep_state: 0x%x, state: 0x%x)\n",
ndn, e->ep_state, state);
e->ep_state |= ENTRY_STATE_NOTINCACHE;
PR_Unlock(cache->c_mutex);
@@ -1519,20 +1520,20 @@ int cache_lock_entry(struct cache *cache, struct backentry *e)
LOG("=> cache_lock_entry (%s)\n", backentry_get_ndn(e), 0, 0);
if (! e->ep_mutexp) {
- /* make sure only one thread does this */
- PR_Lock(cache->c_emutexalloc_mutex);
- if (! e->ep_mutexp) {
- e->ep_mutexp = PR_NewMonitor();
- if (!e->ep_mutexp) {
- LOG("<= cache_lock_entry (DELETED)\n", 0, 0, 0);
- LDAPDebug1Arg(LDAP_DEBUG_ANY,
- "cache_lock_entry: failed to create a lock for %s\n",
- backentry_get_ndn(e));
- LOG("<= cache_lock_entry (FAILED)\n", 0, 0, 0);
- return 1;
- }
- }
- PR_Unlock(cache->c_emutexalloc_mutex);
+ /* make sure only one thread does this */
+ PR_Lock(cache->c_emutexalloc_mutex);
+ if (! e->ep_mutexp) {
+ e->ep_mutexp = PR_NewMonitor();
+ if (!e->ep_mutexp) {
+ LOG("<= cache_lock_entry (DELETED)\n", 0, 0, 0);
+ LDAPDebug1Arg(LDAP_DEBUG_ANY,
+ "cache_lock_entry: failed to create a lock for %s\n",
+ backentry_get_ndn(e));
+ LOG("<= cache_lock_entry (FAILED)\n", 0, 0, 0);
+ return 1;
+ }
+ }
+ PR_Unlock(cache->c_emutexalloc_mutex);
}
/* wait on entry lock (done w/o holding the cache lock) */
@@ -2018,3 +2019,61 @@ dn_lru_verify(struct cache *cache, struct backdn *dn, int in)
ASSERT(is_in == in);
}
#endif
+
+#ifdef CACHE_DEBUG
+void
+check_entry_cache(struct cache *cache, struct backentry *e, int in_cache)
+{
+ Slapi_DN *sdn = slapi_entry_get_sdn(e->ep_entry);
+ struct backentry *debug_e = cache_find_dn(cache,
+ slapi_sdn_get_dn(sdn),
+ slapi_sdn_get_ndn_len(sdn));
+ if (in_cache) {
+ if (debug_e) { /* e is in cache */
+ CACHE_RETURN(cache, &debug_e);
+ if ((e != debug_e) && !(e->ep_state & ENTRY_STATE_DELETED)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "entry 0x%p is not in dn cache but 0x%p having the same dn %s is "
+ "although in_cache flag is set!!!\n",
+ e, debug_e, slapi_sdn_get_dn(sdn));
+ }
+ } else if (!(e->ep_state & ENTRY_STATE_DELETED)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "%s (id %d) is not in dn cache although in_cache flag is set!!!\n",
+ slapi_sdn_get_dn(sdn), e->ep_id);
+ }
+ debug_e = cache_find_id(cache, e->ep_id);
+ if (debug_e) { /* e is in cache */
+ CACHE_RETURN(cache, &debug_e);
+ if ((e != debug_e) && !(e->ep_state & ENTRY_STATE_DELETED)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "entry 0x%p is not in id cache but 0x%p having the same id %d is "
+ "although in_cache flag is set!!!\n",
+ e, debug_e, e->ep_id);
+ }
+ } else {
+ slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
+ "%s (id %d) is not in id cache although in_cache flag is set!!!\n",
+ slapi_sdn_get_dn(sdn), e->ep_id);
+ }
+ } else {
+ if (debug_e) { /* e is in cache */
+ CACHE_RETURN(cache, &debug_e);
+ if (e == debug_e) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "%s (id %d) is in dn cache although in_cache flag is not set!!!\n",
+ slapi_sdn_get_dn(sdn), e->ep_id);
+ }
+ }
+ debug_e = cache_find_id(cache, e->ep_id);
+ if (debug_e) { /* e is in cache: bad */
+ CACHE_RETURN(cache, &debug_e);
+ if (e == debug_e) {
+ slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
+ "%s (id %d) is in id cache although in_cache flag is not set!!!\n",
+ slapi_sdn_get_dn(sdn), e->ep_id);
+ }
+ }
+ }
+}
+#endif
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index e68c138..2d26e40 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -119,7 +119,13 @@ ldbm_back_add( Slapi_PBlock *pb )
int not_an_error = 0;
int parent_switched = 0;
int noabort = 1;
-
+ int myrc = 0;
+ PRUint64 conn_id;
+ int op_id;
+ if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
+ conn_id = 0; /* connection is NULL */
+ }
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e );
slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
@@ -811,6 +817,9 @@ ldbm_back_add( Slapi_PBlock *pb )
retval = parent_update_on_childchange(&parent_modify_c,
is_resurect_operation?PARENTUPDATE_RESURECT:PARENTUPDATE_ADD,
NULL);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_add",
+ "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
/* The modify context now contains info needed later */
if (retval) {
LDAPDebug2Args(LDAP_DEBUG_BACKLDBM, "parent_update_on_childchange: %s, rc=%d\n",
@@ -970,6 +979,9 @@ ldbm_back_add( Slapi_PBlock *pb )
if (parent_found) {
/* Push out the db modifications from the parent entry */
retval = modify_update_all(be,pb,&parent_modify_c,&txn);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_add",
+ "conn=%lu op=%d modify_update_all: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
if (DB_LOCK_DEADLOCK == retval)
{
LDAPDebug( LDAP_DEBUG_ARGS, "add 6 DEADLOCK\n", 0, 0, 0 );
@@ -1098,8 +1110,13 @@ ldbm_back_add( Slapi_PBlock *pb )
if (parent_found)
{
/* switch the parent entry copy into play */
- modify_switch_entries(&parent_modify_c,be);
- parent_switched = 1;
+ myrc = modify_switch_entries(&parent_modify_c,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_add",
+ "conn=%lu op=%d modify_switch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
+ if (0 == myrc) {
+ parent_switched = 1;
+ }
}
if (ruv_c_init) {
@@ -1179,13 +1196,16 @@ error_return:
} else if (0 == rc) {
rc = SLAPI_FAIL_GENERAL;
}
- if (parent_switched){
+ if (parent_switched) {
/*
* Restore the old parent entry, switch the new with the original.
* Otherwise the numsubordinate count will be off, and could later
* be written to disk.
*/
- modify_unswitch_entries( &parent_modify_c,be);
+ myrc = modify_unswitch_entries(&parent_modify_c, be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_add",
+ "conn=%lu op=%d modify_unswitch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
}
diskfull_return:
if (disk_full) {
@@ -1282,7 +1302,10 @@ common_return:
if (ruv_c_init) {
modify_term(&ruv_c, be);
}
- modify_term(&parent_modify_c,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_add",
+ "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry);
+ myrc = modify_term(&parent_modify_c,be);
done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_DN_ENTRY);
done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_UNIQUEID_ENTRY);
done_with_pblock_entry(pb,SLAPI_ADD_PARENT_ENTRY);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 2a1730f..13a78fa 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -99,6 +99,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
int opreturn = 0;
int free_delete_existing_entry = 0;
int not_an_error = 0;
+ int parent_switched = 0;
+ int myrc = 0;
+ PRUint64 conn_id;
+ int op_id;
+ if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
+ conn_id = 0; /* connection is NULL */
+ }
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
slapi_pblock_get( pb, SLAPI_BACKEND, &be);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -292,8 +300,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
retval = slapi_entry_has_children(e->ep_entry);
if (retval) {
ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
- slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete", "Deleting entry %s has %d children.\n",
- slapi_entry_get_dn(e->ep_entry), retval);
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "conn=%lu op=%d Deleting entry %s has %d children.\n",
+ conn_id, op_id, slapi_entry_get_dn(e->ep_entry), retval);
retval = -1;
goto error_return;
}
@@ -539,6 +548,10 @@ ldbm_back_delete( Slapi_PBlock *pb )
op |= PARENTUPDATE_DELETE_TOMBSTONE;
}
retval = parent_update_on_childchange(&parent_modify_c, op, &haschildren);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+ "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
+
/* The modify context now contains info needed later */
if (0 != retval) {
ldap_result_code= LDAP_OPERATIONS_ERROR;
@@ -575,9 +588,11 @@ ldbm_back_delete( Slapi_PBlock *pb )
char *edn = slapi_entry_get_dn(e->ep_entry);
char *tombstone_dn;
Slapi_Value *tomb_value;
-
+
if (slapi_is_special_rdn(edn, RDN_IS_TOMBSTONE)) {
- LDAPDebug1Arg(LDAP_DEBUG_ANY, "Turning a tombstone into a tombstone! \"%s\"\n", edn);
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "conn=%lu op=%d Turning a tombstone into a tombstone! \"%s\"; e: 0x%p, cache_state: 0x%x, refcnt: %d\n",
+ conn_id, op_id, edn, e, e->ep_state, e->ep_refcnt);
ldap_result_code= LDAP_OPERATIONS_ERROR;
retval = -1;
goto error_return;
@@ -708,9 +723,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
if (0 == retval) {
tombstone_in_cache = 1;
} else {
- LDAPDebug2Args(LDAP_DEBUG_ANY,
- "tombstone entry %s failed to add to the cache: %d\n",
- slapi_entry_get_dn(tombstone->ep_entry), retval);
+ slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_delete",
+ "conn=%lu op=%d tombstone entry %s failed to add to the cache: %d\n",
+ conn_id, op_id, slapi_entry_get_dn(tombstone->ep_entry), retval);
tombstone_in_cache = 0;
if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
DEL_SET_ERROR(ldap_result_code,
@@ -1059,6 +1074,9 @@ ldbm_back_delete( Slapi_PBlock *pb )
if (parent_found) {
/* Push out the db modifications from the parent entry */
retval = modify_update_all(be,pb,&parent_modify_c,&txn);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+ "conn=%lu op=%d modify_update_all: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, retval);
if (DB_LOCK_DEADLOCK == retval)
{
LDAPDebug( LDAP_DEBUG_BACKLDBM, "del 4 DEADLOCK\n", 0, 0, 0 );
@@ -1218,7 +1236,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
if (parent_found)
{
/* Replace the old parent entry with the newly modified one */
- modify_switch_entries( &parent_modify_c,be);
+ myrc = modify_switch_entries( &parent_modify_c,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+ "conn=%lu op=%d modify_switch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
+ if (myrc == 0) {
+ parent_switched = 1;
+ }
}
rc= 0;
@@ -1233,6 +1257,9 @@ error_return:
CACHE_RETURN(&inst->inst_dncache, &bdn);
}
}
+#ifdef CACHE_DEBUG
+ check_entry_cache(&inst->inst_cache, tombstone, tombstone_in_cache);
+#endif
if (tombstone_in_cache) { /* successfully replaced */
CACHE_REMOVE( &inst->inst_cache, tombstone );
CACHE_RETURN( &inst->inst_cache, &tombstone );
@@ -1245,6 +1272,9 @@ error_return:
/* Need to return to cache after post op plugins are called */
if (e) {
+#ifdef CACHE_DEBUG
+ check_entry_cache(&inst->inst_cache, e, e_in_cache);
+#endif
if (e_in_cache) {
if (remove_e_from_cache) {
/* The entry is already transformed to a tombstone. */
@@ -1308,7 +1338,17 @@ error_return:
/* txn is no longer valid - reset the txn pointer to the parent */
slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
}
-
+ if (parent_switched) {
+ /*
+ * Restore the old parent entry, switch the new with the original.
+ * Otherwise the numsubordinate count will be off, and could later
+ * be written to disk.
+ */
+ myrc = modify_unswitch_entries(&parent_modify_c, be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+ "conn=%lu op=%d modify_unswitch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
+ }
common_return:
if (orig_entry) {
/* NOTE: #define SLAPI_DELETE_BEPREOP_ENTRY SLAPI_ENTRY_PRE_OP */
@@ -1336,6 +1376,9 @@ common_return:
}
}
}
+#ifdef CACHE_DEBUG
+ check_entry_cache(&inst->inst_cache, tombstone, tombstone_in_cache);
+#endif
if (tombstone_in_cache) { /* successfully replaced */
CACHE_RETURN( &inst->inst_cache, &tombstone );
tombstone = NULL;
@@ -1385,7 +1428,10 @@ diskfull_return:
}
slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
}
- modify_term(&parent_modify_c, be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_delete",
+ "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p, in_cache=%d\n",
+ conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, parent_modify_c.new_entry_in_cache);
+ myrc = modify_term(&parent_modify_c, be);
if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry)
{
/* URP Naming Collision
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 7d424fb..da6a127 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -140,7 +140,7 @@ modify_unswitch_entries(modify_context *mc,backend *be)
ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
int ret = 0;
- if (mc->old_entry!=NULL && mc->new_entry!=NULL) {
+ if (mc->old_entry && mc->new_entry && mc->new_entry_in_cache) {
/* switch the entries, and reset the new, new, entry */
tmp_be = mc->new_entry;
mc->new_entry = mc->old_entry;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 4bb4227..65880f9 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -123,6 +123,13 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
int opreturn = 0;
int free_modrdn_existing_entry = 0;
int not_an_error = 0;
+ int myrc = 0;
+ PRUint64 conn_id;
+ int op_id;
+ if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
+ conn_id = 0; /* connection is NULL */
+ }
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
/* sdn & parentsdn need to be initialized before "goto *_return" */
slapi_sdn_init(&dn_newdn);
@@ -263,6 +270,9 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
slapi_sdn_free(&dn_newsuperiordn);
slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, orig_dn_newsuperiordn);
orig_dn_newsuperiordn = slapi_sdn_dup(orig_dn_newsuperiordn);
+#ifdef CACHE_DEBUG
+ check_entry_cache(&inst->inst_cache, ec, ec_in_cache);
+#endif
if (ec_in_cache) {
/* New entry 'ec' is in the entry cache.
* Remove it from the cache . */
@@ -747,7 +757,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
ldap_result_code= LDAP_ALREADY_EXISTS;
if (is_resurect_operation) {
slapi_log_error(SLAPI_LOG_CACHE, "ldbm_back_modrdn",
- "cache_add_tentative failed: %s\n", slapi_entry_get_dn(ec->ep_entry));
+ "conn=%lu op=%d cache_add_tentative failed: %s\n",
+ conn_id, op_id, slapi_entry_get_dn(ec->ep_entry));
}
goto error_return;
}
@@ -890,6 +901,10 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
if (parententry) {
retval = parent_update_on_childchange(&parent_modify_context,
PARENTUPDATE_DEL, NULL);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry, retval);
+
/* The parent modify context now contains info needed later */
if (retval) {
goto error_return;
@@ -898,6 +913,9 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
if (newparententry) {
retval = parent_update_on_childchange(&newparent_modify_context,
PARENTUPDATE_ADD, NULL);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d parent_update_on_childchange: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry, retval);
/* The newparent modify context now contains info needed later */
if (retval) {
goto error_return;
@@ -908,9 +926,11 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
if (is_resurect_operation && parententry) {
retval = parent_update_on_childchange(&parent_modify_context, PARENTUPDATE_RESURECT, NULL);
if (retval) {
- LDAPDebug(LDAP_DEBUG_BACKLDBM, "parent_update_on_childchange parent %s of %s failed, rc=%d\n",
- slapi_entry_get_dn_const(parent_modify_context.old_entry->ep_entry),
- slapi_entry_get_dn_const(ec->ep_entry), retval);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d parent_update_on_childchange parent %s of %s failed, rc=%d\n",
+ conn_id, op_id,
+ slapi_entry_get_dn_const(parent_modify_context.old_entry->ep_entry),
+ slapi_entry_get_dn_const(ec->ep_entry), retval);
goto error_return;
}
}
@@ -1096,6 +1116,9 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
else /* retval == 0 */
{
retval = modify_update_all(be, pb, &newparent_modify_context, &txn);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d modify_update_all: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry, retval);
if (DB_LOCK_DEADLOCK == retval)
{
/* Retry txn */
@@ -1223,7 +1246,10 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
}
if(newparententry!=NULL)
{
- modify_switch_entries( &newparent_modify_context,be);
+ myrc = modify_switch_entries( &newparent_modify_context,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d modify_switch_entries: old_entry=0x%p, new_entry=0x%p, rc=%d\n",
+ conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry, myrc);
}
slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
@@ -1446,6 +1472,9 @@ common_return:
}
/* remove the new entry from the cache if the op failed -
otherwise, leave it in */
+#ifdef CACHE_DEBUG
+ check_entry_cache(&inst->inst_cache, ec, ec_in_cache);
+#endif
if (ec_in_cache && ec && inst) {
if (retval) {
CACHE_REMOVE( &inst->inst_cache, ec );
@@ -1496,8 +1525,16 @@ common_return:
slapi_sdn_done(&dn_newdn);
slapi_sdn_done(&dn_newrdn);
slapi_sdn_done(&dn_parentdn);
- modify_term(&parent_modify_context,be);
- modify_term(&newparent_modify_context,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p\n",
+ conn_id, op_id, parent_modify_context.old_entry, parent_modify_context.new_entry);
+ myrc = modify_term(&parent_modify_context,be);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d modify_term: rc=%d\n", conn_id, op_id, myrc);
+ slapi_log_error(SLAPI_LOG_BACKLDBM, "ldbm_back_modrdn",
+ "conn=%lu op=%d modify_term: old_entry=0x%p, new_entry=0x%p\n",
+ conn_id, op_id, newparent_modify_context.old_entry, newparent_modify_context.new_entry);
+ myrc = modify_term(&newparent_modify_context,be);
if (free_modrdn_existing_entry) {
done_with_pblock_entry(pb,SLAPI_MODRDN_EXISTING_ENTRY);
} else { /* owned by original_entry */
@@ -1906,6 +1943,7 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm
retval= -1;
goto error_return;
}
+ *e_in_cache = 0;
if (orig_ec_in_cache) {
/* ec was already added to the cache via cache_add_tentative (to reserve its spot in the cache)
and/or id2entry_add - so it already had one refcount - cache_replace adds another refcount -
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 732568d..180ad4c 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -87,6 +87,9 @@ int cache_add_tentative(struct cache *cache, struct backentry *e,
int cache_lock_entry(struct cache *cache, struct backentry *e);
void cache_unlock_entry(struct cache *cache, struct backentry *e);
int cache_replace(struct cache *cache, void *oldptr, void *newptr);
+#ifdef CACHE_DEBUG
+void check_entry_cache(struct cache *cache, struct backentry *e, int in_cache);
+#endif
Hashtable *new_hash(u_long size, u_long offset, HashFn hfn,
HashTestFn tfn);
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 2f1ae92..b197243 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -2431,6 +2431,12 @@ slapi_sdn_get_rdn(const Slapi_DN *sdn,Slapi_RDN *rdn)
slapi_rdn_set_dn(rdn, slapi_sdn_get_dn(sdn));
}
+void
+slapi_sdn_get_rdn_ext(const Slapi_DN *sdn, Slapi_RDN *rdn, int is_tombstone)
+{
+ slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(sdn), is_tombstone);
+}
+
Slapi_DN *
slapi_sdn_dup(const Slapi_DN *sdn)
{
diff --git a/ldap/servers/slapd/rdn.c b/ldap/servers/slapd/rdn.c
index 6e40ed8..d56c143 100644
--- a/ldap/servers/slapd/rdn.c
+++ b/ldap/servers/slapd/rdn.c
@@ -324,15 +324,29 @@ slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn)
rdn->rdn= slapi_ch_strdup(fromrdn->rdn);
}
+/*
+ * flags:
+ * SLAPI_RDN_SET_DN_SKIP_UNIQUEID -- strip uniqueid, and set to rdn
+ * SLAPI_RDN_SET_DN_INCLUDE_UNIQUEID -- set <uniqueid,rdn> to rdn
+ */
void
-slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int skip_tombstone)
+slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int flags)
{
const char *mydn = dn;
slapi_rdn_done(rdn);
- if (skip_tombstone && slapi_is_special_rdn(dn, RDN_IS_TOMBSTONE)) {
- mydn = dn + slapi_uniqueIDRdnSize() + 1/*,*/;
+ if (flags && slapi_is_special_rdn(dn, RDN_IS_TOMBSTONE)) {
+ if (SLAPI_RDN_SET_DN_SKIP_UNIQUEID == flags) {
+ mydn = dn + slapi_uniqueIDRdnSize() + 1/*,*/;
+ slapi_rdn_init_dn(rdn, mydn);
+ } else if (SLAPI_RDN_SET_DN_INCLUDE_UNIQUEID == flags) {
+ Slapi_DN sdn = {0};
+ slapi_sdn_set_dn_byval(&sdn, dn);
+ _slapi_rdn_init_all_dn_ext(rdn, (const Slapi_DN *)&sdn, 1);
+ slapi_sdn_done(&sdn);
+ }
+ } else {
+ slapi_rdn_init_dn(rdn, mydn);
}
- slapi_rdn_init_dn(rdn, mydn);
}
void
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index bf10e45..a93feda 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -3044,7 +3044,9 @@ void slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn);
* \see slapi_rdn_set_rdn()
*/
void slapi_rdn_set_dn(Slapi_RDN *rdn,const char *dn);
-void slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int skip_tombstone);
+#define SLAPI_RDN_SET_DN_SKIP_UNIQUEID 1
+#define SLAPI_RDN_SET_DN_INCLUDE_UNIQUEID 2
+void slapi_rdn_set_dn_ext(Slapi_RDN *rdn,const char *dn, int flags);
Slapi_RDN *slapi_rdn_new_all_dn(const char *dn);
int slapi_rdn_init_all_dn(Slapi_RDN *rdn, const char *dn);
int slapi_rdn_init_all_sdn(Slapi_RDN *rdn, const Slapi_DN *sdn);
9 years, 6 months