diff options
Diffstat (limited to 'daemons/ipa-slapi-plugins')
5 files changed, 0 insertions, 2713 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-memberof/Makefile.am b/daemons/ipa-slapi-plugins/ipa-memberof/Makefile.am deleted file mode 100644 index d0ac7f935..000000000 --- a/daemons/ipa-slapi-plugins/ipa-memberof/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -NULL = - -INCLUDES = \ - -I. \ - -I$(srcdir) \ - -DPREFIX=\""$(prefix)"\" \ - -DBINDIR=\""$(bindir)"\" \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ - $(MOZLDAP_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) - -plugindir = $(libdir)/dirsrv/plugins -plugin_LTLIBRARIES = \ - libipa-memberof-plugin.la \ - $(NULL) - -libipa_memberof_plugin_la_SOURCES = \ - ipa-memberof.c \ - ipa-memberof_config.c \ - $(NULL) - -libipa_memberof_plugin_la_LDFLAGS = -avoid-version - -libipa_memberof_plugin_la_LIBADD = \ - $(MOZLDAP_LIBS) \ - $(NULL) - -appdir = $(IPA_DATA_DIR) -app_DATA = \ - memberof-conf.ldif \ - $(NULL) - -EXTRA_DIST = \ - $(app_DATA) \ - $(NULL) - -MAINTAINERCLEANFILES = \ - *~ \ - Makefile.in diff --git a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c b/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c deleted file mode 100644 index 3baf2f6cf..000000000 --- a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c +++ /dev/null @@ -1,2244 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * This Program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; version 2 of the License. - * - * This Program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA. - * - * In addition, as a special exception, Red Hat, Inc. gives You the additional - * right to link the code of this Program with code not covered under the GNU - * General Public License ("Non-GPL Code") and to distribute linked combinations - * including the two, subject to the limitations in this paragraph. Non-GPL Code - * permitted under this exception must only link to the code of this Program - * through those well defined interfaces identified in the file named EXCEPTION - * found in the source code files (the "Approved Interfaces"). The files of - * Non-GPL Code may instantiate templates or use macros or inline functions from - * the Approved Interfaces without causing the resulting work to be covered by - * the GNU General Public License. Only Red Hat, Inc. may make changes or - * additions to the list of Approved Interfaces. You must obey the GNU General - * Public License in all respects for all of the Program code and other code used - * in conjunction with the Program except the Non-GPL Code covered by this - * exception. If you modify this file, you may extend this exception to your - * version of the file, but you are not obligated to do so. If you do not wish to - * provide this exception without modification, you must delete this exception - * statement from your version and license this file solely under the GPL without - * exception. - * - * Authors: - * Pete Rowley <prowley@redhat.com> - * - * Copyright (C) 2007 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK - **/ - -/* The memberof plugin updates the memberof attribute of entries - * based on modifications performed on groupofuniquenames entries - * - * In addition the plugin provides a DS task that may be started - * administrative clients and that creates the initial memberof - * list for imported entries and/or fixes the memberof list of - * existing entries that have inconsistent state (for example, - * if the memberof attribute was incorrectly edited directly) - * - * To start the memberof task add an entry like: - * - * dn: cn=mytask, cn=memberof task, cn=tasks, cn=config - * objectClass: top - * objectClass: extensibleObject - * cn: mytask - * basedn: dc=example, dc=com - * filter: (uid=test4) - * - * where "basedn" is required and refers to the top most node to perform the - * task on, and where "filter" is an optional attribute that provides a filter - * describing the entries to be worked on - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <dirsrv/slapi-plugin.h> - -#include "string.h" -#include "nspr.h" - -#include "ipa-memberof.h" - -static Slapi_PluginDesc pdesc = { "ipamo", "FreeIPA project", "FreeIPA/1.0", - "IPA memberof plugin" }; - -static void* _PluginID = NULL; -static Slapi_Mutex *memberof_operation_lock = 0; -MemberOfConfig *qsortConfig = 0; - -typedef struct _memberofstringll -{ - const char *dn; - void *next; -} memberofstringll; - -typedef struct _memberof_get_groups_data -{ - MemberOfConfig *config; - Slapi_Value *memberdn_val; - Slapi_ValueSet **groupvals; -} memberof_get_groups_data; - -/****** secrets *********/ -#ifndef SLAPI_TASK_PUBLIC -/*from FDS slap.h - * until we get a proper api for access - */ -#define TASK_RUNNING_AS_TASK 0x0 - -/****************************************************************************** - * Online tasks interface (to support import, export, etc) - * After some cleanup, we could consider making these public. - */ -struct _slapi_task { - struct _slapi_task *next; - char *task_dn; - int task_exitcode; /* for the end user */ - int task_state; /* (see above) */ - int task_progress; /* number between 0 and task_work */ - int task_work; /* "units" of work to be done */ - int task_flags; /* (see above) */ - - /* it is the task's responsibility to allocate this memory & free it: */ - char *task_status; /* transient status info */ - char *task_log; /* appended warnings, etc */ - - void *task_private; /* for use by backends */ - TaskCallbackFn cancel; /* task has been cancelled by user */ - TaskCallbackFn destructor; /* task entry is being destroyed */ - int task_refcount; -}; - -static void slapi_task_set_data(Slapi_Task *task, void *data) -{ - if (task) { - task->task_private = data; - } -} - -/* - * Retrieve some opaque task specific data from the task. - */ -static void * slapi_task_get_data(Slapi_Task *task) -{ - if (task) { - return task->task_private; - } -} - -static void slapi_task_begin(Slapi_Task *task, int total_work) -{ - if (task) { - task->task_work = total_work; - task->task_progress = 0; - task->task_state = SLAPI_TASK_RUNNING; - slapi_task_status_changed(task); - } -} - -static void slapi_task_inc_progress(Slapi_Task *task) -{ - if (task) { - task->task_progress++; - slapi_task_status_changed(task); - } -} - -static void slapi_task_finish(Slapi_Task *task, int rc) -{ - if (task) { - task->task_exitcode = rc; - task->task_state = SLAPI_TASK_FINISHED; - slapi_task_status_changed(task); - } -} - -static void slapi_task_set_destructor_fn(Slapi_Task *task, TaskCallbackFn func) -{ - if (task) { - task->destructor = func; - } -} - -#endif /* !SLAPI_TASK_PUBLIC */ -/****** secrets ********/ - -/*** function prototypes ***/ - -/* exported functions */ -int ipamo_postop_init(Slapi_PBlock *pb ); - -/* plugin callbacks */ -static int memberof_postop_del(Slapi_PBlock *pb ); -static int memberof_postop_modrdn(Slapi_PBlock *pb ); -static int memberof_postop_modify(Slapi_PBlock *pb ); -static int memberof_postop_add(Slapi_PBlock *pb ); -static int memberof_postop_start(Slapi_PBlock *pb); -static int memberof_postop_close(Slapi_PBlock *pb); - -/* supporting cast */ -static int memberof_oktodo(Slapi_PBlock *pb); -static char *memberof_getdn(Slapi_PBlock *pb); -static int memberof_modop_one(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, - char *op_this, char *op_to); -static int memberof_modop_one_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, - char *group_dn, char *op_this, char *op_to, memberofstringll *stack); -static int memberof_add_one(Slapi_PBlock *pb, MemberOfConfig *config, char *addthis, - char *addto); -static int memberof_del_one(Slapi_PBlock *pb, MemberOfConfig *config, char *delthis, - char *delfrom); -static int memberof_mod_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod, - char *groupdn, Slapi_Mod *smod); -static int memberof_add_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Mod *smod); -static int memberof_del_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Mod *smod); -static int memberof_mod_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod, - char *groupdn, Slapi_Attr *attr); -static int memberof_mod_attr_list_r(Slapi_PBlock *pb, MemberOfConfig *config, - int mod, char *group_dn, char *op_this, Slapi_Attr *attr, memberofstringll *stack); -static int memberof_add_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Attr *attr); -static int memberof_del_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Attr *attr); -static int memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *pre_dn, char *post_dn, Slapi_Attr *attr); -static int memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config, char *group_dn); -static void memberof_set_plugin_id(void * plugin_id); -static void *memberof_get_plugin_id(); -static int memberof_compare(MemberOfConfig *config, const void *a, const void *b); -static int memberof_qsort_compare(const void *a, const void *b); -static void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr); -static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, char *dn); -static int memberof_call_foreach_dn(Slapi_PBlock *pb, char *dn, - char *type, plugin_search_entry_callback callback, void *callback_data); -static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, - Slapi_Value *memberdn); -static Slapi_ValueSet *memberof_get_groups(MemberOfConfig *config, char *memberdn); -static int memberof_get_groups_r(MemberOfConfig *config, char *memberdn, - memberof_get_groups_data *data); -static int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data); -static int memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config, - char *group_dn); -static int memberof_test_membership_callback(Slapi_Entry *e, void *callback_data); -static int memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data); -static int memberof_replace_dn_type_callback(Slapi_Entry *e, void *callback_data); -static int memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, - char *pre_dn, char *post_dn); -static int memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, - int mod_op, char *group_dn, char *op_this, char *replace_with, char *op_to, - memberofstringll *stack); -static int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e, - Slapi_Entry *eAfter, int *returncode, char *returntext, - void *arg); -static void memberof_task_destructor(Slapi_Task *task); -static const char *fetch_attr(Slapi_Entry *e, const char *attrname, - const char *default_val); -static void memberof_fixup_task_thread(void *arg); -static int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str); -static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data); - - -/*** implementation ***/ - - -/*** exported functions ***/ - -/* - * ipamo_postop_init() - * - * Register plugin call backs - * - */ -int -ipamo_postop_init(Slapi_PBlock *pb) -{ - int ret = 0; - char *memberof_plugin_identity = 0; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> ipamo_postop_init\n" ); - /* - * Get plugin identity and stored it for later use - * Used for internal operations - */ - - slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &memberof_plugin_identity); - PR_ASSERT (memberof_plugin_identity); - memberof_set_plugin_id(memberof_plugin_identity); - - if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, - SLAPI_PLUGIN_VERSION_01 ) != 0 || - slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, - (void *)&pdesc ) != 0 || - slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN, - (void *) memberof_postop_del ) != 0 || - slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN, - (void *) memberof_postop_modrdn ) != 0 || - slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODIFY_FN, - (void *) memberof_postop_modify ) != 0 || - slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ADD_FN, - (void *) memberof_postop_add ) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, - (void *) memberof_postop_start ) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, - (void *) memberof_postop_close ) != 0) - { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "ipamo_postop_init failed\n" ); - ret = -1; - } - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- ipamo_postop_init\n" ); - return ret; -} - -/* - * memberof_postop_start() - * - * Do plugin start up stuff - * - */ -int memberof_postop_start(Slapi_PBlock *pb) -{ - int rc = 0; - Slapi_Entry *config_e = NULL; /* entry containing plugin config */ - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_start\n" ); - - memberof_operation_lock = slapi_new_mutex(); - if(0 == memberof_operation_lock) - { - rc = -1; - goto bail; - } - - if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &config_e ) != 0 ) { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "missing config entry\n" ); - rc = -1; - goto bail; - } - - if (( rc = memberof_config( config_e )) != LDAP_SUCCESS ) { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "configuration failed (%s)\n", ldap_err2string( rc )); - return( -1 ); - } - - rc = slapi_task_register_handler("memberof task", memberof_task_add); - if(rc) - { - goto bail; - } - - /* - * TODO: start up operation actor thread - * need to get to a point where server failure - * or shutdown doesn't hose our operations - * so we should create a task entry that contains - * all required information to complete the operation - * then the tasks can be restarted safely if - * interrupted - */ - -bail: - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_start\n" ); - - return rc; -} - -/* - * memberof_postop_close() - * - * Do plugin shut down stuff - * - */ -int memberof_postop_close(Slapi_PBlock *pb) -{ - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_close\n" ); - - - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_close\n" ); - return 0; -} - -/* - * memberof_postop_del() - * - * All entries with a memberOf attribute that contains the group DN get retrieved - * and have the their memberOf attribute regenerated (it is far too complex and - * error prone to attempt to change only those dn values involved in this case - - * mainly because the deleted group may itself be a member of other groups which - * may be members of other groups etc. in a big recursive mess involving dependency - * chains that must be created and traversed in order to decide if an entry should - * really have those groups removed too) - */ -int memberof_postop_del(Slapi_PBlock *pb) -{ - int ret = 0; - MemberOfConfig configCopy = {0, 0, 0, 0}; - char *dn; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_del\n" ); - - if(memberof_oktodo(pb) && (dn = memberof_getdn(pb))) - { - struct slapi_entry *e = NULL; - - slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e ); - - /* We need to get the config lock first. Trying to get the - * config lock after we already hold the op lock can cause - * a deadlock. */ - memberof_rlock_config(); - /* copy config so it doesn't change out from under us */ - memberof_copy_config(&configCopy, memberof_get_config()); - memberof_unlock_config(); - - /* get the memberOf operation lock */ - memberof_lock(); - - /* remove this group DN from the - * membership lists of groups - */ - memberof_del_dn_from_groups(pb, &configCopy, dn); - - /* is the entry of interest as a group? */ - if(e && !slapi_filter_test_simple(e, configCopy.group_filter)) - { - Slapi_Attr *attr = 0; - - if(0 == slapi_entry_attr_find(e, configCopy.groupattr, &attr)) - { - memberof_del_attr_list(pb, &configCopy, dn, attr); - } - } - - memberof_unlock(); - - memberof_free_config(&configCopy); - } - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_del\n" ); - return ret; -} - -typedef struct _memberof_del_dn_data -{ - char *dn; - char *type; -} memberof_del_dn_data; - -int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, char *dn) -{ - memberof_del_dn_data data = {dn, config->groupattr}; - - return memberof_call_foreach_dn(pb, dn, - config->groupattr, memberof_del_dn_type_callback, &data); -} - -int memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data) -{ - int rc = 0; - LDAPMod mod; - LDAPMod *mods[2]; - char *val[2]; - Slapi_PBlock *mod_pb = 0; - - mod_pb = slapi_pblock_new(); - - mods[0] = &mod; - mods[1] = 0; - - val[0] = ((memberof_del_dn_data *)callback_data)->dn; - val[1] = 0; - - mod.mod_op = LDAP_MOD_DELETE; - mod.mod_type = ((memberof_del_dn_data *)callback_data)->type; - mod.mod_values = val; - - slapi_modify_internal_set_pb( - mod_pb, slapi_entry_get_dn(e), - mods, 0, 0, - memberof_get_plugin_id(), 0); - - slapi_modify_internal_pb(mod_pb); - - slapi_pblock_get(mod_pb, - SLAPI_PLUGIN_INTOP_RESULT, - &rc); - - slapi_pblock_destroy(mod_pb); - - return rc; -} - -/* - * Does a callback search of "type=dn" under the db suffix that "dn" is in. - * If "dn" is a user, you'd want "type" to be "member". If "dn" is a group, - * you could want type to be either "member" or "memberOf" depending on the - * case. - */ -int memberof_call_foreach_dn(Slapi_PBlock *pb, char *dn, - char *type, plugin_search_entry_callback callback, void *callback_data) -{ - int rc = 0; - Slapi_PBlock *search_pb = slapi_pblock_new(); - Slapi_Backend *be = 0; - Slapi_DN *sdn = 0; - Slapi_DN *base_sdn = 0; - char *filter_str = 0; - - /* get the base dn for the backend we are in - (we don't support having members and groups in - different backends - issues with offline / read only backends) - */ - sdn = slapi_sdn_new_dn_byref(dn); - be = slapi_be_select(sdn); - if(be) - { - base_sdn = (Slapi_DN*)slapi_be_getsuffix(be,0); - } - - if(base_sdn) - { - filter_str = slapi_ch_smprintf("(%s=%s)", type, dn); - } - - if(filter_str) - { - slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn), - LDAP_SCOPE_SUBTREE, filter_str, 0, 0, - 0, 0, - memberof_get_plugin_id(), - 0); - - slapi_search_internal_callback_pb(search_pb, - callback_data, - 0, callback, - 0); - } - - slapi_sdn_free(&sdn); - slapi_pblock_destroy(search_pb); - slapi_ch_free_string(&filter_str); - return rc; -} - -/* - * memberof_postop_modrdn() - * - * All entries with a memberOf attribute that contains the old group DN get retrieved - * and have the old group DN deleted and the new group DN added to their memberOf attribute - */ -int memberof_postop_modrdn(Slapi_PBlock *pb) -{ - int ret = 0; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_modrdn\n" ); - - if(memberof_oktodo(pb)) - { - MemberOfConfig *mainConfig = 0; - MemberOfConfig configCopy = {0, 0, 0, 0}; - struct slapi_entry *pre_e = NULL; - struct slapi_entry *post_e = NULL; - char *pre_dn = 0; - char *post_dn = 0; - int interested = 0; - - slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e ); - slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e ); - - if(pre_e && post_e) - { - pre_dn = slapi_entry_get_ndn(pre_e); - post_dn = slapi_entry_get_ndn(post_e); - } - - /* is the entry of interest? */ - memberof_rlock_config(); - mainConfig = memberof_get_config(); - if(pre_dn && post_dn && - !slapi_filter_test_simple(post_e, mainConfig->group_filter)) - { - interested = 1; - /* copy config so it doesn't change out from under us */ - memberof_copy_config(&configCopy, mainConfig); - } - memberof_unlock_config(); - - if(interested) - { - Slapi_Attr *attr = 0; - - memberof_lock(); - - /* get a list of member attributes present in the group - * entry that is being renamed. */ - if(0 == slapi_entry_attr_find(post_e, configCopy.groupattr, &attr)) - { - memberof_moddn_attr_list(pb, &configCopy, pre_dn, post_dn, attr); - } - - /* modrdn must change the dns in groups that have - * this group as a member. - */ - memberof_replace_dn_from_groups(pb, &configCopy, pre_dn, post_dn); - - memberof_unlock(); - - memberof_free_config(&configCopy); - } - } - - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_modrdn\n" ); - return ret; -} - -typedef struct _replace_dn_data -{ - char *pre_dn; - char *post_dn; - char *type; -} replace_dn_data; - -int memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, - char *pre_dn, char *post_dn) -{ - replace_dn_data data = {pre_dn, post_dn, config->groupattr}; - - return memberof_call_foreach_dn(pb, pre_dn, config->groupattr, - memberof_replace_dn_type_callback, &data); -} - - -int memberof_replace_dn_type_callback(Slapi_Entry *e, void *callback_data) -{ - int rc = 0; - LDAPMod delmod; - LDAPMod addmod; - LDAPMod *mods[3]; - char *delval[2]; - char *addval[2]; - Slapi_PBlock *mod_pb = 0; - - mod_pb = slapi_pblock_new(); - - mods[0] = &delmod; - mods[1] = &addmod; - mods[2] = 0; - - delval[0] = ((replace_dn_data *)callback_data)->pre_dn; - delval[1] = 0; - - delmod.mod_op = LDAP_MOD_DELETE; - delmod.mod_type = ((replace_dn_data *)callback_data)->type; - delmod.mod_values = delval; - - addval[0] = ((replace_dn_data *)callback_data)->post_dn; - addval[1] = 0; - - addmod.mod_op = LDAP_MOD_ADD; - addmod.mod_type = ((replace_dn_data *)callback_data)->type; - addmod.mod_values = addval; - - slapi_modify_internal_set_pb( - mod_pb, slapi_entry_get_dn(e), - mods, 0, 0, - memberof_get_plugin_id(), 0); - - slapi_modify_internal_pb(mod_pb); - - slapi_pblock_get(mod_pb, - SLAPI_PLUGIN_INTOP_RESULT, - &rc); - - slapi_pblock_destroy(mod_pb); - - return rc; -} - -/* - * memberof_postop_modify() - * - * Added members are retrieved and have the group DN added to their memberOf attribute - * Deleted members are retrieved and have the group DN deleted from their memberOf attribute - * On replace of the membership attribute values: - * 1. Sort old and new values - * 2. Iterate through both lists at same time - * 3. Any value not in old list but in new list - add group DN to memberOf attribute - * 4. Any value in old list but not in new list - remove group DN from memberOf attribute - * - * Note: this will suck for large groups but nonetheless is optimal (it's linear) given - * current restrictions i.e. originally adding members in sorted order would allow - * us to sort one list only (the new one) but that is under server control, not this plugin - */ -int memberof_postop_modify(Slapi_PBlock *pb) -{ - int ret = 0; - char *dn = 0; - Slapi_Mods *smods = 0; - Slapi_Mod *smod = 0; - LDAPMod **mods; - Slapi_Mod *next_mod = 0; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_modify\n" ); - - if(memberof_oktodo(pb) && - (dn = memberof_getdn(pb))) - { - int config_copied = 0; - MemberOfConfig *mainConfig = 0; - MemberOfConfig configCopy = {0, 0, 0, 0}; - - /* get the mod set */ - slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); - smods = slapi_mods_new(); - slapi_mods_init_byref(smods, mods); - - next_mod = slapi_mod_new(); - smod = slapi_mods_get_first_smod(smods, next_mod); - while(smod) - { - int interested = 0; - char *type = (char *)slapi_mod_get_type(smod); - - /* We only want to copy the config if we encounter an - * operation that we need to act on. We also want to - * only copy the config the first time it's needed so - * it remains the same for all mods in the operation, - * despite any config changes that may be made. */ - if (!config_copied) - { - memberof_rlock_config(); - mainConfig = memberof_get_config(); - - if(slapi_attr_types_equivalent(type, mainConfig->groupattr)) - { - interested = 1; - /* copy config so it doesn't change out from under us */ - memberof_copy_config(&configCopy, mainConfig); - config_copied = 1; - } - - memberof_unlock_config(); - } else { - if(slapi_attr_types_equivalent(type, configCopy.groupattr)) - { - interested = 1; - } - } - - if(interested) - { - int op = slapi_mod_get_operation(smod); - - memberof_lock(); - - /* the modify op decides the function */ - switch(op & ~LDAP_MOD_BVALUES) - { - case LDAP_MOD_ADD: - { - /* add group DN to targets */ - memberof_add_smod_list(pb, &configCopy, dn, smod); - break; - } - - case LDAP_MOD_DELETE: - { - /* If there are no values in the smod, we should - * just do a replace instead. The user is just - * trying to delete all members from this group - * entry, which the replace code deals with. */ - if (slapi_mod_get_num_values(smod) == 0) - { - memberof_replace_list(pb, &configCopy, dn); - } - else - { - /* remove group DN from target values in smod*/ - memberof_del_smod_list(pb, &configCopy, dn, smod); - } - break; - } - - case LDAP_MOD_REPLACE: - { - /* replace current values */ - memberof_replace_list(pb, &configCopy, dn); - break; - } - - default: - { - slapi_log_error( - SLAPI_LOG_PLUGIN, - MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_postop_modify: unknown mod type\n" ); - break; - } - } - - memberof_unlock(); - } - - slapi_mod_done(next_mod); - smod = slapi_mods_get_next_smod(smods, next_mod); - } - - if (config_copied) - { - memberof_free_config(&configCopy); - } - - slapi_mod_free(&next_mod); - slapi_mods_free(&smods); - } - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_modify\n" ); - return ret; -} - - -/* - * memberof_postop_add() - * - * All members in the membership attribute of the new entry get retrieved - * and have the group DN added to their memberOf attribute - */ -int memberof_postop_add(Slapi_PBlock *pb) -{ - int ret = 0; - int interested = 0; - char *dn = 0; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_add\n" ); - - if(memberof_oktodo(pb) && (dn = memberof_getdn(pb))) - { - MemberOfConfig *mainConfig = 0; - MemberOfConfig configCopy = {0, 0, 0, 0}; - struct slapi_entry *e = NULL; - - slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e ); - - - /* is the entry of interest? */ - memberof_rlock_config(); - mainConfig = memberof_get_config(); - if(e && !slapi_filter_test_simple(e, mainConfig->group_filter)) - { - interested = 1; - /* copy config so it doesn't change out from under us */ - memberof_copy_config(&configCopy, mainConfig); - } - memberof_unlock_config(); - - if(interested) - { - Slapi_Attr *attr = 0; - - memberof_lock(); - - if(0 == slapi_entry_attr_find(e, configCopy.groupattr, &attr)) - { - memberof_add_attr_list(pb, &configCopy, dn, attr); - } - - memberof_unlock(); - - memberof_free_config(&configCopy); - } - } - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_add\n" ); - return ret; -} - -/*** Support functions ***/ - -/* - * memberof_oktodo() - * - * Check that the op succeeded - * Note: we also respond to replicated ops so we don't test for that - * this does require that the memberOf attribute not be replicated - * and this means that memberof is consistent with local state - * not the network system state - * - */ -int memberof_oktodo(Slapi_PBlock *pb) -{ - int ret = 1; - int oprc = 0; - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "--> memberof_postop_oktodo\n" ); - - if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0) - { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_postop_oktodo: could not get parameters\n" ); - ret = -1; - } - - /* this plugin should only execute if the operation succeeded - */ - if(oprc != 0) - { - ret = 0; - } - - slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM, - "<-- memberof_postop_oktodo\n" ); - - return ret; -} - -/* - * memberof_getdn() - * - * Get dn of target entry - * - */ -char *memberof_getdn(Slapi_PBlock *pb) -{ - char *dn = 0; - - slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn); - - return dn; -} - -/* - * memberof_modop_one() - * - * Perform op on memberof attribute of op_to using op_this as the value - * However, if op_to happens to be a group, we must arrange for the group - * members to have the mod performed on them instead, and we must take - * care to not recurse when we have visted a group before - * - * Also, we must not delete entries that are a member of the group - */ -int memberof_modop_one(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, - char *op_this, char *op_to) -{ - return memberof_modop_one_r(pb, config, mod_op, op_this, op_this, op_to, 0); -} - -/* memberof_modop_one_r() - * - * recursive function to perform above (most things don't need the replace arg) - */ - -int memberof_modop_one_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, - char *group_dn, char *op_this, char *op_to, memberofstringll *stack) -{ - return memberof_modop_one_replace_r( - pb, config, mod_op, group_dn, op_this, 0, op_to, stack); -} - -/* memberof_modop_one_replace_r() - * - * recursive function to perform above (with added replace arg) - */ -int memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, - int mod_op, char *group_dn, char *op_this, char *replace_with, - char *op_to, memberofstringll *stack) -{ - int rc = 0; - LDAPMod mod; - LDAPMod replace_mod; - LDAPMod *mods[3]; - char *val[2]; - char *replace_val[2]; - Slapi_PBlock *mod_pb = 0; - char *attrlist[2] = {config->groupattr,0}; - Slapi_DN *op_to_sdn = 0; - Slapi_Entry *e = 0; - memberofstringll *ll = 0; - char *op_str = 0; - Slapi_Value *to_dn_val = slapi_value_new_string(op_to); - Slapi_Value *this_dn_val = slapi_value_new_string(op_this); - - /* determine if this is a group op or single entry */ - op_to_sdn = slapi_sdn_new_dn_byref(op_to); - slapi_search_internal_get_entry( op_to_sdn, attrlist, - &e, memberof_get_plugin_id()); - if(!e) - { - /* In the case of a delete, we need to worry about the - * missing entry being a nested group. There's a small - * window where another thread may have deleted a nested - * group that our group_dn entry refers to. This has the - * potential of us missing some indirect member entries - * that need to be updated. */ - if(LDAP_MOD_DELETE == mod_op) - { - Slapi_PBlock *search_pb = slapi_pblock_new(); - Slapi_DN *base_sdn = 0; - Slapi_Backend *be = 0; - char *filter_str = 0; - int n_entries = 0; - - /* We can't tell for sure if the op_to entry is a - * user or a group since the entry doesn't exist - * anymore. We can safely ignore the missing entry - * if no other entries have a memberOf attribute that - * points to the missing entry. */ - be = slapi_be_select(op_to_sdn); - if(be) - { - base_sdn = (Slapi_DN*)slapi_be_getsuffix(be,0); - } - - if(base_sdn) - { - filter_str = slapi_ch_smprintf("(%s=%s)", - config->memberof_attr, op_to); - } - - if(filter_str) - { - slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn), - LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0, - memberof_get_plugin_id(), 0); - - if (slapi_search_internal_pb(search_pb)) - { - /* get result and log an error */ - int res = 0; - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res); - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_modop_one_replace_r: error searching for members: " - "%d", res); - } else { - slapi_pblock_get(search_pb, SLAPI_NENTRIES, &n_entries); - - if(n_entries > 0) - { - /* We want to fixup the membership for the - * entries that referred to the missing group - * entry. This will fix the references to - * the missing group as well as the group - * represented by op_this. */ - memberof_test_membership(pb, config, op_to); - } - } - - slapi_free_search_results_internal(search_pb); - slapi_ch_free_string(&filter_str); - } - - slapi_pblock_destroy(search_pb); - } - - goto bail; - } - - if(LDAP_MOD_DELETE == mod_op) - { - op_str = "DELETE"; - } - else if(LDAP_MOD_ADD == mod_op) - { - op_str = "ADD"; - } - else if(LDAP_MOD_REPLACE == mod_op) - { - op_str = "REPLACE"; - } - else - { - op_str = "UNKNOWN"; - } - - slapi_log_error( SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_modop_one_replace_r: %s %s in %s\n" - ,op_str, op_this, op_to); - - if(!slapi_filter_test_simple(e, config->group_filter)) - { - /* group */ - Slapi_Value *ll_dn_val = 0; - Slapi_Attr *members = 0; - - ll = stack; - - /* have we been here before? */ - while(ll) - { - ll_dn_val = slapi_value_new_string(ll->dn); - - if(0 == memberof_compare(config, &ll_dn_val, &to_dn_val)) - { - slapi_value_free(&ll_dn_val); - - /* someone set up infinitely - recursive groups - bail out */ - slapi_log_error( SLAPI_LOG_PLUGIN, - MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_modop_one_replace_r: group recursion" - " detected in %s\n" - ,op_to); - goto bail; - } - - slapi_value_free(&ll_dn_val); - ll = ll->next; - } - - /* do op on group */ - slapi_log_error( SLAPI_LOG_PLUGIN, - MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_modop_one_replace_r: descending into group %s\n", - op_to); - /* Add the nested group's DN to the stack so we can detect loops later. */ - ll = (memberofstringll*)slapi_ch_malloc(sizeof(memberofstringll)); - ll->dn = op_to; - ll->next = stack; - - slapi_entry_attr_find( e, config->groupattr, &members ); - if(members) - { - memberof_mod_attr_list_r(pb, config, mod_op, group_dn, op_this, members, ll); - } - - { - /* crazyness follows: - * strict-aliasing doesn't like the required cast - * to void for slapi_ch_free so we are made to - * juggle to get a normal thing done - */ - void *pll = ll; - slapi_ch_free(&pll); - ll = 0; - } - } - /* continue with operation */ - { - /* We want to avoid listing a group as a memberOf itself - * in case someone set up a circular grouping. - */ - if (0 == memberof_compare(config, &this_dn_val, &to_dn_val)) - { - slapi_log_error( SLAPI_LOG_PLUGIN, - MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_modop_one_replace_r: not processing memberOf " - "operations on self entry: %s\n", this_dn_val); - goto bail; - } - - /* For add and del modify operations, we just regenerate the - * memberOf attribute. */ - if(LDAP_MOD_DELETE == mod_op || LDAP_MOD_ADD == mod_op) - { - /* find parent groups and replace our member attr */ - memberof_fix_memberof_callback(e, config); - } else { - /* single entry - do mod */ - mod_pb = slapi_pblock_new(); - - mods[0] = &mod; - if(LDAP_MOD_REPLACE == mod_op) - { - mods[1] = &replace_mod; - mods[2] = 0; - } - else - { - mods[1] = 0; - } - - val[0] = op_this; - val[1] = 0; - mod.mod_op = LDAP_MOD_REPLACE == mod_op?LDAP_MOD_DELETE:mod_op; - mod.mod_type = config->memberof_attr; - mod.mod_values = val; - - if(LDAP_MOD_REPLACE == mod_op) - { - replace_val[0] = replace_with; - replace_val[1] = 0; - - replace_mod.mod_op = LDAP_MOD_ADD; - replace_mod.mod_type = config->memberof_attr; - replace_mod.mod_values = replace_val; - } - - slapi_modify_internal_set_pb( - mod_pb, op_to, - mods, 0, 0, - memberof_get_plugin_id(), 0); - - slapi_modify_internal_pb(mod_pb); - - slapi_pblock_get(mod_pb, - SLAPI_PLUGIN_INTOP_RESULT, - &rc); - - slapi_pblock_destroy(mod_pb); - } - } - -bail: - slapi_sdn_free(&op_to_sdn); - slapi_value_free(&to_dn_val); - slapi_value_free(&this_dn_val); - slapi_entry_free(e); - return rc; -} - - -/* - * memberof_add_one() - * - * Add addthis DN to the memberof attribute of addto - * - */ -int memberof_add_one(Slapi_PBlock *pb, MemberOfConfig *config, char *addthis, char *addto) -{ - return memberof_modop_one(pb, config, LDAP_MOD_ADD, addthis, addto); -} - -/* - * memberof_del_one() - * - * Delete delthis DN from the memberof attribute of delfrom - * - */ -int memberof_del_one(Slapi_PBlock *pb, MemberOfConfig *config, char *delthis, char *delfrom) -{ - return memberof_modop_one(pb, config, LDAP_MOD_DELETE, delthis, delfrom); -} - -/* - * memberof_mod_smod_list() - * - * Perform mod for group DN to the memberof attribute of the list of targets - * - */ -int memberof_mod_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod, - char *group_dn, Slapi_Mod *smod) -{ - int rc = 0; - struct berval *bv = slapi_mod_get_first_value(smod); - int last_size = 0; - char *last_str = 0; - - while(bv) - { - char *dn_str = 0; - - if(last_size > bv->bv_len) - { - dn_str = last_str; - } - else - { - int the_size = (bv->bv_len * 2) + 1; - - if(last_str) - slapi_ch_free_string(&last_str); - - dn_str = (char*)slapi_ch_malloc(the_size); - - last_str = dn_str; - last_size = the_size; - } - - memset(dn_str, 0, last_size); - - strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len); - - memberof_modop_one(pb, config, mod, group_dn, dn_str); - - bv = slapi_mod_get_next_value(smod); - } - - if(last_str) - slapi_ch_free_string(&last_str); - - return rc; -} - -/* - * memberof_add_smod_list() - * - * Add group DN to the memberof attribute of the list of targets - * - */ -int memberof_add_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Mod *smod) -{ - return memberof_mod_smod_list(pb, config, LDAP_MOD_ADD, groupdn, smod); -} - - -/* - * memberof_del_smod_list() - * - * Remove group DN from the memberof attribute of the list of targets - * - */ -int memberof_del_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *groupdn, Slapi_Mod *smod) -{ - return memberof_mod_smod_list(pb, config, LDAP_MOD_DELETE, groupdn, smod); -} - -/** - * Plugin identity mgmt - */ -void memberof_set_plugin_id(void * plugin_id) -{ - _PluginID=plugin_id; -} - -void * memberof_get_plugin_id() -{ - return _PluginID; -} - - -/* - * memberof_mod_attr_list() - * - * Perform mod for group DN to the memberof attribute of the list of targets - * - */ -int memberof_mod_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod, - char *group_dn, Slapi_Attr *attr) -{ - return memberof_mod_attr_list_r(pb, config, mod, group_dn, group_dn, attr, 0); -} - -int memberof_mod_attr_list_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod, - char *group_dn, char *op_this, Slapi_Attr *attr, memberofstringll *stack) -{ - int rc = 0; - Slapi_Value *val = 0; - Slapi_Value *op_this_val = 0; - int last_size = 0; - char *last_str = 0; - int hint = slapi_attr_first_value(attr, &val); - - op_this_val = slapi_value_new_string(op_this); - - while(val) - { - char *dn_str = 0; - struct berval *bv = 0; - - /* We don't want to process a memberOf operation on ourselves. */ - if(0 != memberof_compare(config, &val, &op_this_val)) - { - bv = (struct berval *)slapi_value_get_berval(val); - - if(last_size > bv->bv_len) - { - dn_str = last_str; - } - else - { - int the_size = (bv->bv_len * 2) + 1; - - if(last_str) - slapi_ch_free_string(&last_str); - - dn_str = (char*)slapi_ch_malloc(the_size); - - last_str = dn_str; - last_size = the_size; - } - - memset(dn_str, 0, last_size); - - strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len); - - /* If we're doing a replace (as we would in the MODRDN case), we need - * to specify the new group DN value */ - if(mod == LDAP_MOD_REPLACE) - { - memberof_modop_one_replace_r(pb, config, mod, group_dn, op_this, - group_dn, dn_str, stack); - } - else - { - memberof_modop_one_r(pb, config, mod, group_dn, op_this, dn_str, stack); - } - } - - hint = slapi_attr_next_value(attr, hint, &val); - } - - slapi_value_free(&op_this_val); - - if(last_str) - slapi_ch_free_string(&last_str); - - return rc; -} - -/* - * memberof_add_attr_list() - * - * Add group DN to the memberof attribute of the list of targets - * - */ -int memberof_add_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, char *groupdn, - Slapi_Attr *attr) -{ - return memberof_mod_attr_list(pb, config, LDAP_MOD_ADD, groupdn, attr); -} - -/* - * memberof_del_attr_list() - * - * Remove group DN from the memberof attribute of the list of targets - * - */ -int memberof_del_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, char *groupdn, - Slapi_Attr *attr) -{ - return memberof_mod_attr_list(pb, config, LDAP_MOD_DELETE, groupdn, attr); -} - -/* - * memberof_moddn_attr_list() - * - * Perform mod for group DN to the memberof attribute of the list of targets - * - */ -int memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, - char *pre_dn, char *post_dn, Slapi_Attr *attr) -{ - int rc = 0; - Slapi_Value *val = 0; - int last_size = 0; - char *last_str = 0; - int hint = slapi_attr_first_value(attr, &val); - - while(val) - { - char *dn_str = 0; - struct berval *bv = (struct berval *)slapi_value_get_berval(val); - - if(last_size > bv->bv_len) - { - dn_str = last_str; - } - else - { - int the_size = (bv->bv_len * 2) + 1; - - if(last_str) - slapi_ch_free_string(&last_str); - - dn_str = (char*)slapi_ch_malloc(the_size); - - last_str = dn_str; - last_size = the_size; - } - - memset(dn_str, 0, last_size); - - strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len); - - memberof_modop_one_replace_r(pb, config, LDAP_MOD_REPLACE, - post_dn, pre_dn, post_dn, dn_str, 0); - - hint = slapi_attr_next_value(attr, hint, &val); - } - - if(last_str) - slapi_ch_free_string(&last_str); - - return rc; -} - -/* memberof_get_groups() - * - * Gets a list of all groups that an entry is a member of. - * This is done by looking only at member attribute values. - * A Slapi_ValueSet* is returned. It is up to the caller to - * free it. - */ -Slapi_ValueSet *memberof_get_groups(MemberOfConfig *config, char *memberdn) -{ - Slapi_Value *memberdn_val = slapi_value_new_string(memberdn); - Slapi_ValueSet *groupvals = slapi_valueset_new(); - memberof_get_groups_data data = {config, memberdn_val, &groupvals}; - - memberof_get_groups_r(config, memberdn, &data); - - slapi_value_free(&memberdn_val); - - return groupvals; -} - -int memberof_get_groups_r(MemberOfConfig *config, char *memberdn, memberof_get_groups_data *data) -{ - /* Search for member=<memberdn> - * For each match, add it to the list, recurse and do same search */ - return memberof_call_foreach_dn(NULL, memberdn, config->groupattr, - memberof_get_groups_callback, data); -} - -/* memberof_get_groups_callback() - * - * Callback to perform work of memberof_get_groups() - */ -int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data) -{ - char *group_dn = slapi_entry_get_dn(e); - Slapi_Value *group_dn_val = 0; - Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals; - - /* get the DN of the group */ - group_dn_val = slapi_value_new_string(group_dn); - - /* check if e is the same as our original member entry */ - if (0 == memberof_compare(((memberof_get_groups_data*)callback_data)->config, - &((memberof_get_groups_data*)callback_data)->memberdn_val, &group_dn_val)) - { - /* A recursive group caused us to find our original - * entry we passed to memberof_get_groups(). We just - * skip processing this entry. */ - slapi_log_error( SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_get_groups_callback: group recursion" - " detected in %s\n" ,group_dn); - slapi_value_free(&group_dn_val); - goto bail; - - } - - /* have we been here before? */ - if (groupvals && - slapi_valueset_find(((memberof_get_groups_data*)callback_data)->config->group_slapiattr, - groupvals, group_dn_val)) - { - /* we either hit a recursive grouping, or an entry is - * a member of a group through multiple paths. Either - * way, we can just skip processing this entry since we've - * already gone through this part of the grouping hierarchy. */ - slapi_log_error( SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, - "memberof_get_groups_callback: possible group recursion" - " detected in %s\n" ,group_dn); - slapi_value_free(&group_dn_val); - goto bail; - } - - /* Push group_dn_val into the valueset. This memory is now owned - * by the valueset. */ - slapi_valueset_add_value_ext(groupvals, group_dn_val, SLAPI_VALUE_FLAG_PASSIN); - - /* now recurse to find parent groups of e */ - memberof_get_groups_r(((memberof_get_groups_data*)callback_data)->config, - group_dn, callback_data); - - bail: - return 0; -} - -/* memberof_is_direct_member() - * - * tests for direct membership of memberdn in group groupdn - * returns non-zero when true, zero otherwise - */ -int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, - Slapi_Value *memberdn) -{ - int rc = 0; - Slapi_DN *sdn = 0; - char *attrlist[2] = {config->groupattr,0}; - Slapi_Entry *group_e = 0; - Slapi_Attr *attr = 0; - - sdn = slapi_sdn_new_dn_byref(slapi_value_get_string(groupdn)); - - slapi_search_internal_get_entry(sdn, attrlist, - &group_e, memberof_get_plugin_id()); - - if(group_e) - { - slapi_entry_attr_find(group_e, config->groupattr, &attr ); - if(attr) - { - rc = 0 == slapi_attr_value_find( - attr, slapi_value_get_berval(memberdn)); - } - slapi_entry_free(group_e); - } - - slapi_sdn_free(&sdn); - return rc; -} - -/* memberof_test_membership() - * - * Finds all entries who are a "memberOf" the group - * represented by "group_dn". For each matching entry, we - * call memberof_test_membership_callback(). - * - * for each attribute in the memberof attribute - * determine if the entry is still a member. - * - * test each for direct membership - * move groups entry is memberof to member group - * test remaining groups for membership in member groups - * iterate until a pass fails to move a group over to member groups - * remaining groups should be deleted - */ -int memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config, char *group_dn) -{ - return memberof_call_foreach_dn(pb, group_dn, config->memberof_attr, - memberof_test_membership_callback , config); -} - -/* - * memberof_test_membership_callback() - * - * A callback function to do the work of memberof_test_membership(). - * Note that this not only tests membership, but updates the memberOf - * attributes in the entry to be correct. - */ -int memberof_test_membership_callback(Slapi_Entry *e, void *callback_data) -{ - int rc = 0; - Slapi_Attr *attr = 0; - int total = 0; - Slapi_Value **member_array = 0; - Slapi_Value **candidate_array = 0; - Slapi_Value *entry_dn = 0; - MemberOfConfig *config = (MemberOfConfig *)callback_data; - - entry_dn = slapi_value_new_string(slapi_entry_get_dn(e)); - - if(0 == entry_dn) - { - goto bail; - } - - /* divide groups into member and non-member lists */ - slapi_entry_attr_find(e, config->memberof_attr, &attr ); - if(attr) - { - slapi_attr_get_numvalues( attr, &total); - if(total) - { - Slapi_Value *val = 0; - int hint = 0; - int c_index = 0; - int m_index = 0; - int member_found = 1; - int outer_index = 0; - - candidate_array = - (Slapi_Value**) - slapi_ch_malloc(sizeof(Slapi_Value*)*total); - memset(candidate_array, 0, sizeof(Slapi_Value*)*total); - member_array = - (Slapi_Value**) - slapi_ch_malloc(sizeof(Slapi_Value*)*total); - memset(member_array, 0, sizeof(Slapi_Value*)*total); - - hint = slapi_attr_first_value(attr, &val); - - while(val) - { - /* test for direct membership */ - if(memberof_is_direct_member(config, val, entry_dn)) - { - /* it is a member */ - member_array[m_index] = val; - m_index++; - } - else - { - /* not a member, still a candidate */ - candidate_array[c_index] = val; - c_index++; - } - - hint = slapi_attr_next_value(attr, hint, &val); - } - - /* now iterate over members testing for membership - in candidate groups and moving candidates to members - when successful, quit when a full iteration adds no - new members - */ - while(member_found) - { - member_found = 0; - - /* For each group that this entry is a verified member of, see if - * any of the candidate groups are members. If they are, add them - * to the list of verified groups that this entry is a member of. - */ - while(outer_index < m_index) - { - int inner_index = 0; - - while(inner_index < c_index) - { - /* Check for a special value in this position - * that indicates that the candidate was moved - * to the member array. */ - if((void*)1 == - candidate_array[inner_index]) - { - /* was moved, skip */ - inner_index++; - continue; - } - - if(memberof_is_direct_member( - config, - candidate_array[inner_index], - member_array[outer_index])) - { - member_array[m_index] = - candidate_array - [inner_index]; - m_index++; - - candidate_array[inner_index] = - (void*)1; - - member_found = 1; - } - - inner_index++; - } - - outer_index++; - } - } - - /* here we are left only with values to delete - from the memberof attribute in the candidate list - */ - outer_index = 0; - while(outer_index < c_index) - { - /* Check for a special value in this position - * that indicates that the candidate was moved - * to the member array. */ - if((void*)1 == candidate_array[outer_index]) - { - /* item moved, skip */ - outer_index++; - continue; - } - - memberof_del_one( - 0, config, - (char*)slapi_value_get_string( - candidate_array[outer_index]), - (char*)slapi_value_get_string(entry_dn)); - - outer_index++; - } - { - /* crazyness follows: - * strict-aliasing doesn't like the required cast - * to void for slapi_ch_free so we are made to - * juggle to get a normal thing done - */ - void *pmember_array = member_array; - void *pcandidate_array = candidate_array; - slapi_ch_free(&pcandidate_array); - slapi_ch_free(&pmember_array); - candidate_array = 0; - member_array = 0; - } - } - } - -bail: - slapi_value_free(&entry_dn); - - return rc; -} - -/* - * memberof_replace_list() - * - * Perform replace the group DN list in the memberof attribute of the list of targets - * - */ -int memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config, char *group_dn) -{ - struct slapi_entry *pre_e = NULL; - struct slapi_entry *post_e = NULL; - Slapi_Attr *pre_attr = 0; - Slapi_Attr *post_attr = 0; - - slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e ); - slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e ); - - if(pre_e && post_e) - { - slapi_entry_attr_find( pre_e, config->groupattr, &pre_attr ); - slapi_entry_attr_find( post_e, config->groupattr, &post_attr ); - } - - if(pre_attr || post_attr) - { - int pre_total = 0; - int post_total = 0; - Slapi_Value **pre_array = 0; - Slapi_Value **post_array = 0; - int pre_index = 0; - int post_index = 0; - - /* create arrays of values */ - if(pre_attr) - { - slapi_attr_get_numvalues( pre_attr, &pre_total); - } - - if(post_attr) - { - slapi_attr_get_numvalues( post_attr, &post_total); - } - - /* Stash a plugin global pointer here and have memberof_qsort_compare - * use it. We have to do this because we use memberof_qsort_compare - * as the comparator function for qsort, which requires the function - * to only take two void* args. This is thread-safe since we only - * store and use the pointer while holding the memberOf operation - * lock. */ - qsortConfig = config; - - if(pre_total) - { - pre_array = - (Slapi_Value**) - slapi_ch_malloc(sizeof(Slapi_Value*)*pre_total); - memberof_load_array(pre_array, pre_attr); - qsort( - pre_array, - pre_total, - sizeof(Slapi_Value*), - memberof_qsort_compare); - } - - if(post_total) - { - post_array = - (Slapi_Value**) - slapi_ch_malloc(sizeof(Slapi_Value*)*post_total); - memberof_load_array(post_array, post_attr); - qsort( - post_array, - post_total, - sizeof(Slapi_Value*), - memberof_qsort_compare); - } - - qsortConfig = 0; - - - /* work through arrays, following these rules: - in pre, in post, do nothing - in pre, not in post, delete from entry - not in pre, in post, add to entry - */ - while(pre_index < pre_total || post_index < post_total) - { - if(pre_index == pre_total) - { - /* add the rest of post */ - memberof_add_one( - pb, config, - group_dn, - (char*)slapi_value_get_string( - post_array[post_index])); - - post_index++; - } - else if(post_index == post_total) - { - /* delete the rest of pre */ - memberof_del_one( - pb, config, - group_dn, - (char*)slapi_value_get_string( - pre_array[pre_index])); - - pre_index++; - } - else - { - /* decide what to do */ - int cmp = memberof_compare( - config, - &(pre_array[pre_index]), - &(post_array[post_index])); - - if(cmp < 0) - { - /* delete pre array */ - memberof_del_one( - pb, config, - group_dn, - (char*)slapi_value_get_string( - pre_array[pre_index])); - - pre_index++; - } - else if(cmp > 0) - { - /* add post array */ - memberof_add_one( - pb, config, - group_dn, - (char*)slapi_value_get_string( - post_array[post_index])); - - post_index++; - } - else - { - /* do nothing, advance */ - pre_index++; - post_index++; - } - } - } - slapi_ch_free((void **)&pre_array); - slapi_ch_free((void **)&post_array); - } - - return 0; -} - -/* memberof_load_array() - * - * put attribute values in array structure - */ -void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr) -{ - Slapi_Value *val = 0; - int hint = slapi_attr_first_value(attr, &val); - - while(val) - { - *array = val; - array++; - hint = slapi_attr_next_value(attr, hint, &val); - } -} - -/* memberof_compare() - * - * compare two attr values - */ -int memberof_compare(MemberOfConfig *config, const void *a, const void *b) -{ - Slapi_Value *val1 = *((Slapi_Value **)a); - Slapi_Value *val2 = *((Slapi_Value **)b); - - return slapi_attr_value_cmp( - config->group_slapiattr, - slapi_value_get_berval(val1), - slapi_value_get_berval(val2)); -} - -/* memberof_qsort_compare() - * - * This is a version of memberof_compare that uses a plugin - * global copy of the config. We'd prefer to pass in a copy - * of config that is local to the running thread, but we can't - * do this since qsort is using us as a comparator function. - * We should only use this function when using qsort, and only - * when the memberOf lock is acquired. - */ -int memberof_qsort_compare(const void *a, const void *b) -{ - Slapi_Value *val1 = *((Slapi_Value **)a); - Slapi_Value *val2 = *((Slapi_Value **)b); - - return slapi_attr_value_cmp( - qsortConfig->group_slapiattr, - slapi_value_get_berval(val1), - slapi_value_get_berval(val2)); -} - -void memberof_lock() -{ - slapi_lock_mutex(memberof_operation_lock); -} - -void memberof_unlock() -{ - slapi_unlock_mutex(memberof_operation_lock); -} - -typedef struct _task_data -{ - char *dn; - char *filter_str; -} task_data; - -void memberof_fixup_task_thread(void *arg) -{ - MemberOfConfig configCopy = {0, 0, 0, 0}; - Slapi_Task *task = (Slapi_Task *)arg; - task_data *td = NULL; - int rc = 0; - - /* Fetch our task data from the task */ - td = (task_data *)slapi_task_get_data(task); - - slapi_task_begin(task, 1); - slapi_task_log_notice(task, "Memberof task starts (arg: %s) ...\n", - td->filter_str); - - /* We need to get the config lock first. Trying to get the - * config lock after we already hold the op lock can cause - * a deadlock. */ - memberof_rlock_config(); - /* copy config so it doesn't change out from under us */ - memberof_copy_config(&configCopy, memberof_get_config()); - memberof_unlock_config(); - - /* get the memberOf operation lock */ - memberof_lock(); - - /* do real work */ - rc = memberof_fix_memberof(&configCopy, td->dn, td->filter_str); - - /* release the memberOf operation lock */ - memberof_unlock(); - - memberof_free_config(&configCopy); - - slapi_task_log_notice(task, "Memberof task finished."); - slapi_task_log_status(task, "Memberof task finished."); - slapi_task_inc_progress(task); - - /* this will queue the destruction of the task */ - slapi_task_finish(task, rc); -} - -/* extract a single value from the entry (as a string) -- if it's not in the - * entry, the default will be returned (which can be NULL). - * you do not need to free anything returned by this. - */ -const char *fetch_attr(Slapi_Entry *e, const char *attrname, - const char *default_val) -{ - Slapi_Attr *attr; - Slapi_Value *val = NULL; - - if (slapi_entry_attr_find(e, attrname, &attr) != 0) - return default_val; - slapi_attr_first_value(attr, &val); - return slapi_value_get_string(val); -} - -int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e, - Slapi_Entry *eAfter, int *returncode, char *returntext, - void *arg) -{ - PRThread *thread = NULL; - int rv = SLAPI_DSE_CALLBACK_OK; - task_data *mytaskdata = NULL; - Slapi_Task *task = NULL; - const char *filter; - const char *dn = 0; - - *returncode = LDAP_SUCCESS; - /* get arg(s) */ - if ((dn = fetch_attr(e, "basedn", 0)) == NULL) - { - *returncode = LDAP_OBJECT_CLASS_VIOLATION; - rv = SLAPI_DSE_CALLBACK_ERROR; - goto out; - } - - if ((filter = fetch_attr(e, "filter", "(objectclass=inetuser)")) == NULL) - { - *returncode = LDAP_OBJECT_CLASS_VIOLATION; - rv = SLAPI_DSE_CALLBACK_ERROR; - goto out; - } - - /* setup our task data */ - mytaskdata = (task_data*)slapi_ch_malloc(sizeof(task_data)); - if (mytaskdata == NULL) - { - *returncode = LDAP_OPERATIONS_ERROR; - rv = SLAPI_DSE_CALLBACK_ERROR; - goto out; - } - mytaskdata->dn = slapi_ch_strdup(dn); - mytaskdata->filter_str = slapi_ch_strdup(filter); - - /* allocate new task now */ - task = slapi_new_task(slapi_entry_get_ndn(e)); - - /* register our destructor for cleaning up our private data */ - slapi_task_set_destructor_fn(task, memberof_task_destructor); - - /* Stash a pointer to our data in the task */ - slapi_task_set_data(task, mytaskdata); - - /* start the sample task as a separate thread */ - thread = PR_CreateThread(PR_USER_THREAD, memberof_fixup_task_thread, - (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, - PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE); - if (thread == NULL) - { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "unable to create task thread!\n"); - *returncode = LDAP_OPERATIONS_ERROR; - rv = SLAPI_DSE_CALLBACK_ERROR; - slapi_task_finish(task, *returncode); - } else { - rv = SLAPI_DSE_CALLBACK_OK; - } - -out: - return rv; -} - -void -memberof_task_destructor(Slapi_Task *task) -{ - if (task) { - task_data *mydata = (task_data *)slapi_task_get_data(task); - if (mydata) { - slapi_ch_free_string(&mydata->dn); - slapi_ch_free_string(&mydata->filter_str); - /* Need to cast to avoid a compiler warning */ - slapi_ch_free((void **)&mydata); - } - } -} - -int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str) -{ - int rc = 0; - Slapi_PBlock *search_pb = slapi_pblock_new(); - - slapi_search_internal_set_pb(search_pb, dn, - LDAP_SCOPE_SUBTREE, filter_str, 0, 0, - 0, 0, - memberof_get_plugin_id(), - 0); - - rc = slapi_search_internal_callback_pb(search_pb, - config, - 0, memberof_fix_memberof_callback, - 0); - - slapi_pblock_destroy(search_pb); - - return rc; -} - -/* memberof_fix_memberof_callback() - * Add initial and/or fix up broken group list in entry - * - * 1. Remove all present memberOf values - * 2. Add direct group membership memberOf values - * 3. Add indirect group membership memberOf values - */ -int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data) -{ - int rc = 0; - char *dn = slapi_entry_get_dn(e); - MemberOfConfig *config = (MemberOfConfig *)callback_data; - memberof_del_dn_data del_data = {0, config->memberof_attr}; - Slapi_ValueSet *groups = 0; - - /* get a list of all of the groups this user belongs to */ - groups = memberof_get_groups(config, dn); - - /* If we found some groups, replace the existing memberOf attribute - * with the found values. */ - if (groups && slapi_valueset_count(groups)) - { - Slapi_PBlock *mod_pb = slapi_pblock_new(); - Slapi_Value *val = 0; - Slapi_Mod *smod; - LDAPMod **mods = (LDAPMod **) slapi_ch_malloc(2 * sizeof(LDAPMod *)); - int hint = 0; - - /* NGK - need to allocate the smod */ - smod = slapi_mod_new(); - slapi_mod_init(smod, 0); - slapi_mod_set_operation(smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); - slapi_mod_set_type(smod, config->memberof_attr); - - /* Loop through all of our values and add them to smod */ - hint = slapi_valueset_first_value(groups, &val); - while (val) - { - /* this makes a copy of the berval */ - slapi_mod_add_value(smod, slapi_value_get_berval(val)); - hint = slapi_valueset_next_value(groups, hint, &val); - } - - mods[0] = slapi_mod_get_ldapmod_passout(smod); - mods[1] = 0; - - slapi_modify_internal_set_pb( - mod_pb, dn, mods, 0, 0, - memberof_get_plugin_id(), 0); - - slapi_modify_internal_pb(mod_pb); - - slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); - - ldap_mods_free(mods, 1); - slapi_mod_free(&smod); - /* NGK - need to free the smod */ - slapi_pblock_destroy(mod_pb); - } else { - /* No groups were found, so remove the memberOf attribute - * from this entry. */ - memberof_del_dn_type_callback(e, &del_data); - } - - slapi_valueset_free(groups); - - return rc; -} - diff --git a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h b/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h deleted file mode 100644 index 3e7b5cf4b..000000000 --- a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h +++ /dev/null @@ -1,100 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * This Program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; version 2 of the License. - * - * This Program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA. - * - * In addition, as a special exception, Red Hat, Inc. gives You the additional - * right to link the code of this Program with code not covered under the GNU - * General Public License ("Non-GPL Code") and to distribute linked combinations - * including the two, subject to the limitations in this paragraph. Non-GPL Code - * permitted under this exception must only link to the code of this Program - * through those well defined interfaces identified in the file named EXCEPTION - * found in the source code files (the "Approved Interfaces"). The files of - * Non-GPL Code may instantiate templates or use macros or inline functions from - * the Approved Interfaces without causing the resulting work to be covered by - * the GNU General Public License. Only Red Hat, Inc. may make changes or - * additions to the list of Approved Interfaces. You must obey the GNU General - * Public License in all respects for all of the Program code and other code used - * in conjunction with the Program except the Non-GPL Code covered by this - * exception. If you modify this file, you may extend this exception to your - * version of the file, but you are not obligated to do so. If you do not wish to - * provide this exception without modification, you must delete this exception - * statement from your version and license this file solely under the GPL without - * exception. - * - * - * Copyright (C) 2008 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK **/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -/* - * ipa-memberof.h - memberOf shared definitions - * - */ - -#ifndef _MEMBEROF_H_ -#define _MEMBEROF_H_ - -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <dirsrv/slapi-plugin.h> -#include <nspr.h> - -/****** secrets *********/ -/*from FDS slapi-private.h - * until we get a proper api for access - */ -#define SLAPI_DSE_CALLBACK_OK (1) -#define SLAPI_DSE_CALLBACK_ERROR (-1) -#define SLAPI_DSE_CALLBACK_DO_NOT_APPLY (0) -#define SLAPI_DSE_RETURNTEXT_SIZE 512 -#define DSE_FLAG_PREOP 0x0002 -/*********** end secrets **********/ -/* - * macros - */ -#define MEMBEROF_PLUGIN_SUBSYSTEM "ipa-memberof-plugin" /* used for logging */ -#define MEMBEROF_GROUP_ATTR "member" -#define MEMBEROF_ATTR "memberOf" - - -/* - * structs - */ -typedef struct memberofconfig { - char *groupattr; - char *memberof_attr; - Slapi_Filter *group_filter; - Slapi_Attr *group_slapiattr; -} MemberOfConfig; - - -/* - * functions - */ -int memberof_config(Slapi_Entry *config_e); -void memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src); -void memberof_free_config(MemberOfConfig *config); -MemberOfConfig *memberof_get_config(); -void memberof_lock(); -void memberof_unlock(); -void memberof_rlock_config(); -void memberof_wlock_config(); -void memberof_unlock_config(); - - -#endif /* _MEMBEROF_H_ */ diff --git a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c b/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c deleted file mode 100644 index b2bd374ad..000000000 --- a/daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c +++ /dev/null @@ -1,312 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * This Program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; version 2 of the License. - * - * This Program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA. - * - * In addition, as a special exception, Red Hat, Inc. gives You the additional - * right to link the code of this Program with code not covered under the GNU - * General Public License ("Non-GPL Code") and to distribute linked combinations - * including the two, subject to the limitations in this paragraph. Non-GPL Code - * permitted under this exception must only link to the code of this Program - * through those well defined interfaces identified in the file named EXCEPTION - * found in the source code files (the "Approved Interfaces"). The files of - * Non-GPL Code may instantiate templates or use macros or inline functions from - * the Approved Interfaces without causing the resulting work to be covered by - * the GNU General Public License. Only Red Hat, Inc. may make changes or - * additions to the list of Approved Interfaces. You must obey the GNU General - * Public License in all respects for all of the Program code and other code used - * in conjunction with the Program except the Non-GPL Code covered by this - * exception. If you modify this file, you may extend this exception to your - * version of the file, but you are not obligated to do so. If you do not wish to - * provide this exception without modification, you must delete this exception - * statement from your version and license this file solely under the GPL without - * exception. - * - * - * Copyright (C) 2008 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK **/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -/* - * memberof_config.c - configuration-related code for memberOf plug-in - * - */ - -#include <plstr.h> - -#include "ipa-memberof.h" - -#define MEMBEROF_CONFIG_FILTER "(objectclass=*)" - -/* - * The configuration attributes are contained in the plugin entry e.g. - * cn=MemberOf Plugin,cn=plugins,cn=config - * - * Configuration is a two step process. The first pass is a validation step which - * occurs pre-op - check inputs and error out if bad. The second pass actually - * applies the changes to the run time config. - */ - - -/* - * function prototypes - */ -static int memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, - int *returncode, char *returntext, void *arg); -static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, - int *returncode, char *returntext, void *arg) -{ - return SLAPI_DSE_CALLBACK_OK; -} - -/* - * static variables - */ -/* This is the main configuration which is updated from dse.ldif. The - * config will be copied when it is used by the plug-in to prevent it - * being changed out from under a running memberOf operation. */ -static MemberOfConfig theConfig; -static PRRWLock *memberof_config_lock = 0; -static int inited = 0; - - -static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, - int *returncode, char *returntext, void *arg) -{ - *returncode = LDAP_UNWILLING_TO_PERFORM; - return SLAPI_DSE_CALLBACK_ERROR; -} - -/* - * memberof_config() - * - * Read configuration and create a configuration data structure. - * This is called after the server has configured itself so we can - * perform checks with regards to suffixes if it ever becomes - * necessary. - * Returns an LDAP error code (LDAP_SUCCESS if all goes well). - */ -int -memberof_config(Slapi_Entry *config_e) -{ - int returncode = LDAP_SUCCESS; - char returntext[SLAPI_DSE_RETURNTEXT_SIZE]; - - if ( inited ) { - slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "only one memberOf plugin instance can be used\n" ); - return( LDAP_PARAM_ERROR ); - } - - /* initialize the RW lock to protect the main config */ - memberof_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "memberof_config_lock"); - - /* initialize fields */ - memberof_apply_config(NULL, NULL, config_e, - &returncode, returntext, NULL); - - /* config DSE must be initialized before we get here */ - if (returncode == LDAP_SUCCESS) { - const char *config_dn = slapi_entry_get_dn_const(config_e); - slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, - config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER, - dont_allow_that,NULL); - slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, - config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER, - dont_allow_that, NULL); - slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, - config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER, - dont_allow_that, NULL); - slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, - config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER, - memberof_search,NULL); - } - - inited = 1; - - if (returncode != LDAP_SUCCESS) { - slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, - "Error %d: %s\n", returncode, returntext); - } - - return returncode; -} - - -/* - * memberof_apply_config() - * - * Just use hardcoded config values. - */ -static int -memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, - int *returncode, char *returntext, void *arg) -{ - char *groupattr = NULL; - char *memberof_attr = NULL; - char *filter_str = NULL; - - *returncode = LDAP_SUCCESS; - - groupattr = slapi_ch_strdup(MEMBEROF_GROUP_ATTR); - memberof_attr = slapi_ch_strdup(MEMBEROF_ATTR); - - /* We want to be sure we don't change the config in the middle of - * a memberOf operation, so we obtain an exclusive lock here */ - memberof_wlock_config(); - - if (!theConfig.groupattr || - (groupattr && PL_strcmp(theConfig.groupattr, groupattr))) { - slapi_ch_free_string(&theConfig.groupattr); - theConfig.groupattr = groupattr; - groupattr = NULL; /* config now owns memory */ - - /* We allocate a Slapi_Attr using the groupattr for - * convenience in our memberOf comparison functions */ - slapi_attr_free(&theConfig.group_slapiattr); - theConfig.group_slapiattr = slapi_attr_new(); - slapi_attr_init(theConfig.group_slapiattr, theConfig.groupattr); - - /* The filter is based off of the groupattr, so we - * update it here too. */ - slapi_filter_free(theConfig.group_filter, 1); - filter_str = slapi_ch_smprintf("(%s=*)", theConfig.groupattr); - theConfig.group_filter = slapi_str2filter(filter_str); - slapi_ch_free_string(&filter_str); - } - - if (!theConfig.memberof_attr || - (memberof_attr && PL_strcmp(theConfig.memberof_attr, memberof_attr))) { - slapi_ch_free_string(&theConfig.memberof_attr); - theConfig.memberof_attr = memberof_attr; - memberof_attr = NULL; /* config now owns memory */ - } - - /* release the lock */ - memberof_unlock_config(); - - slapi_ch_free_string(&groupattr); - slapi_ch_free_string(&memberof_attr); - - if (*returncode != LDAP_SUCCESS) - { - return SLAPI_DSE_CALLBACK_ERROR; - } - else - { - return SLAPI_DSE_CALLBACK_OK; - } -} - -/* - * memberof_copy_config() - * - * Makes a copy of the config in src. This function will free the - * elements of dest if they already exist. This should only be called - * if you hold the memberof config lock if src was obtained with - * memberof_get_config(). - */ -void -memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src) -{ - if (dest && src) - { - /* Check if the copy is already up to date */ - if (!dest->groupattr || (src->groupattr - && PL_strcmp(dest->groupattr, src->groupattr))) - { - slapi_ch_free_string(&dest->groupattr); - dest->groupattr = slapi_ch_strdup(src->groupattr); - slapi_filter_free(dest->group_filter, 1); - dest->group_filter = slapi_filter_dup(src->group_filter); - slapi_attr_free(&dest->group_slapiattr); - dest->group_slapiattr = slapi_attr_dup(src->group_slapiattr); - } - - if (!dest->memberof_attr || (src->memberof_attr - && PL_strcmp(dest->memberof_attr, src->memberof_attr))) - { - slapi_ch_free_string(&dest->memberof_attr); - dest->memberof_attr = slapi_ch_strdup(src->memberof_attr); - } - } -} - -/* - * memberof_free_config() - * - * Free's the contents of a config structure. - */ -void -memberof_free_config(MemberOfConfig *config) -{ - if (config) - { - slapi_ch_free_string(&config->groupattr); - slapi_filter_free(config->group_filter, 1); - slapi_attr_free(&config->group_slapiattr); - slapi_ch_free_string(&config->memberof_attr); - } -} - -/* - * memberof_get_config() - * - * Returns a pointer to the main config. You should call - * memberof_rlock_config() first so the main config doesn't - * get modified out from under you. - */ -MemberOfConfig * -memberof_get_config() -{ - return &theConfig; -} - -/* - * memberof_rlock_config() - * - * Gets a non-exclusive lock on the main config. This will - * prevent the config from being changed out from under you - * while you read it, but it will still allow other threads - * to read the config at the same time. - */ -void -memberof_rlock_config() -{ - PR_RWLock_Rlock(memberof_config_lock); -} - -/* - * memberof_wlock_config() - * - * Gets an exclusive lock on the main config. This should - * be called if you need to write to the main config. - */ -void -memberof_wlock_config() -{ - PR_RWLock_Wlock(memberof_config_lock); -} - -/* - * memberof_unlock_config() - * - * Unlocks the main config. - */ -void -memberof_unlock_config() -{ - PR_RWLock_Unlock(memberof_config_lock); -} diff --git a/daemons/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif b/daemons/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif deleted file mode 100644 index 1441afeae..000000000 --- a/daemons/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif +++ /dev/null @@ -1,14 +0,0 @@ -dn: cn=ipa-memberof,cn=plugins,cn=config -changetype: add -objectclass: top -objectclass: nsSlapdPlugin -objectclass: extensibleObject -cn: ipa-memberof -nsslapd-pluginpath: libipa-memberof-plugin -nsslapd-plugininitfunc: ipamo_postop_init -nsslapd-plugintype: postoperation -nsslapd-pluginenabled: on -nsslapd-pluginid: memberof -nsslapd-pluginversion: 1.0 -nsslapd-pluginvendor: Red Hat -nsslapd-plugindescription: Memberof plugin |