Diff for autotools build:
Index: Makefile.am
===================================================================
RCS file: /cvs/dirsec/ldapserver/Makefile.am,v
retrieving revision 1.14
diff -r1.14 Makefile.am
81c81
< libviews-plugin.la
---
#------------------------
# libdna-plugin
#------------------------
libdna_plugin_la_SOURCES = ldap/servers/plugins/dna/dna.c
libdna_plugin_la_CPPFLAGS = $(PLUGIN_CPPFLAGS)
New pre-operation plugin:
General numeric sequencer that allows generation of sequenced unique
numbers such as posix uidNumber, posix gidNumber, Samba SambaSID etc.
in an MMR environment. Rather than network locking or number pooling
schemes, the approach taken is to allow the configuration of an
interval that should be equal to or greater than the number of masters
in the deployment. Then each master is assigned starting numbers in
sequence e.g. server 1, 500; server 2, 501; server 3, 502 etc. When
the interval is configured as 3, the servers will generate sequences
like so: server 1, 500, 503, 506...; server 2, 501, 504, 507; server
3, 502, 505, 508. Of course, in single master environments the
interval may be set to one for a monotonically increasing sequence.
Adding masters that exceed the interval requires that the
configuration be reset, starting from a value higher than the highest
currently assigned value.
Multiple types may be configured. An LDAP search filter must be added
to the configuration for each type, the filter may be as complex as
desired and determines to which entries the configuration applies - at
minimum this filter should restrict the configuration to objectclasses
that allow the type since no schema checking is done by the plugin.
Generated values may have a pre-fix configured to be pre-pended to the
value (useful for systems such as Samba when it needs a new SID). Each
configuration entry may be scoped with a configuration attribute
containing a DN, where conflicts arise due to scope the closest scope
wins.
Configuration is dynamic. That is, once the plugin entry has been
added to cn=plugins, cn=config and the server restarted, any
configuration change will be observed. Configuration entries that do
not contain an attribute type, a starting value, an interval value,
and a filter will be ignored. Which configuration entries have been
skipped can be determined by config level logging.
Example configuration ldif and test ldaifs along with some scripts are
included. The main source is in dna.c.
------------------------------------------------------------------------
#
# 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) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#
LDAP_SRC = ../../..
BUILD_ROOT = ../../../..
NOSTDCLEAN=true # don't let nsconfig.mk define target clean
NOSTDSTRIP=true # don't let nsconfig.mk define target strip
OBJDEST = $(OBJDIR)/lib/libdna
LIBDIR = $(LDAP_PLUGIN_RELDIR)
include $(BUILD_ROOT)/nsdefs.mk
include $(BUILD_ROOT)/nsconfig.mk
include $(LDAP_SRC)/nsldap.mk
ifeq ($(ARCH), WINNT)
DEF_FILE:=./dna.def
endif
DNA_OBJS = dna.o
OBJS = $(addprefix $(OBJDEST)/, $(DNA_OBJS))
DNA_DLL = libdna-plugin
INCLUDES += -I../http -I../../slapd -I../../../include
CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
ifeq ($(ARCH), WINNT)
EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
EXTRA_LIBS += $(LDAP_COMMON_LIBS)
DNA_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
endif
ifeq ($(ARCH), AIX)
EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL)
EXTRA_LIBS += $(LDAP_COMMON_LIBS)
LD=ld
endif
ifeq ($(ARCH), HPUX)
EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
EXTRA_LIBS += $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
EXTRA_LIBS += $(LDAP_COMMON_LIBS)
endif
DNA= $(addprefix $(LIBDIR)/, $(DNA_DLL).$(DLL_SUFFIX))
clientSDK:
all: $(OBJDEST) $(LIBDIR) $(DNA)
ifeq ($(ARCH), WINNT)
$(DNA): $(OBJS) $(DNA_DLL_OBJ) $(DEF_FILE)
$(LINK_DLL) $(DNA_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
else
$(DNA): $(OBJS) $(DNA_DLL_OBJ)
$(LINK_DLL) $(DNA_DLL_OBJ) $(EXTRA_LIBS)
endif
veryclean: clean
clean:
$(RM) $(OBJS)
ifeq ($(ARCH), WINNT)
$(RM) $(DNA_DLL_OBJ)
endif
$(RM) $(DNA)
$(OBJDEST):
$(MKDIR) $(OBJDEST)
$(LIBDIR):
$(MKDIR) $(LIBDIR)
------------------------------------------------------------------------
uid=add_has_magic_number, dc=example, dc=com
uid=add_second_has_magic_number, dc=example, dc=com
uid=no_uid_number, dc=example, dc=com
uid=add_has_uid_number_550, dc=example, dc=com
uid=add_is_sub, ou=sub, dc=example, dc=com
ou=sub, dc=example, dc=com
------------------------------------------------------------------------
/** 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) 2007 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK **/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/**
* Distributed Numeric Assignment plug-in
*/
#include <stdio.h>
#include <ctype.h>
#include <string.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 "dna-plugin"
#define DNA_PLUGIN_VERSION 0x00010000
#define DNA_DN "cn=Distributed Numeric Assignment
Plugin,cn=plugins,cn=config" /* temporary */
#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"
#define FEATURE_DESC "Distributed Numeric Assignment"
#define PLUGIN_DESC "Distributed Numeric Assignment plugin"
static Slapi_PluginDesc pdesc = { FEATURE_DESC,
PLUGIN_MAGIC_VENDOR_STR,
PRODUCTTEXT,
PLUGIN_DESC };
/**
* linked list of config entries
*/
struct _defs {
PRCList list;
char *dn;
char *type;
char *prefix;
int nextval;
int interval;
struct slapi_filter *filter;
char *generate;
char *scope;
} dna_anchor;
typedef struct _defs configEntry;
static PRCList *config;
static PRRWLock *g_dna_cache_lock;
static void *_PluginID = NULL;
static char *_PluginDN = NULL;
/**
*
* DNA plug-in management functions
*
*/
int dna_init(Slapi_PBlock *pb);
static int dna_start(Slapi_PBlock *pb);
static int dna_close(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(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(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(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 dna_init( Slapi_PBlock *pb )
{
int status = DNA_SUCCESS;
char * plugin_identity=NULL;
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "-->
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 ||
/* the config change checking post op */
slapi_register_plugin(
"postoperation", /* op type */
1, /* Enabled */
"dna_init", /* this function desc */
dna_postop_init, /* init func for post op */
PLUGIN_DESC, /* plugin desc */
NULL, /* ? */
plugin_identity /* access control */
)
)
{
slapi_log_error( SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
"dna_init: failed to register plugin\n" );
status = DNA_FAILURE;
}
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "<--
dna_init\n");
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;
char * httpRootDir = NULL;
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "-->
dna_start\n");
config = &dna_anchor.list;
g_dna_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "dna");
/**
* 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 (plugindn == NULL || strlen(plugindn) == 0)
{
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
*/
PR_INIT_CLIST(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;
}
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");
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_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "<--
dna_close\n");
return DNA_SUCCESS;
}
/*
* config looks like this
* - cn=myplugin
* --- ou=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, DNA_DN, 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 (status != DNA_SUCCESS)
{
status = DNA_SUCCESS;
goto cleanup;
}
slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
if (NULL == entries || entries[0] == NULL)
{
status = DNA_SUCCESS;
goto cleanup;
}
for (i = 0; (entries[i] != NULL); i++)
{
status = parseConfigEntry(entries[i]);
}
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 *key = NULL;
char *value = NULL;
configEntry *entry = NULL;
configEntry *config_entry = NULL;
Slapi_Attr *attr = NULL;
PRCList *list = NULL;
int entry_added = 0;
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "-->
parseConfigEntry\n");
entry = (configEntry*) slapi_ch_calloc(1, sizeof(configEntry));
if(0 == 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);
value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL);
if (value) {
entry->nextval = atoi(value);
slapi_ch_free_string(&value);
value = 0;
}
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) {
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 = atoi(value);
slapi_ch_free_string(&value);
value = 0;
}
else
goto bail;
slapi_log_error( SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM , "---------->
dnaInterval [%s] \n",value,0,0);
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 = slapi_str2filter(value);
}
else
goto bail;
slapi_log_error( SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM , "----------> dnaFilter
[%s] \n",value,0,0);
slapi_ch_free_string(&value);
value = 0;
value = slapi_entry_attr_get_charptr(e, DNA_SCOPE);
if (value) {
char *canonical_dn = slapi_dn_normalize(value);
entry->scope = canonical_dn;
}
slapi_log_error( SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM , "---------->
dnaScope [%s] \n",entry->scope,0,0);
/**
* 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(config))
{
list = PR_LIST_HEAD(config);
while(list != config)
{
config_entry = (configEntry*)list;
if(slapi_attr_type_cmp(config_entry->type, entry->type,1))
goto next;
if(slapi_filter_compare(config_entry->filter, entry->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(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), 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(configEntry **entry)
{
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_filter_free(e->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((configEntry**)&entry);
}
static void deleteConfig()
{
PRCList *list;
while(!PR_CLIST_IS_EMPTY(config))
{
list = PR_LIST_HEAD(config);
deleteConfigEntry(list);
}
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;
}
/****************************************************
Functions that actually do things other
than config and startup
****************************************************/
/*
* Perform ldap operationally atomic increment
* Return the next value to be assigned
* Method:
* 1. retrieve entry
* 2. remove current value, add new value in one operation
* 3. if failed, and less than 3 times, goto 1
*/
static int dna_get_next_value(configEntry *config_entry, char **next_value_ret)
{
int ret = -1;
Slapi_DN *dn = 0;
char *attrlist[2];
Slapi_Entry *e = 0;
int attempts = 0;
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] = 0;
while(attempts < 3)
{
attempts++;
/* do update */
if(e)
{
slapi_entry_free(e);
e = 0;
}
ret = slapi_search_internal_get_entry( dn, attrlist, &e,getPluginID());
if(LDAP_SUCCESS == ret)
{
char *old_value;
old_value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL);
if(old_value)
{
LDAPMod mod_add;
LDAPMod mod_delete;
LDAPMod *mods[3];
Slapi_PBlock *pb = slapi_pblock_new();
char *delete_val[2];
char *add_val[2];
char new_value[16];
mods[0] = &mod_delete;
mods[1] = &mod_add;
mods[2] = 0;
if(0 == pb)
goto bail;
/* perform increment */
sprintf(new_value, "%d",
config_entry->interval +
atoi(old_value));
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;
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);
if(LDAP_SUCCESS == ret)
{
*next_value_ret = old_value;
break;
}
else
slapi_ch_free((void**)&old_value);
}
else
break;
}
else
break;
}
bail:
if(dn)
slapi_sdn_free(&dn);
if(e)
slapi_entry_free(e);
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;
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;
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "-->
dna_pre_op\n");
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(config))
{
list = PR_LIST_HEAD(config);
while(list != config)
{
config_entry = (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->filter)
{
if(LDAP_SUCCESS != slapi_vattr_filter_test(pb,
e,
config_entry->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;
int ret = 0;
/* create the value to add */
if(dna_get_next_value(config_entry,&value))
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);
slapi_log_error( SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM , "<--
dna_pre_op\n");
return 0;
}
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();
}
bail:
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(config))
{
list = PR_LIST_HEAD(config);
while(list != config)
{
dnaDumpConfigEntry((configEntry*)list);
list = PR_NEXT_LINK (list);
}
}
dna_unlock();
}
void dnaDumpConfigEntry(configEntry *entry)
{
printf("<- type --------------> %s\n", entry->type);
printf("<---- prefix ---------> %s\n", entry->prefix);
printf("<---- next value -----> %d\n", entry->nextval);
printf("<---- interval -------> %d\n", entry->interval);
printf("<---- filter ---------> %s\n", entry->filter);
printf("<---- generate flag --> %s\n", entry->generate);
}
------------------------------------------------------------------------
# --- 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) 2007 Red Hat, Inc.
# All rights reserved.
# --- END COPYRIGHT BLOCK ---
# plugin configuration entry
dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: nsSlapdPlugin
objectclass: extensibleObject
objectclass: nsContainer
cn: Distributed Numeric Assignment Plugin
nsslapd-plugininitfunc: dna_init
nsslapd-plugintype: preoperation
nsslapd-pluginenabled: on
nsslapd-plugindescription: Distributed Numeric Assignment plugin
nsslapd-pluginvendor: Fedora Project
nsslapd-pluginVersion: 1.1
nsslapd-pluginId: distributed-numeric-assignment
nsslapd-pluginPath: /home/prowley/srv/lib/fedora-ds/plugins/libdna-plugin.so
------------------------------------------------------------------------
# --- 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) 2007 Red Hat, Inc.
# All rights reserved.
# --- END COPYRIGHT BLOCK ---
# add plugin configuration for posix users
dn: cn=Posix,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: nsContainer
objectclass: extensibleObject
cn: Posix
dn: cn=Accounts,cn=Posix,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: extensibleObject
cn: Accounts
dnaType: uidNumber
dnaNextValue: 500
dnaInterval: 4
dnaMagicRegen: 499
dnaFilter: (objectclass=posixAccount)
# add plugin configuration for posix groups
dn: cn=Groups,cn=Posix,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: extensibleObject
cn: Groups
dnaType: gidNumber
dnaNextValue: 500
dnaInterval: 4
dnaMagicRegen: 499
dnaFilter: (objectclass=posixGroup)
------------------------------------------------------------------------
dn: uid=add_has_magic_number, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 1
sn: test
uid: add_has_uid_number
uidNumber: 499
gidNumber: 550
homeDirectory: /
------------------------------------------------------------------------
dn: uid=add_has_magic_number, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 1
sn: test
uid: add_has_uid_number
uidNumber: 499
gidNumber: 550
homeDirectory: /
dn: uid=add_second_has_magic_number, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 2
sn: test
uid: add_second_has_magic_number
uidNumber: 499
gidNumber: 550
homeDirectory: /
dn: uid=no_uid_number, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 3
sn: test
uid: no_uid_number
gidNumber: 550
homeDirectory: /
dn: uid=add_has_uid_number_550, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 4
sn: test
uid: add_has_uid_number
uidNumber: 550
gidNumber: 550
homeDirectory: /
dn: ou=sub, dc=example, dc=com
objectclass: top
objectclass: organizationalunit
ou: sub
dn: uid=add_is_sub, ou=sub, dc=example, dc=com
objectclass: top
objectclass: organizationalperson
objectclass: posixaccount
cn: 4
sn: test
uidNumber: 499
gidNumber: 550
homeDirectory: /
------------------------------------------------------------------------
# --- 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) 2007 Red Hat, Inc.
# All rights reserved.
# --- END COPYRIGHT BLOCK ---
# add Samba SIDs
dn: cn=Example top level,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: extensibleObject
dnaType: title
dnaPrefix: example-
dnaNextValue: 600
dnaInterval: 4
dnaMagicRegen: assign
dnaFilter: (objectclass=organizationalperson)
dnaScope: dc=example, dc=com
dn: cn=Example sub level,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectclass: top
objectclass: extensibleObject
dnaType: title
dnaPrefix: sub-example-
dnaNextValue: 600
dnaInterval: 4
dnaMagicRegen: assign
dnaFilter: (objectclass=organizationalperson)
dnaScope: ou=sub, dc=example, dc=com
------------------------------------------------------------------------
--
Fedora-directory-devel mailing list
Fedora-directory-devel(a)redhat.com
https://www.redhat.com/mailman/listinfo/fedora-directory-devel