summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/roles/roles_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/roles/roles_cache.c')
-rw-r--r--ldap/servers/plugins/roles/roles_cache.c2061
1 files changed, 2061 insertions, 0 deletions
diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c
new file mode 100644
index 00000000..f4dc31c2
--- /dev/null
+++ b/ldap/servers/plugins/roles/roles_cache.c
@@ -0,0 +1,2061 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* This is naughty ... */
+#include "slapi-private.h"
+
+/* include NSPR header files */
+#include "slap.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+#include "avl.h"
+#include "vattr_spi.h"
+#include "roles_cache.h"
+#include "views.h"
+
+#ifdef SOLARIS
+#include <tnf/probe.h>
+#else
+#define TNF_PROBE_0(a,b,c)
+#endif
+
+#define MAX_NESTED_ROLES 30
+
+static char *allUserAttributes[] = {
+ LDAP_ALL_USER_ATTRS,
+ NULL
+};
+
+/* views scoping */
+static void **views_api;
+
+/* Service provider handler */
+static vattr_sp_handle *vattr_handle = NULL;
+
+/* List of nested roles */
+typedef struct _role_object_nested {
+ Slapi_DN *dn; /* value of attribute nsroledn in a nested role definition */
+} role_object_nested;
+
+/* Role object structure */
+typedef struct _role_object {
+ Slapi_DN *dn; /* dn of a role entry */
+ int type; /* ROLE_TYPE_MANAGED|ROLE_TYPE_FILTERED|ROLE_TYPE_NESTED */
+ Slapi_Filter *filter; /* if ROLE_TYPE_FILTERED */
+ Avlnode *avl_tree; /* if ROLE_TYPE_NESTED: tree of nested DNs (avl_data is a role_object_nested struct) */
+} role_object;
+
+/* Structure containing the roles definitions for a given suffix */
+typedef struct _roles_cache_def {
+
+ /* Suffix DN*/
+ Slapi_DN *suffix_dn;
+
+ /* Module level thread control */
+ PRThread *roles_tid;
+ int keeprunning;
+
+ Slapi_Mutex *cache_lock;
+ Slapi_Mutex *stop_lock;
+
+ Slapi_Mutex *change_lock;
+ Slapi_CondVar *something_changed;
+
+ Slapi_Mutex *create_lock;
+ Slapi_CondVar *suffix_created;
+ int is_ready;
+
+ /* Root of the avl tree containing all the roles definitions
+ NB: avl_data field is of type role_object
+ */
+ Avlnode *avl_tree;
+
+ /* Next roles suffix definitions */
+ struct _roles_cache_def *next;
+
+ /* Info passed from the server when an notification is sent to the plugin */
+ char *notified_dn;
+ Slapi_Entry *notified_entry;
+ int notified_operation;
+
+} roles_cache_def;
+
+
+/* Global list containing all the roles definitions per suffix */
+static roles_cache_def *roles_list = NULL;
+
+static PRRWLock *global_lock = NULL;
+
+/* Structure holding the nsrole values */
+typedef struct _roles_cache_build_result
+{
+ Slapi_ValueSet **nsrole_values; /* nsrole computed values */
+ Slapi_Entry *requested_entry; /* entry to get nsrole from */
+ int has_value; /* flag to determine if a new value has been added to the result */
+ int need_value; /* flag to determine if we need the result */
+} roles_cache_build_result;
+
+/* Structure used to check if is_entry_member_of is part of a role defined in its suffix */
+typedef struct _roles_cache_search_in_nested
+{
+ Slapi_Entry *is_entry_member_of;
+ int present; /* flag to know if the entry is part of a role */
+ int hint; /* to check the depth of the nested */
+} roles_cache_search_in_nested;
+
+/* Structure used to handle roles searches */
+typedef struct _roles_cache_search_roles
+{
+ roles_cache_def *suffix_def;
+ int rc; /* to check the depth of the nested */
+} roles_cache_search_roles;
+
+static roles_cache_def* roles_cache_create_suffix(Slapi_DN *sdn);
+static int roles_cache_add_roles_from_suffix(Slapi_DN *suffix_dn, roles_cache_def *suffix_def);
+static void roles_cache_wait_on_change(void * arg);
+static void roles_cache_trigger_update_suffix(void *handle, char *be_name, int old_be_state, int new_be_state);
+static void roles_cache_trigger_update_role(char *dn, Slapi_Entry *role_entry, Slapi_DN *be_dn, int operation);
+static int roles_cache_update(roles_cache_def *suffix_to_update);
+static int roles_get_roles_from_entry(Slapi_DN * suffix, Slapi_PBlock **int_search_pb);
+static int roles_cache_create_role_under(roles_cache_def** roles_cache_suffix, Slapi_Entry *entry);
+static int roles_cache_create_object_from_entry(Slapi_Entry *role_entry, role_object **result, int hint);
+static int roles_cache_determine_class(Slapi_Entry *role_entry);
+static int roles_cache_node_cmp( caddr_t d1, caddr_t d2 );
+static int roles_cache_insert_object(Avlnode **tree, role_object *object);
+static int roles_cache_node_nested_cmp( caddr_t d1, caddr_t d2 );
+static int roles_cache_insert_object_nested(Avlnode **tree, role_object_nested *object);
+static int roles_cache_object_nested_from_dn(Slapi_DN *role_dn, role_object_nested **result);
+static int roles_cache_build_nsrole( caddr_t data, caddr_t arg );
+static int roles_cache_find_node( caddr_t d1, caddr_t d2 );
+static int roles_cache_find_roles_in_suffix(Slapi_DN *target_entry_dn, roles_cache_def **list_of_roles);
+static int roles_is_entry_member_of_object(caddr_t data, caddr_t arg );
+static int roles_check_managed(Slapi_Entry *entry_to_check, role_object *role, int *present);
+static int roles_check_filtered(Slapi_Entry *entry_to_check, role_object *role, int *present);
+static int roles_check_nested(caddr_t data, caddr_t arg);
+static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn);
+static void berval_set_string(struct berval *bv, const char* string);
+static void roles_cache_role_def_delete(roles_cache_def *role_def);
+static void roles_cache_role_def_free(roles_cache_def *role_def);
+static void roles_cache_role_object_free(role_object *this_role);
+static void roles_cache_role_object_nested_free(role_object_nested *this_role);
+static int roles_cache_dump( caddr_t data, caddr_t arg );
+static int roles_cache_add_entry_cb(Slapi_Entry* e, void *callback_data);
+static void roles_cache_result_cb( int rc, void *callback_data);
+static Slapi_DN* roles_cache_get_top_suffix(Slapi_DN *suffix);
+
+/* ============== FUNCTIONS ================ */
+
+/* roles_cache_init
+ ----------------
+ create the cache for all the existing suffixes
+ starts up the threads which wait for changes
+ also registers vattr callbacks
+
+ return 0 if OK
+ return -1 otherwise
+*/
+int roles_cache_init()
+{
+ int rc = 0;
+ void *node = NULL;
+ Slapi_DN *sdn = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_init\n");
+
+ if ( global_lock == NULL )
+ {
+ global_lock = PR_NewRWLock(0,"roles_cache");
+ }
+
+ /* grab the views interface */
+ if(slapi_apib_get_interface(Views_v1_0_GUID, &views_api))
+ {
+ /* lets be tolerant if views is disabled */
+ views_api = 0;
+ }
+
+ /* For each top suffix, get the roles definitions defined below it */
+ PR_RWLock_Wlock(global_lock);
+
+ sdn = slapi_get_first_suffix(&node, 0);
+ while (sdn)
+ {
+
+ if ( (new_suffix = roles_cache_create_suffix(sdn)) == NULL )
+ {
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+
+ if ( roles_cache_add_roles_from_suffix(sdn, new_suffix) != 0 )
+ {
+ /* No roles in that suffix, stop the thread and remove it ? */
+ }
+ sdn = slapi_get_next_suffix(&node, 0);
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ /* to expose roles_check to ACL plugin */
+ slapi_register_role_check(roles_check);
+
+ /* Register a callback on backends creation|modification|deletion,
+ so that we update the corresponding cache */
+ slapi_register_backend_state_change(NULL, roles_cache_trigger_update_suffix);
+
+ if ( slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
+ roles_sp_get_value,
+ roles_sp_compare_value,
+ roles_sp_list_types) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_init: slapi_vattrspi_register failed\n");
+
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+ else if ( slapi_vattrspi_regattr(vattr_handle,NSROLEATTR,"", NULL) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_init: slapi_vattrspi_regattr failed\n");
+ free(vattr_handle);
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_init\n");
+ return rc;
+}
+
+/* roles_cache_create_suffix
+ -------------------------
+ Create a new entry in the global list
+ return a pointer on the suffix stucture: OK
+ return NULL: fail
+ */
+static roles_cache_def *roles_cache_create_suffix(Slapi_DN *sdn)
+{
+ roles_cache_def *current_suffix = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_create_suffix\n");
+
+ /* Allocate a new suffix block */
+ new_suffix = (roles_cache_def*)slapi_ch_calloc(1, sizeof(roles_cache_def));
+ if ( new_suffix == NULL )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Unable to allocate memory, cannot create role cache\n");
+ return(NULL);
+ }
+
+ new_suffix->cache_lock = slapi_new_mutex();
+ new_suffix->change_lock = slapi_new_mutex();
+ new_suffix->stop_lock = slapi_new_mutex();
+ new_suffix->create_lock = slapi_new_mutex();
+ if ( new_suffix->stop_lock == NULL ||
+ new_suffix->change_lock == NULL ||
+ new_suffix->cache_lock == NULL ||
+ new_suffix->create_lock == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->something_changed = slapi_new_condvar(new_suffix->change_lock);
+ if ( new_suffix->something_changed == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->suffix_created = slapi_new_condvar(new_suffix->create_lock);
+ if ( new_suffix->suffix_created == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->keeprunning = 1;
+
+ new_suffix->suffix_dn = slapi_sdn_dup(sdn);
+
+ /* those 3 items are used to give back info to the thread when
+ it is awakened */
+ new_suffix->notified_dn = NULL;
+ new_suffix->notified_entry = NULL;
+ new_suffix->notified_operation = 0;
+
+ /* Create the global list */
+ if ( roles_list == NULL )
+ {
+ roles_list = new_suffix;
+ }
+ else
+ {
+ current_suffix = roles_list;
+ while ( current_suffix != NULL )
+ {
+ if ( current_suffix->next == NULL )
+ {
+ current_suffix->next = new_suffix;
+ break;
+ }
+ else
+ {
+ current_suffix = current_suffix->next;
+ }
+ }
+ }
+
+ /* to prevent deadlock */
+ new_suffix->is_ready = 0;
+ if ( (new_suffix->roles_tid = PR_CreateThread (PR_USER_THREAD,
+ roles_cache_wait_on_change,
+ (void*)new_suffix,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: PR_CreateThread failed\n");
+ roles_cache_role_def_delete(new_suffix);
+ return(NULL);
+ }
+
+ slapi_lock_mutex(new_suffix->create_lock);
+ if (new_suffix->is_ready != 1)
+ {
+ slapi_wait_condvar(new_suffix->suffix_created, NULL);
+ }
+ slapi_unlock_mutex(new_suffix->create_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_create_suffix\n");
+ return(new_suffix);
+}
+
+/* roles_cache_wait_on_change
+ --------------------------
+ Sit around waiting on a notification that something has
+ changed, then fires off the updates
+ */
+static void roles_cache_wait_on_change(void * arg)
+{
+ roles_cache_def *roles_def = (roles_cache_def*)arg;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_wait_on_change\n");
+
+ slapi_lock_mutex(roles_def->stop_lock);
+ slapi_lock_mutex(roles_def->change_lock);
+
+ while ( roles_def->keeprunning)
+ {
+ slapi_unlock_mutex(roles_def->change_lock);
+ slapi_lock_mutex(roles_def->change_lock);
+
+ /* means that the thread corresponding to that suffix is ready to receive notifications
+ from the server */
+ slapi_lock_mutex(roles_def->create_lock);
+ if ( roles_def->is_ready == 0 )
+ {
+ slapi_notify_condvar( roles_def->suffix_created, 1 );
+ roles_def->is_ready = 1;
+ }
+ slapi_unlock_mutex(roles_def->create_lock);
+
+ /* XXX In case the BE containing this role_def signaled
+ a shut down between the unlock/lock above should
+ test roles_def->keeprunning before
+ going to sleep.
+ */
+ slapi_wait_condvar(roles_def->something_changed, NULL);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "roles_cache_wait_on_change \n");
+
+ if ( roles_def->keeprunning )
+ {
+ roles_cache_update(roles_def);
+ }
+ }
+
+ /* shut down the cache */
+ slapi_unlock_mutex(roles_def->change_lock);
+ slapi_unlock_mutex(roles_def->stop_lock);
+
+ roles_cache_role_def_free(roles_def);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_wait_on_change thread exit\n");
+}
+
+/* roles_cache_trigger_update_suffix
+ --------------------------------
+ This is called when a backend changes state (created|modified|deleted)
+ We simply signal to update the associated role cache in this case
+ */
+static void roles_cache_trigger_update_suffix(void *handle, char *be_name, int old_be_state, int new_be_state)
+{
+ roles_cache_def *current_role = roles_list;
+ const Slapi_DN *be_suffix_dn = NULL;
+ Slapi_DN *top_suffix_dn = NULL;
+ Slapi_Backend *backend = NULL;
+ int found = 0;
+
+ PR_RWLock_Wlock(global_lock);
+
+ if ( (new_be_state == SLAPI_BE_STATE_DELETE) || (new_be_state == SLAPI_BE_STATE_OFFLINE) )
+ {
+ /* Invalidate and rebuild the whole cache */
+ roles_cache_def *current_role = NULL;
+ roles_cache_def *next_role = NULL;
+ Slapi_DN *sdn = NULL;
+ void *node = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ /* Go through all the roles list and trigger the associated structure */
+ current_role = roles_list;
+ while ( current_role )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+ current_role->keeprunning = 0;
+ next_role = current_role->next;
+ slapi_notify_condvar(current_role->something_changed, 1 );
+ slapi_unlock_mutex(current_role->change_lock);
+
+ current_role = next_role;
+ }
+
+ /* rebuild a new one */
+ roles_list = NULL;
+
+ sdn = slapi_get_first_suffix(&node, 0);
+ while (sdn)
+ {
+
+ if ( (new_suffix = roles_cache_create_suffix(sdn)) == NULL )
+ {
+ PR_RWLock_Unlock(global_lock);
+ return;
+ }
+
+ roles_cache_add_roles_from_suffix(sdn, new_suffix);
+ sdn = slapi_get_next_suffix(&node, 0);
+ }
+ PR_RWLock_Unlock(global_lock);
+ return;
+ }
+
+ /* Backend back on line or new one created*/
+ backend = slapi_be_select_by_instance_name(be_name);
+ if ( backend != NULL )
+ {
+ be_suffix_dn = slapi_be_getsuffix(backend, 0);
+ top_suffix_dn = roles_cache_get_top_suffix((Slapi_DN *)be_suffix_dn);
+ }
+
+ while ( (current_role != NULL) && !found && (top_suffix_dn != NULL) )
+ {
+ /* The backend already exists (back online): so invalidate "old roles definitions" */
+ if ( slapi_sdn_compare(current_role->suffix_dn, top_suffix_dn) == 0 )
+ {
+ roles_cache_role_def_delete(current_role);
+ found = 1;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+
+ if ( top_suffix_dn != NULL )
+ {
+ /* Add the new definitions in the cache */
+ roles_cache_def *new_suffix = roles_cache_create_suffix(top_suffix_dn);
+
+ if ( new_suffix != NULL )
+ {
+ roles_cache_add_roles_from_suffix(top_suffix_dn, new_suffix);
+ }
+ slapi_sdn_free(&top_suffix_dn);
+ }
+
+ PR_RWLock_Unlock(global_lock);
+}
+
+/* roles_cache_trigger_update_role
+ --------------------------------
+ Call when an entry containing a role definition has been added, modified
+ or deleted
+ */
+static void roles_cache_trigger_update_role(char *dn, Slapi_Entry *roles_entry, Slapi_DN *be_dn, int operation)
+{
+ int found = 0;
+ roles_cache_def *current_role = NULL;
+
+ PR_RWLock_Wlock(global_lock);
+
+ current_role = roles_list;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_trigger_update_role: %x \n", roles_list);
+
+ /* Go through all the roles list and trigger the associated structure */
+
+ /* be_dn is already the top suffix for that dn */
+ while ( (current_role != NULL) && !found )
+ {
+ if ( slapi_sdn_compare(current_role->suffix_dn, be_dn) == 0 )
+ {
+ found = 1;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+
+ if ( found )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+
+ slapi_entry_free (current_role->notified_entry);
+ current_role->notified_entry = roles_entry;
+ slapi_ch_free ((void**)&(current_role->notified_dn));
+ current_role->notified_dn = dn;
+ current_role->notified_operation = operation;
+
+ roles_cache_update(current_role);
+
+ slapi_unlock_mutex(current_role->change_lock);
+ }
+
+ PR_RWLock_Unlock(global_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_trigger_update_role: %x \n", roles_list);
+}
+
+/* roles_cache_update
+ ------------------
+ Update the cache associated to a suffix
+ Return 0: ok
+ Return -1: fail
+ */
+static int roles_cache_update(roles_cache_def *suffix_to_update)
+{
+ int rc = 0;
+ int operation;
+ Slapi_Entry *entry = NULL;
+ Slapi_DN *dn = NULL;
+ role_object *to_delete = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_update \n");
+
+ slapi_lock_mutex(suffix_to_update->cache_lock);
+
+ operation = suffix_to_update->notified_operation;
+ entry = suffix_to_update->notified_entry;
+ dn = slapi_sdn_new();
+ slapi_sdn_set_dn_byval(dn, suffix_to_update->notified_dn);
+
+ if ( (entry != NULL) && (dn != NULL) )
+ {
+ if ( (operation == SLAPI_OPERATION_MODIFY) ||
+ (operation == SLAPI_OPERATION_DELETE) )
+ {
+ /* delete it */
+ int dummy;
+
+ to_delete = (role_object *)avl_delete(&(suffix_to_update->avl_tree), dn, roles_cache_find_node, &dummy);
+ roles_cache_role_object_free(to_delete);
+ to_delete = NULL;
+ if ( slapi_is_loglevel_set(SLAPI_LOG_PLUGIN) )
+ {
+ avl_apply(suffix_to_update->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER);
+ }
+
+ }
+ if ( (operation == SLAPI_OPERATION_MODIFY) ||
+ (operation ==SLAPI_OPERATION_ADD) )
+ {
+ rc = roles_cache_create_role_under(&suffix_to_update,entry);
+ }
+ if ( entry != NULL )
+ {
+ slapi_entry_free(entry);
+ }
+ suffix_to_update->notified_entry = NULL;
+
+ }
+ slapi_unlock_mutex(suffix_to_update->cache_lock);
+
+ if ( dn != NULL )
+ {
+ slapi_sdn_free(&dn);
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_update \n");
+ return(rc);
+}
+
+/* roles_cache_stop
+ ----------------
+
+ XXX the stop_lock of a roles_cache_def
+ doesn't seem to serve any useful purpose...
+
+ */
+void roles_cache_stop()
+{
+ roles_cache_def *current_role = NULL;
+ roles_cache_def *next_role = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_stop\n");
+
+ /* Go through all the roles list and trigger the associated structure */
+ PR_RWLock_Wlock(global_lock);
+ current_role = roles_list;
+ while ( current_role )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+ current_role->keeprunning = 0;
+ next_role = current_role->next;
+ slapi_notify_condvar(current_role->something_changed, 1 );
+ slapi_unlock_mutex(current_role->change_lock);
+
+ current_role = next_role;
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_stop\n");
+}
+
+/* roles_cache_is_role_entry
+ -------------------------
+ Check if the entry is a role
+ return -1: error in processing
+ return 0: entry is not a role
+ return 1: entry is a role
+*/
+static int roles_cache_is_role_entry(struct slapi_entry *entry)
+{
+ Slapi_Attr *pObjclasses = NULL;
+ Slapi_Value *val = NULL;
+ char *pObj = NULL;
+ int index = 0;
+
+ int nsroledefinition = 0;
+ int nsrolesimpleOrComplex = 0;
+ int nsroletype = 0;
+
+ if ( entry == NULL )
+ {
+ return(0);
+ }
+
+ if ( slapi_entry_attr_find(entry, "objectclass", &pObjclasses) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_is_role_entry: failed to get objectclass from %s\n",slapi_entry_get_dn_const(entry));
+ return(-1);
+ }
+
+ /* Check out the object classes to see if this was a nsroledefinition */
+
+ val = 0;
+ index = slapi_attr_first_value( pObjclasses, &val );
+ while(val)
+ {
+ const char *p;
+ int len = 0;
+
+ pObj = (char*)slapi_value_get_string(val);
+
+ for ( p = pObj, len = 0;
+ (*p != '\0') && (*p != ' ');
+ p++, len++ )
+ {
+ ; /* NULL */
+ }
+
+ if ( !strncasecmp(pObj, (char*)"nsroledefinition", len) )
+ {
+ nsroledefinition = 1;
+ }
+ if ( !strncasecmp(pObj, (char*)"nssimpleroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nscomplexroledefinition", len) )
+ {
+ nsrolesimpleOrComplex = 1;
+ }
+ if( !strncasecmp(pObj, (char*)"nsmanagedroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nsfilteredroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nsnestedroledefinition", len)
+ )
+ {
+ nsroletype = 1;
+ }
+ index = slapi_attr_next_value( pObjclasses, index, &val );
+ }
+ if ( (nsroledefinition == 0) ||
+ (nsrolesimpleOrComplex == 0) ||
+ (nsroletype == 0) )
+ {
+ return(0);
+ }
+ return(1);
+}
+
+/* roles_cache_change_notify
+ -------------------------
+ determines if the change effects the cache and if so
+ signals a rebuild
+ -- called when modify|modrdn|add|delete operation is performed --
+ -- called from a postoperation on an entry
+ XXX this implies that the client may have already received his LDAP response,
+ but that there will be a delay before he sees the effect in the roles cache.
+ Should we be doing this processing in a BE_POST_MODIFY postop
+ which is called _before_ the response goes to the client ?
+*/
+void roles_cache_change_notify(Slapi_PBlock *pb)
+{
+ char *dn = NULL;
+ struct slapi_entry *e = NULL;
+ struct slapi_entry *pre = NULL;
+ struct slapi_entry *entry = NULL;
+ Slapi_Backend *be = NULL;
+ Slapi_Operation *pb_operation = NULL;
+ int operation;
+ int do_update = 0;
+ int rc = -1;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_change_notify\n");
+
+ /* if the current operation has failed, don't even try the post operation */
+ slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ if ( rc != LDAP_SUCCESS )
+ {
+ return;
+ }
+
+ /* Don't update local cache when remote entries are updated */
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ if ( ( be!=NULL ) &&
+ ( slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) )
+ {
+ return;
+ }
+
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ if( dn == NULL )
+ {
+ return;
+ }
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &pb_operation);
+ operation = operation_get_type(pb_operation);
+
+ switch (operation)
+ {
+ case SLAPI_OPERATION_DELETE:
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+ if( e == NULL )
+ {
+ return;
+ }
+ break;
+
+ case SLAPI_OPERATION_ADD:
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ if ( e == NULL )
+ {
+ return;
+ }
+ break;
+
+ case SLAPI_OPERATION_MODIFY:
+ case SLAPI_OPERATION_MODRDN:
+ /* those operations are treated the same way and modify is a deletion followed by an addition.
+ the only point to take care is that dn is the olddn */
+ operation = SLAPI_OPERATION_MODIFY;
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre);
+ if( pre == NULL )
+ {
+ return;
+ }
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ if ( e == NULL )
+ {
+ return;
+ }
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_change_notify: unknown operation %d\n",operation);
+ return;
+ }
+
+ if ( operation != SLAPI_OPERATION_MODIFY )
+ {
+ if ( roles_cache_is_role_entry(e) != 1 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify: not a role entry\n");
+ return;
+ }
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else
+ {
+ int is_pre_role = roles_cache_is_role_entry(pre);
+ int is_post_role = roles_cache_is_role_entry(e);
+ if ( (is_pre_role==1) && (is_post_role==1) ) /* role definition has changed */
+ {
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else if ( is_pre_role == 1 ) /* entry is no more a role */
+ {
+ operation = SLAPI_OPERATION_DELETE;
+ do_update = 1;
+ }
+ else if ( is_post_role == 1 ) /* entry is now a role */
+ {
+ operation = SLAPI_OPERATION_ADD;
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify: not a role entry\n");
+ return;
+ }
+ }
+
+ if ( do_update )
+ {
+#ifdef moretrace
+if ( e != NULL )
+{
+ Slapi_Attr *attr = NULL;
+ int rc;
+
+ /* Get the list of nested roles */
+ rc = slapi_entry_attr_find(e,ROLE_NESTED_ATTR_NAME,&attr);
+
+ if ( (rc == 0) && attr)
+ {
+ /* Recurse to get the definition objects for them */
+ Slapi_Value **va = attr_get_present_values(attr);
+ int i = 0;
+ char *string = NULL;
+
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ string = (char*)slapi_value_get_string(va[i]);
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "roles_cache_change_notify:%s\n",string);
+ }
+ }
+}
+#endif
+ Slapi_DN *top_suffix = roles_cache_get_top_suffix(*(be->be_suffix));
+
+ if ( top_suffix != NULL )
+ {
+ roles_cache_trigger_update_role( slapi_ch_strdup(dn), entry,
+ top_suffix,
+ operation);
+
+ slapi_sdn_free(&top_suffix);
+ }
+
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify\n");
+
+}
+
+/* roles_cache_get_top_suffix
+ -------------------------
+ The returned Slapi_DN must be freed with slapi_sdn_free().
+*/
+static Slapi_DN* roles_cache_get_top_suffix(Slapi_DN *suffix)
+{
+ Slapi_DN *current_suffix = NULL;
+ Slapi_DN parent_suffix;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_get_top_suffix\n");
+
+ if ( suffix == NULL )
+ {
+ return(NULL);
+ }
+ current_suffix = slapi_sdn_new();
+ slapi_sdn_init(&parent_suffix);
+
+ /* we must get the top suffix for that DN */
+ slapi_sdn_copy(suffix,current_suffix);
+ while ( !slapi_sdn_isempty(current_suffix) )
+ {
+ if ( slapi_is_root_suffix(current_suffix) != 1 )
+ {
+ slapi_sdn_get_parent(current_suffix,&parent_suffix);
+ slapi_sdn_copy(&parent_suffix, current_suffix);
+ }
+ else
+ {
+ slapi_sdn_done(&parent_suffix);
+ return(current_suffix);
+ }
+ }
+ /* we should not return that way ... */
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_get_top_suffix\n");
+ slapi_sdn_done(&parent_suffix);
+ slapi_sdn_free(&current_suffix);
+ return(NULL);
+}
+
+/* roles_cache_add_roles_from_suffix
+ -------------------------------
+ Get the roles entries under the suffix
+ return 0: OK
+ return -1: this suffix has no role defined
+ */
+static int roles_cache_add_roles_from_suffix(Slapi_DN *suffix_dn, roles_cache_def *suffix_def)
+{
+ /* Search subtree-level under this entry */
+ int rc = -1;
+ roles_cache_search_roles info;
+ Slapi_PBlock *int_search_pb = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_get_roles_from_entry\n");
+
+ info.suffix_def = suffix_def;
+ info.rc = LDAP_NO_SUCH_OBJECT;
+
+ /* Get the roles definitions of the given suffix_dn */
+ int_search_pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb(int_search_pb,
+ (char*)slapi_sdn_get_ndn(suffix_dn),
+ LDAP_SCOPE_SUBTREE,
+ ROLE_DEFINITION_FILTER,
+ allUserAttributes,
+ 0 /* attrsonly */,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ roles_get_plugin_identity(),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions : get local roles only */ );
+
+ slapi_search_internal_callback_pb(int_search_pb,
+ &info /* callback_data */,
+ roles_cache_result_cb,
+ roles_cache_add_entry_cb,
+ NULL /* referral_callback */);
+
+ slapi_pblock_destroy (int_search_pb);
+ int_search_pb = NULL;
+
+ if ( info.rc == LDAP_SUCCESS )
+ {
+ rc = 0;
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_get_roles_from_entry\n");
+
+ return(rc);
+}
+
+/* roles_cache_add_entry_cb
+ -----------------------
+*/
+static int roles_cache_add_entry_cb(Slapi_Entry* e, void *callback_data)
+{
+ roles_cache_search_roles *info=(roles_cache_search_roles *)callback_data;
+
+ roles_cache_def *suffix = info->suffix_def;
+
+ roles_cache_create_role_under(&suffix, e);
+ return(0);
+}
+
+/* roles_cache_result_cb
+ -----------------------
+*/
+static void roles_cache_result_cb( int rc, void *callback_data) {
+ roles_cache_search_roles *info=(roles_cache_search_roles *)callback_data;
+
+ info->rc = rc;
+}
+
+
+/* roles_cache_create_role_under
+ ----------------------------
+ Create the avl tree of roles definitions defined in the scope
+ of the suffix
+ Return 0: OK
+ Return -1: fail
+*/
+static int roles_cache_create_role_under(roles_cache_def** roles_cache_suffix, Slapi_Entry *entry)
+{
+ int rc;
+ role_object *new_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_create_role_under: %s - %x\n",
+ slapi_sdn_get_dn((*roles_cache_suffix)->suffix_dn),
+ (*roles_cache_suffix)->avl_tree);
+
+ rc = roles_cache_create_object_from_entry(entry,&new_role,0);
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_role_under: create node for entry %s - rc: %d SUFFIX: %x\n",
+ slapi_entry_get_dn_const(entry), rc, (*roles_cache_suffix)->avl_tree);
+
+ if ( (rc == 0) && new_role)
+ {
+ /* Add to the tree where avl_data is a role_object struct */
+ rc = roles_cache_insert_object(&((*roles_cache_suffix)->avl_tree),new_role);
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_create_role_under:%s in tree %x rc: %d\n",
+ (char*)slapi_sdn_get_ndn(new_role->dn),
+ (*roles_cache_suffix)->avl_tree, rc);
+ }
+ return(rc);
+}
+
+
+/* roles_cache_create_object_from_entry
+ ------------------------------------
+ Create a node role_object from the information contained in role_entry
+ Return 0
+ Return ENOMEM: fail
+ Return SLAPI_ROLE_DEFINITION_ERROR: fail
+ Return SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED: fail
+ Return SLAPI_ROLE_ERROR_FILTER_BAD: fail
+*/
+static int roles_cache_create_object_from_entry(Slapi_Entry *role_entry, role_object **result, int hint)
+{
+ int rc = 0;
+ int type = 0;
+ role_object *this_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_create_object_from_entry\n");
+
+ *result = NULL;
+
+ /* Do not allow circular dependencies */
+ if ( hint > MAX_NESTED_ROLES )
+ {
+ char *ndn = NULL;
+
+ ndn = slapi_entry_get_ndn( role_entry );
+ slapi_log_error(
+ SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "Maximum roles nesting exceeded (%d), not retrieving roles from entry %s--probable circular definition\n",
+ MAX_NESTED_ROLES,
+ ndn);
+
+ return (0);
+ }
+
+ /* Create the role cache definition */
+ this_role = (role_object*)slapi_ch_calloc(1, sizeof(role_object));
+ if (this_role == NULL )
+ {
+ return ENOMEM;
+ }
+
+ /* Check the entry is OK */
+ /* Determine role type and assign to structure */
+ /* We determine the role type by reading the objectclass */
+ if ( roles_cache_is_role_entry(role_entry) == 0 )
+ {
+ /* Bad type */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_DEFINITION_ERROR;
+ }
+
+ type = roles_cache_determine_class(role_entry);
+
+ if (type != 0)
+ {
+ this_role->type = type;
+ }
+ else
+ {
+ /* Bad type */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_DEFINITION_ERROR;
+ }
+
+ this_role->dn = slapi_sdn_new();
+ slapi_sdn_copy(slapi_entry_get_sdn(role_entry),this_role->dn);
+
+ /* Depending upon role type, pull out the remaining information we need */
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+
+ /* Nothing further needed */
+ break;
+
+ case ROLE_TYPE_FILTERED:
+ {
+
+ Slapi_Filter *filter = NULL;
+ char *filter_attr_value = NULL;
+
+ /* Get the filter and retrieve the filter attribute */
+ filter_attr_value = slapi_entry_attr_get_charptr(role_entry,ROLE_FILTER_ATTR_NAME);
+ if ( filter_attr_value == NULL )
+ {
+ /* Means probably no attribute or no value there */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED;
+ }
+
+ /* Turn it into a slapi filter object */
+ filter = slapi_str2filter(filter_attr_value);
+ slapi_ch_free((void**)&filter_attr_value);
+
+ if ( filter == NULL )
+ {
+ /* An error has occured */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_ERROR_FILTER_BAD;
+ }
+ /* Store on the object */
+ this_role->filter = filter;
+
+ break;
+ }
+
+ case ROLE_TYPE_NESTED:
+ {
+ Slapi_Attr *attr = NULL;
+
+ /* Get the list of nested roles */
+ rc = slapi_entry_attr_find(role_entry,ROLE_NESTED_ATTR_NAME,&attr);
+
+ if ( (rc == 0) && attr)
+ {
+ /* Recurse to get the definition objects for them */
+ Slapi_Value **va = attr_get_present_values(attr);
+ int i = 0;
+ char *string = NULL;
+ Slapi_DN nested_role_dn;
+ role_object_nested *nested_role_object = NULL;
+
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ string = (char*)slapi_value_get_string(va[i]);
+
+ /* Make a DN from the string */
+ slapi_sdn_init_dn_byref(&nested_role_dn,string);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_create_object_from_entry: dn %s, nested %s\n",
+ (char*)slapi_sdn_get_ndn(this_role->dn),string);
+
+ /* Make a role object nested from the DN */
+ rc = roles_cache_object_nested_from_dn(&nested_role_dn,&nested_role_object);
+
+ /* Insert it into the nested list */
+ if ( (rc == 0) && nested_role_object)
+ {
+ /* Add to the tree where avl_data is a role_object_nested struct */
+ rc = roles_cache_insert_object_nested(&(this_role->avl_tree),nested_role_object);
+ }
+ slapi_sdn_done(&nested_role_dn);
+ }
+ }
+
+ break;
+ }
+
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM, "wrong role type\n");
+ }
+
+ if ( rc == 0 )
+ {
+ *result = this_role;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_create_object_from_entry\n");
+
+
+ return rc;
+}
+
+/* roles_cache_determine_class:
+ ----------------------------
+ Determine the type of role depending on the objectclass
+ Return the type of the role
+ */
+static int roles_cache_determine_class(Slapi_Entry *role_entry)
+{
+ /* Examine the entry's objectclass attribute */
+ int found_managed = 0;
+ int found_filtered = 0;
+ int found_nested = 0;
+ Slapi_Attr *attr= NULL;
+ struct berval bv = {0};
+ int rc = 0;
+ int type = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_determine_class\n");
+
+ rc = slapi_entry_attr_find(role_entry,"objectclass",&attr);
+ if ( rc != 0 )
+ {
+ /* No objectclass, definitely an error */
+ return 0;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_MANAGED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_managed = 1;
+ type = ROLE_TYPE_MANAGED;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_FILTERED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_filtered = 1;
+ type = ROLE_TYPE_FILTERED;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_NESTED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_nested = 1;
+ type = ROLE_TYPE_NESTED;
+ }
+
+ if ( (found_managed + found_nested + found_filtered) > 1 )
+ {
+ /* Means some goofball configured a role definition which is trying to be more than one different type. error. */
+ return 0;
+ }
+
+ if ( (found_managed + found_nested + found_filtered) == 0)
+ {
+ /* Means this entry isn't any of the role types we handle. error. */
+ return 0;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_determine_class\n");
+
+ /* Return the appropriate type ordinal */
+ return type;
+}
+
+/* roles_cache_node_cmp:
+ ---------------------
+ Comparison function to add a new node in the avl tree (avl_data is of type role_object)
+ */
+static int roles_cache_node_cmp( caddr_t d1, caddr_t d2 )
+{
+ role_object *role_to_insert = (role_object*)d1;
+ role_object *current_role = (role_object*)d2;
+
+ /* role_to_insert and current_role are never NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_node_cmp\n");
+
+ return (slapi_sdn_compare((Slapi_DN *)role_to_insert->dn, (Slapi_DN *)current_role->dn));
+}
+
+/* roles_cache_insert_object:
+ --------------------------
+ Insert a new node in the avl tree of a specific suffix
+ */
+static int roles_cache_insert_object(Avlnode **tree, role_object *object)
+{
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_insert_object: %s in tree %x\n",
+ (char*)slapi_sdn_get_ndn(object->dn),
+ *tree);
+ return (avl_insert(tree, (caddr_t)object, roles_cache_node_cmp, avl_dup_error));
+}
+
+/* roles_cache_node_nested_cmp:
+ ----------------------------
+ Comparison function to add a new node in the avl tree
+ */
+static int roles_cache_node_nested_cmp( caddr_t d1, caddr_t d2 )
+{
+ role_object_nested *role_to_insert = (role_object_nested*)d1;
+ role_object_nested *current_role = (role_object_nested*)d2;
+
+ /* role_to_insert and current_role are never NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_node_nested_cmp\n");
+
+ return slapi_sdn_compare(role_to_insert->dn, current_role->dn);
+}
+
+/* roles_cache_insert_object_nested:
+ ---------------------------------
+ Insert a new node in the avl tree of a specific suffix
+ */
+static int roles_cache_insert_object_nested(Avlnode **tree, role_object_nested *object)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_insert_object_nested: %s in tree %x: \n",
+ (char*)slapi_sdn_get_ndn(object->dn), *tree);
+
+ return (avl_insert(tree, (caddr_t)object, roles_cache_node_nested_cmp, avl_dup_error));
+}
+
+/* roles_cache_object_nested_from_dn
+ ----------------------------------
+ Get the role associated to an entry DN
+ Return 0: OK
+ Return ENOMEM: fail
+ */
+static int roles_cache_object_nested_from_dn(Slapi_DN *role_dn, role_object_nested **result)
+{
+ role_object_nested *nested_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_object_nested_from_dn\n");
+
+ *result = NULL;
+
+ /* Create the role cache definition */
+ nested_role = (role_object_nested*)slapi_ch_calloc(1, sizeof(role_object_nested));
+ if (nested_role == NULL )
+ {
+ return ENOMEM;
+ }
+
+ nested_role->dn = slapi_sdn_new();
+ slapi_sdn_copy(role_dn,nested_role->dn);
+ *result = nested_role;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_object_nested_from_dn\n");
+ return 0;
+}
+
+/* roles_cache_listroles
+ --------------------
+ Lists all the roles an entry posesses
+ return_values = 0 means that we don't need the nsrole values
+ return_values = 1 means that we need the nsrole values
+ Return 0: the entry has nsrole
+ Return -1: the entry has no nsrole
+ */
+int roles_cache_listroles(Slapi_Entry *entry, int return_values, Slapi_ValueSet **valueset_out)
+{
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+ int rc = 0;
+ Avlnode * tree = NULL;
+ roles_cache_build_result arg;
+ Slapi_Backend *backend = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_listroles\n");
+
+ backend = slapi_mapping_tree_find_backend_for_sdn(slapi_entry_get_sdn(entry));
+ if ( (backend != NULL) && slapi_be_is_flag_set(backend,SLAPI_BE_FLAG_REMOTE_DATA) )
+ {
+ /* the entry is not local, so don't return anything */
+ return (-1);
+ }
+
+ if ( return_values )
+ {
+ *valueset_out = (Slapi_ValueSet*)slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
+ slapi_valueset_init(*valueset_out);
+ }
+
+ /* First get a list of all the in-scope roles */
+ /* XXX really need a mutex for this read operation ? */
+ PR_RWLock_Rlock(global_lock);
+
+ rc = roles_cache_find_roles_in_suffix( slapi_entry_get_sdn(entry),&roles_cache);
+
+ PR_RWLock_Unlock(global_lock);
+
+ /* Traverse the tree checking if the entry has any of the roles */
+ if ( roles_cache != NULL )
+ {
+ if ( roles_cache->avl_tree )
+ {
+ arg.nsrole_values = valueset_out;
+ arg.need_value = return_values;
+ arg.requested_entry = entry;
+ arg.has_value = 0;
+
+ /* XXX really need a mutex for this read operation ? */
+ slapi_lock_mutex(roles_cache->cache_lock);
+
+ avl_apply(roles_cache->avl_tree, (IFP)roles_cache_build_nsrole, &arg, -1, AVL_INORDER);
+
+ slapi_unlock_mutex(roles_cache->cache_lock);
+
+ if( !arg.has_value )
+ {
+ if ( return_values )
+ {
+ slapi_valueset_free(*valueset_out);
+ *valueset_out = NULL;
+ }
+ rc = -1;
+ }
+ /* Free the list (we already did that) */
+ }
+ else
+ {
+ if ( return_values )
+ {
+ slapi_valueset_free(*valueset_out);
+ *valueset_out = NULL;
+ }
+ rc = -1;
+ }
+ }
+ else
+ {
+ /* no roles associated */
+ rc = -1;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_listroles\n");
+ return rc;
+}
+
+/* roles_cache_build_nsrole
+ ------------------------
+ Traverse the tree containing roles definitions for a suffix and for each
+ one of them, check wether the entry is a member of it or not
+ For ones which check out positive, we add their DN to the value
+ always return 0 to allow to trverse all the tree
+ */
+static int roles_cache_build_nsrole( caddr_t data, caddr_t arg )
+{
+ Slapi_Value *value = NULL;
+ roles_cache_build_result *result = (roles_cache_build_result*)arg;
+ role_object *this_role = (role_object*)data;
+ roles_cache_search_in_nested get_nsrole;
+ /* Return a value different from the stop flag to be able
+ to go through all the tree */
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_build_nsrole: role %s\n",
+ (char*) slapi_sdn_get_ndn(this_role->dn));
+
+ value = slapi_value_new_string("");
+
+ get_nsrole.is_entry_member_of = result->requested_entry;
+ get_nsrole.present = 0;
+ get_nsrole.hint = 0;
+
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)&get_nsrole);
+
+ /* If so, add its DN to the attribute */
+ if (get_nsrole.present)
+ {
+ result->has_value = 1;
+ if ( result->need_value )
+ {
+ slapi_value_set_string(value,(char*) slapi_sdn_get_ndn(this_role->dn));
+ slapi_valueset_add_value(*(result->nsrole_values),value);
+ }
+ else
+ {
+ /* we don't need the value but we already know there is one nsrole.
+ stop the traversal
+ */
+ rc = -1;
+ }
+ }
+
+ slapi_value_free(&value);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_build_nsrole\n");
+
+ return rc;
+}
+
+
+/* roles_check
+ -----------
+ Checks if an entry has a presented role, assuming that we've already verified
+that
+ the role both exists and is in scope
+ return 0: no processing error
+ return -1: error
+ */
+int roles_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present)
+{
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+ roles_cache_search_in_nested get_nsrole;
+
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check\n");
+
+ *present = 0;
+
+ PR_RWLock_Rlock(global_lock);
+
+ if ( roles_cache_find_roles_in_suffix(slapi_entry_get_sdn(entry_to_check),
+ &roles_cache) != 0 )
+ {
+ PR_RWLock_Unlock(global_lock);
+ return -1;
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ this_role = (role_object *)avl_find(roles_cache->avl_tree, role_dn, (IFP)roles_cache_find_node);
+
+ /* MAB: For some reason the assumption made by this function (the role exists and is in scope)
+ * does not seem to be true... this_role might be NULL after the avl_find call (is the avl_tree
+ * broken? Anyway, this is crashing the 5.1 server on 29-Aug-01, so I am applying the following patch
+ * to avoid the crash inside roles_is_entry_member_of_object */
+ /* Begin patch */
+ if (!this_role) {
+ /* Assume that the entry is not member of the role (*present=0) and leave... */
+ return rc;
+ }
+ /* End patch */
+
+ get_nsrole.is_entry_member_of = entry_to_check;
+ get_nsrole.present = 0;
+ get_nsrole.hint = 0;
+
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)&get_nsrole);
+ *present = get_nsrole.present;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_check\n");
+
+ return rc;
+}
+
+/* roles_cache_find_node:
+ ---------------------
+ Comparison function to add a new node in the avl tree
+ */
+static int roles_cache_find_node( caddr_t d1, caddr_t d2 )
+{
+ Slapi_DN *data = (Slapi_DN *)d1;
+ role_object *role= (role_object *)d2;
+
+ /* role is not NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_find_node: %s %s\n",
+ slapi_sdn_get_dn(data), slapi_sdn_get_dn(role->dn));
+
+ return (slapi_sdn_compare(data, (Slapi_DN *)role->dn));
+}
+
+/* roles_cache_find_roles_in_suffix
+ -------------------------------
+ Find all the roles in scope to an entry
+ */
+static int roles_cache_find_roles_in_suffix(Slapi_DN *target_entry_dn, roles_cache_def **list_of_roles)
+{
+ int rc = -1;
+ Slapi_Backend *backend = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_find_roles_in_suffix\n");
+
+ *list_of_roles = NULL;
+ backend = slapi_mapping_tree_find_backend_for_sdn(target_entry_dn);
+ if ( (backend != NULL) && !slapi_be_is_flag_set(backend,SLAPI_BE_FLAG_REMOTE_DATA) )
+ {
+ Slapi_DN *suffix = roles_cache_get_top_suffix(*(backend->be_suffix));
+ roles_cache_def *current_role = roles_list;
+
+ /* Go through all the roles list and trigger the associated structure */
+ while ( (current_role != NULL) && (suffix != NULL) )
+ {
+ if ( slapi_sdn_compare(current_role->suffix_dn, suffix) == 0 )
+ {
+ *list_of_roles = current_role;
+ /* OK, we have found one */
+ slapi_sdn_free(&suffix);
+ return 0;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+ if ( suffix != NULL )
+ {
+ slapi_sdn_free(&suffix);
+ }
+ /* If we got out that way, means that we didn't have find
+ roles definitions for that suffix */
+ return rc;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_find_roles_in_suffix\n");
+ return rc;
+}
+
+/* roles_is_entry_member_of_object
+ --------------------------------
+ Check if the entry is part of a role defined in its suffix
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_is_entry_member_of_object(caddr_t data, caddr_t argument )
+{
+ int rc = -1;
+
+ roles_cache_search_in_nested *get_nsrole = (roles_cache_search_in_nested*)argument;
+ role_object *this_role = (role_object*)data;
+
+ Slapi_Entry *entry_to_check = get_nsrole->is_entry_member_of;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_is_entry_member_of_object\n");
+
+ if (!roles_is_inscope(entry_to_check, this_role->dn))
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_is_entry_member_of_object-> entry not in scope of role\n");
+ return rc;
+ }
+
+ if ( this_role != NULL )
+ {
+ /* Determine the role type */
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+ rc = roles_check_managed(entry_to_check,this_role,&get_nsrole->present);
+ break;
+ case ROLE_TYPE_FILTERED:
+ rc = roles_check_filtered(entry_to_check,this_role,&get_nsrole->present);
+ break;
+ case ROLE_TYPE_NESTED:
+ {
+ /* Go through the tree of the nested DNs */
+ get_nsrole->hint++;
+ avl_apply(this_role->avl_tree, (IFP)roles_check_nested, get_nsrole, 0, AVL_INORDER);
+ get_nsrole->hint--;
+
+ /* kexcoff?? */
+ rc = get_nsrole->present;
+ break;
+ }
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_is_entry_member_of_object-> invalid role type\n");
+ }
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_is_entry_member_of_object\n");
+ return rc;
+}
+
+/* roles_check_managed
+ -------------------------
+ Check a managed role: we just need to check the content of the entry's nsRoleDN attribute
+ against the role DN
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_managed(Slapi_Entry *entry_to_check, role_object *role, int *present)
+{
+ int rc = 0;
+ Slapi_Attr *attr = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check_managed\n");
+ /* Get the attribute */
+ rc = slapi_entry_attr_find(entry_to_check,ROLE_MANAGED_ATTR_NAME,&attr);
+
+ if ( rc == 0)
+ {
+ struct berval bv = {0};
+ char *dn_string = NULL;
+
+ /* Check content against the presented DN */
+ /* We assume that this function handles normalization and so on */
+ dn_string = (char*) slapi_sdn_get_ndn(role->dn);
+ berval_set_string(&bv,dn_string);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ *present = 1;
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_check_managed: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role->dn),*present);
+ return rc;
+}
+
+/* roles_check_filtered
+ --------------------------
+ Check a filtered role: call slapi_filter_test here on the entry
+ and the filter from the role object
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_filtered(Slapi_Entry *entry_to_check, role_object *role, int *present)
+{
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check_filtered\n");
+ rc = slapi_filter_test_simple(entry_to_check,role->filter);
+ if ( rc == 0 )
+ {
+ *present = 1;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_check_filtered: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role->dn),*present);
+ return rc;
+}
+
+
+/* roles_check_nested
+ ------------------------
+ Check a nested role
+ return 0: ok
+ return -1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_nested(caddr_t data, caddr_t arg)
+{
+ roles_cache_search_in_nested *get_nsrole = (roles_cache_search_in_nested*)arg;
+ int rc = -1;
+ role_object_nested *current_nested_role = (role_object_nested*)data;
+
+
+ /* do not allow circular dependencies, the cheap and easy way */
+ if( get_nsrole->hint > MAX_NESTED_ROLES)
+ {
+ char *ndn = NULL;
+
+ ndn = slapi_entry_get_ndn( get_nsrole->is_entry_member_of );
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "Maximum roles nesting exceeded (max %d current %d), not checking roles in entry %s--probable circular definition\n",
+ MAX_NESTED_ROLES,
+ get_nsrole->hint,
+ ndn);
+
+ /* Stop traversal value */
+ return 0;
+ }
+
+ /* Here we traverse the list of nested roles, calling the appropriate
+ evaluation function for those in turn */
+
+ if (current_nested_role)
+ {
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "-->roles_check_nested: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(get_nsrole->is_entry_member_of),
+ (char*)slapi_sdn_get_ndn(current_nested_role->dn),
+ get_nsrole->present);
+
+ if ( roles_cache_find_roles_in_suffix(current_nested_role->dn,
+ &roles_cache) != 0 )
+ {
+ return rc;
+ }
+
+ if ( slapi_is_loglevel_set(SLAPI_LOG_PLUGIN) )
+ {
+ avl_apply(roles_cache->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER);
+ }
+
+ this_role = (role_object *)avl_find(roles_cache->avl_tree,
+ current_nested_role->dn,
+ (IFP)roles_cache_find_node);
+
+ if ( this_role == NULL )
+ {
+ /* the nested role doesn't exist */
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "The nested role %s doesn't exist\n",
+ (char*)slapi_sdn_get_ndn(current_nested_role->dn));
+ return rc;
+ }
+ /* get the role_object data associated to that dn */
+ if ( roles_is_inscope(get_nsrole->is_entry_member_of, this_role->dn) )
+ {
+ /* The list of nested roles is contained in the role definition */
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)get_nsrole);
+ if ( get_nsrole->present == 1 )
+ {
+ return 0;
+ }
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_check_nested\n");
+ return rc;
+}
+
+/* roles_is_inscope
+ ----------------------
+ Tells us if a presented role is in scope with respect to the presented entry
+ */
+static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn)
+{
+ int rc;
+
+ Slapi_DN role_parent;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_is_inscope\n");
+
+ slapi_sdn_init(&role_parent);
+ slapi_sdn_get_parent(role_dn,&role_parent);
+
+ rc = slapi_sdn_scope_test(slapi_entry_get_sdn( entry_to_check ),
+ &role_parent,
+ LDAP_SCOPE_SUBTREE);
+ /* we need to check whether the entry would be returned by a view in scope */
+ if(!rc && views_api)
+ {
+ rc = views_entry_exists(views_api, (char*)slapi_sdn_get_ndn(&role_parent), entry_to_check);
+ }
+
+ slapi_sdn_done(&role_parent);
+
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_is_inscope: entry %s role %s result %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role_dn), rc);
+
+ return (rc);
+}
+
+static void berval_set_string(struct berval *bv, const char* string)
+{
+ bv->bv_len= strlen(string);
+ bv->bv_val= (void*)string; /* We cast away the const, but we're not going to change anything
+*/
+}
+
+/* roles_cache_role_def_delete
+ ----------------------------
+*/
+static void roles_cache_role_def_delete(roles_cache_def *role_def)
+{
+ roles_cache_def *current = roles_list;
+ roles_cache_def *previous = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_def_delete\n");
+
+ while ( current!= NULL )
+ {
+ if ( slapi_sdn_compare(current->suffix_dn, role_def->suffix_dn) == 0 )
+ {
+ if ( previous== NULL )
+ {
+ roles_list = current->next;
+ }
+ else
+ {
+ previous->next = current->next;
+ }
+ slapi_lock_mutex(role_def->change_lock);
+ role_def->keeprunning = 0;
+ slapi_notify_condvar(role_def->something_changed, 1 );
+ slapi_unlock_mutex(role_def->change_lock);
+ break;
+ }
+ else
+ {
+ previous = current;
+ current = current->next;
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_def_delete\n");
+}
+
+/* roles_cache_role_def_free
+ ----------------------------
+*/
+static void roles_cache_role_def_free(roles_cache_def *role_def)
+{
+ roles_cache_def *next_def = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_def_free\n");
+ if ( role_def == NULL )
+ {
+ return;
+ }
+
+ slapi_lock_mutex(role_def->stop_lock);
+
+ avl_free(role_def->avl_tree, (IFP)roles_cache_role_object_free);
+ slapi_sdn_free(&(role_def->suffix_dn));
+ slapi_destroy_mutex(role_def->cache_lock);
+ role_def->cache_lock = NULL;
+ slapi_destroy_mutex(role_def->change_lock);
+ role_def->change_lock = NULL;
+ slapi_destroy_condvar(role_def->something_changed);
+ slapi_destroy_mutex(role_def->create_lock);
+ role_def->create_lock = NULL;
+ slapi_destroy_condvar(role_def->suffix_created);
+
+ slapi_ch_free((void**)&role_def->notified_dn);
+ if ( role_def->notified_entry != NULL )
+ {
+ slapi_entry_free(role_def->notified_entry);
+ }
+
+ slapi_unlock_mutex(role_def->stop_lock);
+ slapi_destroy_mutex(role_def->stop_lock);
+ role_def->stop_lock = NULL;
+
+ slapi_ch_free((void**)&role_def);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_def_free\n");
+}
+
+/* roles_cache_role_object_free
+ ----------------------------
+*/
+static void roles_cache_role_object_free(role_object *this_role)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_free\n");
+
+ if ( this_role == NULL )
+ {
+ return;
+ }
+
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+ /* Nothing further needed */
+ break;
+ case ROLE_TYPE_FILTERED:
+ /* Free the filter */
+ if (this_role->filter)
+ {
+ slapi_filter_free(this_role->filter,1);
+ this_role->filter = NULL;
+ }
+ break;
+ case ROLE_TYPE_NESTED:
+ /* Free the list of nested roles */
+ {
+ avl_free(this_role->avl_tree, roles_cache_role_object_nested_free);
+ }
+ break;
+ }
+
+ slapi_sdn_free(&this_role->dn);
+
+ /* Free the object */
+ slapi_ch_free((void**)&this_role);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_object_free\n");
+}
+
+/* roles_cache_role_object_nested_free
+ ------------------------------------
+*/
+static void roles_cache_role_object_nested_free(role_object_nested *this_role)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_nested_free\n");
+
+ if ( this_role == NULL )
+ {
+ return;
+ }
+
+ slapi_sdn_free(&this_role->dn);
+
+ /* Free the object */
+ slapi_ch_free((void**)&this_role);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_object_nested_free\n");
+}
+
+static int roles_cache_dump( caddr_t data, caddr_t arg )
+{
+ role_object *this_role = (role_object*)data;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_dump: %x - %s - %x\n",
+ this_role, (char*)slapi_sdn_get_ndn(this_role->dn), this_role->avl_tree);
+
+ return 0;
+}