[389-ds-base] branch 389-ds-base-1.4.0 updated: Issue 50292 - Fix Plugin CLI and UI issues
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
spichugi pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 2b689f8 Issue 50292 - Fix Plugin CLI and UI issues
2b689f8 is described below
commit 2b689f8b1d6d0fade86ceea0c31ffb7ede9fbfc8
Author: Simon Pichugin <spichugi(a)redhat.com>
AuthorDate: Fri Mar 15 01:00:50 2019 +0100
Issue 50292 - Fix Plugin CLI and UI issues
Description: Fix 'All plugins' tab rendering issue.
Fix nsds5replicalastinitstatus typo.
Fix generic_object_add logic for cases when RDN is in props and BaseDN is supplied.
Add Posix Winsync API plugin
Add PAM PTA plugin
Fix underscore issues in plugin arguments.
Fix Linked Attribute plugin Fixup task arguments and name.
Change a 'print()' function to a 'log.info()' function.
https://pagure.io/389-ds-base/issue/50292
Reviewed by: mreynolds, wibrown (Thanks!)
---
src/cockpit/389-console/src/plugins.jsx | 2 +
src/lib389/lib389/agreement.py | 2 +-
src/lib389/lib389/cli_conf/__init__.py | 17 ++-
src/lib389/lib389/cli_conf/plugin.py | 2 +
.../lib389/cli_conf/plugins/accountpolicy.py | 7 +-
src/lib389/lib389/cli_conf/plugins/attruniq.py | 35 +++--
src/lib389/lib389/cli_conf/plugins/automember.py | 18 +--
src/lib389/lib389/cli_conf/plugins/dna.py | 15 +-
src/lib389/lib389/cli_conf/plugins/linkedattr.py | 15 +-
.../lib389/cli_conf/plugins/managedentries.py | 20 +--
src/lib389/lib389/cli_conf/plugins/memberof.py | 14 +-
.../lib389/cli_conf/plugins/passthroughauth.py | 169 ++++++++++++++++++---
.../lib389/cli_conf/plugins/posix_winsync.py | 53 +++++++
.../lib389/cli_conf/plugins/retrochangelog.py | 10 +-
src/lib389/lib389/cli_conf/plugins/rootdn_ac.py | 8 +-
src/lib389/lib389/plugins.py | 113 ++++++++++++--
src/lib389/lib389/tasks.py | 1 -
17 files changed, 395 insertions(+), 106 deletions(-)
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index e14b92d..cab8952 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -296,6 +296,8 @@ export class Plugins extends React.Component {
}
this.toggleLoading();
});
+ } else {
+ this.pluginList();
}
});
}
diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py
index 1f3fefc..128a607 100644
--- a/src/lib389/lib389/agreement.py
+++ b/src/lib389/lib389/agreement.py
@@ -317,7 +317,7 @@ class Agreement(DSLdapObject):
if 'nsds5beginreplicarefresh' not in status_attrs_dict:
status_attrs_dict['nsds5beginreplicarefresh'] = [""]
if 'nsds5replicalastinitstatus' not in status_attrs_dict:
- status_attrs_dict['nsds5replicalastinitstatus'] = ["unavilable"]
+ status_attrs_dict['nsds5replicalastinitstatus'] = ["unavailable"]
if 'nsds5replicachangessentsincestartup' not in status_attrs_dict:
status_attrs_dict['nsds5replicachangessentsincestartup'] = ['0']
if ensure_str(status_attrs_dict['nsds5replicachangessentsincestartup'][0]) == '':
diff --git a/src/lib389/lib389/cli_conf/__init__.py b/src/lib389/lib389/cli_conf/__init__.py
index 9e1daed..2567f1e 100644
--- a/src/lib389/lib389/cli_conf/__init__.py
+++ b/src/lib389/lib389/cli_conf/__init__.py
@@ -30,18 +30,21 @@ def generic_object_add(dsldap_objects_class, inst, log, args, arg_to_attr, dn=No
"""
log = log.getChild('generic_object_add')
+ # If Base DN was initially provided then 'props' should contain the RDN
+ # if 'props' doesn't have the RDN - it will fail with the right error during the validation in the 'create'
+ rdn = None
# Gather the attributes
attrs = _args_to_attrs(args, arg_to_attr)
props.update({attr: value for (attr, value) in attrs.items() if value != ""})
# Get RDN attribute and Base DN from the DN if Base DN is not specified
- if dn is not None and basedn is None:
- dn_parts = ldap.dn.explode_dn(dn)
-
- rdn = dn_parts[0]
- basedn = ",".join(dn_parts[1:])
- else:
- raise ValueError('If Base DN is not specified - DN parameter should be')
+ if basedn is None:
+ if dn is not None:
+ dn_parts = ldap.dn.explode_dn(dn)
+ rdn = dn_parts[0]
+ basedn = ",".join(dn_parts[1:])
+ else:
+ raise ValueError('If Base DN is not specified - DN parameter should be specified instead')
new_object = dsldap_objects_class(inst, dn=dn)
new_object.create(rdn=rdn, basedn=basedn, properties=props)
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
index 9509b84..db2ba58 100644
--- a/src/lib389/lib389/cli_conf/plugin.py
+++ b/src/lib389/lib389/cli_conf/plugin.py
@@ -26,6 +26,7 @@ from lib389.cli_conf.plugins import managedentries as cli_managedentries
from lib389.cli_conf.plugins import passthroughauth as cli_passthroughauth
from lib389.cli_conf.plugins import retrochangelog as cli_retrochangelog
from lib389.cli_conf.plugins import automember as cli_automember
+from lib389.cli_conf.plugins import posix_winsync as cli_posix_winsync
SINGULAR = Plugin
MANY = Plugins
@@ -111,6 +112,7 @@ def create_parser(subparsers):
cli_managedentries.create_parser(subcommands)
cli_passthroughauth.create_parser(subcommands)
cli_retrochangelog.create_parser(subcommands)
+ cli_posix_winsync.create_parser(subcommands)
list_parser = subcommands.add_parser('list', help="List current configured (enabled and disabled) plugins")
list_parser.set_defaults(func=plugin_list)
diff --git a/src/lib389/lib389/cli_conf/plugins/accountpolicy.py b/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
index e2fa1e1..e585d2a 100644
--- a/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
+++ b/src/lib389/lib389/cli_conf/plugins/accountpolicy.py
@@ -55,9 +55,10 @@ def accountpolicy_show_config(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def accountpolicy_del_config(inst, basedn, log, args):
@@ -69,7 +70,7 @@ def accountpolicy_del_config(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--always-record-login', choices=['yes', 'no'],
+ parser.add_argument('--always-record-login', choices=['yes', 'no'], type=str.lower,
help='Sets that every entry records its last login time (alwaysRecordLogin)')
parser.add_argument('--alt-state-attr',
help='Provides a backup attribute for the server to reference '
diff --git a/src/lib389/lib389/cli_conf/plugins/attruniq.py b/src/lib389/lib389/cli_conf/plugins/attruniq.py
index 17dac15..a26154c 100644
--- a/src/lib389/lib389/cli_conf/plugins/attruniq.py
+++ b/src/lib389/lib389/cli_conf/plugins/attruniq.py
@@ -9,15 +9,16 @@
import json
import ldap
from lib389.plugins import AttributeUniquenessPlugin, AttributeUniquenessPlugins
-from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, generic_object_add
+from lib389.cli_conf import (add_generic_plugin_parsers, generic_object_edit, generic_object_add,
+ generic_enable, generic_disable, generic_status)
from lib389._constants import DN_PLUGIN
arg_to_attr = {
- 'attr-name': 'uniqueness-attribute-name',
+ 'attr_name': 'uniqueness-attribute-name',
'subtree': 'uniqueness-subtrees',
- 'across-all-subtrees': 'uniqueness-across-all-subtrees',
- 'top-entry-oc': 'uniqueness-top-entry-oc',
- 'subtree-entries-oc': 'uniqueness-subtree-entries-oc'
+ 'across_all_subtrees': 'uniqueness-across-all-subtrees',
+ 'top_entry_oc': 'uniqueness-top-entry-oc',
+ 'subtree_entries_oc': 'uniqueness-subtree-entries-oc'
}
@@ -32,13 +33,13 @@ def attruniq_list(inst, basedn, log, args):
else:
result.append(plugin.rdn)
if args.json:
- print(json.dumps({"type": "list", "items": result_json}))
+ log.info(json.dumps({"type": "list", "items": result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Attribute Uniqueness plugin instances")
+ log.info("No Attribute Uniqueness plugin instances")
def attruniq_add(inst, basedn, log, args):
@@ -63,9 +64,9 @@ def attruniq_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = plugin.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(plugin.display())
+ log.info(plugin.display())
def attruniq_del(inst, basedn, log, args):
@@ -85,7 +86,7 @@ def _add_parser_args(parser):
parser.add_argument('--subtree', nargs='+',
help='Sets the DN under which the plug-in checks for uniqueness of '
'the attributes value. This attribute is multi-valued (uniqueness-subtrees)')
- parser.add_argument('--across-all-subtrees', choices=['on', 'off'],
+ parser.add_argument('--across-all-subtrees', choices=['on', 'off'], type=str.lower,
help='If enabled (on), the plug-in checks that the attribute is unique across all subtrees '
'set. If you set the attribute to off, uniqueness is only enforced within the subtree '
'of the updated entry (uniqueness-across-all-subtrees)')
@@ -120,3 +121,15 @@ def create_parser(subparsers):
delete = subcommands.add_parser('delete', help='Delete the config entry')
delete.add_argument('NAME', help='Sets the name of the plug-in configuration record')
delete.set_defaults(func=attruniq_del)
+
+ enable = subcommands.add_parser('enable', help='enable plugin')
+ enable.add_argument('NAME', help='Sets the name of the plug-in configuration record')
+ enable.set_defaults(func=generic_enable)
+
+ disable = subcommands.add_parser('disable', help='disable plugin')
+ disable.add_argument('NAME', help='Sets the name of the plug-in configuration record')
+ disable.set_defaults(func=generic_disable)
+
+ status = subcommands.add_parser('status', help='display plugin status')
+ status.add_argument('NAME', help='Sets the name of the plug-in configuration record')
+ status.set_defaults(func=generic_status)
diff --git a/src/lib389/lib389/cli_conf/plugins/automember.py b/src/lib389/lib389/cli_conf/plugins/automember.py
index d9fe1dd..fbd270a 100644
--- a/src/lib389/lib389/cli_conf/plugins/automember.py
+++ b/src/lib389/lib389/cli_conf/plugins/automember.py
@@ -14,16 +14,16 @@ from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, gen
arg_to_attr_definition = {
- 'default-group': 'autoMemberDefaultGroup',
+ 'default_group': 'autoMemberDefaultGroup',
'filter': 'autoMemberFilter',
- 'grouping-attr': 'autoMemberGroupingAttr',
+ 'grouping_attr': 'autoMemberGroupingAttr',
'scope': 'autoMemberScope'
}
arg_to_attr_regex = {
'exclusive': 'autoMemberExclusiveRegex',
'inclusive': 'autoMemberInclusiveRegex',
- 'target-group': 'autoMemberTargetGroup'
+ 'target_group': 'autoMemberTargetGroup'
}
@@ -42,7 +42,7 @@ def definition_list(inst, basedn, log, args):
log.info("No automember definitions were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def definition_add(inst, basedn, log, args):
@@ -68,9 +68,9 @@ def definition_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = definition.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(definition.display())
+ log.info(definition.display())
def definition_del(inst, basedn, log, args):
@@ -98,7 +98,7 @@ def regex_list(inst, basedn, log, args):
log.info("No automember regexes were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def regex_add(inst, basedn, log, args):
@@ -129,9 +129,9 @@ def regex_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = regex.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(regex.display())
+ log.info(regex.display())
def regex_del(inst, basedn, log, args):
diff --git a/src/lib389/lib389/cli_conf/plugins/dna.py b/src/lib389/lib389/cli_conf/plugins/dna.py
index 08f66a4..6033c17 100644
--- a/src/lib389/lib389/cli_conf/plugins/dna.py
+++ b/src/lib389/lib389/cli_conf/plugins/dna.py
@@ -54,7 +54,7 @@ def dna_list(inst, basedn, log, args):
log.info("No DNA configurations were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def dna_add(inst, basedn, log, args):
@@ -80,9 +80,9 @@ def dna_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.NAME)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def dna_del(inst, basedn, log, args):
@@ -109,7 +109,7 @@ def dna_config_list(inst, basedn, log, args):
log.info("No DNA shared configurations were found")
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def dna_config_add(inst, basedn, log, args):
@@ -146,9 +146,9 @@ def dna_config_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = shared_config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(shared_config.display())
+ log.info(shared_config.display())
def dna_config_del(inst, basedn, log, args):
@@ -160,7 +160,8 @@ def dna_config_del(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--type', help='Sets which attributes have unique numbers being generated for them (dnaType)')
+ parser.add_argument('--type', nargs='+',
+ help='Sets which attributes have unique numbers being generated for them (dnaType)')
parser.add_argument('--prefix', help='Defines a prefix that can be prepended to the generated '
'number values for the attribute (dnaPrefix)')
parser.add_argument('--next-value', help='Gives the next available number which can be assigned (dnaNextValue)')
diff --git a/src/lib389/lib389/cli_conf/plugins/linkedattr.py b/src/lib389/lib389/cli_conf/plugins/linkedattr.py
index 716f0e2..781767c 100644
--- a/src/lib389/lib389/cli_conf/plugins/linkedattr.py
+++ b/src/lib389/lib389/cli_conf/plugins/linkedattr.py
@@ -30,13 +30,13 @@ def linkedattr_list(inst, basedn, log, args):
else:
result.append(config.rdn)
if args.json:
- print(json.dumps({"type": "list", "items": result_json}))
+ log.info(json.dumps({"type": "list", "items": result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin config instances")
def linkedattr_add(inst, basedn, log, args):
@@ -62,9 +62,9 @@ def linkedattr_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def linkedattr_del(inst, basedn, log, args):
@@ -80,7 +80,7 @@ def fixup(inst, basedn, log, args):
log.info('Attempting to add task entry... This will fail if LinkedAttributes plug-in is not enabled.')
if not plugin.status():
log.error("'%s' is disabled. Fix up task can't be executed" % plugin.rdn)
- fixup_task = plugin.fixup(args.basedn, args.filter)
+ fixup_task = plugin.fixup(args.linkdn)
fixup_task.wait()
exitcode = fixup_task.get_exit_code()
if exitcode != 0:
@@ -104,8 +104,7 @@ def create_parser(subparsers):
add_generic_plugin_parsers(subcommands, LinkedAttributesPlugin)
fixup_parser = subcommands.add_parser('fixup', help='Run the fix-up task for linked attributes plugin')
- fixup_parser.add_argument('basedn', help="basedn that contains entries to fix up")
- fixup_parser.add_argument('-f', '--filter', help='Filter for entries to fix up linked attributes.')
+ fixup_parser.add_argument('-l', '--linkdn', help="Base DN that contains entries to fix up")
fixup_parser.set_defaults(func=fixup)
list = subcommands.add_parser('list', help='List available plugin configs')
diff --git a/src/lib389/lib389/cli_conf/plugins/managedentries.py b/src/lib389/lib389/cli_conf/plugins/managedentries.py
index cb5235b..071df7b 100644
--- a/src/lib389/lib389/cli_conf/plugins/managedentries.py
+++ b/src/lib389/lib389/cli_conf/plugins/managedentries.py
@@ -48,13 +48,13 @@ def mep_config_list(inst, basedn, log, args):
else:
result.append(config.rdn)
if args.json:
- print(json.dumps({"type": "list", "items": result_json}))
+ log.info(json.dumps({"type": "list", "items": result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin instances")
def mep_config_add(inst, basedn, log, args):
@@ -87,9 +87,9 @@ def mep_config_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def mep_config_del(inst, basedn, log, args):
@@ -113,13 +113,13 @@ def mep_template_list(inst, basedn, log, args):
else:
result.append(template.rdn)
if args.json:
- print(json.dumps({"type": "list", "items": result_json}))
+ log.info(json.dumps({"type": "list", "items": result_json}))
else:
if len(result) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Linked Attributes plugin instances")
+ log.info("No Linked Attributes plugin instances")
def mep_template_add(inst, basedn, log, args):
@@ -148,9 +148,9 @@ def mep_template_show(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = template.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(template.display())
+ log.info(template.display())
def mep_template_del(inst, basedn, log, args):
diff --git a/src/lib389/lib389/cli_conf/plugins/memberof.py b/src/lib389/lib389/cli_conf/plugins/memberof.py
index 666dd74..eb3d5e0 100644
--- a/src/lib389/lib389/cli_conf/plugins/memberof.py
+++ b/src/lib389/lib389/cli_conf/plugins/memberof.py
@@ -56,9 +56,9 @@ def memberof_show_config(inst, basedn, log, args):
raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
if args and args.json:
o_str = config.get_all_attrs_json()
- print(o_str)
+ log.info(o_str)
else:
- print(config.display())
+ log.info(config.display())
def memberof_del_config(inst, basedn, log, args):
@@ -69,10 +69,12 @@ def memberof_del_config(inst, basedn, log, args):
log.info("Successfully deleted the %s", targetdn)
-def fixup(inst, basedn, log, args):
+def do_fixup(inst, basedn, log, args):
plugin = MemberOfPlugin(inst)
- log.info('Attempting to add task entry... This will fail if MemberOf plug-in is not enabled.')
- assert plugin.status(), "'%s' is disabled. Fix up task can't be executed" % plugin.rdn
+ log.info('Attempting to add task entry...')
+ if not plugin.status():
+ log.error("'%s' is disabled. Fix up task can't be executed" % plugin.rdn)
+ return
fixup_task = plugin.fixup(args.DN, args.filter)
fixup_task.wait()
exitcode = fixup_task.get_exit_code()
@@ -132,7 +134,7 @@ def create_parser(subparsers):
del_config_.add_argument('DN', help='The config entry full DN')
fixup = subcommands.add_parser('fixup', help='Run the fix-up task for memberOf plugin')
- fixup.set_defaults(func=fixup)
+ fixup.set_defaults(func=do_fixup)
fixup.add_argument('DN', help="Base DN that contains entries to fix up")
fixup.add_argument('-f', '--filter',
help='Filter for entries to fix up.\n If omitted, all entries with objectclass '
diff --git a/src/lib389/lib389/cli_conf/plugins/passthroughauth.py b/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
index 616119a..c5d0646 100644
--- a/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
+++ b/src/lib389/lib389/cli_conf/plugins/passthroughauth.py
@@ -8,8 +8,22 @@
import json
import ldap
-from lib389.plugins import PassThroughAuthenticationPlugin
-from lib389.cli_conf import add_generic_plugin_parsers
+from lib389.plugins import (PassThroughAuthenticationPlugin, PAMPassThroughAuthPlugin,
+ PAMPassThroughAuthConfigs, PAMPassThroughAuthConfig)
+
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, generic_object_add
+
+arg_to_attr_pam = {
+ 'exclude_suffix': 'pamExcludeSuffix',
+ 'include_suffix': 'pamIncludeSuffix',
+ 'missing_suffix': 'pamMissingSuffix',
+ 'filter': 'pamFilter',
+ 'id_attr': 'pamIDAttr',
+ 'id_map_method': 'pamIDMapMethod',
+ 'fallback': 'pamFallback',
+ 'secure': 'pamSecure',
+ 'service': 'pamService'
+}
def pta_list(inst, basedn, log, args):
@@ -18,13 +32,13 @@ def pta_list(inst, basedn, log, args):
result = []
urls = plugin.get_urls()
if args.json:
- print(json.dumps({"type": "list", "items": urls}))
+ log.info(json.dumps({"type": "list", "items": urls}))
else:
if len(urls) > 0:
for i in result:
- print(i)
+ log.info(i)
else:
- print("No Pass Through Auth attributes were found")
+ log.info("No Pass Through Auth URLs were found")
def pta_add(inst, basedn, log, args):
@@ -62,27 +76,132 @@ def pta_del(inst, basedn, log, args):
log.info("Successfully deleted %s", args.URL)
+def pam_pta_list(inst, basedn, log, args):
+ log = log.getChild('pam_pta_list')
+ configs = PAMPassThroughAuthConfigs(inst)
+ result = []
+ result_json = []
+ for config in configs.list():
+ if args.json:
+ result_json.append(config.get_all_attrs_json())
+ else:
+ result.append(config.rdn)
+ if args.json:
+ log.info(json.dumps({"type": "list", "items": result_json}))
+ else:
+ if len(result) > 0:
+ for i in result:
+ log.info(i)
+ else:
+ log.info("No PAM Pass Through Auth plugin config instances")
+
+
+def pam_pta_add(inst, basedn, log, args):
+ log = log.getChild('pam_pta_add')
+ plugin = PAMPassThroughAuthPlugin(inst)
+ props = {'cn': args.NAME}
+ generic_object_add(PAMPassThroughAuthConfig, inst, log, args, arg_to_attr_pam, basedn=plugin.dn, props=props)
+
+
+def pam_pta_edit(inst, basedn, log, args):
+ log = log.getChild('pam_pta_edit')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+ generic_object_edit(config, log, args, arg_to_attr_pam)
+
+
+def pam_pta_show(inst, basedn, log, args):
+ log = log.getChild('pam_pta_show')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+
+ if not config.exists():
+ raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % args.name)
+ if args and args.json:
+ o_str = config.get_all_attrs_json()
+ log.info(o_str)
+ else:
+ log.info(config.display())
+
+
+def pam_pta_del(inst, basedn, log, args):
+ log = log.getChild('pam_pta_del')
+ configs = PAMPassThroughAuthConfigs(inst)
+ config = configs.get(args.NAME)
+ config.delete()
+ log.info("Successfully deleted the %s", config.dn)
+
+
+def _add_parser_args_pam(parser):
+ parser.add_argument('--exclude-suffix', nargs='+',
+ help='Specifies a suffix to exclude from PAM authentication (pamExcludeSuffix)')
+ parser.add_argument('--include-suffix', nargs='+',
+ help='Sets a suffix to include for PAM authentication (pamIncludeSuffix)')
+ parser.add_argument('--missing-suffix', choices=['ERROR', 'ALLOW', 'IGNORE'],
+ help='Identifies how to handle missing include or exclude suffixes (pamMissingSuffix)')
+ parser.add_argument('--filter',
+ help='Sets an LDAP filter to use to identify specific entries within '
+ 'the included suffixes for which to use PAM pass-through authentication (pamFilter)')
+ parser.add_argument('--id-attr', nargs='+',
+ help='Contains the attribute name which is used to hold the PAM user ID (pamIDAttr)')
+ parser.add_argument('--id_map_method',
+ help='Gives the method to use to map the LDAP bind DN to a PAM identity (pamIDMapMethod)')
+ parser.add_argument('--fallback', choices=['TRUE', 'FALSE'], type=str.upper,
+ help='Sets whether to fallback to regular LDAP authentication '
+ 'if PAM authentication fails (pamFallback)')
+ parser.add_argument('--secure', choices=['TRUE', 'FALSE'], type=str.upper,
+ help='Requires secure TLS connection for PAM authentication (pamSecure)')
+ parser.add_argument('--service',
+ help='Contains the service name to pass to PAM (pamService)')
+
+
def create_parser(subparsers):
- passthroughauth_parser = subparsers.add_parser('pass-through-auth', help='Manage and configure Pass-Through Authentication plugin')
+ passthroughauth_parser = subparsers.add_parser('pass-through-auth',
+ help='Manage and configure Pass-Through Authentication plugins '
+ '(URLs and PAM)')
subcommands = passthroughauth_parser.add_subparsers(help='action')
add_generic_plugin_parsers(subcommands, PassThroughAuthenticationPlugin)
- list = subcommands.add_parser('list', help='List available plugin configs')
- list.set_defaults(func=pta_list)
-
- add = subcommands.add_parser('add', help='Add the config entry')
- add.add_argument('URL', help='The full LDAP URL in format '
- '"ldap|ldaps://authDS/subtree maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
- 'If one optional parameter is specified the rest should be specified too')
- add.set_defaults(func=pta_add)
-
- edit = subcommands.add_parser('modify', help='Edit the config entry')
- edit.add_argument('OLD_URL', help='The full LDAP URL you get from the "list" command')
- edit.add_argument('NEW_URL', help='The full LDAP URL in format '
- '"ldap|ldaps://authDS/subtree maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
- 'If one optional parameter is specified the rest should be specified too')
- edit.set_defaults(func=pta_edit)
-
- delete = subcommands.add_parser('delete', help='Delete the config entry')
- delete.add_argument('URL', help='The full LDAP URL you get from the "list" command')
- delete.set_defaults(func=pta_del)
+ list = subcommands.add_parser('list', help='List pass-though plugin URLs or PAM configurations.')
+ subcommands_list = list.add_subparsers(help='action')
+ list_urls = subcommands_list.add_parser('urls', help='List URLs.')
+ list_urls.set_defaults(func=pta_list)
+ list_pam = subcommands_list.add_parser('pam-configs', help='List PAM configurations.')
+ list_pam.set_defaults(func=pam_pta_list)
+
+ url = subcommands.add_parser('url', help='Manage PTA URL configurations.')
+ subcommands_url = url.add_subparsers(help='action')
+
+ add_url = subcommands_url.add_parser('add', help='Add the config entry')
+ add_url.add_argument('URL',
+ help='The full LDAP URL in format '
+ '"ldap|ldaps://authDS/subtree maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
+ 'If one optional parameter is specified the rest should be specified too')
+ add_url.set_defaults(func=pta_add)
+
+ edit_url = subcommands_url.add_parser('modify', help='Edit the config entry')
+ edit_url.add_argument('OLD_URL', help='The full LDAP URL you get from the "list" command')
+ edit_url.add_argument('NEW_URL',
+ help='The full LDAP URL in format '
+ '"ldap|ldaps://authDS/subtree maxconns,maxops,timeout,ldver,connlifetime,startTLS". '
+ 'If one optional parameter is specified the rest should be specified too')
+ edit_url.set_defaults(func=pta_edit)
+
+ delete_url = subcommands_url.add_parser('delete', help='Delete the config entry')
+ delete_url.add_argument('URL', help='The full LDAP URL you get from the "list" command')
+ delete_url.set_defaults(func=pta_del)
+
+ pam = subcommands.add_parser('pam-config', help='Manage PAM PTA configurations.')
+ pam.add_argument('NAME', help='The PAM PTA configuration name')
+ subcommands_pam = pam.add_subparsers(help='action')
+
+ add = subcommands_pam.add_parser('add', help='Add the config entry')
+ add.set_defaults(func=pam_pta_add)
+ _add_parser_args_pam(add)
+ edit = subcommands_pam.add_parser('set', help='Edit the config entry')
+ edit.set_defaults(func=pam_pta_edit)
+ _add_parser_args_pam(edit)
+ show = subcommands_pam.add_parser('show', help='Display the config entry')
+ show.set_defaults(func=pam_pta_show)
+ delete = subcommands_pam.add_parser('delete', help='Delete the config entry')
+ delete.set_defaults(func=pam_pta_del)
diff --git a/src/lib389/lib389/cli_conf/plugins/posix_winsync.py b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py
new file mode 100644
index 0000000..5c5d6cc
--- /dev/null
+++ b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py
@@ -0,0 +1,53 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2019 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+
+from lib389.plugins import POSIXWinsyncPlugin
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
+
+arg_to_attr = {
+ 'create_memberof_task': 'posixWinsyncCreateMemberOfTask',
+ 'lower_case_uid': 'posixWinsyncLowerCaseUID',
+ 'map_member_uid': 'posixWinsyncMapMemberUID',
+ 'map_nested_grouping': 'posixWinsyncMapNestedGrouping',
+ 'ms_sfu_schema': 'posixWinsyncMsSFUSchema'
+}
+
+
+def winsync_edit(inst, basedn, log, args):
+ log = log.getChild('winsync_edit')
+ plugin = POSIXWinsyncPlugin(inst)
+ generic_object_edit(plugin, log, args, arg_to_attr)
+
+
+def _add_parser_args(parser):
+ parser.add_argument('--create-memberof-task', choices=['true', 'false'], type=str.lower,
+ help=' sets whether to run the memberOf fix-up task immediately after a sync run in order '
+ 'to update group memberships for synced users (posixWinsyncCreateMemberOfTask)')
+ parser.add_argument('--lower-case-uid', choices=['true', 'false'], type=str.lower,
+ help='Sets whether to store (and, if necessary, convert) the UID value in the memberUID '
+ 'attribute in lower case.(posixWinsyncLowerCaseUID)')
+ parser.add_argument('--map-member-uid', choices=['true', 'false'], type=str.lower,
+ help='Sets whether to map the memberUID attribute in an Active Directory group to '
+ 'the uniqueMember attribute in a Directory Server group (posixWinsyncMapMemberUID)')
+ parser.add_argument('--map-nested-grouping', choices=['true', 'false'], type=str.lower,
+ help='Manages if nested groups are updated when memberUID attributes in '
+ 'an Active Directory POSIX group change (posixWinsyncMapNestedGrouping)')
+ parser.add_argument('--ms-sfu-schema', choices=['true', 'false'], type=str.lower,
+ help='Sets whether to the older Microsoft System Services for Unix 3.0 (msSFU30) '
+ 'schema when syncing Posix attributes from Active Directory (posixWinsyncMsSFUSchema)')
+
+
+def create_parser(subparsers):
+ winsync = subparsers.add_parser('posix-winsync', help='Manage and configure The Posix Winsync API plugin')
+ subcommands = winsync.add_subparsers(help='action')
+ add_generic_plugin_parsers(subcommands, POSIXWinsyncPlugin)
+
+ edit = subcommands.add_parser('set', help='Edit the plugin')
+ edit.set_defaults(func=winsync_edit)
+ _add_parser_args(edit)
+
diff --git a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
index 912c127..e677310 100644
--- a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
+++ b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
@@ -10,10 +10,11 @@ from lib389.plugins import RetroChangelogPlugin
from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
arg_to_attr = {
- 'is-replicated': 'isReplicated',
+ 'is_replicated': 'isReplicated',
'attribute': 'nsslapd-attribute',
'directory': 'nsslapd-changelogdir',
- 'max-age': 'nsslapd-changelogmaxage',
+ 'max_age': 'nsslapd-changelogmaxage',
+ 'exclude_suffix': 'nsslapd-exclude-suffix'
}
@@ -24,7 +25,7 @@ def retrochangelog_edit(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--is-replicated', choices=['true', 'false'],
+ parser.add_argument('--is-replicated', choices=['true', 'false'], type=str.lower,
help='Sets a flag to indicate on a change in the changelog whether the change is newly made '
'on that server or whether it was replicated over from another server (isReplicated)')
parser.add_argument('--attribute',
@@ -36,6 +37,9 @@ def _add_parser_args(parser):
parser.add_argument('--max-age',
help='This attribute specifies the maximum age of any entry '
'in the changelog (nsslapd-changelogmaxage)')
+ parser.add_argument('--exclude-suffix',
+ help='This attribute specifies the suffix which will be excluded '
+ 'from the scope of the plugin (nsslapd-exclude-suffix)')
def create_parser(subparsers):
diff --git a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
index 63838a9..1bd974d 100644
--- a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
+++ b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
@@ -27,20 +27,20 @@ def rootdn_edit(inst, basedn, log, args):
def _add_parser_args(parser):
- parser.add_argument('--allow-host',
+ parser.add_argument('--allow-host', nargs='+',
help='Sets what hosts, by fully-qualified domain name, the root user is allowed to use '
'to access the Directory Server. Any hosts not listed are implicitly denied '
'(rootdn-allow-host)')
- parser.add_argument('--deny-host',
+ parser.add_argument('--deny-host', nargs='+',
help='Sets what hosts, by fully-qualified domain name, the root user is not allowed to use '
'to access the Directory Server Any hosts not listed are implicitly allowed '
'(rootdn-deny-host). If an host address is listed in both the rootdn-allow-host and '
'rootdn-deny-host attributes, it is denied access.')
- parser.add_argument('--allow-ip',
+ parser.add_argument('--allow-ip', nargs='+',
help='Sets what IP addresses, either IPv4 or IPv6, for machines the root user is allowed '
'to use to access the Directory Server Any IP addresses not listed are implicitly '
'denied (rootdn-allow-ip)')
- parser.add_argument('--deny-ip',
+ parser.add_argument('--deny-ip', nargs='+',
help='Sets what IP addresses, either IPv4 or IPv6, for machines the root user is not allowed '
'to use to access the Directory Server. Any IP addresses not listed are implicitly '
'allowed (rootdn-deny-ip) If an IP address is listed in both the rootdn-allow-ip and '
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
index 71615e0..0b78c21 100644
--- a/src/lib389/lib389/plugins.py
+++ b/src/lib389/lib389/plugins.py
@@ -122,8 +122,22 @@ class AttributeUniquenessPlugin(Plugin):
:type dn: str
"""
+ _plugin_properties = {
+ 'nsslapd-pluginEnabled': 'off',
+ 'nsslapd-pluginPath': 'libattr-unique-plugin',
+ 'nsslapd-pluginInitfunc': 'NSUniqueAttr_Init',
+ 'nsslapd-pluginType': 'betxnpreoperation',
+ 'nsslapd-plugin-depends-on-type': 'database',
+ 'nsslapd-pluginId': 'NSUniqueAttr',
+ 'nsslapd-pluginVendor': '389 Project',
+ 'nsslapd-pluginVersion': 'none',
+ 'nsslapd-pluginDescription': 'Enforce unique attribute values',
+ }
+
def __init__(self, instance, dn="cn=attribute uniqueness,cn=plugins,cn=config"):
super(AttributeUniquenessPlugin, self).__init__(instance, dn)
+ self._protected = False
+ self._create_objectclasses = ['top', 'nsslapdplugin', 'extensibleObject']
## These are some wrappers to the important attributes
# This plugin will be "tricky" in that it can have "many" instance
@@ -170,14 +184,18 @@ class AttributeUniquenessPlugins(DSLdapObjects):
"""
def __init__(self, instance, basedn="cn=plugins,cn=config"):
- super(Plugins, self).__init__(instance=instance)
- self._objectclasses = ['top', 'nsslapdplugin']
+ super(DSLdapObjects, self).__init__(instance)
+ self._instance = instance
+ self._objectclasses = ['top', 'nsslapdplugin', 'extensibleObject']
self._filterattrs = ['cn', 'nsslapd-pluginPath']
self._childobject = AttributeUniquenessPlugin
self._basedn = basedn
# This is used to allow entry to instance to work
self._list_attrlist = ['dn', 'nsslapd-pluginPath']
self._search_filter = "(nsslapd-pluginId=NSUniqueAttr)"
+ self._scope = ldap.SCOPE_SUBTREE
+ self._server_controls = None
+ self._client_controls = None
def list(self):
"""Get a list of all plugin instances where nsslapd-pluginId: NSUniqueAttr
@@ -215,7 +233,7 @@ class AttributeUniquenessPlugins(DSLdapObjects):
# Filter based on the objectclasses and the basedn
# Based on the selector, we should filter on that too.
# This will yield and & filter for objectClass with as many terms as needed.
- filterstr = "&(cn=%s)%s" % (selector, self._search_filter)
+ filterstr = "(&(cn=%s)%s)" % (selector, self._search_filter)
self._log.debug('_gen_selector filter = %s' % filterstr)
return self._instance.search_ext_s(
base=self._basedn,
@@ -1185,21 +1203,19 @@ class LinkedAttributesPlugin(Plugin):
def __init__(self, instance, dn="cn=Linked Attributes,cn=plugins,cn=config"):
super(LinkedAttributesPlugin, self).__init__(instance, dn)
- def fixup(self, basedn, _filter=None):
+ def fixup(self, linkdn):
"""Create a fixup linked attributes task
- :param basedn: Basedn to fix up
- :type basedn: str
- :param _filter: a filter for entries to fix up
- :type _filter: str
+ :param linkdn: Link DN to fix up
+ :type linkdn: str
:returns: an instance of Task(DSLdapObject)
"""
task = tasks.FixupLinkedAttributesTask(self._instance)
- task_properties = {'basedn': basedn}
- if _filter is not None:
- task_properties['filter'] = _filter
+ task_properties = {}
+ if linkdn is not None:
+ task_properties['linkdn'] = linkdn
task.create(properties=task_properties)
return task
@@ -1235,6 +1251,7 @@ class LinkedAttributesConfigs(DSLdapObjects):
super(LinkedAttributesConfigs, self).__init__(instance)
self._objectclasses = ['top', 'extensibleObject']
self._filterattrs = ['cn']
+ self._scope = ldap.SCOPE_ONELEVEL
self._childobject = LinkedAttributesConfig
self._basedn = basedn
@@ -1265,6 +1282,80 @@ class PassThroughAuthenticationPlugin(Plugin):
return result
+class POSIXWinsyncPlugin(Plugin):
+ """A single instance of Posix Winsync API plugin entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ def __init__(self, instance, dn="cn=Posix Winsync API,cn=plugins,cn=config"):
+ super(POSIXWinsyncPlugin, self).__init__(instance, dn)
+
+
+class PAMPassThroughAuthPlugin(Plugin):
+ """A single instance of PAM Pass Through Auth plugin entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ def __init__(self, instance, dn="cn=PAM Pass Through Auth,cn=plugins,cn=config"):
+ super(PAMPassThroughAuthPlugin, self).__init__(instance, dn)
+
+
+class PAMPassThroughAuthConfig(Plugin):
+ """A single instance of PAM Pass Through Auth config entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param dn: Entry DN
+ :type dn: str
+ """
+
+ _plugin_properties = {
+ 'cn' : 'USN',
+ 'nsslapd-pluginEnabled': 'off',
+ 'nsslapd-pluginPath': 'libpam-passthru-plugin',
+ 'nsslapd-pluginInitfunc': 'pam_passthruauth_init',
+ 'nsslapd-pluginType': 'betxnpreoperation',
+ 'nsslapd-plugin-depends-on-type': 'database',
+ 'nsslapd-pluginId': 'PAM',
+ 'nsslapd-pluginVendor': '389 Project',
+ 'nsslapd-pluginVersion': '1.3.7.0',
+ 'nsslapd-pluginDescription': 'PAM Pass Through Auth plugin'
+ }
+
+ def __init__(self, instance, dn=None):
+ super(PAMPassThroughAuthConfig, self).__init__(instance, dn)
+ self._rdn_attribute = 'cn'
+ self._must_attributes = ['cn']
+ self._create_objectclasses = ['top', 'extensibleObject', 'nsslapdplugin', 'pamConfig']
+ self._protected = False
+
+
+class PAMPassThroughAuthConfigs(DSLdapObjects):
+ """A DSLdapObjects entity which represents PAM Pass Through Auth config entry
+
+ :param instance: An instance
+ :type instance: lib389.DirSrv
+ :param basedn: Base DN for all account entries below
+ :type basedn: str
+ """
+
+ def __init__(self, instance, basedn="cn=PAM Pass Through Auth,cn=plugins,cn=config"):
+ super(PAMPassThroughAuthConfigs, self).__init__(instance)
+ self._objectclasses = ['top', 'extensibleObject', 'nsslapdplugin', 'pamConfig']
+ self._filterattrs = ['cn']
+ self._scope = ldap.SCOPE_ONELEVEL
+ self._childobject = PAMPassThroughAuthConfig
+ self._basedn = basedn
+
+
class USNPlugin(Plugin):
"""A single instance of USN (Update Sequence Number) plugin entry
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
index d98b3e0..b55c29f 100644
--- a/src/lib389/lib389/tasks.py
+++ b/src/lib389/lib389/tasks.py
@@ -131,7 +131,6 @@ class FixupLinkedAttributesTask(Task):
dn = "cn=" + self.cn + "," + DN_FIXUP_LINKED_ATTIBUTES
super(FixupLinkedAttributesTask, self).__init__(instance, dn)
- self._must_attributes.extend(['basedn'])
class MemberOfFixupTask(Task):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50289 - Fix various database UI issues
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new e568d47 Ticket 50289 - Fix various database UI issues
e568d47 is described below
commit e568d4747127d0122d976c18aae09d31567d2bdc
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Mon Mar 18 13:02:42 2019 -0400
Ticket 50289 - Fix various database UI issues
Description:
Fixed these issues:
- https://bugzilla.redhat.com/show_bug.cgi?id=1664621 - backup freezes when no suffix present
- https://bugzilla.redhat.com/show_bug.cgi?id=1685395 - Perform Backup fails when Backend Name is not configured
- https://bugzilla.redhat.com/show_bug.cgi?id=1688587 - typo when restarting instance
- https://bugzilla.redhat.com/show_bug.cgi?id=1688775 - db tree breaks when suffix contains spaces.
- https://bugzilla.redhat.com/show_bug.cgi?id=1688919 - backups fail with empty name
Also fixed issue where if you start an instance in UI the configuration is correctly loaded.
https://pagure.io/389-ds-base/issue/50289
Reviewed by: spichugi(Thanks!)
---
ldap/servers/slapd/task.c | 15 ++--
src/cockpit/389-console/src/database.jsx | 32 +++++----
src/cockpit/389-console/src/ds.js | 16 ++---
src/cockpit/389-console/src/index.es6 | 11 ++-
src/cockpit/389-console/src/index.html | 1 +
.../389-console/src/lib/database/backups.jsx | 17 +++--
src/cockpit/389-console/src/plugins.jsx | 2 +-
src/cockpit/389-console/src/servers.js | 48 ++++++++-----
src/lib389/lib389/backend.py | 14 ++++
src/lib389/lib389/cli_conf/backend.py | 7 +-
src/lib389/lib389/pwpolicy.py | 84 +++++++++++-----------
11 files changed, 147 insertions(+), 100 deletions(-)
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 8741570..b42e872 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -1486,7 +1486,7 @@ task_backup_add(Slapi_PBlock *pb __attribute__((unused)),
Slapi_Entry *e,
Slapi_Entry *eAfter __attribute__((unused)),
int *returncode,
- char *returntext __attribute__((unused)),
+ char *returntext,
void *arg __attribute__((unused)))
{
Slapi_Backend *be = NULL;
@@ -1529,18 +1529,19 @@ task_backup_add(Slapi_PBlock *pb __attribute__((unused)),
}
slapi_ch_free_string(&cookie);
if (NULL == be || NULL == be->be_database->plg_db2archive) {
- slapi_log_err(SLAPI_LOG_ERR,
- "task_backup_add", "no db2archive function defined.\n");
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "no db2archive function defined. There is no backend/suffix present");
+ slapi_log_err(SLAPI_LOG_ERR, "task_backup_add", "Error: %s\n", returntext);
*returncode = LDAP_UNWILLING_TO_PERFORM;
rv = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
if (!SLAPI_PLUGIN_IS_V3(be->be_database)) {
- slapi_log_err(SLAPI_LOG_ERR,
- "task_backup_add", "Can't perform an backup with pre-V3 "
- "backend plugin %s\n",
- be->be_database->plg_name);
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Can't perform an backup with pre-V3 backend plugin %s\n",
+ be->be_database->plg_name);
+ slapi_log_err(SLAPI_LOG_ERR, "task_backup_add", "Error: %s\n", returntext);
*returncode = LDAP_UNWILLING_TO_PERFORM;
rv = SLAPI_DSE_CALLBACK_ERROR;
goto out;
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
index ccc2c19..cbcb126 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -97,11 +97,13 @@ export class Database extends React.Component {
}
componentWillMount () {
- this.loadGlobalConfig();
- this.loadChainingConfig();
- this.loadLDIFs();
- this.loadBackups();
- this.loadSuffixList();
+ if (!this.state.loaded) {
+ this.loadGlobalConfig();
+ this.loadChainingConfig();
+ this.loadLDIFs();
+ this.loadBackups();
+ this.loadSuffixList();
+ }
}
componentDidMount() {
@@ -183,7 +185,7 @@ export class Database extends React.Component {
}), this.setState({configUpdated: 0}));
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading database configuration - ${err}`
);
@@ -269,7 +271,7 @@ export class Database extends React.Component {
), this.loadAvailableControls());
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading default chaining configuration - ${err}`
);
@@ -313,11 +315,14 @@ export class Database extends React.Component {
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
"backend", "get-tree",
];
- log_cmd("getTree", "Start building the suffix tree", cmd);
+ log_cmd("loadSuffixTree", "Start building the suffix tree", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
- let treeData = JSON.parse(content);
+ let treeData = [];
+ if (content != "") {
+ treeData = JSON.parse(content);
+ }
let basicData = [
{
text: "Global Database Configuration",
@@ -356,7 +361,6 @@ export class Database extends React.Component {
this.setState(() => ({
nodes: basicData,
node_name: current_node,
-
}), this.update_tree_nodes);
});
}
@@ -770,7 +774,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading indexes for ${suffix} - ${err}`
);
@@ -924,7 +928,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading indexes for ${suffix} - ${err}`
);
@@ -960,7 +964,7 @@ export class Database extends React.Component {
const cmd = [
"dsctl", "-j", this.props.serverId, "backups"
];
- log_cmd("loadLDIFs", "Load Backups", cmd);
+ log_cmd("loadBackups", "Load Backups", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
@@ -995,7 +999,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Failed to get attributes - ${err}`
);
diff --git a/src/cockpit/389-console/src/ds.js b/src/cockpit/389-console/src/ds.js
index d309845..8d5e3dc 100644
--- a/src/cockpit/389-console/src/ds.js
+++ b/src/cockpit/389-console/src/ds.js
@@ -300,13 +300,6 @@ function popup_success(msg) {
// all the save functions for all the pages here. This is not used for modal forms
function save_all () {
save_config(); // Server Config Page
- //
- // TODO:
- // save_chaining();
- // save_chaining_suffix();
- // save_global_backend();
- // save_suffix();
- // save_security();
}
function load_repl_suffix_dropdowns() {
@@ -342,7 +335,7 @@ function load_repl_suffix_dropdowns() {
var loading_cfg = 0;
-function load_config (){
+function load_config (refresh){
// If we are currently loading config don't do it twice
if (loading_cfg == 1){
return;
@@ -409,6 +402,13 @@ function load_config (){
$("#server-config").show();
clearInterval(loading_config);
loading_cfg = 0;
+
+ if (refresh) {
+ // Reload reactJS pages by clicking dummy element
+ let reload_el = document.getElementById('reload-page');
+ reload_el.click();
+ }
+
console.log("Completed configuration initialization.");
}
}, 300);
diff --git a/src/cockpit/389-console/src/index.es6 b/src/cockpit/389-console/src/index.es6
index 7dfd433..404cbb0 100644
--- a/src/cockpit/389-console/src/index.es6
+++ b/src/cockpit/389-console/src/index.es6
@@ -14,16 +14,18 @@ function renderReactDOM(clear) {
.getElementById("select-server")
.value.replace("slapd-", "");
}
+ let d = new Date();
+ let n = d.getTime(); // might not be needed MARK
// Plugins Tab
ReactDOM.render(
- <Plugins serverId={serverIdElem} />,
+ <Plugins serverId={serverIdElem} key={n} />,
document.getElementById("plugins")
);
// Database tab
ReactDOM.render(
- <Database serverId={serverIdElem} />,
+ <Database serverId={serverIdElem} key={n} />,
document.getElementById("database")
);
}
@@ -45,10 +47,7 @@ document.addEventListener("DOMContentLoaded", function() {
.getElementById("select-server")
.addEventListener("change", renderReactWrapper);
document
- .getElementById("start-server-btn")
- .addEventListener("click", renderReactWrapper);
- document
- .getElementById("restart-server-btn")
+ .getElementById("reload-page")
.addEventListener("click", renderReactWrapper);
document
.getElementById("remove-server-btn")
diff --git a/src/cockpit/389-console/src/index.html b/src/cockpit/389-console/src/index.html
index 5015717..96586d1 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -35,6 +35,7 @@
</head>
<body>
+ <div id="reload-page" hidden></div>
<div id="loading-page" class="ds-center ds-loading-spinner" hidden>
<h3 id="loading-msg">Loading Directory Server Configuration...</h3>
<p><span class="spinner spinner-lg spinner-inline"></span></p>
diff --git a/src/cockpit/389-console/src/lib/database/backups.jsx b/src/cockpit/389-console/src/lib/database/backups.jsx
index 646fb95..6ddcc44 100644
--- a/src/cockpit/389-console/src/lib/database/backups.jsx
+++ b/src/cockpit/389-console/src/lib/database/backups.jsx
@@ -86,6 +86,7 @@ export class Backups extends React.Component {
this.setState({
showExportModal: true,
exportSpinner: false,
+ ldifName: "",
ldifSuffix: this.props.suffixes[0]
});
}
@@ -147,7 +148,8 @@ export class Backups extends React.Component {
showBackupModal () {
this.setState({
showBackupModal: true,
- backupSpinning: false
+ backupSpinning: false,
+ backupName: ""
});
}
@@ -289,10 +291,15 @@ export class Backups extends React.Component {
backupSpinning: true
});
- const cmd = [
+ let cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
- "backup", "create", this.state.backupName
+ "backup", "create"
];
+
+ if (this.state.backupName != "") {
+ cmd.push(this.state.backupName);
+ }
+
log_cmd("doBackup", "Add backup task", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -615,7 +622,7 @@ class ExportModal extends React.Component {
</Col>
</Row>
<p />
- <Row title="Name of exported LDIF file">
+ <Row title="Name of exported LDIF file, if left blank the data and time will be used as the file name">
<Col sm={3}>
<ControlLabel>LDIF File Name</ControlLabel>
</Col>
@@ -691,7 +698,7 @@ export class BackupModal extends React.Component {
</Modal.Header>
<Modal.Body>
<Form horizontal autoComplete="off">
- <Row title="LDIF file to import">
+ <Row title="Backup name, if left blank the date and time will be used as the name">
<Col sm={3}>
<ControlLabel>Backup Name</ControlLabel>
</Col>
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index 5481d1a..e14b92d 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -182,7 +182,7 @@ export class Plugins extends React.Component {
})
.fail(err => {
if (err != 0) {
- console.error("pluginList failed", err);
+ console.log("pluginList failed", err);
}
this.toggleLoading();
});
diff --git a/src/cockpit/389-console/src/servers.js b/src/cockpit/389-console/src/servers.js
index 4d1865c..f23b785 100644
--- a/src/cockpit/389-console/src/servers.js
+++ b/src/cockpit/389-console/src/servers.js
@@ -413,19 +413,35 @@ function do_backup(server_inst, backup_name) {
var cmd = ['status-dirsrv', server_inst];
$("#backup-spinner").show();
cockpit.spawn(cmd, { superuser: true}).
- done(function() {
- var cmd = [DSCONF, server_inst, 'backup', 'create', backup_name];
- log_cmd('#ds-backup-btn (click)', 'Backup server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
- done(function(data) {
- $("#backup-spinner").hide();
- popup_success("Backup has been created");
- $("#backup-form").modal('toggle');
- }).
- fail(function(data) {
- $("#backup-spinner").hide();
- popup_err("Failed to backup the server", data.message);
- })
+ done(function(status_data) {
+ var status_json = JSON.parse(status_data);
+ if (status_json.running == true) {
+ var cmd = [DSCONF, "-j", server_inst, 'backup', 'create', backup_name];
+ log_cmd('#ds-backup-btn (click)', 'Backup server instance', cmd);
+ cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
+ done(function(data) {
+ $("#backup-spinner").hide();
+ popup_success("Backup has been created");
+ $("#backup-form").modal('toggle');
+ }).
+ fail(function(data) {
+ $("#backup-spinner").hide();
+ popup_err("Failed to backup the server", data.message);
+ })
+ } else {
+ var cmd = [DSCTL, server_inst, 'db2bak', backup_name];
+ log_cmd('#ds-backup-btn (click)', 'Backup server instance (offline)', cmd);
+ cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).
+ done(function(data) {
+ $("#backup-spinner").hide();
+ popup_success("Backup has been created");
+ $("#backup-form").modal('toggle');
+ }).
+ fail(function(data) {
+ $("#backup-spinner").hide();
+ popup_err("Failed to backup the server", data.message);
+ });
+ }
}).
fail(function() {
var cmd = [DSCTL, server_inst, 'db2bak', backup_name];
@@ -466,7 +482,7 @@ $(document).ready( function() {
log_cmd('#start-server-btn (click)', 'Start server instance', cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
$("#start-instance-form").modal('toggle');
- load_config();
+ load_config(true);
popup_success("Started instance \"" + server_id + "\"");
}).fail(function(data) {
$("#start-instance-form").modal('toggle');
@@ -492,13 +508,13 @@ $(document).ready( function() {
document.getElementById("restart-server-btn").addEventListener("click", function() {
- $("#ds-restart-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Retarting instance <b>" + server_id + "</b>...");
+ $("#ds-restart-inst").html("<span class=\"spinner spinner-xs spinner-inline\"></span> Restarting instance <b>" + server_id + "</b>...");
$("#restart-instance-form").modal('toggle');
var cmd = [DSCTL, server_inst, 'restart'];
log_cmd('#restart-server-btn (click)', 'Restart server instance', cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
$("#restart-instance-form").modal('toggle');
- load_config();
+ load_config(true);
popup_success("Restarted instance \"" + server_id + "\"");
}).fail(function(data) {
$("#restart-instance-form").modal('toggle');
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
index 7535c06..64a40c1 100644
--- a/src/lib389/lib389/backend.py
+++ b/src/lib389/lib389/backend.py
@@ -480,8 +480,20 @@ class Backend(DSLdapObject):
:returns: DSLdapObject of the created entry
"""
+ # normalize suffix (remove spaces between comps)
+ if dn is not None:
+ dn_comps = ldap.dn.explode_dn(dn.lower())
+ dn = ",".join(dn_comps)
+
+ if properties is not None:
+ suffix_dn = properties['nsslapd-suffix'].lower()
+ dn_comps = ldap.dn.explode_dn(suffix_dn)
+ ndn = ",".join(dn_comps)
+ properties['nsslapd-suffix'] = ndn
+
sample_entries = properties.pop(BACKEND_SAMPLE_ENTRIES, False)
parent_suffix = properties.pop('parent', False)
+
# Okay, now try to make the backend.
super(Backend, self).create(dn, properties, basedn)
@@ -798,6 +810,8 @@ class Backends(DSLdapObjects):
task = ExportTask(self._instance)
task_properties = {'nsInstance': be_names}
+ if ldif == "":
+ ldif = None
if ldif is not None and not ldif.startswith("/"):
if ldif.endswith(".ldif"):
task_properties['nsFilename'] = os.path.join(self._instance.ds_paths.ldif_dir, ldif)
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
index dbc8aa6..18da186 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -376,9 +376,14 @@ def backend_get_tree(inst, basedn, log, args):
for be in be_insts:
suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
be_name = be.get_attr_val_utf8('cn')
- mt = be._mts.get(suffix)
+ try:
+ mt = be._mts.get(suffix)
+ except ldap.NO_SUCH_OBJECT:
+ log.debug("Failed to find the mapping tree entry using this suffix: {}".format(suffix))
+ continue
sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
if sub is not None:
+ # Skip sub suffixes for now, we will get them later
continue
nodes.append(build_node(suffix, be_name))
diff --git a/src/lib389/lib389/pwpolicy.py b/src/lib389/lib389/pwpolicy.py
index d665d1f..2221958 100644
--- a/src/lib389/lib389/pwpolicy.py
+++ b/src/lib389/lib389/pwpolicy.py
@@ -27,48 +27,48 @@ class PwPolicyManager(object):
def __init__(self, instance):
self._instance = instance
self.log = instance.log
- self.pwp_attributes = [
- 'passwordstoragescheme',
- 'passwordChange',
- 'passwordMustChange',
- 'passwordHistory',
- 'passwordInHistory',
- 'passwordAdminDN',
- 'passwordTrackUpdateTime',
- 'passwordWarning',
- 'passwordMaxAge',
- 'passwordMinAge',
- 'passwordExp',
- 'passwordGraceLimit',
- 'passwordSendExpiringTime',
- 'passwordLockout',
- 'passwordUnlock',
- 'passwordMaxFailure',
- 'passwordLockoutDuration',
- 'passwordResetFailureCount',
- 'passwordCheckSyntax',
- 'passwordMinLength',
- 'passwordMinDigits',
- 'passwordMinAlphas',
- 'passwordMinUppers',
- 'passwordMinLowers',
- 'passwordMinSpecials',
- 'passwordMaxRepeats',
- 'passwordMin8bit',
- 'passwordMinCategories',
- 'passwordMinTokenLength',
- 'passwordDictPath',
- 'passwordDictCheck',
- 'passwordPalindrome',
- 'passwordMaxSequence',
- 'passwordMaxClassChars',
- 'passwordMaxSeqSets',
- 'passwordBadWords',
- 'passwordUserAttributes',
- 'passwordIsGlobalPolicy',
- 'nsslapd-pwpolicy-local',
- 'nsslapd-allow-hashed-passwords'
- ]
+ self.arg_to_attr = {
+ 'pwdlocal': 'nsslapd-pwpolicy-local',
+ 'pwdscheme': 'passwordstoragescheme',
+ 'pwdchange': 'passwordChange',
+ 'pwdmustchange': 'passwordMustChange',
+ 'pwdhistory': 'passwordHistory',
+ 'pwdhistorycount': 'passwordInHistory',
+ 'pwdadmin': 'passwordAdminDN',
+ 'pwdtrack': 'passwordTrackUpdateTime',
+ 'pwdwarning': 'passwordWarning',
+ 'pwdisglobal': 'passwordIsGlobalPolicy',
+ 'pwdexpire': 'passwordExp',
+ 'pwdmaxage': 'passwordMaxAge',
+ 'pwdminage': 'passwordMinAge',
+ 'pwdgracelimit': 'passwordGraceLimit',
+ 'pwdsendexpiring': 'passwordSendExpiringTime',
+ 'pwdlockout': 'passwordLockout',
+ 'pwdunlock': 'passwordUnlock',
+ 'pwdlockoutduration': 'passwordLockoutDuration',
+ 'pwdmaxfailures': 'passwordMaxFailure',
+ 'pwdresetfailcount': 'passwordResetFailureCount',
+ 'pwdchecksyntax': 'passwordCheckSyntax',
+ 'pwdminlen': 'passwordMinLength',
+ 'pwdmindigits': 'passwordMinDigits',
+ 'pwdminalphas': 'passwordMinAlphas',
+ 'pwdminuppers': 'passwordMinUppers',
+ 'pwdminlowers': 'passwordMinLowers',
+ 'pwdminspecials': 'passwordMinSpecials',
+ 'pwdmin8bits': 'passwordMin8bit',
+ 'pwdmaxrepeats': 'passwordMaxRepeats',
+ 'pwdpalindrome': 'passwordPalindrome',
+ 'pwdmaxseq': 'passwordMaxSequence',
+ 'pwdmaxseqsets': 'passwordMaxSeqSets',
+ 'pwdmaxclasschars': 'passwordMaxClassChars',
+ 'pwdmincatagories': 'passwordMinCategories',
+ 'pwdmintokenlen': 'passwordMinTokenLength',
+ 'pwdbadwords': 'passwordBadWords',
+ 'pwduserattrs': 'passwordUserAttributes',
+ 'pwddictcheck': 'passwordDictCheck',
+ 'pwddictpath': 'passwordDictPath',
+ 'pwdallowhash': 'nsslapd-allow-hashed-passwords'
+ }
def is_user_policy(self, dn):
"""Check if the entry has a user password policy
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 50300 - Fix memory leak in automember plugin
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 502281f Ticket 50300 - Fix memory leak in automember plugin
502281f is described below
commit 502281ff6ec0c866281e06adf4bec74062c64752
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Fri Mar 22 16:27:15 2019 -0400
Ticket 50300 - Fix memory leak in automember plugin
Description: We were allocating a pblock long before it was used, and
we were returning from the function on an error before we
freed it. The fix just allocates the pblock right before
it's used, and then it is properly freed.
https://pagure.io/389-ds-base/issue/50300
Reviewed by: mreynolds (one line commit rule)
(cherry picked from commit 37f919a79a719c485742bb0bc2e09d8b2018a2b6)
---
ldap/servers/plugins/automember/automember.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
index fcf0cdb..24fd874 100644
--- a/ldap/servers/plugins/automember/automember.c
+++ b/ldap/servers/plugins/automember/automember.c
@@ -1628,7 +1628,7 @@ out:
static int
automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd, int add)
{
- Slapi_PBlock *mod_pb = slapi_pblock_new();
+ Slapi_PBlock *mod_pb = NULL;
int result = LDAP_SUCCESS;
LDAPMod mod;
LDAPMod *mods[2];
@@ -1708,6 +1708,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
member_value, grouping_attr, group_dn);
}
+ mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, group_dn,
mods, 0, 0, automember_get_plugin_id(), 0);
slapi_modify_internal_pb(mod_pb);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50300 - Fix memory leak in automember plugin
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new d55de4d Ticket 50300 - Fix memory leak in automember plugin
d55de4d is described below
commit d55de4d59ae5cca061c1f61e1a3378291d3a0255
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Fri Mar 22 16:27:15 2019 -0400
Ticket 50300 - Fix memory leak in automember plugin
Description: We were allocating a pblock long before it was used, and
we were returning from the function on an error before we
freed it. The fix just allocates the pblock right before
it's used, and then it is properly freed.
https://pagure.io/389-ds-base/issue/50300
Reviewed by: mreynolds (one line commit rule)
(cherry picked from commit 37f919a79a719c485742bb0bc2e09d8b2018a2b6)
---
ldap/servers/plugins/automember/automember.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
index fcf0cdb..24fd874 100644
--- a/ldap/servers/plugins/automember/automember.c
+++ b/ldap/servers/plugins/automember/automember.c
@@ -1628,7 +1628,7 @@ out:
static int
automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd, int add)
{
- Slapi_PBlock *mod_pb = slapi_pblock_new();
+ Slapi_PBlock *mod_pb = NULL;
int result = LDAP_SUCCESS;
LDAPMod mod;
LDAPMod *mods[2];
@@ -1708,6 +1708,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
member_value, grouping_attr, group_dn);
}
+ mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, group_dn,
mods, 0, 0, automember_get_plugin_id(), 0);
slapi_modify_internal_pb(mod_pb);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch master updated: Ticket 50300 - Fix memory leak in automember plugin
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch master
in repository 389-ds-base.
The following commit(s) were added to refs/heads/master by this push:
new 37f919a Ticket 50300 - Fix memory leak in automember plugin
37f919a is described below
commit 37f919a79a719c485742bb0bc2e09d8b2018a2b6
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Fri Mar 22 16:27:15 2019 -0400
Ticket 50300 - Fix memory leak in automember plugin
Description: We were allocating a pblock long before it was used, and
we were returning from the function on an error before we
freed it. The fix just allocates the pblock right before
it's used, and then it is properly freed.
https://pagure.io/389-ds-base/issue/50300
Reviewed by: mreynolds (one line commit rule)
---
ldap/servers/plugins/automember/automember.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
index fcf0cdb..24fd874 100644
--- a/ldap/servers/plugins/automember/automember.c
+++ b/ldap/servers/plugins/automember/automember.c
@@ -1628,7 +1628,7 @@ out:
static int
automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd, int add)
{
- Slapi_PBlock *mod_pb = slapi_pblock_new();
+ Slapi_PBlock *mod_pb = NULL;
int result = LDAP_SUCCESS;
LDAPMod mod;
LDAPMod *mods[2];
@@ -1708,6 +1708,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
member_value, grouping_attr, group_dn);
}
+ mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, group_dn,
mods, 0, 0, automember_get_plugin_id(), 0);
slapi_modify_internal_pb(mod_pb);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[lib389] branch master updated: Add deprecation notice
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mhonek pushed a commit to branch master
in repository lib389.
The following commit(s) were added to refs/heads/master by this push:
new 9f0eb93 Add deprecation notice
9f0eb93 is described below
commit 9f0eb933bc166b9522e1d0bb967d97627ba5a84f
Author: Matúš Honěk <mhonek(a)redhat.com>
AuthorDate: Thu Mar 21 16:06:16 2019 +0100
Add deprecation notice
---
README.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/README.md b/README.md
index 95d8df0..d0c8be3 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,10 @@
+## Attention: Repository in read-only mode
+*lib389* has been merged into *389-ds-base* project. If you encounter issues or want to contribute in general, please, file a new issue with [389-ds-base issue tracker](https://pagure.io/389-ds-base/new_issue).
+
+- - -
+- - -
+- - -
+
Lib389
======
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 50265: the warning about skew time could last forever
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
lkrispen pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 68f791e Ticket 50265: the warning about skew time could last forever
68f791e is described below
commit 68f791e9a3b6ee77185c74845c4d967eb67e8aa0
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
AuthorDate: Wed Mar 20 12:00:42 2019 +0100
Ticket 50265: the warning about skew time could last forever
Bug: if the local system time is set back more than 300 seconds
a worning about too much time skew is logged and the sampled
time is updated. This adjustment is done at every write operation
and can increase the time skew and be logged infinitely
Fix: the intention of the adjustment was to avoid a roll over of seq_num
if the sampled time is not increased for more than 65k oberations.
But this is already handled with an explicite check for seq_num
rollover. The extra adjustment for negative time skew can be removed.
Reviewed by: Thierry, William. Thanks.
---
ldap/servers/slapd/csngen.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/ldap/servers/slapd/csngen.c b/ldap/servers/slapd/csngen.c
index 3afc917..68dbbda 100644
--- a/ldap/servers/slapd/csngen.c
+++ b/ldap/servers/slapd/csngen.c
@@ -191,22 +191,14 @@ csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify)
slapi_rwlock_unlock(gen->lock);
return rc;
}
- } else if (delta < -300) {
- /*
- * The maxseqnum could support up to 65535 CSNs per second.
- * That means that we could avoid duplicated CSN's for
- * delta up to 300 secs if update rate is 200/sec (usually
- * the max rate is below 20/sec).
- * Beyond 300 secs, we advance gen->state.sampled_time by
- * one sec to recycle seqnum.
- */
- slapi_log_err(SLAPI_LOG_WARNING, "csngen_new_csn", "Too much time skew (%d secs). Current seqnum=%0x\n", delta, gen->state.seq_num);
- rc = _csngen_adjust_local_time(gen, gen->state.sampled_time + 1);
- if (rc != CSN_SUCCESS) {
- slapi_rwlock_unlock(gen->lock);
- return rc;
- }
}
+ /* if (delta < 0) this means the local system time was set back
+ * the new csn will be generated based on sampled time, which is
+ * ahead of system time and previously generated csns.
+ * the time stamp of the csn will not change until system time
+ * catches up or is corrected by remote csns.
+ * But we need to ensure that the seq_num does not overflow.
+ */
if (gen->state.seq_num == CSN_MAX_SEQNUM) {
slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn", "Sequence rollover; "
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50265: the warning about skew time could last forever
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
lkrispen pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new c01d34c Ticket 50265: the warning about skew time could last forever
c01d34c is described below
commit c01d34cf88028ae557cfb9372ce275ae525d2835
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
AuthorDate: Wed Mar 20 12:00:42 2019 +0100
Ticket 50265: the warning about skew time could last forever
Bug: if the local system time is set back more than 300 seconds
a worning about too much time skew is logged and the sampled
time is updated. This adjustment is done at every write operation
and can increase the time skew and be logged infinitely
Fix: the intention of the adjustment was to avoid a roll over of seq_num
if the sampled time is not increased for more than 65k oberations.
But this is already handled with an explicite check for seq_num
rollover. The extra adjustment for negative time skew can be removed.
Reviewed by: Thierry, William. Thanks.
---
ldap/servers/slapd/csngen.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/ldap/servers/slapd/csngen.c b/ldap/servers/slapd/csngen.c
index 3afc917..68dbbda 100644
--- a/ldap/servers/slapd/csngen.c
+++ b/ldap/servers/slapd/csngen.c
@@ -191,22 +191,14 @@ csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify)
slapi_rwlock_unlock(gen->lock);
return rc;
}
- } else if (delta < -300) {
- /*
- * The maxseqnum could support up to 65535 CSNs per second.
- * That means that we could avoid duplicated CSN's for
- * delta up to 300 secs if update rate is 200/sec (usually
- * the max rate is below 20/sec).
- * Beyond 300 secs, we advance gen->state.sampled_time by
- * one sec to recycle seqnum.
- */
- slapi_log_err(SLAPI_LOG_WARNING, "csngen_new_csn", "Too much time skew (%d secs). Current seqnum=%0x\n", delta, gen->state.seq_num);
- rc = _csngen_adjust_local_time(gen, gen->state.sampled_time + 1);
- if (rc != CSN_SUCCESS) {
- slapi_rwlock_unlock(gen->lock);
- return rc;
- }
}
+ /* if (delta < 0) this means the local system time was set back
+ * the new csn will be generated based on sampled time, which is
+ * ahead of system time and previously generated csns.
+ * the time stamp of the csn will not change until system time
+ * catches up or is corrected by remote csns.
+ * But we need to ensure that the seq_num does not overflow.
+ */
if (gen->state.seq_num == CSN_MAX_SEQNUM) {
slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn", "Sequence rollover; "
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 50260 - Invalid cache flushing improvements
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 9901025 Ticket 50260 - Invalid cache flushing improvements
9901025 is described below
commit 99010255ee5dc6bec1eeae4f9378eafe71ccc7a6
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Sun Mar 17 13:09:07 2019 -0400
Ticket 50260 - Invalid cache flushing improvements
Description: The original version of the fix only checked if backend
transaction "post" operation plugins failed, but it did
not check for errors from the backend transaction "pre"
operation plugin. To address this we flush invalid
entries whenever any error occurs.
We were also not flushing invalid cache entries when
modrdn errors occurred. Modrdns only make changes to
the DN hashtable inside the entry cache, but we were only
checking the ID hashtable. So we also need to check the
DN hashtable in the entry cache for invalid entries.
https://pagure.io/389-ds-base/issue/50260
Reviewed by: firstyear & tbordaz(Thanks!!)
(cherry picked from commit 33fbced25277b88695bfba7262e606380e9d891f)
---
dirsrvtests/tests/suites/betxns/betxn_test.py | 23 +++++++++------
ldap/servers/slapd/back-ldbm/cache.c | 42 +++++++++++++++++++++++++--
ldap/servers/slapd/back-ldbm/ldbm_add.c | 9 +++---
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 11 +++----
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 10 +++----
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 10 +++----
6 files changed, 74 insertions(+), 31 deletions(-)
diff --git a/dirsrvtests/tests/suites/betxns/betxn_test.py b/dirsrvtests/tests/suites/betxns/betxn_test.py
index f03fb93..84f5e20 100644
--- a/dirsrvtests/tests/suites/betxns/betxn_test.py
+++ b/dirsrvtests/tests/suites/betxns/betxn_test.py
@@ -86,9 +86,7 @@ def test_betxt_7bit(topology_st, dynamic_plugins):
log.fatal('Error while searching for test entry: ' + e.message['desc'])
assert False
- #
# Cleanup - remove the user
- #
try:
topology_st.standalone.delete_s(USER_DN)
except ldap.LDAPError as e:
@@ -241,14 +239,15 @@ def test_betxn_memberof(topology_st, dynamic_plugins):
except ldap.LDAPError as e:
log.info('test_betxn_memberof: Group2 was correctly rejected (mod add): error ' + e.message['desc'])
- #
+ # verify entry cache reflects the current/correct state of group1
+ assert not group1.is_member(group2.dn)
+
# Done
- #
log.info('test_betxn_memberof: PASSED')
def test_betxn_modrdn_memberof_cache_corruption(topology_st):
- """Test modrdn operations and memberOf
+ """Test modrdn operations and memberOf be txn post op failures
:id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
@@ -297,9 +296,7 @@ def test_betxn_modrdn_memberof_cache_corruption(topology_st):
with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group.rename('cn=group_to_people', newsuperior=peoplebase)
- #
# Done
- #
log.info('test_betxn_modrdn_memberof: PASSED')
@@ -374,15 +371,23 @@ def test_ri_and_mep_cache_corruption(topology_st):
log.fatal("MEP group was not created for the user")
assert False
+ # Test MEP be txn pre op failure does not corrupt entry cache
+ # Should get the same exception for both rename attempts
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
+ mep_group.rename("cn=modrdn group")
+
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
+ mep_group.rename("cn=modrdn group")
+
# Mess with MEP so it fails
mep_plugin.disable()
mep_group.delete()
mep_plugin.enable()
- # Add another group for verify entry cache is not corrupted
+ # Add another group to verify entry cache is not corrupted
test_group = groups.create(properties={'cn': 'test_group'})
- # Delete user, should fail, and user should still be a member
+ # Delete user, should fail in MEP be txn post op, and user should still be a member
with pytest.raises(ldap.NO_SUCH_OBJECT):
user.delete()
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index 458d791..02453ab 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -517,7 +517,8 @@ flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
/*
* Flush all the cache entries that were added after the "start time"
* This is called when a backend transaction plugin fails, and we need
- * to remove all the possible invalid entries in the cache.
+ * to remove all the possible invalid entries in the cache. We need
+ * to check both the ID and DN hashtables when checking the entry cache.
*
* If the ref count is 0, we can straight up remove it from the cache, but
* if the ref count is greater than 1, then the entry is currently in use.
@@ -528,8 +529,8 @@ flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
static void
flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
{
+ Hashtable *ht = cache->c_idtable; /* start with the ID table as it's in both ENTRY and DN caches */
void *e, *laste = NULL;
- Hashtable *ht = cache->c_idtable;
cache_lock(cache);
@@ -570,6 +571,43 @@ flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
}
}
+ if (type == ENTRY_CACHE) {
+ /* Also check the DN hashtable */
+ ht = cache->c_dntable;
+
+ for (size_t i = 0; i < ht->size; i++) {
+ e = ht->slot[i];
+ while (e) {
+ struct backcommon *entry = (struct backcommon *)e;
+ uint64_t remove_it = 0;
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
+ /* Mark the entry to be removed */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[ENTRY CACHE] Removing entry id (%d)\n",
+ entry->ep_id);
+ remove_it = 1;
+ }
+ laste = e;
+ e = HASH_NEXT(ht, e);
+
+ if (remove_it) {
+ /* since we have the cache lock we know we can trust refcnt */
+ entry->ep_state |= ENTRY_STATE_INVALID;
+ if (entry->ep_refcnt == 0) {
+ entry->ep_refcnt++;
+ lru_delete(cache, laste);
+ entrycache_remove_int(cache, laste);
+ entrycache_return(cache, (struct backentry **)&laste);
+ } else {
+ /* Entry flagged for removal */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
+ "[ENTRY CACHE] Flagging entry to be removed later: id (%d) refcnt: %d\n",
+ entry->ep_id, entry->ep_refcnt);
+ }
+ }
+ }
+ }
+ }
+
cache_unlock(cache);
}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index aa5b59a..264f0ce 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -1221,11 +1221,6 @@ ldbm_back_add(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
@@ -1253,6 +1248,10 @@ ldbm_back_add(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
if (addingentry_id_assigned) {
next_id_return(be, addingentry->ep_id);
}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 3f687eb..1ad8464 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -1279,11 +1279,6 @@ replace_entry:
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
if (parent_found) {
@@ -1370,6 +1365,11 @@ commit_return:
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
if (tombstone) {
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
@@ -1388,6 +1388,7 @@ error_return:
CACHE_RETURN(&inst->inst_cache, &tombstone);
tombstone = NULL;
}
+
if (retval == DB_RUNRECOVERY) {
dblayer_remember_disk_filled(li);
ldbm_nasty("ldbm_back_delete", "Delete", 79, retval);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index b90b3e0..b0c477e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -873,11 +873,6 @@ ldbm_back_modify(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN);
@@ -901,6 +896,11 @@ ldbm_back_modify(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
if (postentry != NULL) {
slapi_entry_free(postentry);
postentry = NULL;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 73e50eb..65610d6 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -1217,11 +1217,6 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN);
@@ -1290,6 +1285,11 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
/* result already sent above - just free stuff */
if (postentry) {
slapi_entry_free(postentry);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50260 - Invalid cache flushing improvements
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 67aaee4 Ticket 50260 - Invalid cache flushing improvements
67aaee4 is described below
commit 67aaee4708765945f5935ed12ddfbeb973fd1f5a
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Sun Mar 17 13:09:07 2019 -0400
Ticket 50260 - Invalid cache flushing improvements
Description: The original version of the fix only checked if backend
transaction "post" operation plugins failed, but it did
not check for errors from the backend transaction "pre"
operation plugin. To address this we flush invalid
entries whenever any error occurs.
We were also not flushing invalid cache entries when
modrdn errors occurred. Modrdns only make changes to
the DN hashtable inside the entry cache, but we were only
checking the ID hashtable. So we also need to check the
DN hashtable in the entry cache for invalid entries.
https://pagure.io/389-ds-base/issue/50260
Reviewed by: firstyear & tbordaz(Thanks!!)
(cherry picked from commit 33fbced25277b88695bfba7262e606380e9d891f)
---
dirsrvtests/tests/suites/betxns/betxn_test.py | 51 ++++++++++++---------------
ldap/servers/slapd/back-ldbm/cache.c | 42 ++++++++++++++++++++--
ldap/servers/slapd/back-ldbm/ldbm_add.c | 9 +++--
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 11 +++---
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 10 +++---
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 10 +++---
6 files changed, 82 insertions(+), 51 deletions(-)
diff --git a/dirsrvtests/tests/suites/betxns/betxn_test.py b/dirsrvtests/tests/suites/betxns/betxn_test.py
index 2aaddde..94e6081 100644
--- a/dirsrvtests/tests/suites/betxns/betxn_test.py
+++ b/dirsrvtests/tests/suites/betxns/betxn_test.py
@@ -57,24 +57,20 @@ def test_betxt_7bit(topology_st):
user = users.create(properties=TEST_USER_PROPERTIES)
# Attempt a modrdn, this should fail
-
- try:
+ with pytest.raises(ldap.LDAPError):
user.rename(BAD_RDN)
- log.fatal('test_betxt_7bit: Modrdn operation incorrectly succeeded')
- assert False
- except ldap.LDAPError as e:
- log.info('Modrdn failed as expected: error %s' % str(e))
# Make sure the operation did not succeed, attempt to search for the new RDN
+ with pytest.raises(ldap.LDAPError):
+ users.get(u'Fu\u00c4\u00e8')
+ # Make sure original entry is present
user_check = users.get("testuser")
-
assert user_check.dn.lower() == user.dn.lower()
- #
# Cleanup - remove the user
- #
user.delete()
+
log.info('test_betxt_7bit: PASSED')
@@ -153,17 +149,11 @@ def test_betxn_memberof(topology_st):
memberof = MemberOfPlugin(topology_st.standalone)
memberof.enable()
memberof.set_autoaddoc('referral')
- # memberof.add_groupattr('member') # This is already the default.
topology_st.standalone.restart()
groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
- group1 = groups.create(properties={
- 'cn': 'group1',
- })
-
- group2 = groups.create(properties={
- 'cn': 'group2',
- })
+ group1 = groups.create(properties={'cn': 'group1'})
+ group2 = groups.create(properties={'cn': 'group2'})
# We may need to mod groups to not have nsMemberOf ... ?
if not ds_is_older('1.3.7'):
@@ -171,21 +161,18 @@ def test_betxn_memberof(topology_st):
group2.remove('objectClass', 'nsMemberOf')
# Add group2 to group1 - it should fail with objectclass violation
- try:
+ with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group1.add_member(group2.dn)
- log.fatal('test_betxn_memberof: Group2 was incorrectly allowed to be added to group1')
- assert False
- except ldap.LDAPError as e:
- log.info('test_betxn_memberof: Group2 was correctly rejected (mod add): error: ' + str(e))
- #
+ # verify entry cache reflects the current/correct state of group1
+ assert not group1.is_member(group2.dn)
+
# Done
- #
log.info('test_betxn_memberof: PASSED')
def test_betxn_modrdn_memberof_cache_corruption(topology_st):
- """Test modrdn operations and memberOf
+ """Test modrdn operations and memberOf be txn post op failures
:id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
@@ -234,9 +221,7 @@ def test_betxn_modrdn_memberof_cache_corruption(topology_st):
with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group.rename('cn=group_to_people', newsuperior=peoplebase)
- #
# Done
- #
log.info('test_betxn_modrdn_memberof: PASSED')
@@ -311,15 +296,23 @@ def test_ri_and_mep_cache_corruption(topology_st):
log.fatal("MEP group was not created for the user")
assert False
+ # Test MEP be txn pre op failure does not corrupt entry cache
+ # Should get the same exception for both rename attempts
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
+ mep_group.rename("cn=modrdn group")
+
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
+ mep_group.rename("cn=modrdn group")
+
# Mess with MEP so it fails
mep_plugin.disable()
mep_group.delete()
mep_plugin.enable()
- # Add another group for verify entry cache is not corrupted
+ # Add another group to verify entry cache is not corrupted
test_group = groups.create(properties={'cn': 'test_group'})
- # Delete user, should fail, and user should still be a member
+ # Delete user, should fail in MEP be txn post op, and user should still be a member
with pytest.raises(ldap.NO_SUCH_OBJECT):
user.delete()
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index ba9d26f..a03cdaa 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -517,7 +517,8 @@ flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
/*
* Flush all the cache entries that were added after the "start time"
* This is called when a backend transaction plugin fails, and we need
- * to remove all the possible invalid entries in the cache.
+ * to remove all the possible invalid entries in the cache. We need
+ * to check both the ID and DN hashtables when checking the entry cache.
*
* If the ref count is 0, we can straight up remove it from the cache, but
* if the ref count is greater than 1, then the entry is currently in use.
@@ -528,8 +529,8 @@ flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
static void
flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
{
+ Hashtable *ht = cache->c_idtable; /* start with the ID table as it's in both ENTRY and DN caches */
void *e, *laste = NULL;
- Hashtable *ht = cache->c_idtable;
cache_lock(cache);
@@ -570,6 +571,43 @@ flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
}
}
+ if (type == ENTRY_CACHE) {
+ /* Also check the DN hashtable */
+ ht = cache->c_dntable;
+
+ for (size_t i = 0; i < ht->size; i++) {
+ e = ht->slot[i];
+ while (e) {
+ struct backcommon *entry = (struct backcommon *)e;
+ uint64_t remove_it = 0;
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
+ /* Mark the entry to be removed */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[ENTRY CACHE] Removing entry id (%d)\n",
+ entry->ep_id);
+ remove_it = 1;
+ }
+ laste = e;
+ e = HASH_NEXT(ht, e);
+
+ if (remove_it) {
+ /* since we have the cache lock we know we can trust refcnt */
+ entry->ep_state |= ENTRY_STATE_INVALID;
+ if (entry->ep_refcnt == 0) {
+ entry->ep_refcnt++;
+ lru_delete(cache, laste);
+ entrycache_remove_int(cache, laste);
+ entrycache_return(cache, (struct backentry **)&laste);
+ } else {
+ /* Entry flagged for removal */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
+ "[ENTRY CACHE] Flagging entry to be removed later: id (%d) refcnt: %d\n",
+ entry->ep_id, entry->ep_refcnt);
+ }
+ }
+ }
+ }
+ }
+
cache_unlock(cache);
}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index 8c0439c..0d82ae9 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -1221,11 +1221,6 @@ ldbm_back_add(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
@@ -1253,6 +1248,10 @@ ldbm_back_add(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
if (addingentry_id_assigned) {
next_id_return(be, addingentry->ep_id);
}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 98b3d82..e9f3e32 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -1279,11 +1279,6 @@ replace_entry:
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
if (parent_found) {
@@ -1370,6 +1365,11 @@ commit_return:
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
if (tombstone) {
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
@@ -1388,6 +1388,7 @@ error_return:
CACHE_RETURN(&inst->inst_cache, &tombstone);
tombstone = NULL;
}
+
if (retval == DB_RUNRECOVERY) {
dblayer_remember_disk_filled(li);
ldbm_nasty("ldbm_back_delete", "Delete", 79, retval);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index b90b3e0..b0c477e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -873,11 +873,6 @@ ldbm_back_modify(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN);
@@ -901,6 +896,11 @@ ldbm_back_modify(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
if (postentry != NULL) {
slapi_entry_free(postentry);
postentry = NULL;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 73e50eb..65610d6 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -1217,11 +1217,6 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
-
- /* Revert the caches if this is the parent operation */
- if (parent_op) {
- revert_cache(inst, &parent_time);
- }
goto error_return;
}
retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN);
@@ -1290,6 +1285,11 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
+
/* result already sent above - just free stuff */
if (postentry) {
slapi_entry_free(postentry);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years, 1 month