mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add new plugin used to modify related attributes after a modrdn operation.
This commit is contained in:
@@ -282,6 +282,7 @@ AC_CONFIG_FILES([
|
||||
ipa-slapi-plugins/ipa-winsync/Makefile
|
||||
ipa-slapi-plugins/ipa-version/Makefile
|
||||
ipa-slapi-plugins/ipa-uuid/Makefile
|
||||
ipa-slapi-plugins/ipa-modrdn/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -2,6 +2,7 @@ NULL =
|
||||
|
||||
SUBDIRS = \
|
||||
ipa-enrollment \
|
||||
ipa-modrdn \
|
||||
ipa-pwd-extop \
|
||||
ipa-uuid \
|
||||
ipa-version \
|
||||
|
||||
42
daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am
Normal file
42
daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am
Normal file
@@ -0,0 +1,42 @@
|
||||
NULL =
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I/usr/include/dirsrv \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(MOZLDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_modrdn.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_modrdn_la_SOURCES = \
|
||||
ipa_modrdn.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_modrdn_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_modrdn_la_LIBADD = \
|
||||
$(MOZLDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
modrdn-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
||||
991
daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
Normal file
991
daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
Normal file
@@ -0,0 +1,991 @@
|
||||
/** 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) 2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
/**
|
||||
* IPA MODRDN plug-in
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "slapi-plugin.h"
|
||||
#include "nspr.h"
|
||||
#include "prclist.h"
|
||||
|
||||
#define IPAMODRDN_PLUGIN_NAME "ipa-modrdn-plugin"
|
||||
#define IPAMODRDN_PLUGIN_VERSION 0x00010000
|
||||
|
||||
#define IPAMODRDN_DN "cn=IPA MODRDN,cn=plugins,cn=config" /* temporary */
|
||||
|
||||
#define EOK 0
|
||||
#define EFAIL -1
|
||||
|
||||
#ifndef discard_const
|
||||
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
|
||||
#endif
|
||||
|
||||
#define log_func discard_const(__func__)
|
||||
|
||||
#define LOG(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_PLUGIN, \
|
||||
IPAMODRDN_PLUGIN_NAME, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_CONFIG(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_CONFIG, \
|
||||
IPAMODRDN_PLUGIN_NAME, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_FATAL(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_FATAL, log_func, \
|
||||
"[file %s, line %d]: " fmt, \
|
||||
__FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TRACE(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_TRACE, log_func, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_OOM() LOG_FATAL("Out of Memory!\n")
|
||||
|
||||
/**
|
||||
* IPA MODRDN config types
|
||||
*/
|
||||
#define IPAMODRDN_SATTR "ipaModRDNsourceAttr"
|
||||
#define IPAMODRDN_TATTR "ipaModRDNtargetAttr"
|
||||
#define IPAMODRDN_PREFIX "ipaModRDNprefix"
|
||||
#define IPAMODRDN_SUFFIX "ipaModRDNsuffix"
|
||||
#define IPAMODRDN_FILTER "ipaModRDNfilter"
|
||||
#define IPAMODRDN_SCOPE "ipaModRDNscope"
|
||||
|
||||
#define IPAMODRDN_FEATURE_DESC "IPA MODRDN"
|
||||
#define IPAMODRDN_PLUGIN_DESC "IPA MODRDN plugin"
|
||||
#define IPAMODRDN_POSTOP_DESC "IPA MODRDN postop plugin"
|
||||
|
||||
static Slapi_PluginDesc pdesc = {
|
||||
IPAMODRDN_FEATURE_DESC,
|
||||
"Red Hat, Inc.",
|
||||
"1.0",
|
||||
IPAMODRDN_PLUGIN_DESC
|
||||
};
|
||||
|
||||
/**
|
||||
* linked list of config entries
|
||||
*/
|
||||
|
||||
struct configEntry {
|
||||
PRCList list;
|
||||
char *dn;
|
||||
char *sattr;
|
||||
char *tattr;
|
||||
char *prefix;
|
||||
char *suffix;
|
||||
char *filter;
|
||||
Slapi_Filter *slapi_filter;
|
||||
char *scope;
|
||||
};
|
||||
|
||||
static PRCList *ipamodrdn_global_config = NULL;
|
||||
static PRRWLock *g_ipamodrdn_cache_lock;
|
||||
|
||||
static void *_PluginID = NULL;
|
||||
static char *_PluginDN = NULL;
|
||||
|
||||
static int g_plugin_started = 0;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* management functions
|
||||
*
|
||||
*/
|
||||
int ipamodrdn_init(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_start(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_close(Slapi_PBlock * pb);
|
||||
|
||||
/**
|
||||
*
|
||||
* Local operation functions
|
||||
*
|
||||
*/
|
||||
static int ipamodrdn_load_plugin_config();
|
||||
static int ipamodrdn_parse_config_entry(Slapi_Entry * e, bool apply);
|
||||
static void ipamodrdn_delete_config();
|
||||
static void ipamodrdn_free_config_entry(struct configEntry ** entry);
|
||||
|
||||
/**
|
||||
*
|
||||
* helpers
|
||||
*
|
||||
*/
|
||||
static char *ipamodrdn_get_dn(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_dn_is_config(char *dn);
|
||||
static int ipamodrdn_list_contains_attr(char **list, char *attr);
|
||||
static int ipamodrdn_list_contains_attrs(char **list, char **attrs);
|
||||
static void ipamodrdn_list_remove_attr(char **list, char *attr);
|
||||
|
||||
/**
|
||||
*
|
||||
* the ops (where the real work is done)
|
||||
*
|
||||
*/
|
||||
static int ipamodrdn_config_check_post_op(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_post_op(Slapi_PBlock * pb);
|
||||
|
||||
/**
|
||||
* debug functions - global, for the debugger
|
||||
*/
|
||||
void ipamodrdn_dump_config();
|
||||
void ipamodrdn_dump_config_entry(struct configEntry *);
|
||||
|
||||
/**
|
||||
* set the debug level
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
int *module_ldap_debug = 0;
|
||||
|
||||
void plugin_init_debug_level(int *level_ptr)
|
||||
{
|
||||
module_ldap_debug = level_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* Deal with cache locking
|
||||
*
|
||||
*/
|
||||
void ipamodrdn_read_lock()
|
||||
{
|
||||
PR_RWLock_Rlock(g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
void ipamodrdn_write_lock()
|
||||
{
|
||||
PR_RWLock_Wlock(g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
void ipamodrdn_unlock()
|
||||
{
|
||||
PR_RWLock_Unlock(g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the plug-in version
|
||||
*
|
||||
*/
|
||||
int ipamodrdn_version()
|
||||
{
|
||||
return IPAMODRDN_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin identity mgmt
|
||||
*/
|
||||
void setPluginID(void *pluginID)
|
||||
{
|
||||
_PluginID = pluginID;
|
||||
}
|
||||
|
||||
void *getPluginID()
|
||||
{
|
||||
return _PluginID;
|
||||
}
|
||||
|
||||
void setPluginDN(char *pluginDN)
|
||||
{
|
||||
_PluginDN = pluginDN;
|
||||
}
|
||||
|
||||
char *getPluginDN()
|
||||
{
|
||||
return _PluginDN;
|
||||
}
|
||||
|
||||
/*
|
||||
ipamodrdn_init
|
||||
-------------
|
||||
adds our callbacks to the list
|
||||
*/
|
||||
int
|
||||
ipamodrdn_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int status = EOK;
|
||||
char *plugin_identity = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/**
|
||||
* Store the plugin identity for later use.
|
||||
* Used for internal operations
|
||||
*/
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
|
||||
PR_ASSERT(plugin_identity);
|
||||
setPluginID(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_START_FN,
|
||||
(void *) ipamodrdn_start) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
|
||||
(void *) ipamodrdn_close) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
|
||||
(void *) ipamodrdn_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0) {
|
||||
LOG_FATAL("failed to register plugin\n");
|
||||
status = EFAIL;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipamodrdn_start
|
||||
--------------
|
||||
Kicks off the config cache.
|
||||
It is called after ipamodrdn_init.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_start(Slapi_PBlock * pb)
|
||||
{
|
||||
char *plugindn = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Check if we're already started */
|
||||
if (g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
g_ipamodrdn_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "ipaModRDN");
|
||||
|
||||
if (!g_ipamodrdn_cache_lock) {
|
||||
LOG_FATAL("lock creation failed\n");
|
||||
|
||||
return EFAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plug-in target dn from the system
|
||||
* and store it for future use. This should avoid
|
||||
* hardcoding of DN's in the code.
|
||||
*/
|
||||
slapi_pblock_get(pb, SLAPI_TARGET_DN, &plugindn);
|
||||
if (NULL == plugindn || 0 == strlen(plugindn)) {
|
||||
LOG("had to use hard coded config dn\n");
|
||||
plugindn = IPAMODRDN_DN;
|
||||
} else {
|
||||
LOG("config at %s\n", plugindn);
|
||||
|
||||
}
|
||||
|
||||
setPluginDN(plugindn);
|
||||
|
||||
/*
|
||||
* Load the config for our plug-in
|
||||
*/
|
||||
ipamodrdn_global_config = (PRCList *)
|
||||
slapi_ch_calloc(1, sizeof(struct configEntry));
|
||||
PR_INIT_CLIST(ipamodrdn_global_config);
|
||||
|
||||
if (ipamodrdn_load_plugin_config() != EOK) {
|
||||
LOG_FATAL("unable to load plug-in configuration\n");
|
||||
return EFAIL;
|
||||
}
|
||||
|
||||
g_plugin_started = 1;
|
||||
LOG("ready for service\n");
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
done:
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
ipamodrdn_close
|
||||
--------------
|
||||
closes down the cache
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_close(Slapi_PBlock * pb)
|
||||
{
|
||||
LOG_TRACE( "--in-->\n");
|
||||
|
||||
ipamodrdn_delete_config();
|
||||
|
||||
slapi_ch_free((void **)&ipamodrdn_global_config);
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* config looks like this
|
||||
* - cn=myplugin
|
||||
* --- cn=posix
|
||||
* ------ cn=accounts
|
||||
* ------ cn=groups
|
||||
* --- cn=samba
|
||||
* --- cn=etc
|
||||
* ------ cn=etc etc
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_load_plugin_config()
|
||||
{
|
||||
int status = EOK;
|
||||
int result;
|
||||
int i;
|
||||
time_t now;
|
||||
Slapi_PBlock *search_pb;
|
||||
Slapi_Entry **entries = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
ipamodrdn_write_lock();
|
||||
ipamodrdn_delete_config();
|
||||
|
||||
search_pb = slapi_pblock_new();
|
||||
|
||||
slapi_search_internal_set_pb(search_pb, getPluginDN(),
|
||||
LDAP_SCOPE_SUBTREE, "objectclass=*",
|
||||
NULL, 0, NULL, NULL, getPluginID(), 0);
|
||||
slapi_search_internal_pb(search_pb);
|
||||
slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
|
||||
|
||||
if (LDAP_SUCCESS != result) {
|
||||
status = EFAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
|
||||
&entries);
|
||||
if (NULL == entries || NULL == entries[0]) {
|
||||
status = EOK;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; (entries[i] != NULL); i++) {
|
||||
/* We don't care about the status here because we may have
|
||||
* some invalid config entries, but we just want to continue
|
||||
* looking for valid ones. */
|
||||
ipamodrdn_parse_config_entry(entries[i], true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
slapi_free_search_results_internal(search_pb);
|
||||
slapi_pblock_destroy(search_pb);
|
||||
ipamodrdn_unlock();
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipamodrdn_parse_config_entry()
|
||||
*
|
||||
* Parses a single config entry. If apply is non-zero, then
|
||||
* we will load and start using the new config. You can simply
|
||||
* validate config without making any changes by setting apply
|
||||
* to 0.
|
||||
*
|
||||
* Returns EOK if the entry is valid and EFAIL
|
||||
* if it is invalid.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_parse_config_entry(Slapi_Entry * e, bool apply)
|
||||
{
|
||||
char *value;
|
||||
struct configEntry *entry = NULL;
|
||||
struct configEntry *config_entry;
|
||||
PRCList *list;
|
||||
int entry_added = 0;
|
||||
int i = 0;
|
||||
int ret = EOK;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* If this is the main MODRDN plug-in config entry, just bail. */
|
||||
if (strcasecmp(getPluginDN(), slapi_entry_get_ndn(e)) == 0) {
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
entry = (struct configEntry *)
|
||||
slapi_ch_calloc(1, sizeof(struct configEntry));
|
||||
if (NULL == entry) {
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
value = slapi_entry_get_ndn(e);
|
||||
if (value) {
|
||||
entry->dn = slapi_ch_strdup(value);
|
||||
}
|
||||
|
||||
LOG_CONFIG("----------> dn [%s]\n", entry->dn);
|
||||
|
||||
entry->sattr = slapi_entry_attr_get_charptr(e, IPAMODRDN_SATTR);
|
||||
if (!entry->sattr) {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_SATTR, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SATTR, entry->sattr);
|
||||
|
||||
entry->tattr = slapi_entry_attr_get_charptr(e, IPAMODRDN_TATTR);
|
||||
if (!entry->tattr) {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_TATTR, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_TATTR, entry->tattr);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_PREFIX);
|
||||
if (value && value[0]) {
|
||||
entry->prefix = value;
|
||||
} else {
|
||||
entry->prefix = "";
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_PREFIX, entry->prefix);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_SUFFIX);
|
||||
if (value && value[0]) {
|
||||
entry->suffix = value;
|
||||
} else {
|
||||
entry->suffix = "";
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SUFFIX, entry->suffix);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_FILTER);
|
||||
if (value) {
|
||||
entry->filter = value;
|
||||
if (NULL == (entry->slapi_filter = slapi_str2filter(value))) {
|
||||
LOG_FATAL("Error: Invalid search filter in entry [%s]: [%s]\n",
|
||||
entry->dn, value);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_FILTER, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_FILTER, value);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_SCOPE);
|
||||
if (value) {
|
||||
entry->scope = value;
|
||||
} else {
|
||||
LOG_FATAL("The %s config config setting is required for %s.\n",
|
||||
IPAMODRDN_SCOPE, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SCOPE, entry->scope);
|
||||
|
||||
/* If we were only called to validate config, we can
|
||||
* just bail out before applying the config changes */
|
||||
if (!apply) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally add the entry to the list.
|
||||
* We sort by scope dn length with longer
|
||||
* dn's first - this allows the scope
|
||||
* checking code to be simple and quick and
|
||||
* cunningly linear.
|
||||
*/
|
||||
if (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
while (list != ipamodrdn_global_config) {
|
||||
config_entry = (struct configEntry *) list;
|
||||
|
||||
if (slapi_dn_issuffix(entry->scope, config_entry->scope)) {
|
||||
PR_INSERT_BEFORE(&(entry->list), list);
|
||||
LOG_CONFIG("store [%s] before [%s] \n",
|
||||
entry->scope, config_entry->scope);
|
||||
entry_added = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
next:
|
||||
list = PR_NEXT_LINK(list);
|
||||
|
||||
if (ipamodrdn_global_config == list) {
|
||||
/* add to tail */
|
||||
PR_INSERT_BEFORE(&(entry->list), list);
|
||||
LOG_CONFIG("store [%s] at tail\n", entry->scope);
|
||||
entry_added = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* first entry */
|
||||
PR_INSERT_LINK(&(entry->list), ipamodrdn_global_config);
|
||||
LOG_CONFIG("store [%s] at head \n", entry->scope);
|
||||
entry_added = 1;
|
||||
}
|
||||
|
||||
bail:
|
||||
if (0 == entry_added) {
|
||||
/* Don't log error if we weren't asked to apply config */
|
||||
if (apply && (entry != NULL)) {
|
||||
LOG_FATAL("Invalid config entry [%s] skipped\n", entry->dn);
|
||||
}
|
||||
ipamodrdn_free_config_entry(&entry);
|
||||
} else {
|
||||
ret = EOK;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_free_config_entry(struct configEntry **entry)
|
||||
{
|
||||
struct configEntry *e;
|
||||
|
||||
if (!entry || !*entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
e = *entry;
|
||||
|
||||
if (e->dn) {
|
||||
LOG_CONFIG("freeing config entry [%s]\n", e->dn);
|
||||
slapi_ch_free_string(&e->dn);
|
||||
}
|
||||
if (e->sattr) {
|
||||
slapi_ch_free_string(&e->sattr);
|
||||
}
|
||||
if (e->tattr) {
|
||||
slapi_ch_free_string(&e->tattr);
|
||||
}
|
||||
if (e->prefix) {
|
||||
slapi_ch_free_string(&e->prefix);
|
||||
}
|
||||
if (e->suffix) {
|
||||
slapi_ch_free_string(&e->prefix);
|
||||
}
|
||||
if (e->filter) {
|
||||
slapi_ch_free_string(&e->filter);
|
||||
}
|
||||
if (e->slapi_filter) {
|
||||
slapi_filter_free(e->slapi_filter, 1);
|
||||
}
|
||||
if (e->scope) {
|
||||
slapi_ch_free_string(&e->scope);
|
||||
}
|
||||
|
||||
slapi_ch_free((void **)entry);
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_delete_configEntry(PRCList *entry)
|
||||
{
|
||||
PR_REMOVE_LINK(entry);
|
||||
ipamodrdn_free_config_entry((struct configEntry **) &entry);
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_delete_config()
|
||||
{
|
||||
PRCList *list;
|
||||
|
||||
while (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
ipamodrdn_delete_configEntry(list);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
Helpers
|
||||
****************************************************/
|
||||
|
||||
static char *ipamodrdn_get_dn(Slapi_PBlock * pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if (slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn)) {
|
||||
LOG_FATAL("failed to get dn of changed entry");
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
/* config check
|
||||
matching config dn or a descendent reloads config
|
||||
*/
|
||||
static int ipamodrdn_dn_is_config(char *dn)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if (slapi_dn_issuffix(dn, getPluginDN())) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
Functions that actually do things other
|
||||
than config and startup
|
||||
****************************************************/
|
||||
|
||||
/*
|
||||
* ipamodrdn_list_contains_attr()
|
||||
*
|
||||
* Checks if a attr is contained in a list of attrs.
|
||||
* Returns 1 if the attr is found, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_list_contains_attr(char **list, char *attr)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
|
||||
if (list && attr) {
|
||||
for (i = 0; list[i]; i++) {
|
||||
if (slapi_attr_types_equivalent(attr, list[i])) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipamodrdn_list_contains_attrs()
|
||||
*
|
||||
* Checks if all attrs in one list (attrs) are contained
|
||||
* in another list of attrs (list). Returns 1 if all
|
||||
* attrs are found, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_list_contains_attrs(char **list, char **attrs)
|
||||
{
|
||||
int ret = 1;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
if (list && attrs) {
|
||||
for (i = 0; attrs[i]; i++) {
|
||||
int found = 0;
|
||||
|
||||
for (j = 0; list[j]; j++) {
|
||||
if (slapi_attr_types_equivalent(attrs[i], list[i])) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipamodrdn_list_remove_attr()
|
||||
*
|
||||
* Removes a attr from a list of attrs.
|
||||
*/
|
||||
static void
|
||||
ipamodrdn_list_remove_attr(char **list, char *attr)
|
||||
{
|
||||
int i = 0;
|
||||
int found_attr = 0;
|
||||
|
||||
if (list && attr) {
|
||||
/* Go through the list until we find the attr that
|
||||
* we want to remove. We simply free the attr we
|
||||
* want to remove and shift the remaining array
|
||||
* elements down by one index. This will leave us
|
||||
* with two NULL elements at the end of the list,
|
||||
* but this should not cause any problems. */
|
||||
for (i = 0; list[i]; i++) {
|
||||
if (found_attr) {
|
||||
list[i] = list[i + 1];
|
||||
} else if (slapi_attr_types_equivalent(attr, list[i])) {
|
||||
slapi_ch_free_string(&list[i]);
|
||||
list[i] = list[i + 1];
|
||||
found_attr = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ipamodrdn_change_attr(struct configEntry *cfgentry,
|
||||
char *targetdn, const char *value)
|
||||
{
|
||||
Slapi_PBlock *mod_pb = slapi_pblock_new();
|
||||
LDAPMod mod;
|
||||
LDAPMod *mods[2];
|
||||
char *val[2] = { NULL };
|
||||
int ret;
|
||||
|
||||
val[0] = slapi_ch_smprintf("%s%s%s",
|
||||
cfgentry->prefix, value, cfgentry->suffix);
|
||||
if (!val[0]) {
|
||||
LOG_OOM();
|
||||
ret = EFAIL;
|
||||
goto done;
|
||||
}
|
||||
val[1] = 0;
|
||||
|
||||
mod.mod_op = LDAP_MOD_REPLACE;
|
||||
mod.mod_type = cfgentry->tattr;
|
||||
mod.mod_values = val;
|
||||
|
||||
mods[0] = &mod;
|
||||
mods[1] = 0;
|
||||
|
||||
LOG("Setting %s to %s in entry (%s)\n", cfgentry->tattr, targetdn);
|
||||
|
||||
/* Perform the modify operation. */
|
||||
slapi_modify_internal_set_pb(mod_pb, targetdn, mods,
|
||||
0, 0, getPluginID(), 0);
|
||||
slapi_modify_internal_pb(mod_pb);
|
||||
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to change attribute with error %d\n", ret);
|
||||
ret = EFAIL;
|
||||
}
|
||||
ret = EOK;
|
||||
|
||||
done:
|
||||
if (val[0]) slapi_ch_free_string(&(val[0]));
|
||||
slapi_pblock_destroy(mod_pb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* for mods and adds:
|
||||
where dn's are supplied, the closest in scope
|
||||
is used as long as the type filter matches
|
||||
and the attr value has not been generated yet.
|
||||
*/
|
||||
|
||||
static int ipamodrdn_post_op(Slapi_PBlock *pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
PRCList *list = NULL;
|
||||
struct configEntry *cfgentry = NULL;
|
||||
struct slapi_entry *e = NULL;
|
||||
Slapi_Attr *sattr = NULL;
|
||||
Slapi_Attr *tattr = NULL;
|
||||
char *value = NULL;
|
||||
char *errstr = NULL;
|
||||
int ret = LDAP_SUCCESS;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Just bail if we aren't ready to service requests yet. */
|
||||
if (!g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
|
||||
if (NULL == e) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
dn = slapi_entry_get_ndn(e);
|
||||
if (NULL == dn) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ipamodrdn_read_lock();
|
||||
|
||||
if (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
|
||||
for(list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
list != ipamodrdn_global_config;
|
||||
list = PR_NEXT_LINK(list)) {
|
||||
cfgentry = (struct configEntry *) list;
|
||||
|
||||
/* is the entry in scope? */
|
||||
if (cfgentry->scope) {
|
||||
if (!slapi_dn_issuffix(dn, cfgentry->scope)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* does the entry match the filter? */
|
||||
if (cfgentry->slapi_filter) {
|
||||
ret = slapi_vattr_filter_test(pb, e,
|
||||
cfgentry->slapi_filter, 0);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (slapi_entry_attr_find(e, cfgentry->sattr, &sattr) != 0) {
|
||||
LOG_TRACE("Source attr %s not found for %d\n",
|
||||
cfgentry->sattr, dn);
|
||||
continue;
|
||||
}
|
||||
if (slapi_entry_attr_find(e, cfgentry->tattr, &tattr) != 0) {
|
||||
LOG_TRACE("Target attr %s not found for %d\n",
|
||||
cfgentry->tattr, dn);
|
||||
} else {
|
||||
Slapi_Value *val;
|
||||
const char *strval;
|
||||
|
||||
slapi_attr_first_value(sattr, &val);
|
||||
if (!val) {
|
||||
LOG_FATAL("Source attr %s is empty\n", cfgentry->sattr);
|
||||
continue;
|
||||
}
|
||||
strval = slapi_value_get_string(val);
|
||||
|
||||
ret = ipamodrdn_change_attr(cfgentry, dn, strval);
|
||||
if (ret != EOK) {
|
||||
LOG_FATAL("Failed to set target attr %s for %d\n",
|
||||
cfgentry->tattr, dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipamodrdn_unlock();
|
||||
|
||||
ret = LDAP_SUCCESS;
|
||||
|
||||
done:
|
||||
if (ret) {
|
||||
LOG("operation failure [%d]\n", ret);
|
||||
ret = EFAIL;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipamodrdn_config_check_post_op(Slapi_PBlock * pb)
|
||||
{
|
||||
char *dn;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if ((dn = ipamodrdn_get_dn(pb))) {
|
||||
if (ipamodrdn_dn_is_config(dn)) {
|
||||
ipamodrdn_load_plugin_config();
|
||||
}
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************
|
||||
End of
|
||||
Functions that actually do things other
|
||||
than config and startup
|
||||
****************************************************/
|
||||
|
||||
/**
|
||||
* debug functions to print config
|
||||
*/
|
||||
void ipamodrdn_dump_config()
|
||||
{
|
||||
PRCList *list;
|
||||
|
||||
ipamodrdn_read_lock();
|
||||
|
||||
if (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
while (list != ipamodrdn_global_config) {
|
||||
ipamodrdn_dump_config_entry((struct configEntry *) list);
|
||||
list = PR_NEXT_LINK(list);
|
||||
}
|
||||
}
|
||||
|
||||
ipamodrdn_unlock();
|
||||
}
|
||||
|
||||
|
||||
void ipamodrdn_dump_config_entry(struct configEntry * entry)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("<---- source attr-----> %s\n", entry->sattr);
|
||||
printf("<---- target attr-----> %s\n", entry->tattr);
|
||||
printf("<---- prefix ---------> %s\n", entry->prefix);
|
||||
printf("<---- suffix ---------> %s\n", entry->suffix);
|
||||
printf("<---- filter ---------> %s\n", entry->filter);
|
||||
printf("<---- scope ----------> %s\n", entry->scope);
|
||||
}
|
||||
15
daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
Normal file
15
daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
Normal file
@@ -0,0 +1,15 @@
|
||||
dn: cn=IPA MODRDN,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: IPA MODRDN
|
||||
nsslapd-pluginpath: libipa_modrdn
|
||||
nsslapd-plugininitfunc: ipamodrdn_init
|
||||
nsslapd-plugintype: postoperation
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipamodrdn_version
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat, Inc.
|
||||
nsslapd-plugindescription: IPA MODRDN plugin
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
@@ -263,6 +263,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_enrollment_extop.la
|
||||
rm %{buildroot}/%{plugin_dir}/libipa_winsync.la
|
||||
rm %{buildroot}/%{plugin_dir}/libipa_repl_version.la
|
||||
rm %{buildroot}/%{plugin_dir}/libipa_uuid.la
|
||||
rm %{buildroot}/%{plugin_dir}/libipa_modrdn.la
|
||||
|
||||
# Some user-modifiable HTML files are provided. Move these to /etc
|
||||
# and link back.
|
||||
@@ -410,6 +411,7 @@ fi
|
||||
%attr(755,root,root) %{plugin_dir}/libipa_winsync.so
|
||||
%attr(755,root,root) %{plugin_dir}/libipa_repl_version.so
|
||||
%attr(755,root,root) %{plugin_dir}/libipa_uuid.so
|
||||
%attr(755,root,root) %{plugin_dir}/libipa_modrdn.so
|
||||
%dir %{_localstatedir}/lib/ipa
|
||||
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
|
||||
%dir %{_localstatedir}/cache/ipa
|
||||
|
||||
Reference in New Issue
Block a user