Re: [Fedora-directory-devel] Please review: distributed numeric assignment plugin

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Made values unsigned longs, failed sooner when errors not due to race conditions in dna_get_next_value(), also made dna_pre_op() return an error code on failure - probably a bad idea to just silently not work :)

Pete Rowley wrote:
Richard Megginson wrote:
Pete Rowley wrote:
Rob Crittenden wrote:
Pete Rowley wrote:
New pre-operation plugin:

In dna_get_next_value() what could cause a call to slapi_search_internal_get_entry() to fail that you have to try 3 times?

It's actually the mod operation that can fail, the original value is deleted and the new value added in one operation with two mods, if the original value has changed since the search the mod operation will fail. It's a way to get an atomic increment.
Ok. So I think the errors should be treated a little differently. If the search fails, that's bad - probably a fatal error, or perhaps someone deleted the configuration entry out from under you. I think that if the mod fails, you should check the error code, for something like LDAP_TYPE_OR_VALUE_EXISTS, which means the mod->add failed because attribute already has that value, or whatever specific error is returned from the mod->delete value operation when the value doesn't exist. Other errors are probably fatal.
ok
Would it be better to use an unsigned long to represent the value or is this longer than any possible uid (the downside, or upside, being that 64-bit could support significantly larger numbers)? If so the new_value field would need to be expanded.

Yes it should probably be unsigned long, I'll change that.
rob

------------------------------------------------------------------------

--
Fedora-directory-devel mailing list
Fedora-directory-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel


------------------------------------------------------------------------

--
Fedora-directory-devel mailing list
Fedora-directory-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel
------------------------------------------------------------------------

--
Fedora-directory-devel mailing list
Fedora-directory-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel


------------------------------------------------------------------------

--
Fedora-directory-devel mailing list
Fedora-directory-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel


--
Pete

/** 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;
	unsigned long nextval;
	unsigned long 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 = strtoul(value,0,0);
		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 = strtoul(value,0,0);
		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 = LDAP_SUCCESS;
	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 && LDAP_SUCCESS == ret)
	{
		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, "%lu",
					config_entry->interval +
					strtoul(old_value,0,0));

				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);
					if(LDAP_NO_SUCH_ATTRIBUTE != ret)
					{
						/* not the result of a race
						   to change the value
						*/
						break;
					}
					else
						/* we lost the race to mod
						   try again
						*/
						ret = LDAP_SUCCESS;
				}
			}
			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;
	int ret = 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 && LDAP_SUCCESS == ret)
                {
                        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;

                                /* create the value to add */
                                if(ret = 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 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();
	}

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 -----> %lu\n", entry->nextval);
	printf("<---- interval -------> %lu\n", entry->interval);
	printf("<---- filter ---------> %s\n", entry->filter);
	printf("<---- generate flag --> %s\n", entry->generate);
}


Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

--
Fedora-directory-devel mailing list
Fedora-directory-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/fedora-directory-devel

[Index of Archives]     [Fedora Directory Announce]     [Fedora Users]     [Older Fedora Users Mail]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Review]     [Fedora Art]     [Fedora Music]     [Fedora Packaging]     [CentOS]     [Fedora SELinux]     [Big List of Linux Books]     [KDE Users]     [Fedora Art]     [Fedora Docs]

  Powered by Linux