diff options
Diffstat (limited to 'daemons/ipa-slapi-plugins/dna/dna.c')
-rw-r--r-- | daemons/ipa-slapi-plugins/dna/dna.c | 1462 |
1 files changed, 0 insertions, 1462 deletions
diff --git a/daemons/ipa-slapi-plugins/dna/dna.c b/daemons/ipa-slapi-plugins/dna/dna.c deleted file mode 100644 index cb6a0629c..000000000 --- a/daemons/ipa-slapi-plugins/dna/dna.c +++ /dev/null @@ -1,1462 +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. - * - * - * Author: Pete Rowley - * - * Copyright (C) 2007 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK **/ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - - -/** - * Distributed Numeric Assignment plug-in - */ - -#include <dirsrv/slapi-plugin.h> - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <errno.h> -/*#include "portable.h"*/ -#include "nspr.h" -/*#include "slapi-private.h"*/ -/*#include "dirlite_strings.h"*/ -/*#include "dirver.h"*/ - -#include "prclist.h" -#include "ldif.h" - -/* get file mode flags for unix */ -#ifndef _WIN32 -#include <sys/stat.h> -#endif - -#define DNA_PLUGIN_SUBSYSTEM "ipa-dna-plugin" -#define DNA_PLUGIN_VERSION 0x00020000 - -/* temporary */ -#define DNA_DN "cn=ipa-dna,cn=plugins,cn=config" - -#define DNA_SUCCESS 0 -#define DNA_FAILURE -1 - -/** - * DNA config types - */ -#define DNA_TYPE "dnaType" -#define DNA_PREFIX "dnaPrefix" -#define DNA_NEXTVAL "dnaNextValue" -#define DNA_INTERVAL "dnaInterval" -#define DNA_GENERATE "dnaMagicRegen" -#define DNA_FILTER "dnaFilter" -#define DNA_SCOPE "dnaScope" - -/* since v2 */ -#define DNA_MAXVAL "dnaMaxValue" -#define DNA_SHARED_CFG_DN "dnaSharedCfgDN" - -/* Shared Config */ -#define DNA_GLOBAL_RANGE "dnaGlobalRange" -#define DNA_RANGE "dnaRange" -#define DNA_MAX_RANGE_SIZE "dnaMaxRangeSize" -#define DNA_CHUNK_SIZE "dnaChunkSize" - - - -#define FEATURE_DESC "IPA Distributed Numeric Assignment" -#define PLUGIN_DESC "IPA Distributed Numeric Assignment plugin" -#define PLUGIN_DESC_INT_PREOP PLUGIN_DESC " preop internal" -#define PLUGIN_DESC_POSTOP PLUGIN_DESC " postop" -#define PLUGIN_DESC_INT_POSTOP PLUGIN_DESC " postop internal" - -static Slapi_PluginDesc pdesc = { FEATURE_DESC, - "FreeIPA project", "FreeIPA/1.0", - PLUGIN_DESC -}; - - -/** - * linked list of config entries - */ - -struct configEntry { - PRCList list; - char *dn; - char *type; - char *prefix; - PRUint64 nextval; - PRUint64 interval; - PRUint64 maxval; - char *filter; - struct slapi_filter *slapi_filter; - char *generate; - char *scope; -}; - -static PRCList *dna_global_config = NULL; -static PRRWLock *g_dna_cache_lock; - -static void *_PluginID = NULL; -static char *_PluginDN = NULL; - -static int g_plugin_started = 0; - - -/* - * new value lock - */ -static Slapi_Mutex *g_new_value_lock; - -/** - * - * DNA plug-in management functions - * - */ -int ipa_dna_init(Slapi_PBlock * pb); -static int dna_start(Slapi_PBlock * pb); -static int dna_close(Slapi_PBlock * pb); -static int dna_internal_preop_init(Slapi_PBlock *pb); -static int dna_postop_init(Slapi_PBlock * pb); - -/** - * - * Local operation functions - * - */ -static int loadPluginConfig(); -static int parseConfigEntry(Slapi_Entry * e); -static void deleteConfig(); -static void freeConfigEntry(struct configEntry ** entry); - -/** - * - * helpers - * - */ -static char *dna_get_dn(Slapi_PBlock * pb); -static int dna_dn_is_config(char *dn); -static int dna_get_next_value(struct configEntry * config_entry, - char **next_value_ret); - -/** - * - * the ops (where the real work is done) - * - */ -static int dna_config_check_post_op(Slapi_PBlock * pb); -static int dna_pre_op(Slapi_PBlock * pb, int modtype); -static int dna_mod_pre_op(Slapi_PBlock * pb); -static int dna_add_pre_op(Slapi_PBlock * pb); - -/** - * debug functions - global, for the debugger - */ -void dnaDumpConfig(); -void dnaDumpConfigEntry(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 dna_read_lock() -{ - PR_RWLock_Rlock(g_dna_cache_lock); -} - -void dna_write_lock() -{ - PR_RWLock_Wlock(g_dna_cache_lock); -} - -void dna_unlock() -{ - PR_RWLock_Unlock(g_dna_cache_lock); -} - -/** - * - * Get the dna plug-in version - * - */ -int dna_version() -{ - return DNA_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; -} - -/* - dna_init - ------------- - adds our callbacks to the list -*/ -int ipa_dna_init(Slapi_PBlock * pb) -{ - int status = DNA_SUCCESS; - char *plugin_identity = NULL; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> ipa_dna_init\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_START_FN, - (void *) dna_start) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, - (void *) dna_close) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, - (void *) &pdesc) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, - (void *) dna_mod_pre_op) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, - (void *) dna_add_pre_op) != 0 || - /* internal preoperation */ - slapi_register_plugin("internalpreoperation", /* op type */ - 1, /* Enabled */ - "dna_internal_preop_init", /* this function desc */ - dna_internal_preop_init, /* init func */ - PLUGIN_DESC_INT_PREOP, /* plugin desc */ - NULL, /* ? */ - plugin_identity /* access control */ - ) || - /* the config change checking post op */ - slapi_register_plugin("postoperation", /* op type */ - 1, /* Enabled */ - "dna_postop_init", /* this function desc */ - dna_postop_init, /* init func for post op */ - PLUGIN_DESC_POSTOP, /* plugin desc */ - NULL, /* ? */ - plugin_identity /* access control */ - ) - ) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "ipa_dna_init: failed to register plugin\n"); - status = DNA_FAILURE; - } - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- ipa_dna_init\n"); - return status; -} - - -static int -dna_internal_preop_init(Slapi_PBlock *pb) -{ - int status = DNA_SUCCESS; - - 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_INTERNAL_PRE_MODIFY_FN, - (void *) dna_mod_pre_op) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, - (void *) dna_add_pre_op) != 0) { - status = DNA_FAILURE; - } - - return status; -} - - -static int dna_postop_init(Slapi_PBlock * pb) -{ - int status = DNA_SUCCESS; - - 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_ADD_FN, - (void *) dna_config_check_post_op) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, - (void *) dna_config_check_post_op) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, - (void *) dna_config_check_post_op) != 0 || - slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, - (void *) dna_config_check_post_op) != 0) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_postop_init: failed to register plugin\n"); - status = DNA_FAILURE; - } - - return status; -} - -/* - dna_start - -------------- - Kicks off the config cache. - It is called after dna_init. -*/ -static int dna_start(Slapi_PBlock * pb) -{ - char *plugindn = NULL; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_start\n"); - - /* Check if we're already started */ - if (g_plugin_started) { - goto done; - } - - g_dna_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "dna"); - g_new_value_lock = slapi_new_mutex(); - - if (!g_dna_cache_lock || !g_new_value_lock) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_start: lock creation failed\n"); - - return DNA_FAILURE; - } - - /** - * 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)) { - slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, - "dna_start: had to use hard coded config dn\n"); - plugindn = DNA_DN; - } else { - slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, - "dna_start: config at %s\n", plugindn); - - } - - setPluginDN(plugindn); - - /** - * Load the config for our plug-in - */ - dna_global_config = (PRCList *) - slapi_ch_calloc(1, sizeof(struct configEntry)); - PR_INIT_CLIST(dna_global_config); - - if (loadPluginConfig() != DNA_SUCCESS) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_start: unable to load plug-in configuration\n"); - return DNA_FAILURE; - } - - g_plugin_started = 1; - slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, - "dna: ready for service\n"); - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_start\n"); - -done: - return DNA_SUCCESS; -} - -/* - dna_close - -------------- - closes down the cache -*/ -static int dna_close(Slapi_PBlock * pb) -{ - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_close\n"); - - deleteConfig(); - - slapi_ch_free((void **)&dna_global_config); - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_close\n"); - - return DNA_SUCCESS; -} - -/* - * config looks like this - * - cn=myplugin - * --- cn=posix - * ------ cn=accounts - * ------ cn=groups - * --- cn=samba - * --- cn=etc - * ------ cn=etc etc - */ -static int loadPluginConfig() -{ - int status = DNA_SUCCESS; - int result; - int i; - Slapi_PBlock *search_pb; - Slapi_Entry **entries = NULL; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> loadPluginConfig\n"); - - dna_write_lock(); - deleteConfig(); - - 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 = DNA_FAILURE; - goto cleanup; - } - - slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, - &entries); - if (NULL == entries || NULL == entries[0]) { - status = DNA_SUCCESS; - goto cleanup; - } - - for (i = 0; (entries[i] != NULL); i++) { - status = parseConfigEntry(entries[i]); - if (DNA_SUCCESS != status) - break; - } - - cleanup: - slapi_free_search_results_internal(search_pb); - slapi_pblock_destroy(search_pb); - dna_unlock(); - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- loadPluginConfig\n"); - - return status; -} - -static int parseConfigEntry(Slapi_Entry * e) -{ - char *value; - struct configEntry *entry; - struct configEntry *config_entry; - PRCList *list; - int entry_added = 0; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> parseConfigEntry\n"); - - entry = (struct configEntry *) - slapi_ch_calloc(1, sizeof(struct configEntry)); - if (NULL == entry) - goto bail; - - value = slapi_entry_get_ndn(e); - if (value) { - entry->dn = strdup(value); - } - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dn [%s]\n", entry->dn, 0, 0); - - value = slapi_entry_attr_get_charptr(e, DNA_TYPE); - if (value) { - entry->type = value; - } else - goto bail; - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaType [%s]\n", entry->type, 0, 0); - - /* FIXME: check the attribute type, it must suport matching rules and be - * indexed, these are requirements and failure to meet them should result in - * the configuration to be disarded and an ERROR logged prominently */ - - value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL); - if (value) { - entry->nextval = strtoul(value, 0, 0); - slapi_ch_free_string(&value); - } else - goto bail; - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaNextValue [%d]\n", entry->nextval, 0, - 0); - - value = slapi_entry_attr_get_charptr(e, DNA_PREFIX); - if (value && value[0]) { - entry->prefix = value; - } - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaPrefix [%s]\n", entry->prefix, 0, 0); - - value = slapi_entry_attr_get_charptr(e, DNA_INTERVAL); - if (value) { - entry->interval = strtoul(value, 0, 0); - } else - goto bail; - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaInterval [%s]\n", value, 0, 0); - - slapi_ch_free_string(&value); - - value = slapi_entry_attr_get_charptr(e, DNA_GENERATE); - if (value) { - entry->generate = value; - } - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaMagicRegen [%s]\n", entry->generate, - 0, 0); - - value = slapi_entry_attr_get_charptr(e, DNA_FILTER); - if (value) { - entry->filter = value; - entry->slapi_filter = slapi_str2filter(value); - } else - goto bail; - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaFilter [%s]\n", value, 0, 0); - - value = slapi_entry_attr_get_charptr(e, DNA_SCOPE); - if (value) { - entry->scope = slapi_dn_normalize(value); - } - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaScope [%s]\n", entry->scope, 0, 0); - - /* optional, if not specified set -1 which is converted to the max unisgnee - * value */ - value = slapi_entry_attr_get_charptr(e, DNA_MAXVAL); - if (value) { - entry->maxval = strtoul(value, 0, 0); - - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "----------> dnaMaxValue [%ld]\n", value, 0, 0); - - slapi_ch_free_string(&value); - } else - entry->maxval = -1; - - - /** - * Finally add the entry to the list - * we group by type then by filter - * and finally sort by 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(dna_global_config)) { - list = PR_LIST_HEAD(dna_global_config); - while (list != dna_global_config) { - config_entry = (struct configEntry *) list; - - if (slapi_attr_type_cmp(config_entry->type, entry->type, 1)) - goto next; - - if (slapi_filter_compare(config_entry->slapi_filter, - entry->slapi_filter)) - goto next; - - if (slapi_dn_issuffix(entry->scope, config_entry->scope)) { - PR_INSERT_BEFORE(&(entry->list), list); - slapi_log_error(SLAPI_LOG_CONFIG, - DNA_PLUGIN_SUBSYSTEM, - "store [%s] before [%s] \n", entry->scope, - config_entry->scope, 0); - entry_added = 1; - break; - } - - next: - list = PR_NEXT_LINK(list); - - if (dna_global_config == list) { - /* add to tail */ - PR_INSERT_BEFORE(&(entry->list), list); - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "store [%s] at tail\n", entry->scope, 0, - 0); - entry_added = 1; - break; - } - } - } else { - /* first entry */ - PR_INSERT_LINK(&(entry->list), dna_global_config); - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "store [%s] at head \n", entry->scope, 0, 0); - entry_added = 1; - } - - bail: - if (0 == entry_added) { - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "config entry [%s] skipped\n", entry->dn, 0, 0); - freeConfigEntry(&entry); - } - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- parseConfigEntry\n"); - - return DNA_SUCCESS; -} - -static void freeConfigEntry(struct configEntry ** entry) -{ - struct configEntry *e = *entry; - - if (e->dn) { - slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM, - "freeing config entry [%s]\n", e->dn, 0, 0); - slapi_ch_free_string(&e->dn); - } - - if (e->type) - slapi_ch_free_string(&e->type); - - if (e->prefix) - 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->generate) - slapi_ch_free_string(&e->generate); - - if (e->scope) - slapi_ch_free_string(&e->scope); - - slapi_ch_free((void **) entry); -} - -static void deleteConfigEntry(PRCList * entry) -{ - PR_REMOVE_LINK(entry); - freeConfigEntry((struct configEntry **) & entry); -} - -static void deleteConfig() -{ - PRCList *list; - - while (!PR_CLIST_IS_EMPTY(dna_global_config)) { - list = PR_LIST_HEAD(dna_global_config); - deleteConfigEntry(list); - } - - return; -} - -/**************************************************** - Distributed ranges Helpers -****************************************************/ - -static int dna_fix_maxval(Slapi_DN *dn, PRUint64 *cur, PRUint64 *max) -{ - /* TODO: check the main partition to see if another range - * is available, and set the new local configuration - * accordingly. - * If a new range is not available run the retrieval task - * and simply return error - */ - - return LDAP_OPERATIONS_ERROR; -} - -static void dna_notice_allocation(Slapi_DN *dn, PRUint64 new) -{ - /* TODO: check if we passed a new chunk threshold and update - * the shared configuration on the public partition. - */ - - return; -} - -/**************************************************** - Helpers -****************************************************/ - -static char *dna_get_dn(Slapi_PBlock * pb) -{ - char *dn = 0; - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_get_dn\n"); - - if (slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn)) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_get_dn: failed to get dn of changed entry"); - goto bail; - } - -/* slapi_dn_normalize( dn ); -*/ - bail: - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_get_dn\n"); - - return dn; -} - -/* config check - matching config dn or a descendent reloads config -*/ -static int dna_dn_is_config(char *dn) -{ - int ret = 0; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_is_config\n"); - - if (slapi_dn_issuffix(dn, getPluginDN())) { - ret = 1; - } - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_is_config\n"); - - return ret; -} - -#define DNA_LDAP_TAG_SK_REVERSE 0x81L - -static LDAPControl *dna_build_sort_control(const char *attr) -{ - LDAPControl *ctrl; - BerElement *ber; - int rc; - - ber = ber_alloc(); - if (NULL == ber) - return NULL; - - rc = ber_printf(ber, "{{stb}}", attr, DNA_LDAP_TAG_SK_REVERSE, 1); - if (-1 == rc) { - ber_free(ber, 1); - return NULL; - } - - rc = slapi_build_control(LDAP_CONTROL_SORTREQUEST, ber, 1, &ctrl); - - ber_free(ber, 1); - - if (LDAP_SUCCESS != rc) - return NULL; - - return ctrl; -} - -/**************************************************** - Functions that actually do things other - than config and startup -****************************************************/ - -/* we do search all values between newval and maxval asking the - * server to sort them, then we check the first free spot and - * use it as newval */ -static int dna_first_free_value(struct configEntry *config_entry, - PRUint64 *newval, - PRUint64 maxval, - PRUint64 increment) -{ - Slapi_Entry **entries = NULL; - Slapi_PBlock *pb = NULL; - LDAPControl **ctrls; - char *attrs[2]; - char *filter; - char *prefix; - char *type; - int preflen; - int result, status; - PRUint64 tmpval, sval, i; - char *strval = NULL; - - prefix = config_entry->prefix; - type = config_entry->type; - tmpval = *newval; - - attrs[0] = type; - attrs[1] = NULL; - - ctrls = (LDAPControl **)slapi_ch_calloc(2, sizeof(LDAPControl)); - if (NULL == ctrls) - return LDAP_OPERATIONS_ERROR; - - ctrls[0] = dna_build_sort_control(config_entry->type); - if (NULL == ctrls[0]) { - slapi_ch_free((void **)&ctrls); - return LDAP_OPERATIONS_ERROR; - } - - filter = slapi_ch_smprintf("(&%s(&(%s>=%s%llu)(%s<=%s%llu)))", - config_entry->filter, - type, prefix?prefix:"", tmpval, - type, prefix?prefix:"", maxval); - if (NULL == filter) { - ldap_control_free(ctrls[0]); - slapi_ch_free((void **)&ctrls); - return LDAP_OPERATIONS_ERROR; - } - - pb = slapi_pblock_new(); - if (NULL == pb) { - ldap_control_free(ctrls[0]); - slapi_ch_free((void **)&ctrls); - slapi_ch_free_string(&filter); - return LDAP_OPERATIONS_ERROR; - } - - slapi_search_internal_set_pb(pb, config_entry->scope, - LDAP_SCOPE_SUBTREE, filter, - attrs, 0, ctrls, - NULL, getPluginID(), 0); - slapi_search_internal_pb(pb); -/* - ldap_control_free(ctrls[0]); -*/ - slapi_ch_free_string(&filter); - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result); - if (LDAP_SUCCESS != result) { - status = LDAP_OPERATIONS_ERROR; - goto cleanup; - } - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, - &entries); - - if (NULL == entries || NULL == entries[0]) { - /* no values means we already have a good value */ - status = LDAP_SUCCESS; - goto cleanup; - } - - /* entries are sorted and filtered for value >= tval therefore if the - * first one does not match tval it means that the value is free, - * otherwise we need to cycle through values until we find a mismatch, - * the first mismatch is the first free pit */ - - preflen = prefix?strlen(prefix):0; - sval = 0; - for (i = 0; NULL != entries[i]; i++) { - strval = slapi_entry_attr_get_charptr(entries[i], type); - if (preflen) { - if (strlen(strval) <= preflen) { - /* something very wrong here ... */ - status = LDAP_OPERATIONS_ERROR; - goto cleanup; - } - strval = &strval[preflen-1]; - } - - errno = 0; - sval = strtoul(strval, 0, 0); - if (errno) { - /* something very wrong here ... */ - status = LDAP_OPERATIONS_ERROR; - goto cleanup; - } - slapi_ch_free_string(&strval); - - if (tmpval != sval) - break; - - if (maxval < sval) - break; - - tmpval += increment; - } - - *newval = tmpval; - status = LDAP_SUCCESS; - -cleanup: - slapi_ch_free_string(&strval); - slapi_free_search_results_internal(pb); - slapi_pblock_destroy(pb); - - return status; -} - -/* - * Perform ldap operationally atomic increment - * Return the next value to be assigned - * Method: - * 1. retrieve entry - * 2. do increment operations - * 3. remove current value, add new value in one operation - * 4. if failed, and less than 3 times, goto 1 - */ -static int dna_get_next_value(struct configEntry *config_entry, - char **next_value_ret) -{ - Slapi_PBlock *pb = NULL; - char *old_value = NULL; - Slapi_Entry *e = NULL; - Slapi_DN *dn = NULL; - char *attrlist[4]; - int attempts; - int ret; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_get_next_value\n"); - - /* get pre-requisites to search */ - dn = slapi_sdn_new_dn_byref(config_entry->dn); - attrlist[0] = DNA_NEXTVAL; - attrlist[1] = DNA_MAXVAL; - attrlist[2] = DNA_INTERVAL; - attrlist[3] = NULL; - - - /* the operation is constructed such that race conditions - * to increment the value are detected and avoided - one wins, - * one loses - however, there is no need for the server to compete - * with itself so we lock here - */ - - slapi_lock_mutex(g_new_value_lock); - - for (attempts = 0; attempts < 3; attempts++) { - - LDAPMod mod_add; - LDAPMod mod_delete; - LDAPMod *mods[3]; - char *delete_val[2]; - char *add_val[2]; - char new_value[16]; - char *interval; - char *max_value; - PRUint64 increment = 1; /* default increment */ - PRUint64 setval = 0; - PRUint64 newval = 0; - PRUint64 maxval = -1; - - /* do update */ - ret = slapi_search_internal_get_entry(dn, attrlist, &e, - getPluginID()); - if (LDAP_SUCCESS != ret) { - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - - old_value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL); - if (NULL == old_value) { - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - - setval = strtoul(old_value, 0, 0); - - max_value = slapi_entry_attr_get_charptr(e, DNA_MAXVAL); - if (max_value) { - maxval = strtoul(max_value, 0, 0); - slapi_ch_free_string(&max_value); - } - - /* if not present the default is 1 */ - interval = slapi_entry_attr_get_charptr(e, DNA_INTERVAL); - if (NULL != interval) { - increment = strtoul(interval, 0, 0); - } - - slapi_entry_free(e); - e = NULL; - - /* check the value is actually in range */ - - /* verify the new value is actually free and get the first - * one free if not*/ - ret = dna_first_free_value(config_entry, &setval, maxval, increment); - if (LDAP_SUCCESS != ret) - goto done; - - /* try for a new range or fail */ - if (setval > maxval) { - ret = dna_fix_maxval(dn, &setval, &maxval); - if (LDAP_SUCCESS != ret) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_get_next_value: no more IDs available!!\n"); - goto done; - } - - /* verify the new value is actually free and get the first - * one free if not */ - ret = dna_first_free_value(config_entry, &setval, maxval, increment); - if (LDAP_SUCCESS != ret) - goto done; - } - - if (setval > maxval) { - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - - newval = setval + increment; - - /* try for a new range or fail */ - if (newval > maxval) { - ret = dna_fix_maxval(dn, &newval, &maxval); - if (LDAP_SUCCESS != ret) { - slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM, - "dna_get_next_value: no more IDs available!!\n"); - goto done; - } - } - - /* try to set the new value */ - - sprintf(new_value, "%llu", newval); - - delete_val[0] = old_value; - delete_val[1] = 0; - - mod_delete.mod_op = LDAP_MOD_DELETE; - mod_delete.mod_type = DNA_NEXTVAL; - mod_delete.mod_values = delete_val; - - add_val[0] = new_value; - add_val[1] = 0; - - mod_add.mod_op = LDAP_MOD_ADD; - mod_add.mod_type = DNA_NEXTVAL; - mod_add.mod_values = add_val; - - mods[0] = &mod_delete; - mods[1] = &mod_add; - mods[2] = 0; - - pb = slapi_pblock_new(); - if (NULL == pb) { - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - - slapi_modify_internal_set_pb(pb, config_entry->dn, - mods, 0, 0, getPluginID(), 0); - - slapi_modify_internal_pb(pb); - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret); - - slapi_pblock_destroy(pb); - pb = NULL; - slapi_ch_free_string(&interval); - slapi_ch_free_string(&old_value); - - if (LDAP_SUCCESS == ret) { - *next_value_ret = slapi_ch_smprintf("%llu", setval); - if (NULL == *next_value_ret) { - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - - dna_notice_allocation(dn, newval); - goto done; - } - - if (LDAP_NO_SUCH_ATTRIBUTE != ret) { - /* not the result of a race - to change the value - */ - goto done; - } - } - - done: - - slapi_unlock_mutex(g_new_value_lock); - - if (LDAP_SUCCESS != ret) - slapi_ch_free_string(&old_value); - - if (dn) - slapi_sdn_free(&dn); - - if (e) - slapi_entry_free(e); - - if (pb) - slapi_pblock_destroy(pb); - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_get_next_value\n"); - - return ret; -} - -/* for mods and adds: - where dn's are supplied, the closest in scope - is used as long as the type and filter - are identical - otherwise all matches count -*/ - -static int dna_pre_op(Slapi_PBlock * pb, int modtype) -{ - char *dn = 0; - PRCList *list = 0; - struct configEntry *config_entry = 0; - struct slapi_entry *e = 0; - char *last_type = 0; - char *value = 0; - int generate = 0; - Slapi_Mods *smods = 0; - Slapi_Mod *smod = 0; - LDAPMod **mods; - int free_entry = 0; - char *errstr = NULL; - int ret = 0; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_pre_op\n"); - - /* Just bail if we aren't ready to service requests yet. */ - if (!g_plugin_started) - goto bail; - - if (0 == (dn = dna_get_dn(pb))) - goto bail; - - if (dna_dn_is_config(dn)) - goto bail; - - if (LDAP_CHANGETYPE_ADD == modtype) { - slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); - } else { - /* xxxPAR: Ideally SLAPI_MODIFY_EXISTING_ENTRY should be - * available but it turns out that is only true if you are - * a dbm backend pre-op plugin - lucky dbm backend pre-op - * plugins. - * I think that is wrong since the entry is useful for filter - * tests and schema checks and this plugin shouldn't be limited - * to a single backend type, but I don't want that fight right - * now so we go get the entry here - * - slapi_pblock_get( pb, SLAPI_MODIFY_EXISTING_ENTRY, &e); - */ - Slapi_DN *tmp_dn = slapi_sdn_new_dn_byref(dn); - if (tmp_dn) { - slapi_search_internal_get_entry(tmp_dn, 0, &e, getPluginID()); - slapi_sdn_free(&tmp_dn); - free_entry = 1; - } - - /* grab the mods - we'll put them back later with - * our modifications appended - */ - slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); - smods = slapi_mods_new(); - slapi_mods_init_passin(smods, mods); - } - - if (0 == e) - goto bailmod; - - dna_read_lock(); - - if (!PR_CLIST_IS_EMPTY(dna_global_config)) { - list = PR_LIST_HEAD(dna_global_config); - - while (list != dna_global_config && LDAP_SUCCESS == ret) { - config_entry = (struct configEntry *) list; - - /* did we already service this type? */ - if (last_type) { - if (!slapi_attr_type_cmp(config_entry->type, last_type, 1)) - goto next; - } - - /* is the entry in scope? */ - if (config_entry->scope) { - if (!slapi_dn_issuffix(dn, config_entry->scope)) - goto next; - } - - /* does the entry match the filter? */ - if (config_entry->slapi_filter) { - if (LDAP_SUCCESS != slapi_vattr_filter_test(pb, - e, - config_entry-> - slapi_filter, 0)) - goto next; - } - - - if (LDAP_CHANGETYPE_ADD == modtype) { - /* does attribute contain the magic value - or is the type not there? - */ - value = - slapi_entry_attr_get_charptr(e, config_entry->type); - if ((value - && !slapi_UTF8CASECMP(config_entry->generate, value)) - || 0 == value) { - generate = 1; - } - } else { - /* check mods for magic value */ - Slapi_Mod *next_mod = slapi_mod_new(); - smod = slapi_mods_get_first_smod(smods, next_mod); - while (smod) { - char *type = (char *) - slapi_mod_get_type(smod); - - if (slapi_attr_types_equivalent(type, - config_entry->type)) { - struct berval *bv = - slapi_mod_get_first_value(smod); - int len = strlen(config_entry->generate); - - - if (len == bv->bv_len) { - if (!slapi_UTF8NCASECMP(bv->bv_val, - config_entry->generate, - len)) - - generate = 1; - break; - } - } - - slapi_mod_done(next_mod); - smod = slapi_mods_get_next_smod(smods, next_mod); - } - - slapi_mod_free(&next_mod); - } - - if (generate) { - char *new_value; - int len; - - /* create the value to add */ - ret = dna_get_next_value(config_entry, &value); - if (DNA_SUCCESS != ret) { - errstr = slapi_ch_smprintf("Allocation of a new value for" - " %s failed! Unable to proceed.", - config_entry->type); - break; - } - - len = strlen(value) + 1; - if (config_entry->prefix) { - len += strlen(config_entry->prefix); - } - - new_value = slapi_ch_malloc(len); - - if (config_entry->prefix) { - strcpy(new_value, config_entry->prefix); - strcat(new_value, value); - } else - strcpy(new_value, value); - - /* do the mod */ - if (LDAP_CHANGETYPE_ADD == modtype) { - /* add - add to entry */ - slapi_entry_attr_set_charptr(e, - config_entry->type, - new_value); - } else { - /* mod - add to mods */ - slapi_mods_add_string(smods, - LDAP_MOD_REPLACE, - config_entry->type, new_value); - } - - /* free up */ - slapi_ch_free_string(&value); - slapi_ch_free_string(&new_value); - - /* make sure we don't generate for this - * type again - */ - if (LDAP_SUCCESS == ret) { - last_type = config_entry->type; - } - - generate = 0; - } - next: - list = PR_NEXT_LINK(list); - } - } - - dna_unlock(); - - bailmod: - if (LDAP_CHANGETYPE_MODIFY == modtype) { - /* these are the mods you made, really, - * I didn't change them, honest, just had a quick look - */ - mods = slapi_mods_get_ldapmods_passout(smods); - slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods); - slapi_mods_free(&smods); - } - - bail: - - if (free_entry && e) - slapi_entry_free(e); - - if (ret) { - slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM, - "dna_pre_op: operation failure [%d]\n", ret); - slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL); - slapi_ch_free((void **)&errstr); - ret = DNA_FAILURE; - } - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_pre_op\n"); - - return ret; -} - -static int dna_add_pre_op(Slapi_PBlock * pb) -{ - return dna_pre_op(pb, LDAP_CHANGETYPE_ADD); -} - -static int dna_mod_pre_op(Slapi_PBlock * pb) -{ - return dna_pre_op(pb, LDAP_CHANGETYPE_MODIFY); -} - -static int dna_config_check_post_op(Slapi_PBlock * pb) -{ - char *dn; - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "--> dna_config_check_post_op\n"); - - if ((dn = dna_get_dn(pb))) { - if (dna_dn_is_config(dn)) - loadPluginConfig(); - } - - slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM, - "<-- dna_config_check_post_op\n"); - - return 0; -} - -/**************************************************** - End of - Functions that actually do things other - than config and startup -****************************************************/ - -/** - * debug functions to print config - */ -void dnaDumpConfig() -{ - PRCList *list; - - dna_read_lock(); - - if (!PR_CLIST_IS_EMPTY(dna_global_config)) { - list = PR_LIST_HEAD(dna_global_config); - while (list != dna_global_config) { - dnaDumpConfigEntry((struct configEntry *) list); - list = PR_NEXT_LINK(list); - } - } - - dna_unlock(); -} - - -void dnaDumpConfigEntry(struct configEntry * entry) -{ - printf("<- type --------------> %s\n", entry->type); - printf("<---- prefix ---------> %s\n", entry->prefix); - printf("<---- next value -----> %lu\n", entry->nextval); - printf("<---- interval -------> %lu\n", entry->interval); - printf("<---- generate flag --> %s\n", entry->generate); -} |