| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413 |
- /** 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 <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 "dna-plugin"
- #define DNA_PLUGIN_VERSION 0x00020000
- #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"
- /* 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 "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 configEntry {
- PRCList list;
- char *dn;
- char *type;
- char *prefix;
- PRUint64 nextval;
- PRUint64 interval;
- PRUint64 maxval;
- char *filter;
- 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;
- /*
- * new value lock
- */
- static Slapi_Mutex *g_new_value_lock;
- /**
- *
- * 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(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 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;
- slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
- "--> dna_start\n");
- 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;
- }
- 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_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;
- if (NULL == (entry->slapi_filter = slapi_str2filter(value))) {
- slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM ,
- "Error: Invalid search filter in entry [%s]: [%s]\n",
- entry->dn, value);
- goto bail;
- }
- } 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");
- 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);
- }
|