diff options
Diffstat (limited to 'ldap/servers/plugins/chainingdb/cb_instance.c')
-rw-r--r-- | ldap/servers/plugins/chainingdb/cb_instance.c | 1871 |
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; +} |