summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/chainingdb/cb_instance.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/chainingdb/cb_instance.c')
-rw-r--r--ldap/servers/plugins/chainingdb/cb_instance.c1871
1 files changed, 1871 insertions, 0 deletions
diff --git a/ldap/servers/plugins/chainingdb/cb_instance.c b/ldap/servers/plugins/chainingdb/cb_instance.c
new file mode 100644
index 00000000..60af726f
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_instance.c
@@ -0,0 +1,1871 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+** 1 set/get function for each parameter of a backend instance
+** NOTE: Some parameters won't be taken into account until the server has restarted
+** In such cases, the internal conf is not updated but the new value is stored in the
+** dse.ldif file.
+**/
+
+/* Get functions */
+
+static void *cb_instance_hosturl_get(void *arg);
+static void *cb_instance_binduser_get(void *arg);
+static void *cb_instance_userpassword_get(void *arg);
+static void *cb_instance_maxbconn_get(void *arg);
+static void *cb_instance_maxconn_get(void *arg);
+static void *cb_instance_abandonto_get(void *arg);
+static void *cb_instance_maxbconc_get(void *arg);
+static void *cb_instance_maxconc_get(void *arg);
+static void *cb_instance_imperson_get(void *arg);
+static void *cb_instance_connlife_get(void *arg);
+static void *cb_instance_bindto_get(void *arg);
+static void *cb_instance_opto_get(void *arg);
+static void *cb_instance_ref_get(void *arg);
+static void *cb_instance_acl_get(void *arg);
+static void *cb_instance_bindretry_get(void *arg);
+static void *cb_instance_sizelimit_get(void *arg);
+static void *cb_instance_timelimit_get(void *arg);
+static void *cb_instance_hoplimit_get(void *arg);
+static void *cb_instance_max_idle_get(void *arg);
+static void *cb_instance_max_test_get(void *arg);
+
+
+/* Set functions */
+
+static int cb_instance_hosturl_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_binduser_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_userpassword_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxbconn_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxconn_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_abandonto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxbconc_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxconc_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_imperson_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_connlife_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_bindto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_opto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_ref_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_acl_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_bindretry_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_sizelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_timelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_hoplimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_max_idle_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_max_test_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+
+/* Default hardwired values */
+
+cb_instance_config_info cb_the_instance_config[] = {
+{CB_CONFIG_HOSTURL,CB_CONFIG_TYPE_STRING,"",&cb_instance_hosturl_get,&cb_instance_hosturl_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDUSER, CB_CONFIG_TYPE_STRING, "", &cb_instance_binduser_get, &cb_instance_binduser_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_USERPASSWORD,CB_CONFIG_TYPE_STRING,"",&cb_instance_userpassword_get,&cb_instance_userpassword_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXBINDCONNECTIONS,CB_CONFIG_TYPE_INT,CB_DEF_BIND_MAXCONNECTIONS,&cb_instance_maxbconn_get, &cb_instance_maxbconn_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXCONNECTIONS,CB_CONFIG_TYPE_INT,CB_DEF_MAXCONNECTIONS,&cb_instance_maxconn_get, &cb_instance_maxconn_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_ABANDONTIMEOUT,CB_CONFIG_TYPE_INT,CB_DEF_ABANDON_TIMEOUT,&cb_instance_abandonto_get, &cb_instance_abandonto_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXBINDCONCURRENCY,CB_CONFIG_TYPE_INT,CB_DEF_BIND_MAXCONCURRENCY,&cb_instance_maxbconc_get, &cb_instance_maxbconc_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXCONCURRENCY,CB_CONFIG_TYPE_INT,CB_DEF_MAXCONCURRENCY,&cb_instance_maxconc_get, &cb_instance_maxconc_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_IMPERSONATION,CB_CONFIG_TYPE_ONOFF,CB_DEF_IMPERSONATION,&cb_instance_imperson_get, &cb_instance_imperson_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_CONNLIFETIME,CB_CONFIG_TYPE_INT,CB_DEF_CONNLIFETIME,&cb_instance_connlife_get, &cb_instance_connlife_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDTIMEOUT,CB_CONFIG_TYPE_INT,CB_DEF_BINDTIMEOUT,&cb_instance_bindto_get, &cb_instance_bindto_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_TIMEOUT,CB_CONFIG_TYPE_INT,"0",&cb_instance_opto_get, &cb_instance_opto_set,0},
+{CB_CONFIG_REFERRAL,CB_CONFIG_TYPE_ONOFF,CB_DEF_SEARCHREFERRAL,&cb_instance_ref_get, &cb_instance_ref_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_LOCALACL,CB_CONFIG_TYPE_ONOFF,CB_DEF_LOCALACL,&cb_instance_acl_get, &cb_instance_acl_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDRETRY,CB_CONFIG_TYPE_INT,CB_DEF_BINDRETRY,&cb_instance_bindretry_get, &cb_instance_bindretry_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_SIZELIMIT,CB_CONFIG_TYPE_INT,CB_DEF_SIZELIMIT,&cb_instance_sizelimit_get, &cb_instance_sizelimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_TIMELIMIT,CB_CONFIG_TYPE_INT,CB_DEF_TIMELIMIT,&cb_instance_timelimit_get, &cb_instance_timelimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_HOPLIMIT,CB_CONFIG_TYPE_INT,CB_DEF_HOPLIMIT,&cb_instance_hoplimit_get, &cb_instance_hoplimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAX_IDLE_TIME,CB_CONFIG_TYPE_INT,CB_DEF_MAX_IDLE_TIME,&cb_instance_max_idle_get, &cb_instance_max_idle_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAX_TEST_TIME,CB_CONFIG_TYPE_INT,CB_DEF_MAX_TEST_TIME,&cb_instance_max_test_get, &cb_instance_max_test_set,CB_ALWAYS_SHOW},
+{NULL, 0, NULL, NULL, NULL, 0}
+};
+
+/* Others forward declarations */
+
+int cb_instance_delete_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_search_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_add_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+static int
+cb_instance_config_set(void *arg, char *attr_name, cb_instance_config_info *config_array,
+struct berval *bval, char *err_buf, int phase, int apply_mod);
+
+
+int
+cb_dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg)
+{
+ *returncode=LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static char *cb_skeleton_entries[] =
+{
+
+ "dn:cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:monitor\n",
+
+ ""
+};
+
+/*
+** Initialize a backend instance with a default configuration
+*/
+
+static void cb_instance_config_set_default(cb_backend_instance *inst)
+{
+ cb_instance_config_info *config;
+ char err_buf[CB_BUFSIZE];
+
+ for (config = cb_the_instance_config; config->config_name != NULL; config++) {
+ cb_instance_config_set((void *)inst,
+ config->config_name, cb_the_instance_config, NULL /* use default */, err_buf,
+ CB_CONFIG_PHASE_INITIALIZATION, 1 /* apply */);
+ }
+
+ /* Set backend instance flags */
+ if (inst->inst_be)
+ slapi_be_set_flag(inst->inst_be,SLAPI_BE_FLAG_REMOTE_DATA);
+}
+
+/*
+** Allocate a new chaining backend instance. Internal structure
+*/
+
+static cb_backend_instance * cb_instance_alloc(cb_backend * cb, char * name, char * basedn) {
+
+ int i;
+
+ cb_backend_instance * inst =
+ (cb_backend_instance *)slapi_ch_calloc(1, sizeof(cb_backend_instance));
+
+ /* associated_be_is_disabled defaults to 0 - this may be a problem if the associated
+ be is disabled at instance creation time
+ */
+ inst->inst_name = slapi_ch_strdup(name);
+ inst->monitor.mutex = slapi_new_mutex();
+ inst->monitor_availability.cpt_lock = slapi_new_mutex();
+ inst->monitor_availability.lock_timeLimit = slapi_new_mutex();
+ inst->pool= (cb_conn_pool *) slapi_ch_calloc(1,sizeof(cb_conn_pool));
+ inst->pool->conn.conn_list_mutex = slapi_new_mutex();
+ inst->pool->conn.conn_list_cv = slapi_new_condvar(inst->pool->conn.conn_list_mutex);
+ inst->pool->bindit=1;
+
+ inst->bind_pool= (cb_conn_pool *) slapi_ch_calloc(1,sizeof(cb_conn_pool));
+ inst->bind_pool->conn.conn_list_mutex = slapi_new_mutex();
+ inst->bind_pool->conn.conn_list_cv = slapi_new_condvar(inst->bind_pool->conn.conn_list_mutex);
+
+ inst->backend_type=cb;
+ /* initialize monitor_availability */
+ inst->monitor_availability.farmserver_state = FARMSERVER_AVAILABLE ; /* we expect the farm to be available */
+ inst->monitor_availability.cpt = 0 ; /* set up the failed conn counter to 0 */
+
+ /* create RW lock to protect the config */
+ inst->rwl_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, slapi_ch_strdup(name));
+
+ /* quick hack */
+ /* put a ref to the config lock in the pool */
+ /* so that the connection mgmt module can */
+ /* access the config safely */
+
+ inst->pool->rwl_config_lock = inst->rwl_config_lock;
+ inst->bind_pool->rwl_config_lock = inst->rwl_config_lock;
+
+ for (i=0; i < MAX_CONN_ARRAY; i++) {
+ inst->pool->connarray[i] = NULL;
+ inst->bind_pool->connarray[i] = NULL;
+ }
+
+ /* Config is now merged with the backend entry */
+ inst->configDn=slapi_ch_strdup(basedn);
+
+ inst->monitorDn=(char *) slapi_ch_calloc(1,strlen(basedn)+15);
+ sprintf(inst->monitorDn,"cn=monitor,%s",basedn);
+
+ inst->eq_ctx = NULL;
+
+ return inst;
+}
+
+void cb_instance_free(cb_backend_instance * inst) {
+
+ if (inst) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ if ( inst->eq_ctx != NULL )
+ {
+ slapi_eq_cancel(inst->eq_ctx);
+ inst->eq_ctx = NULL;
+ }
+
+ if (inst->bind_pool)
+ cb_close_conn_pool(inst->bind_pool);
+ if (inst->pool)
+ cb_close_conn_pool(inst->pool);
+
+ slapi_destroy_condvar(inst->bind_pool->conn.conn_list_cv);
+ slapi_destroy_condvar(inst->pool->conn.conn_list_cv);
+ slapi_destroy_mutex(inst->monitor.mutex);
+ slapi_destroy_mutex(inst->bind_pool->conn.conn_list_mutex);
+ slapi_destroy_mutex(inst->pool->conn.conn_list_mutex);
+ slapi_destroy_mutex(inst->monitor_availability.cpt_lock);
+ slapi_destroy_mutex(inst->monitor_availability.lock_timeLimit);
+ slapi_ch_free((void **) &inst->configDn);
+ slapi_ch_free((void **) &inst->monitorDn);
+ slapi_ch_free((void **) &inst->inst_name);
+ charray_free(inst->every_attribute);
+
+ slapi_ch_free((void **) &inst->bind_pool);
+ slapi_ch_free((void **) &inst->pool);
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ PR_DestroyRWLock(inst->rwl_config_lock);
+
+ slapi_ch_free((void **) &inst);
+ }
+/* XXXSD */
+}
+
+/*
+** Check the change the configuration of an existing chaining
+** backend instance.
+*/
+
+int cb_instance_modify_config_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int i;
+ char * attr_name;
+ returntext[0] = '\0';
+
+ CB_ASSERT(inst!=NULL);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ /* First pass to validate input */
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ /* specific processing for multi-valued attributes */
+ if ( !strcasecmp ( attr_name, CB_CONFIG_SUFFIX )) {
+ sprintf(returntext, "suffix modification not allowed\n");
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+ continue;
+ } else
+
+ /* CB_CONFIG_BINDUSER & CB_CONFIG_USERPASSWORD may be added */
+ /* or deleted */
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_USERPASSWORD )) {
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_BINDUSER )) {
+
+ /* Make sure value is not forbidden */
+ if ((mods[i]->mod_op & LDAP_MOD_REPLACE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 0);
+ continue;
+ }
+ }
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 0);
+ }
+ }
+ *returncode= rc;
+ return ((LDAP_SUCCESS == rc) ? 1:-1);
+}
+
+
+/*
+** Change the configuration of an existing chaining
+** backend instance.
+*/
+
+int cb_instance_modify_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int i;
+ int reopen_conn=0;
+ char * attr_name;
+ returntext[0] = '\0';
+
+ CB_ASSERT(inst!=NULL);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ /* input checked in the preop modify callback */
+
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ /* specific processing for multi-valued attributes */
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+ char * config_attr_value;
+ int done=0;
+ int j;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ done=1;
+ }
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ continue;
+ }
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+ char * config_attr_value;
+ int done=0;
+ int j;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ done=1;
+ }
+ /* XXXSD assume dns */
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ continue;
+ }
+
+
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+
+ /* Special processing for binddn & password */
+ /* because they are optional */
+
+ if (( !strcasecmp ( attr_name, CB_CONFIG_BINDUSER )) ||
+ ( !strcasecmp ( attr_name, CB_CONFIG_USERPASSWORD ))) {
+
+ if (mods[i]->mod_op & LDAP_MOD_DELETE) {
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, NULL, returntext,
+ CB_CONFIG_PHASE_RUNNING, 1); }
+ else {
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 1);
+ }
+ if (rc==CB_REOPEN_CONN) {
+ reopen_conn=1;
+ rc=LDAP_SUCCESS;
+ }
+ continue;
+ }
+
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 1);
+
+ /* Update requires to reopen connections */
+ /* Expensive operation so do it only once */
+ if (rc==CB_REOPEN_CONN) {
+ reopen_conn=1;
+ rc=LDAP_SUCCESS;
+ }
+ }
+ }
+
+ *returncode= rc;
+
+ if (reopen_conn) {
+ cb_stale_all_connections(inst);
+ }
+
+ return ((LDAP_SUCCESS == rc) ? SLAPI_DSE_CALLBACK_OK:SLAPI_DSE_CALLBACK_ERROR);
+}
+
+/*
+** Parse and instantiate backend instances
+*/
+
+int
+cb_parse_instance_config_entry(cb_backend * cb, Slapi_Entry * e) {
+
+ int rc =LDAP_SUCCESS;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ cb_backend_instance *inst=NULL;
+ char *instname;
+ Slapi_PBlock *search_pb=NULL;
+ char retmsg[CB_BUFSIZE];
+
+ CB_ASSERT(e!=NULL);
+
+ /*
+ ** Retrieve the instance name and make sure it is not
+ ** already declared.
+ */
+
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ return LDAP_LOCAL_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* Emulate a add config entry to configure */
+ /* this backend instance. */
+
+ cb_instance_add_config_callback(NULL,e,NULL,&rc,retmsg,inst);
+ if ( rc != LDAP_SUCCESS ) {
+ cb_instance_free(inst);
+ }
+ return rc;
+}
+
+/*
+** Update the instance configuration
+*/
+
+static int
+cb_instance_config_initialize(cb_backend_instance * inst, Slapi_Entry * e , int phase, int apply) {
+
+ int rc =LDAP_SUCCESS;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ struct berval * bval;
+ int using_def_connlifetime,i;
+ char err_buf[CB_BUFSIZE];
+ int urlfound=0;
+ char *rootdn;
+
+ using_def_connlifetime=1;
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char * attr_name=NULL;
+ slapi_attr_get_type(attr, &attr_name);
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_SUFFIX )) {
+ if (apply && ( inst->inst_be != NULL )) {
+ Slapi_DN *suffix;
+ suffix = slapi_sdn_new();
+ i = slapi_attr_first_value(attr, &sval);
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ slapi_sdn_init_dn_byref(suffix, bval->bv_val);
+
+ if (!slapi_be_issuffix(inst->inst_be, suffix)) {
+ slapi_be_addsuffix(inst->inst_be, suffix);
+ }
+ slapi_sdn_done(suffix);
+ slapi_sdn_free(&suffix);
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ }
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ i = slapi_attr_first_value(attr, &sval);
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(bval->bv_val)));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ i = slapi_attr_first_value(attr, &sval);
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(bval->bv_val));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ continue;
+ }
+
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_HOSTURL )) {
+ urlfound=1;
+ }
+
+
+ /* We are assuming that each of these attributes are to have
+ * only one value. If they have more than one value, like
+ * the nsslapd-suffix attribute, then they need to be
+ * handled differently. */
+
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+
+ if (cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, bval, err_buf, phase, apply ) != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL,
+ CB_PLUGIN_SUBSYSTEM,"Error with config attribute %s : %s\n",
+ attr_name, err_buf);
+ rc=LDAP_LOCAL_ERROR;
+ break;
+ }
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CONNLIFETIME )) {
+ using_def_connlifetime=0;
+ }
+ }
+
+
+ /*
+ ** Check for mandatory attributes
+ ** Post-Processing
+ */
+
+ if (LDAP_SUCCESS == rc) {
+ if (!urlfound) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance entry. Mandatory attr <%s> missing\n",
+ CB_CONFIG_HOSTURL);
+ rc= LDAP_LOCAL_ERROR;
+ }
+
+ if (apply ) {
+ if ( using_def_connlifetime &&
+ strchr( inst->pool->hostname, ' ' ) != NULL ) {
+
+ cb_instance_config_set((void *)inst, CB_CONFIG_CONNLIFETIME,
+ cb_the_instance_config, NULL /* use default */, err_buf,
+ CB_CONFIG_PHASE_INITIALIZATION, 1 );
+ }
+ }
+ }
+
+ /*
+ ** Additional checks
+ ** It is forbidden to use directory manager as proxy user
+ ** due to a bug in the acl check
+ */
+
+ rootdn=cb_get_rootdn();
+
+ if (inst->impersonate && inst->pool && inst->pool->binddn &&
+ !strcmp(inst->pool->binddn,rootdn)) { /* UTF8 aware */
+ slapi_log_error( SLAPI_LOG_FATAL,
+ CB_PLUGIN_SUBSYSTEM,"Error with config attribute %s (%s: forbidden value)\n",
+ CB_CONFIG_BINDUSER, rootdn);
+ rc=LDAP_LOCAL_ERROR;
+ }
+ slapi_ch_free((void **)&rootdn);
+
+ return rc;
+}
+
+/********************************************************
+** Get and set functions for chaining backend instances *
+*********************************************************
+*/
+
+static void *cb_instance_hosturl_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->url);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_hosturl_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance *inst=(cb_backend_instance *) arg;
+ char *url = (char *) value;
+ LDAPURLDesc *ludp=NULL;
+ int rc=LDAP_SUCCESS;
+
+ if (( rc = ldap_url_parse( url, &ludp )) != 0 ) {
+ strcpy(errorbuf,cb_urlparse_err2string( rc ));
+ if (CB_CONFIG_PHASE_INITIALIZATION == phase)
+ inst->pool->url=slapi_ch_strdup("");
+ return(LDAP_INVALID_SYNTAX);
+ }
+
+ if (apply) {
+
+ char * ptr;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modification */
+ /* Don't free char * pointer now */
+ /* STore them in a waste basket */
+ /* Will be relesase when the backend stops */
+
+ if (inst->pool->hostname)
+ charray_add(&inst->pool->waste_basket,inst->pool->hostname);
+ if (inst->pool->url)
+ charray_add(&inst->pool->waste_basket,inst->pool->url);
+
+ if (inst->bind_pool->hostname)
+ charray_add(&inst->bind_pool->waste_basket,inst->bind_pool->hostname);
+ if (inst->bind_pool->url)
+ charray_add(&inst->bind_pool->waste_basket,inst->bind_pool->url);
+
+ /* Require connection cleanup */
+ rc=CB_REOPEN_CONN;
+ }
+
+ /* Normal case. Extract useful data from */
+ /* the url and update the configuration */
+
+ if ((ludp->lud_host==NULL) || (strlen(ludp->lud_host)==0)) {
+ inst->pool->hostname=(char *)slapi_ch_strdup((char *)get_localhost_DNS());
+ } else {
+ inst->pool->hostname = slapi_ch_strdup( ludp->lud_host );
+ }
+ inst->pool->url = slapi_ch_strdup( url);
+ inst->pool->secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
+
+ if ((ludp->lud_port==0) && inst->pool->secure)
+ inst->pool->port=CB_LDAP_SECURE_PORT;
+ else
+ inst->pool->port = ludp->lud_port;
+
+ /* Build a charray of <host>:<port> */
+ /* hostname is of the form <host>[:port] <host>[:port] */
+
+ { char * aBufCopy, * aHostName;
+ char * iter = NULL;
+ aBufCopy= aBufCopy=slapi_ch_strdup(inst->pool->hostname);
+
+ aHostName=ldap_utf8strtok_r(aBufCopy," ", &iter);
+ charray_free(inst->url_array);
+ inst->url_array=NULL;
+ while (aHostName) {
+
+ char * aHostPort = slapi_ch_calloc(1,strlen(aHostName)+30);
+ if ( NULL == ( ptr=strstr(aHostName,":")))
+ sprintf(aHostPort,"%s://%s:%d/",
+ inst->pool->secure ? "ldaps" : "ldap",
+ aHostName,inst->pool->port);
+ else
+ sprintf(aHostPort,"%s://%s/",
+ inst->pool->secure ? "ldaps" : "ldap",
+ aHostName);
+
+ charray_add(&inst->url_array,aHostPort);
+ aHostName=ldap_utf8strtok_r(NULL," ", &iter);
+ }
+
+ slapi_ch_free((void **) &aBufCopy);
+ }
+
+ inst->bind_pool->port=inst->pool->port;
+ inst->bind_pool->secure=inst->pool->secure;
+ inst->bind_pool->hostname=slapi_ch_strdup(inst->pool->hostname);
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+
+ if ( ludp != NULL ) {
+ ldap_free_urldesc( ludp );
+ }
+ return rc;
+}
+
+static void *cb_instance_binduser_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->binddn2); /* not normalized */
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_binduser_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif */
+ /* Free user later */
+
+ charray_add(&inst->pool->waste_basket,inst->pool->binddn);
+ charray_add(&inst->pool->waste_basket,inst->pool->binddn2);
+ rc=CB_REOPEN_CONN;
+ }
+
+ inst->pool->binddn=slapi_ch_strdup((char *) value);
+ inst->pool->binddn2=slapi_ch_strdup((char *) value);
+ slapi_dn_normalize_case(inst->pool->binddn);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ } else {
+
+ /* Security check */
+ /* directory manager of the farm server should not be used as */
+ /* proxing user. This is hard to check, so assume same directory */
+ /* manager across servers. */
+
+ char * rootdn = cb_get_rootdn();
+ char * theValueCopy = NULL;
+
+ if (value) {
+ theValueCopy=slapi_ch_strdup((char *) value);
+ slapi_dn_normalize_case(theValueCopy);
+ }
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ if (inst->impersonate && theValueCopy &&
+ !strcmp(theValueCopy,rootdn)) { /* UTF8-aware. See cb_get_dn() */
+ rc=LDAP_UNWILLING_TO_PERFORM;
+ if (errorbuf) {
+ sprintf(errorbuf,"value %s not allowed",rootdn);
+ }
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ slapi_ch_free((void **)&theValueCopy);
+ slapi_ch_free((void **)&rootdn);
+ }
+
+ return rc;
+}
+
+
+static void *cb_instance_userpassword_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->password);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_userpassword_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif */
+ charray_add(&inst->pool->waste_basket,inst->pool->password);
+ rc=CB_REOPEN_CONN;
+ }
+
+ inst->pool->password=slapi_ch_strdup((char *) value);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return rc;
+}
+
+static void *cb_instance_sizelimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->sizelimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_sizelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->sizelimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ if (inst->inst_be)
+ be_set_sizelimit(inst->inst_be, (int) value);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_timelimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->timelimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_timelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->timelimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ if (inst->inst_be)
+ be_set_timelimit(inst->inst_be, (int) value);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_max_test_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->max_test_time;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_max_test_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->max_test_time=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_max_idle_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->max_idle_time;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_max_idle_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->max_idle_time=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+static void *cb_instance_hoplimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->hoplimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_hoplimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->hoplimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxbconn_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->bind_pool->conn.maxconnections;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxbconn_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.maxconnections=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxconn_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->pool->conn.maxconnections;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxconn_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.maxconnections=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_abandonto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->abandon_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_abandonto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+
+ if (apply) {
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif not supported */
+ /* Stored in ldif only */
+ return LDAP_SUCCESS;
+ }
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->abandon_timeout.tv_sec=(int) value;
+ inst->abandon_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxbconc_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->bind_pool->conn.maxconcurrency;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxbconc_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.maxconcurrency=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxconc_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->pool->conn.maxconcurrency;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxconc_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.maxconcurrency=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_imperson_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->impersonate;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_imperson_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->impersonate=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ } else {
+ /* Security check: Make sure the proxing user is */
+ /* not the directory manager. */
+
+ char * rootdn=cb_get_rootdn();
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ if (((int) value) && inst->pool && inst->pool->binddn &&
+ !strcmp(inst->pool->binddn,rootdn)) { /* UTF-8 aware */
+ rc=LDAP_UNWILLING_TO_PERFORM;
+ if (errorbuf)
+ sprintf(errorbuf,"Proxy mode incompatible with %s value (%s not allowed)",
+ CB_CONFIG_BINDUSER,rootdn);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ slapi_ch_free((void **)&rootdn);
+ }
+
+ return rc;
+}
+
+static void *cb_instance_connlife_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->pool->conn.connlifetime;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_connlife_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.connlifetime=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_bindto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->bind_pool->conn.op_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_bindto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.op_timeout.tv_sec=(int) value;
+ inst->bind_pool->conn.op_timeout.tv_usec=0;
+ inst->bind_pool->conn.bind_timeout.tv_sec=(int) value;
+ inst->bind_pool->conn.bind_timeout.tv_usec=0;
+ /* Used to bind to the farm server */
+ inst->pool->conn.bind_timeout.tv_sec=(int) value;
+ inst->pool->conn.bind_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_opto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->pool->conn.op_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_opto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.op_timeout.tv_sec=(int) value;
+ inst->pool->conn.op_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_ref_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->searchreferral;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_ref_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->searchreferral=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_acl_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->local_acl;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_acl_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+
+ if (apply) {
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif not supported */
+ /* Stored in ldif only */
+ return LDAP_SUCCESS;
+ }
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->local_acl=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_bindretry_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->bind_retry;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_bindretry_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_retry=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+
+
+/* Finds an entry in a config_info array with the given name. Returns
+ * the entry on success and NULL when not found.
+ */
+static cb_instance_config_info *cb_get_config_info(cb_instance_config_info *config_array, char *attr_name)
+{
+ int x;
+
+ for(x = 0; config_array[x].config_name != NULL; x++) {
+ if (!strcasecmp(config_array[x].config_name, attr_name)) {
+ return &(config_array[x]);
+ }
+ }
+ return NULL;
+}
+
+/*
+** Update an attribute value
+** For now, unknown attributes are ignored
+** Return a LDAP error code OR CB_REOPEN_CONN when the
+** update requires to close open connections.
+*/
+
+static int
+cb_instance_config_set(void *arg, char *attr_name, cb_instance_config_info *config_array,
+struct berval *bval, char *err_buf, int phase, int apply_mod)
+{
+ cb_instance_config_info *config;
+ int use_default;
+ int int_val;
+ long long_val;
+ int retval=LDAP_LOCAL_ERROR;
+
+ config = cb_get_config_info(config_array, attr_name);
+ if (NULL == config) {
+ /* Ignore unknown attributes */
+ return LDAP_SUCCESS;
+ }
+
+ /* If the config phase is initialization or if bval is NULL, we will use
+ * the default value for the attribute. */
+ if (CB_CONFIG_PHASE_INITIALIZATION == phase || NULL == bval) {
+ use_default = 1;
+ } else {
+ use_default = 0;
+ /* Since we are setting the value for the config attribute, we
+ * need to turn on the CB_PREVIOUSLY_SET flag to make
+ * sure this attribute is shown. */
+ config->config_flags |= CB_PREVIOUSLY_SET;
+ }
+
+ switch(config->config_type) {
+ case CB_CONFIG_TYPE_INT:
+ if (use_default) {
+ int_val = cb_atoi(config->config_default_value);
+ } else {
+ int_val = cb_atoi((char *)bval->bv_val);
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_INT_OCTAL:
+ if (use_default) {
+ int_val = (int) strtol(config->config_default_value, NULL, 8);
+ } else {
+ int_val = (int) strtol((char *)bval->bv_val, NULL, 8);
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_LONG:
+ if (use_default) {
+ long_val = cb_atol(config->config_default_value);
+ } else {
+ long_val = cb_atol((char *)bval->bv_val);
+ }
+ retval = config->config_set_fn(arg, (void *) long_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_STRING:
+ if (use_default) {
+ retval = config->config_set_fn(arg, config->config_default_value, err_buf, phase, apply_mod);
+ } else {
+ retval = config->config_set_fn(arg, bval->bv_val, err_buf, phase, apply_mod);
+ }
+ break;
+ case CB_CONFIG_TYPE_ONOFF:
+ if (use_default) {
+ int_val = !strcasecmp(config->config_default_value, "on");
+ } else {
+ int_val = !strcasecmp((char *) bval->bv_val, "on");
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ }
+ return retval;
+}
+
+/* Utility function used in creating config entries. Using the
+ * config_info, this function gets info and formats in the correct
+ * way.
+ */
+void cb_instance_config_get(void *arg, cb_instance_config_info *config, char *buf)
+{
+ char *tmp_string;
+
+ if (config == NULL) {
+ buf[0] = '\0';
+ }
+
+ switch(config->config_type) {
+ case CB_CONFIG_TYPE_INT:
+ sprintf(buf, "%d", (int) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_INT_OCTAL:
+ sprintf(buf, "%o", (int) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_LONG:
+ sprintf(buf, "%d", (long) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_STRING:
+ /* Remember the get function for strings returns memory
+ * that must be freed. */
+ tmp_string = (char *) config->config_get_fn(arg);
+ sprintf(buf, "%s", (char *) tmp_string);
+ slapi_ch_free((void **)&tmp_string);
+ break;
+ case CB_CONFIG_TYPE_ONOFF:
+ if ((int) config->config_get_fn(arg)) {
+ sprintf(buf,"%s","on");
+ } else {
+ sprintf(buf,"%s","off");
+ }
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Invalid attribute syntax.\n");
+
+ }
+}
+
+/*
+** Search for instance config entry
+** Always return 'active' values because some configuration changes
+** won't be taken into account until the server restarts
+*/
+
+int cb_instance_search_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg) {
+
+ char buf[CB_BUFSIZE];
+ struct berval val;
+ struct berval *vals[2];
+ int i = 0;
+ cb_backend_instance *inst = (cb_backend_instance *)arg;
+ cb_instance_config_info * config;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* suffixes */
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+
+ {
+ const Slapi_DN *aSuffix;
+ i=0;
+ if (inst->inst_be) {
+ while ((aSuffix=slapi_be_getsuffix(inst->inst_be,i))) {
+ val.bv_val = (char *)slapi_sdn_get_dn(aSuffix);
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_SUFFIX,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_SUFFIX,(struct berval **)vals );
+ }
+ i++;
+ }
+ }
+ }
+
+ for (i=0; inst->chaining_components && inst->chaining_components[i]; i++) {
+ val.bv_val = inst->chaining_components[i];
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_CHAINING_COMPONENTS,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_CHAINING_COMPONENTS,(struct berval **)vals );
+ }
+ }
+
+ for (i=0; inst->illegal_attributes && inst->illegal_attributes[i]; i++) {
+ val.bv_val = inst->illegal_attributes[i];
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_ILLEGAL_ATTRS,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_ILLEGAL_ATTRS,(struct berval **)vals );
+ }
+ }
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ /* standard attributes */
+ for(config = cb_the_instance_config; config->config_name != NULL; config++) {
+ if (!(config->config_flags & (CB_ALWAYS_SHOW | CB_PREVIOUSLY_SET))) {
+ /* This config option shouldn't be shown */
+ continue;
+ }
+
+ cb_instance_config_get((void *) inst, config, buf);
+
+ val.bv_val = buf;
+ val.bv_len = strlen(buf);
+ if (val.bv_len)
+ slapi_entry_attr_replace(e, config->config_name, vals);
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+** Ooops!!! The backend instance is beeing deleted
+*/
+
+int cb_instance_delete_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ int rc;
+ Slapi_Entry * anEntry=NULL;
+ Slapi_DN * aDn;
+
+ CB_ASSERT( inst!=NULL );
+
+ /* notify the front-end */
+ slapi_mtn_be_stopping(inst->inst_be);
+
+ /* Now it is safe to stop */
+ /* No pending op */
+
+
+ /* unregister callbacks */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_search_config_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_delete_config_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_modify_config_check_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_modify_config_callback);
+
+ /* At this point, the monitor entry should have been removed */
+ /* If not, manually call delete callback */
+
+ aDn = slapi_sdn_new_dn_byref(inst->monitorDn);
+ if ( LDAP_SUCCESS==(slapi_search_internal_get_entry(aDn,NULL, &anEntry,inst->backend_type->identity))) {
+ cb_delete_monitor_callback( NULL, anEntry, NULL, &rc , NULL, inst );
+ if (anEntry)
+ slapi_entry_free(anEntry);
+ }
+ slapi_sdn_done(aDn);
+ slapi_sdn_free(&aDn);
+
+ /* free resources */
+ cb_close_conn_pool(inst->bind_pool);
+ cb_close_conn_pool(inst->pool);
+ slapi_be_free(&(inst->inst_be));
+ cb_instance_free(inst);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static void cb_instance_add_monitor_later(time_t when, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+
+ if ( inst != NULL )
+ {
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+
+ /* create the monitor entry if it is not there yet */
+ if (LDAP_SUCCESS == cb_config_add_dse_entries(inst->backend_type, cb_skeleton_entries,
+ inst->inst_name,CB_PLUGIN_NAME, NULL))
+ {
+
+ /* add monitor callbacks */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_search_monitor_callback, (void *) inst);
+
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_dont_allow_that, (void *) NULL);
+
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP , inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_delete_monitor_callback, (void *) inst);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+}
+
+
+int cb_instance_add_config_check_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ int rc=LDAP_SUCCESS;
+ cb_backend_instance *inst;
+ cb_backend *cb=(cb_backend *) arg;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ char *instname=NULL;
+
+ if (returntext)
+ returntext[0]='\0';
+
+ /* Basic entry check */
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ }
+ if ( instname == NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ *returncode = LDAP_LOCAL_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* build the backend instance from the default hardcoded conf, */
+ /* the default instance config and the specific entry specified */
+ if ((rc=cb_build_backend_instance_config(inst,e,0))
+ != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Can't instantiate chaining backend instance %s.\n",inst->inst_name);
+ *returncode=rc;
+ cb_instance_free(inst);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Free the dummy instance */
+ *returncode=rc;
+ cb_instance_free(inst);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Create the default instance config from hard-coded values */
+/*
+** Initialize the backend instance with the config entry
+** passed in arguments.
+** <arg> : (cb_backend *)
+*/
+
+int cb_instance_add_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ int rc=LDAP_SUCCESS;
+ cb_backend_instance *inst;
+ cb_backend *cb=(cb_backend *) arg;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ char *instname=NULL;
+
+ if (returntext)
+ returntext[0]='\0';
+
+ /* Basic entry check */
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ }
+ if ( instname == NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ *returncode = LDAP_LOCAL_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* build the backend instance from the default hardcoded conf, */
+ /* the default instance config and the specific entry specified */
+ if ((rc=cb_build_backend_instance_config(inst,e,0))
+ != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Can't instantiate chaining backend instance %s.\n",inst->inst_name);
+ *returncode=rc;
+ cb_instance_free(inst);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Instantiate a Slapi_Backend if necessary */
+ if (!inst->isconfigured) {
+
+ Slapi_PBlock *aPb=NULL;
+
+ inst->inst_be = slapi_be_new(CB_CHAINING_BACKEND_TYPE,slapi_ch_strdup(inst->inst_name),0,0);
+ aPb=slapi_pblock_new();
+ slapi_pblock_set(aPb, SLAPI_PLUGIN, inst->backend_type->plugin);
+ slapi_be_setentrypoint(inst->inst_be,0,(void *)NULL,aPb);
+ slapi_be_set_instance_info(inst->inst_be,inst);
+ slapi_pblock_set(aPb, SLAPI_PLUGIN, NULL);
+ slapi_pblock_destroy(aPb);
+ }
+
+ cb_build_backend_instance_config(inst,e,1);
+
+ /* kexcoff: the order of the following calls is very important to prevent the deletion of the
+ instance to happen before the creation of the monitor part of the config.
+ However, not sure it solves all the situations, but at least it is worth to maintain
+ this order. */
+
+ if (!inst->isconfigured)
+ {
+ /* Add monitor entry and callback on it
+ * called from an add...
+ * we can't call recursively into the DSE to do more adds, they'll
+ * silently fail. instead, schedule the adds to happen in 1 second.
+ */
+ inst->eq_ctx = slapi_eq_once(cb_instance_add_monitor_later, (void *)inst, time(NULL)+1);
+ }
+
+ /* Get the list of operational attrs defined in the schema */
+ /* see cb_search file for a reason for that */
+
+ inst->every_attribute=slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_OPATTR);
+ charray_add(&inst->every_attribute,slapi_ch_strdup(LDAP_ALL_USER_ATTRS));
+
+ if (!inst->isconfigured)
+ {
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)",cb_instance_modify_config_check_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)",cb_instance_modify_config_callback, (void *) inst);
+
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)", cb_instance_search_config_callback, (void *) inst);
+
+ /* allow deletion otherwise impossible to remote a backend instance */
+ /* dynamically... */
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)", cb_instance_delete_config_callback, (void *) inst);
+ }
+
+ /* Notify the front-end */
+ /* After the call below, we can receive ops */
+ slapi_mtn_be_started(inst->inst_be);
+
+ inst->isconfigured=1;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Create the default instance config from hard-coded values */
+
+int cb_create_default_backend_instance_config(cb_backend * cb) {
+
+
+ int rc;
+ cb_backend_instance *dummy;
+ Slapi_Entry *e=slapi_entry_alloc();
+ char defaultDn[CB_BUFSIZE];
+ char *olddn;
+ struct berval val;
+ struct berval *vals[2];
+ Slapi_PBlock *pb;
+
+ dummy = cb_instance_alloc(cb, "dummy", "o=dummy");
+ cb_instance_config_set_default(dummy);
+ cb_instance_search_config_callback(NULL,e,NULL, &rc, NULL,(void *) dummy);
+
+
+ /* set right dn and objectclass */
+
+ sprintf(defaultDn,"cn=default instance config,%s",cb->pluginDN);
+ olddn = slapi_entry_get_dn(e);
+ slapi_ch_free((void **) &olddn);
+
+ slapi_entry_set_dn(e,slapi_ch_strdup(defaultDn));
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ val.bv_val = "top";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "objectclass", (struct berval **)vals );
+ val.bv_val = CB_CONFIG_EXTENSIBLEOCL;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_merge( e, "objectclass", (struct berval **)vals );
+ val.bv_val = "default instance config";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "cn", (struct berval **)vals );
+
+ /* create entry */
+ pb = slapi_pblock_new();
+ slapi_add_entry_internal_set_pb(pb, e, NULL, cb->identity, 0);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if ( LDAP_SUCCESS != rc ) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Add %s failed (%s)\n",defaultDn,ldap_err2string(rc));
+ }
+
+ slapi_pblock_destroy(pb);
+ /* cleanup */
+ cb_instance_free(dummy);
+ /* BEWARE: entry is consummed */
+ return rc;
+}
+
+/* Extract backend instance configuration from the LDAP entry */
+
+int cb_build_backend_instance_config(cb_backend_instance *inst, Slapi_Entry * conf, int apply) {
+
+ cb_backend *cb = inst->backend_type;
+ Slapi_PBlock *default_pb;
+ Slapi_Entry **default_entries = NULL;
+ Slapi_Entry *default_conf=NULL;
+ int default_res, rc;
+ char defaultDn[CB_BUFSIZE];
+ cb_backend_instance * current_inst;
+
+ rc=LDAP_SUCCESS;
+
+ if (apply)
+ current_inst=inst;
+ else
+ current_inst=cb_instance_alloc(cb,inst->inst_name,"cn=dummy");
+
+ /* set default configuration */
+ cb_instance_config_set_default(current_inst);
+
+ /* 2: Overwrite values present in the default instance config */
+
+ sprintf(defaultDn,"cn=default instance config,%s",cb->pluginDN);
+
+ default_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(default_pb, defaultDn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, cb->identity, 0);
+ slapi_search_internal_pb (default_pb);
+ slapi_pblock_get(default_pb, SLAPI_PLUGIN_INTOP_RESULT, &default_res);
+ if ( LDAP_SUCCESS == default_res ) {
+ slapi_pblock_get(default_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &default_entries);
+ if (default_entries && default_entries[0] ) {
+
+ struct berval val;
+ struct berval *vals[2];
+ vals[0] = &val;
+ vals[1] = NULL;
+ default_conf=default_entries[0];
+
+ /* hack: add a dummy url (mandatory) to avoid error */
+ /* will be overwritten by the one in conf entry */
+ val.bv_val = "ldap://localhost/";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( default_conf, CB_CONFIG_HOSTURL, (struct berval **)vals );
+
+ rc=cb_instance_config_initialize(current_inst,default_conf,CB_CONFIG_PHASE_STARTUP,1);
+ }
+ }
+ slapi_free_search_results_internal(default_pb);
+ slapi_pblock_destroy(default_pb);
+
+ if (rc == LDAP_SUCCESS)
+ rc=cb_instance_config_initialize(current_inst,conf,CB_CONFIG_PHASE_STARTUP,1);
+
+ if (!apply)
+ cb_instance_free(current_inst);
+
+ return rc;
+}