Skip to content
Commits on Source (18)
......@@ -952,6 +952,8 @@ update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
ldap/admin/src/scripts/50refintprecedence.ldif \
ldap/admin/src/scripts/50retroclprecedence.ldif \
ldap/admin/src/scripts/50rootdnaccesscontrolplugin.ldif \
ldap/admin/src/scripts/50pbkdf2pwdstorageplugin.ldif \
ldap/admin/src/scripts/50cryptpwdstorageplugin.ldif \
ldap/admin/src/scripts/50contentsync.ldif \
ldap/admin/src/scripts/60upgradeschemafiles.pl \
ldap/admin/src/scripts/60upgradeconfigfiles.pl \
......
......@@ -10,7 +10,7 @@ vendor="389 Project"
# PACKAGE_VERSION is constructed from these
VERSION_MAJOR=1
VERSION_MINOR=3
VERSION_MAINT=7.10
VERSION_MAINT=8.2
# NOTE: VERSION_PREREL is automatically set for builds made out of a git tree
VERSION_PREREL=
VERSION_DATE=$(date -u +%Y%m%d)
......
import logging
import pytest
import os
import ldap
import time
from lib389._constants import *
from lib389.topologies import topology_st as topo
from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
from lib389.idm.domain import Domain
DEBUGGING = os.getenv("DEBUGGING", default=False)
if DEBUGGING:
logging.getLogger(__name__).setLevel(logging.DEBUG)
else:
logging.getLogger(__name__).setLevel(logging.INFO)
log = logging.getLogger(__name__)
BIND_DN2 = 'uid=tuser,ou=People,dc=example,dc=com'
BIND_RDN2 = 'tuser'
BIND_DN = 'uid=tuser1,ou=People,dc=example,dc=com'
BIND_RDN = 'tuser1'
SRCH_FILTER = "uid=tuser1"
SRCH_FILTER2 = "uid=tuser"
aci_list_A = ['(targetattr != "userPassword") (version 3.0; acl "Anonymous access"; allow (read, search, compare)userdn = "ldap:///anyone";)',
'(targetattr = "*") (version 3.0;acl "allow tuser";allow (all)(userdn = "ldap:///uid=tuser5,ou=People,dc=example,dc=com");)',
'(targetattr != "uid || mail") (version 3.0; acl "deny-attrs"; deny (all) (userdn = "ldap:///anyone");)',
'(targetfilter = "(inetUserStatus=1)") ( version 3.0; acl "deny-specific-entry"; deny(all) (userdn = "ldap:///anyone");)']
aci_list_B = ['(targetattr != "userPassword") (version 3.0; acl "Anonymous access"; allow (read, search, compare)userdn = "ldap:///anyone";)',
'(targetattr != "uid || mail") (version 3.0; acl "deny-attrs"; deny (all) (userdn = "ldap:///anyone");)',
'(targetfilter = "(inetUserStatus=1)") ( version 3.0; acl "deny-specific-entry"; deny(all) (userdn = "ldap:///anyone");)']
@pytest.fixture(scope="module")
def aci_setup(topo):
topo.standalone.log.info("Add {}".format(BIND_DN))
user = UserAccount(topo.standalone, BIND_DN)
user_props = TEST_USER_PROPERTIES.copy()
user_props.update({'sn': BIND_RDN,
'cn': BIND_RDN,
'uid': BIND_RDN,
'inetUserStatus': '1',
'objectclass': 'extensibleObject',
'userpassword': PASSWORD})
user.create(properties=user_props, basedn=SUFFIX)
topo.standalone.log.info("Add {}".format(BIND_DN2))
user2 = UserAccount(topo.standalone, BIND_DN2)
user_props = TEST_USER_PROPERTIES.copy()
user_props.update({'sn': BIND_RDN2,
'cn': BIND_RDN2,
'uid': BIND_RDN2,
'userpassword': PASSWORD})
user2.create(properties=user_props, basedn=SUFFIX)
def test_multi_deny_aci(topo, aci_setup):
"""Test that mutliple deny rules work, and that they the cache properly
stores the result
:id: 294c366d-850e-459e-b5a0-3cc828ec3aca
:setup: Standalone Instance
:steps:
1. Add aci_list_A aci's and verify two searches on the same connection
behave the same
2. Add aci_list_B aci's and verify search fails as expected
:expectedresults:
1. Both searches do not return any entries
2. Seaches do not return any entries
"""
if DEBUGGING:
# Maybe add aci logging?
pass
suffix = Domain(topo.standalone, DEFAULT_SUFFIX)
for run in range(2):
topo.standalone.log.info("Pass " + str(run + 1))
# Test ACI List A
topo.standalone.log.info("Testing two searches behave the same...")
topo.standalone.simple_bind_s(DN_DM, PASSWORD)
suffix.set('aci', aci_list_A, ldap.MOD_REPLACE)
time.sleep(1)
topo.standalone.simple_bind_s(BIND_DN, PASSWORD)
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 1")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 2")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user")
assert False
# Bind a different user who has rights
topo.standalone.simple_bind_s(BIND_DN2, PASSWORD)
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user (2)")
assert False
if run > 0:
# Second pass
topo.standalone.restart()
# Reset ACI's and do the second test
topo.standalone.log.info("Testing search does not return any entries...")
topo.standalone.simple_bind_s(DN_DM, PASSWORD)
suffix.set('aci', aci_list_B, ldap.MOD_REPLACE)
time.sleep(1)
topo.standalone.simple_bind_s(BIND_DN, PASSWORD)
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 1")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 2")
assert False
if run > 0:
# Second pass
topo.standalone.restart()
# Bind as different user who has rights
topo.standalone.simple_bind_s(BIND_DN2, PASSWORD)
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as good user (2)")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 1")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 2")
assert False
# back to user 1
topo.standalone.simple_bind_s(BIND_DN, PASSWORD)
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as user1")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER2)
if entries is None or len(entries) == 0:
topo.standalone.log.fatal("Failed to get entry as user1 (2)")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 1")
assert False
entries = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, SRCH_FILTER)
if entries and entries[0]:
topo.standalone.log.fatal("Incorrectly got an entry returned from search 2")
assert False
topo.standalone.log.info("Test PASSED")
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main(["-s", CURRENT_FILE])
# --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2018 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
#
import logging
import pytest
import os
import ldap
from lib389._constants import *
from lib389.replica import ReplicationManager
from lib389.plugins import MemberOfPlugin
from lib389.agreement import Agreements
from lib389.idm.user import UserAccount, TEST_USER_PROPERTIES
from lib389.idm.group import Groups
from lib389.topologies import topology_m1h1c1 as topo
DEBUGGING = os.getenv("DEBUGGING", default=False)
if DEBUGGING:
logging.getLogger(__name__).setLevel(logging.DEBUG)
else:
logging.getLogger(__name__).setLevel(logging.INFO)
log = logging.getLogger(__name__)
BIND_DN = 'uid=tuser1,ou=People,dc=example,dc=com'
BIND_RDN = 'tuser1'
def config_memberof(server):
"""Configure memberOf plugin and configure fractional
to prevent total init to send memberof
"""
memberof = MemberOfPlugin(server)
memberof.enable()
memberof.set_autoaddoc('nsMemberOf')
server.restart()
agmts = Agreements(server)
for agmt in agmts.list():
log.info('update %s to add nsDS5ReplicatedAttributeListTotal' % agmt.dn)
agmt.replace_many(('nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE '),
('nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE memberOf'))
def test_basic_with_hub(topo):
"""Check that basic operations work in cascading replication, this includes
testing plugins that perform internal operatons, and replicated password
policy state attributes.
:id: 4ac85552-45bc-477b-89a4-226dfff8c6cc
:setup: 1 master, 1 hub, 1 consumer
:steps:
1. Enable memberOf plugin and set password account lockout settings
2. Restart the instance
3. Add a user
4. Add a group
5. Test that the replication works
6. Add the user as a member to the group
7. Test that the replication works
8. Issue bad binds to update passwordRetryCount
9. Test that replicaton works
10. Check that passwordRetyCount was replicated
:expectedresults:
1. Should be a success
2. Should be a success
3. Should be a success
4. Should be a success
5. Should be a success
6. Should be a success
7. Should be a success
8. Should be a success
9. Should be a success
10. Should be a success
"""
repl_manager = ReplicationManager(DEFAULT_SUFFIX)
master = topo.ms["master1"]
consumer = topo.cs["consumer1"]
hub = topo.hs["hub1"]
for inst in topo:
config_memberof(inst)
inst.config.set('passwordlockout', 'on')
inst.config.set('passwordlockoutduration', '60')
inst.config.set('passwordmaxfailure', '3')
inst.config.set('passwordIsGlobalPolicy', 'on')
# Create user
user1 = UserAccount(master, BIND_DN)
user_props = TEST_USER_PROPERTIES.copy()
user_props.update({'sn': BIND_RDN,
'cn': BIND_RDN,
'uid': BIND_RDN,
'inetUserStatus': '1',
'objectclass': 'extensibleObject',
'userpassword': PASSWORD})
user1.create(properties=user_props, basedn=SUFFIX)
# Create group
groups = Groups(master, DEFAULT_SUFFIX)
group = groups.create(properties={'cn': 'group'})
# Test replication
repl_manager.test_replication(master, consumer)
# Trigger memberOf plugin by adding user to group
group.replace('member', user1.dn)
# Test replication once more
repl_manager.test_replication(master, consumer)
# Issue bad password to update passwordRetryCount
try:
master.simple_bind_s(user1.dn, "badpassword")
except:
pass
# Test replication one last time
master.simple_bind_s(DN_DM, PASSWORD)
repl_manager.test_replication(master, consumer)
# Finally check if passwordRetyCount was replicated to the hub and consumer
user1 = UserAccount(hub, BIND_DN)
count = user1.get_attr_val_int('passwordRetryCount')
if count is None:
log.fatal('PasswordRetyCount was not replicated to hub')
assert False
if int(count) != 1:
log.fatal('PasswordRetyCount has unexpected value: {}'.format(count))
assert False
user1 = UserAccount(consumer, BIND_DN)
count = user1.get_attr_val_int('passwordRetryCount')
if count is None:
log.fatal('PasswordRetyCount was not replicated to consumer')
assert False
if int(count) != 1:
log.fatal('PasswordRetyCount has unexpected value: {}'.format(count))
assert False
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main(["-s", CURRENT_FILE])
dn: cn=CRYPT-MD5,cn=Password Storage Schemes,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
cn: CRYPT-MD5
nsslapd-pluginPath: libpwdstorage-plugin
nsslapd-pluginInitfunc: crypt_md5_pwd_storage_scheme_init
nsslapd-pluginType: pwdstoragescheme
nsslapd-pluginEnabled: on
nsslapd-pluginId: ID
nsslapd-pluginVersion: PACKAGE_VERSION
nsslapd-pluginVendor: VENDOR
nsslapd-pluginDescription: DESC
dn: cn=CRYPT-SHA256,cn=Password Storage Schemes,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
cn: CRYPT-SHA256
nsslapd-pluginPath: libpwdstorage-plugin
nsslapd-pluginInitfunc: crypt_sha256_pwd_storage_scheme_init
nsslapd-pluginType: pwdstoragescheme
nsslapd-pluginEnabled: on
nsslapd-pluginId: ID
nsslapd-pluginVersion: PACKAGE_VERSION
nsslapd-pluginVendor: VENDOR
nsslapd-pluginDescription: DESC
dn: cn=CRYPT-SHA512,cn=Password Storage Schemes,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
cn: CRYPT-SHA512
nsslapd-pluginPath: libpwdstorage-plugin
nsslapd-pluginInitfunc: crypt_sha512_pwd_storage_scheme_init
nsslapd-pluginType: pwdstoragescheme
nsslapd-pluginEnabled: on
nsslapd-pluginId: ID
nsslapd-pluginVersion: PACKAGE_VERSION
nsslapd-pluginVendor: VENDOR
nsslapd-pluginDescription: DESC
dn: cn=PBKDF2_SHA256,cn=Password Storage Schemes,cn=plugins,cn=config
objectclass: top
objectclass: nsSlapdPlugin
cn: PBKDF2_SHA256
nsslapd-pluginpath: libpwdstorage-plugin
nsslapd-plugininitfunc: pbkdf2_sha256_pwd_storage_scheme_init
nsslapd-plugintype: pwdstoragescheme
nsslapd-pluginenabled: on
nsslapd-pluginDescription: DESC
nsslapd-pluginVersion: PACKAGE_VERSION
nsslapd-pluginVendor: VENDOR
nsslapd-pluginid: ID
......@@ -1088,9 +1088,23 @@ acl_read_access_allowed_on_entry(
** a DENY rule, then we don't have access to
** the entry ( nice trick to get in )
*/
if (aclpb->aclpb_state &
ACLPB_EXECUTING_DENY_HANDLES)
if (aclpb->aclpb_state & ACLPB_EXECUTING_DENY_HANDLES) {
aclEvalContext *c_ContextEval = &aclpb->aclpb_curr_entryEval_context;
AclAttrEval *c_attrEval = NULL;
/*
* The entire entry is blocked, but previously evaluated allow aci's might
* show some of the attributes as readable in the acl cache, so reset all
* the cached attributes' status to FAIL.
*/
for (size_t j = 0; j < c_ContextEval->acle_numof_attrs; j++) {
c_attrEval = &c_ContextEval->acle_attrEval[j];
c_attrEval->attrEval_r_status &= ~ACL_ATTREVAL_SUCCESS;
c_attrEval->attrEval_r_status |= ACL_ATTREVAL_FAIL;
c_attrEval->attrEval_s_status &= ~ACL_ATTREVAL_SUCCESS;
c_attrEval->attrEval_s_status |= ACL_ATTREVAL_FAIL;
}
return LDAP_INSUFFICIENT_ACCESS;
}
/* The other case is I don't have an
** explicit allow rule -- which is fine.
......@@ -2908,6 +2922,12 @@ acl__TestRights(Acl_PBlock *aclpb, int access, const char **right, const char **
result_reason->deciding_aci = NULL;
result_reason->reason = ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS;
/* If we have deny handles we should process them */
if (aclpb->aclpb_num_deny_handles > 0) {
aclpb->aclpb_state &= ~ACLPB_EXECUTING_ALLOW_HANDLES;
aclpb->aclpb_state |= ACLPB_EXECUTING_DENY_HANDLES;
}
TNF_PROBE_1_DEBUG(acl__TestRights_end, "ACL", "",
tnf_string, no_allows, "");
......
......@@ -20,19 +20,9 @@
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#if defined(hpux) || defined(LINUX) || defined(__FreeBSD__)
#ifndef __USE_XOPEN
#define __USE_XOPEN /* linux */
#endif /* __USE_XOPEN */
#include <unistd.h>
#else /* hpux */
#include <crypt.h>
#endif /* hpux */
#include <crypt.h> /* for crypt_r */
#include "pwdstorage.h"
static PRLock *cryptlock = NULL; /* Some implementations of crypt are not thread safe. ie. ours & Irix */
/* characters used in crypt encoding */
static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
......@@ -43,39 +33,21 @@ static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
#define CRYPT_SHA512 3
int
crypt_start(Slapi_PBlock *pb __attribute__((unused)))
{
if (!cryptlock) {
cryptlock = PR_NewLock();
}
return 0;
}
int
crypt_close(Slapi_PBlock *pb __attribute__((unused)))
{
if (cryptlock) {
PR_DestroyLock(cryptlock);
cryptlock = NULL;
}
return 0;
}
int
crypt_pw_cmp(const char *userpwd, const char *dbpwd)
{
int rc;
char *cp;
PR_Lock(cryptlock);
/* we use salt (first 2 chars) of encoded password in call to crypt() */
cp = crypt(userpwd, dbpwd);
struct crypt_data data;
data.initialized = 0;
/* we use salt (first 2 chars) of encoded password in call to crypt_r() */
cp = crypt_r(userpwd, dbpwd, &data);
if (cp) {
rc = slapi_ct_memcmp(dbpwd, cp, strlen(dbpwd));
} else {
rc = -1;
}
PR_Unlock(cryptlock);
return rc;
}
......@@ -88,6 +60,8 @@ crypt_pw_enc_by_hash(const char *pwd, int hash_algo)
char *enc = NULL;
long v;
static unsigned int seed = 0;
struct crypt_data data;
data.initialized = 0;
if (seed == 0) {
seed = (unsigned int)slapi_rand();
......@@ -113,12 +87,10 @@ crypt_pw_enc_by_hash(const char *pwd, int hash_algo)
algo_salt = strdup(salt);
}
PR_Lock(cryptlock);
cry = crypt(pwd, algo_salt);
cry = crypt_r(pwd, algo_salt, &data);
if (cry != NULL) {
enc = slapi_ch_smprintf("%c%s%c%s", PWD_HASH_PREFIX_START, CRYPT_SCHEME_NAME, PWD_HASH_PREFIX_END, cry);
}
PR_Unlock(cryptlock);
slapi_ch_free_string(&algo_salt);
return (enc);
......
......@@ -245,8 +245,6 @@ crypt_pwd_storage_scheme_init(Slapi_PBlock *pb)
(void *)SLAPI_PLUGIN_VERSION_01);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&crypt_pdesc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)&crypt_start);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)&crypt_close);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
(void *)crypt_pw_enc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
......@@ -269,8 +267,6 @@ crypt_md5_pwd_storage_scheme_init(Slapi_PBlock *pb)
(void *)SLAPI_PLUGIN_VERSION_01);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&crypt_md5_pdesc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)&crypt_start);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)&crypt_close);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
(void *)crypt_pw_md5_enc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
......@@ -293,8 +289,6 @@ crypt_sha256_pwd_storage_scheme_init(Slapi_PBlock *pb)
(void *)SLAPI_PLUGIN_VERSION_01);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&crypt_sha256_pdesc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)&crypt_start);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)&crypt_close);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
(void *)crypt_pw_sha256_enc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
......@@ -317,8 +311,6 @@ crypt_sha512_pwd_storage_scheme_init(Slapi_PBlock *pb)
(void *)SLAPI_PLUGIN_VERSION_01);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
(void *)&crypt_sha512_pdesc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)&crypt_start);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)&crypt_close);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
(void *)crypt_pw_sha512_enc);
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
......
......@@ -74,8 +74,6 @@ char *sha512_pw_enc(const char *pwd);
char *salted_sha512_pw_enc(const char *pwd);
int clear_pw_cmp(const char *userpwd, const char *dbpwd);
char *clear_pw_enc(const char *pwd);
int crypt_start(Slapi_PBlock *pb);
int crypt_close(Slapi_PBlock *pb);
int crypt_pw_cmp(const char *userpwd, const char *dbpwd);
char *crypt_pw_enc(const char *pwd);
char *crypt_pw_md5_enc(const char *pwd);
......
......@@ -2523,7 +2523,7 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
replmsg = NULL;
}
}
PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s%s%s",
PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) %s%sLDAP error: %s%s%s%s%s",
ldaprc, message ? message : "", message ? "" : " - ",
slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "",
connrc ? " - " : "", connrc ? connmsg : "");
......@@ -2531,7 +2531,7 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
/* ldaprc == LDAP_SUCCESS */
else if (replrc != 0) {
if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED) {
PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s",
PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) %s",
ldaprc, "Replication session successful");
} else if (replrc == NSDS50_REPL_DISABLED) {
if (agmt_is_enabled(ra)) {
......@@ -2539,7 +2539,7 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
"Replication agreement for \"%s\" can not be updated while the suffix is disabled.\n"
"You must enable it then restart the server for replication to take place).\n",
ra->long_name ? ra->long_name : "a replica");
PR_snprintf(ra->last_init_status, STATUS_LEN, "%d Total update aborted: "
PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) Total update aborted: "
"Replication agreement for \"%s\" can not be updated while the suffix is disabled.\n"
"You must enable it then restart the server for replication to take place).",
replrc, ra->long_name ? ra->long_name : "a replica");
......@@ -2548,29 +2548,29 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Total update aborted: "
"Replication agreement for \"%s\" can not be updated while the agreement is disabled\n",
ra->long_name ? ra->long_name : "a replica");
PR_snprintf(ra->last_init_status, STATUS_LEN, "%d Total update aborted: "
PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) Total update aborted: "
"Replication agreement for \"%s\" can not be updated while the agreement is disabled.",
replrc, ra->long_name ? ra->long_name : "a replica");
}
} else {
PR_snprintf(ra->last_init_status, STATUS_LEN,
"%d Replication error acquiring replica: %s%s%s%s%s",
"Error (%d) Replication error acquiring replica: %s%s%s%s%s",
replrc, protocol_response2string(replrc),
message ? " - " : "", message ? message : "",
connrc ? " - " : "", connrc ? connmsg : "");
}
} else if (connrc != CONN_OPERATION_SUCCESS) {
PR_snprintf(ra->last_init_status, STATUS_LEN,
"%d connection error: %s%s%s",
"Error (%d) connection error: %s%s%s",
connrc, connmsg,
message ? " - " : "", message ? message : "");
} else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
{
PR_snprintf(ra->last_init_status, STATUS_LEN,
"%d %s",
"Error (%d) %s",
ldaprc, message);
} else { /* agmt_set_last_init_status(0,0,NULL) to reset agmt */
PR_snprintf(ra->last_init_status, STATUS_LEN, "%d", ldaprc);
PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d)", ldaprc);
}
}
}
......
......@@ -1059,6 +1059,16 @@ write_changelog_and_ruv(Slapi_PBlock *pb)
goto common_return;
}
/* Skip internal operations with no op csn if this is a read-only replica */
if (op_params->csn == NULL &&
operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
replica_get_type(r) == REPLICA_TYPE_READONLY)
{
slapi_log_err(SLAPI_LOG_REPL, "write_changelog_and_ruv",
"Skipping internal operation on read-only replica\n");
goto common_return;
}
/* we might have stripped all the mods - in that case we do not
log the operation */
if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
......
......@@ -109,10 +109,8 @@ tombstone_to_conflict_check_parent (
0);
slapi_search_internal_pb(newpb);
slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
switch(op_result)
{
case LDAP_SUCCESS:
{
switch (op_result) {
case LDAP_SUCCESS: {
Slapi_Entry **entries = NULL;
slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
if (entries != NULL && entries[0] != NULL) {
......@@ -133,8 +131,7 @@ tombstone_to_conflict_check_parent (
slapi_sdn_free(&newsuperior);
}
}
}
break;
} break;
default:
break;
}
......@@ -227,13 +224,15 @@ conflict_to_tombstone(char *sessionid, Slapi_Entry *entry, CSN *opcsn)
}
}
if (op_result) goto done;
if (op_result)
goto done;
slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
"conflict_to_tombstone - %s - Renaming entry %s to %s\n",
sessionid, slapi_entry_get_dn_const(entry), newrdn);
op_result = urp_fixup_rename_entry(entry, newrdn, NULL, OP_FLAG_NOOP);
if (op_result) goto done;
if (op_result)
goto done;
op_result = urp_fixup_delete_entry(uniqueid, slapi_entry_get_dn_const(entry), opcsn, 0);
......
......@@ -157,7 +157,7 @@ ldbm_back_monitor_instance_search(Slapi_PBlock *pb __attribute__((unused)),
#ifdef DEBUG
{
/* debugging for hash statistics */
char *x;
char *x = NULL;
cache_debug_hash(&(inst->inst_cache), &x);
val.bv_val = x;
val.bv_len = strlen(x);
......
......@@ -1716,7 +1716,9 @@ connection_threadmain()
if ((tag != LDAP_REQ_UNBIND) && !thread_turbo_flag && !replication_connection) {
if (!more_data) {
conn->c_flags &= ~CONN_FLAG_MAX_THREADS;
PR_EnterMonitor(conn->c_mutex);
connection_make_readable_nolock(conn);
PR_ExitMonitor(conn->c_mutex);
/* once the connection is readable, another thread may access conn,
* so need locking from here on */
signal_listner();
......@@ -1822,9 +1824,17 @@ connection_threadmain()
/* If we're in turbo mode, we keep our reference to the connection alive */
/* can't use the more_data var because connection could have changed in another thread */
slapi_log_err(SLAPI_LOG_CONNS, "connection_threadmain", "conn %" PRIu64 " check more_data %d thread_turbo_flag %d"
"repl_conn_bef %d, repl_conn_now %d\n",
conn->c_connid, more_data, thread_turbo_flag,
replication_connection, conn->c_isreplication_session);
if (!replication_connection && conn->c_isreplication_session) {
/* it a connection that was just flagged as replication connection */
more_data = 0;
} else {
/* normal connection or already established replication connection */
more_data = conn_buffered_data_avail_nolock(conn, &conn_closed) ? 1 : 0;
slapi_log_err(SLAPI_LOG_CONNS, "connection_threadmain", "conn %" PRIu64 " check more_data %d thread_turbo_flag %d\n",
conn->c_connid, more_data, thread_turbo_flag);
}
if (!more_data) {
if (!thread_turbo_flag) {
/*
......
......@@ -331,15 +331,19 @@ csngen_adjust_time(CSNGen *gen, const CSN *csn)
/* let's revisit the seq num - if the new time is > the old
tiem, we should reset the seq number to remote + 1 if
this won't cause a wrap around */
if (new_time > cur_time) {
if (new_time >= cur_time) {
/* just set seq_num regardless of whether the current one
is < or > than the remote one - the goal of this function
is to make sure we generate CSNs > the remote CSN - if
we have increased the time, we can decrease the seqnum
and still guarantee that any new CSNs generated will be
> any current CSNs we have generated */
if (remote_seqnum < gen->state.seq_num) {
gen->state.seq_num ++;
} else {
gen->state.seq_num = remote_seqnum + 1;
}
}
if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
slapi_log_err(SLAPI_LOG_REPL, "csngen_adjust_time",
"gen state after %08lx%04x:%ld:%ld:%ld\n",
......
......@@ -1087,12 +1087,18 @@ slapd_daemon(daemon_ports_t *ports, ns_thrpool_t *tp)
/* we have exited from ns_thrpool_wait. This means we are shutting down! */
/* Please see https://firstyear.fedorapeople.org/nunc-stans/md_docs_job-safety.html */
/* tldr is shutdown needs to run first to allow job_done on an ARMED job */
for (size_t i = 0; i < listeners; i++) {
PRStatus shutdown_status = ns_job_done(listener_idxs[i].ns_job);
for (uint64_t i = 0; i < listeners; i++) {
PRStatus shutdown_status;
if (listener_idxs[i].ns_job) {
shutdown_status = ns_job_done(listener_idxs[i].ns_job);
if (shutdown_status != PR_SUCCESS) {
slapi_log_err(SLAPI_LOG_CRIT, "ns_set_shutdown", "Failed to shutdown listener idx %" PRIu64 " !\n", i);
}
PR_ASSERT(shutdown_status == PR_SUCCESS);
} else {
slapi_log_err(SLAPI_LOG_CRIT, "slapd_daemon", "Listeners uninitialized. Possibly the server was shutdown while starting\n");
}
listener_idxs[i].ns_job = NULL;
}
} else {
......@@ -1197,8 +1203,10 @@ slapd_daemon(daemon_ports_t *ports, ns_thrpool_t *tp)
* All the connection close jobs "should" complete before
* shutdown at least.
*/
if (enable_nunc_stans) {
ns_thrpool_shutdown(tp);
ns_thrpool_wait(tp);
}
threads = g_get_active_threadcnt();
if (threads > 0) {
......@@ -1676,22 +1684,25 @@ ns_handle_closure(struct ns_job_t *job)
/**
* Schedule more I/O for this connection, or make sure that it
* is closed in the event loop.
* caller must hold c_mutex
* It returns
* 0 on success
* 1 on need to retry
*/
void
ns_connection_post_io_or_closing(Connection *conn)
static int
ns_connection_post_io_or_closing_try(Connection *conn)
{
struct timeval tv;
if (!enable_nunc_stans) {
return;
return 0;
}
/*
* Cancel any existing ns jobs we have registered.
*/
if (conn->c_job != NULL) {
ns_job_done(conn->c_job);
conn->c_job = NULL;
return 1;
}
if (CONN_NEEDS_CLOSING(conn)) {
......@@ -1701,7 +1712,7 @@ ns_connection_post_io_or_closing(Connection *conn)
slapi_log_err(SLAPI_LOG_CONNS, "ns_connection_post_io_or_closing", "Already a close "
"job in progress on conn %" PRIu64 " for fd=%d\n",
conn->c_connid, conn->c_sd);
return;
return 0;
} else {
conn->c_ns_close_jobs++; /* now 1 active closure job */
connection_acquire_nolock_ext(conn, 1 /* allow acquire even when closing */); /* event framework now has a reference */
......@@ -1745,7 +1756,7 @@ ns_connection_post_io_or_closing(Connection *conn)
* The error occurs when we get a connection in a closing state.
* For now we return, but there is probably a better way to handle the error case.
*/
return;
return 0;
}
#endif
ns_result_t job_result = ns_add_io_timeout_job(conn->c_tp, conn->c_prfd, &tv,
......@@ -1767,6 +1778,28 @@ ns_connection_post_io_or_closing(Connection *conn)
conn->c_connid, conn->c_sd);
}
}
return 0;
}
void
ns_connection_post_io_or_closing(Connection *conn)
{
while (ns_connection_post_io_or_closing_try(conn)) {
/* we should retry later */
/* We are not suppose to work immediately on the connection that is taken by
* another job
* release the lock and give some time
*/
if (CONN_NEEDS_CLOSING(conn) && conn->c_ns_close_jobs) {
return;
} else {
PR_ExitMonitor(conn->c_mutex);
DS_Sleep(PR_MillisecondsToInterval(100));
PR_EnterMonitor(conn->c_mutex);
}
}
}
/* This function must be called without the thread flag, in the
......@@ -2467,7 +2500,9 @@ ns_handle_new_connection(struct ns_job_t *job)
* that poll() was avoided, even at the expense of putting this new fd back
* in nunc-stans to poll for read ready.
*/
PR_EnterMonitor(c->c_mutex);
ns_connection_post_io_or_closing(c);
PR_ExitMonitor(c->c_mutex);
return;
}
......
......@@ -472,7 +472,7 @@ get_substring_filter(
f->f_sub_initial = val;
eval = (char *)slapi_escape_filter_value(val, -1);
if (eval) {
if (fstr_len < strlen(*fstr) + strlen(eval) + 1) {
if (fstr_len <= strlen(*fstr) + strlen(eval) + 1) {
fstr_len += (strlen(eval) + 1) * 2;
*fstr = slapi_ch_realloc(*fstr, fstr_len);
}
......@@ -486,7 +486,7 @@ get_substring_filter(
charray_add(&f->f_sub_any, val);
eval = (char *)slapi_escape_filter_value(val, -1);
if (eval) {
if (fstr_len < strlen(*fstr) + strlen(eval) + 1) {
if (fstr_len <= strlen(*fstr) + strlen(eval) + 1) {
fstr_len += (strlen(eval) + 1) * 2;
*fstr = slapi_ch_realloc(*fstr, fstr_len);
}
......@@ -504,7 +504,7 @@ get_substring_filter(
f->f_sub_final = val;
eval = (char *)slapi_escape_filter_value(val, -1);
if (eval) {
if (fstr_len < strlen(*fstr) + strlen(eval) + 1) {
if (fstr_len <= strlen(*fstr) + strlen(eval) + 1) {
fstr_len += (strlen(eval) + 1) * 2;
*fstr = slapi_ch_realloc(*fstr, fstr_len);
}
......@@ -530,7 +530,7 @@ get_substring_filter(
}
filter_compute_hash(f);
if (fstr_len < strlen(*fstr) + 3) {
if (fstr_len <= strlen(*fstr) + 3) {
fstr_len += 3;
*fstr = slapi_ch_realloc(*fstr, fstr_len);
}
......
......@@ -161,6 +161,11 @@ do_escape_string(
break;
}
do {
if (bufSpace < 4) {
memcpy(bufNext, "..", 2);
bufNext += 2;
goto bail;
}
if (esc == UTIL_ESCAPE_BACKSLASH) {
/* *s is '\\' */
/* If *(s+1) and *(s+2) are both hex digits,
......@@ -179,11 +184,6 @@ do_escape_string(
*bufNext++ = '\\';
--bufSpace;
}
if (bufSpace < 3) {
memcpy(bufNext, "..", 2);
bufNext += 2;
goto bail;
}
PR_snprintf(bufNext, 3, "%02x", *(unsigned char *)s);
bufNext += 2;
bufSpace -= 2;
......