summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/chainingdb/cb_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/chainingdb/cb_utils.c')
-rw-r--r--ldap/servers/plugins/chainingdb/cb_utils.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/ldap/servers/plugins/chainingdb/cb_utils.c b/ldap/servers/plugins/chainingdb/cb_utils.c
new file mode 100644
index 00000000..b73effd0
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_utils.c
@@ -0,0 +1,375 @@
+/** 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"
+
+/* return the rootdn configured in the server */
+
+char * cb_get_rootdn() {
+
+ char * ret=slapi_get_rootdn();
+ if (ret == NULL)
+ ret = slapi_ch_strdup(CB_DIRECTORY_MANAGER_DN);
+ if (ret)
+ slapi_dn_normalize_case(ret); /* UTF8-aware */
+ return ret;
+}
+
+void
+cb_send_ldap_result(Slapi_PBlock *pb, int err, char *matched,char *text, int nentries, struct berval **urls )
+{
+ cb_set_acl_policy(pb);
+ slapi_send_ldap_result( pb, err, matched, text, nentries ,urls);
+}
+
+Slapi_Entry * cb_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) {
+
+ Slapi_Entry * e = slapi_entry_alloc();
+ char * a=NULL;
+ BerElement * ber=NULL;
+
+ if ( e == NULL ) return NULL;
+ if (msg == NULL) {
+ slapi_entry_free(e);
+ return NULL;
+ }
+
+ /*
+ * dn not allocated by slapi
+ * attribute type and values ARE allocated
+ */
+
+ slapi_entry_set_dn( e, ldap_get_dn( ld, msg ) );
+
+ for ( a = ldap_first_attribute( ld, msg, &ber ); a!=NULL;
+ a=ldap_next_attribute( ld, msg, ber ) ) {
+ if(attrsonly) {
+ slapi_entry_add_value(e, a, (Slapi_Value *)NULL);
+ ldap_memfree(a);
+ } else {
+ struct berval ** aVal = ldap_get_values_len( ld, msg, a);
+ slapi_entry_add_values( e, a, aVal);
+
+ ldap_memfree(a);
+ ldap_value_free_len(aVal);
+ }
+ }
+ if ( NULL != ber )
+ ldap_ber_free( ber, 0 );
+
+ return e;
+}
+
+struct berval ** referrals2berval(char ** referrals) {
+
+ int i;
+ struct berval ** val=NULL;
+
+ if (referrals == NULL)
+ return NULL;
+
+ for (i=0;referrals[i];i++) {}
+
+ val = (struct berval **) slapi_ch_calloc(1,(i+1)*sizeof(struct berval *));
+
+ for (i=0;referrals[i];i++) {
+
+ val[i]=(struct berval *) slapi_ch_malloc(sizeof(struct berval));
+ val[i]->bv_len= strlen(referrals[i]);
+ val[i]->bv_val = slapi_ch_strdup(referrals[i]);
+ }
+
+ return val;
+}
+
+char *
+cb_urlparse_err2string( int err )
+{
+ char *s="internal error";
+
+ switch( err ) {
+ case 0:
+ s = "no error";
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ s = "missing ldap:// or ldaps://";
+ break;
+ case LDAP_URL_ERR_NODN:
+ s = "missing suffix";
+ break;
+ case LDAP_URL_ERR_BADSCOPE:
+ s = "invalid search scope";
+ break;
+ case LDAP_URL_ERR_MEM:
+ s = "unable to allocate memory";
+ break;
+ case LDAP_URL_ERR_PARAM:
+ s = "bad parameter to an LDAP URL function";
+ break;
+ }
+
+ return( s );
+}
+
+/*
+** Return LDAP_SUCCESS if an internal operation needs to be forwarded to
+** the farm server. We check chaining policy for internal operations
+** We also check max hop count for loop detection for both internal
+** and external operations
+*/
+
+int cb_forward_operation(Slapi_PBlock * pb ) {
+
+ Slapi_Operation *op=NULL;
+ Slapi_Backend *be;
+ struct slapi_componentid *cid = NULL;
+ char *pname;
+ cb_backend_instance *cb;
+ int retcode;
+ LDAPControl **ctrls=NULL;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+
+ /* Loop detection */
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &ctrls );
+
+ if ( NULL != ctrls ) {
+ struct berval *ctl_value=NULL;
+ int iscritical=0;
+
+ if (slapi_control_present(ctrls,CB_LDAP_CONTROL_CHAIN_SERVER,&ctl_value,&iscritical)) {
+
+ /* Decode control data */
+ /* hop INTEGER (0 .. maxInt) */
+
+ int hops = 0;
+ int rc;
+ BerElement *ber = NULL;
+
+ if ((ber = ber_init(ctl_value)) == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_forward_operation: ber_init: Memory allocation failed");
+ return LDAP_NO_MEMORY;
+ }
+ rc = ber_scanf(ber,"i",&hops);
+ if (LBER_ERROR == rc) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Loop detection control badly encoded.");
+ ber_free(ber,1);
+ return LDAP_LOOP_DETECT;
+ }
+
+ if (hops <=0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Max hop count exceeded. Loop detected.\n");
+ ber_free(ber,1);
+ return LDAP_LOOP_DETECT;
+ }
+ ber_free(ber,1);
+ }
+ }
+
+ if ( !operation_is_flag_set(op, OP_FLAG_INTERNAL))
+ return LDAP_SUCCESS;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if ( cid == NULL ) {
+ /* programming error in the front-end */
+ slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "NULL component identity in an internal operation.");
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ pname=cid->sci_component_name;
+
+ if (cb_debug_on()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "internal op received from %s component \n",pname ? pname : "NULL");
+ }
+
+ /* First, make sure chaining is not denied */
+ if (operation_is_flag_set(op, SLAPI_OP_FLAG_NEVER_CHAIN))
+ return LDAP_UNWILLING_TO_PERFORM;
+
+ /* unidentified caller. should not happen */
+ if (pname == NULL)
+ return LDAP_UNWILLING_TO_PERFORM;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ /* Local policy */
+ PR_RWLock_Rlock(cb->rwl_config_lock);
+ if ( cb->chaining_components != NULL ) {
+ retcode=charray_inlist(cb->chaining_components,pname);
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+ if ( retcode )
+ retcode=LDAP_SUCCESS;
+ else
+ retcode=LDAP_UNWILLING_TO_PERFORM;
+ return retcode;
+ }
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+
+ /* Global policy */
+ PR_RWLock_Rlock(cb->backend_type->config.rwl_config_lock);
+ retcode=charray_inlist(cb->backend_type->config.chaining_components,pname);
+ PR_RWLock_Unlock(cb->backend_type->config.rwl_config_lock);
+
+ if ( retcode )
+ retcode=LDAP_SUCCESS;
+ else
+ retcode=LDAP_UNWILLING_TO_PERFORM;
+ return retcode;
+}
+
+/* better atol -- it understands a trailing multiplier k/m/g
+ * for example, "32k" will be returned as 32768
+ */
+long cb_atol(char *str)
+{
+ long multiplier = 1;
+ char *x = str;
+
+ /* find possible trailing k/m/g */
+ while ((*x >= '0') && (*x <= '9')) x++;
+ switch (*x) {
+ case 'g':
+ case 'G':
+ multiplier *= 1024;
+ case 'm':
+ case 'M':
+ multiplier *= 1024;
+ case 'k':
+ case 'K':
+ multiplier *= 1024;
+ }
+ return (atol(str) * multiplier);
+}
+
+int cb_atoi(char *str)
+{
+ return (int)cb_atol(str);
+}
+
+
+/* This function is used by the instance modify callback to add a new
+ * suffix. It return LDAP_SUCCESS on success.
+ */
+int cb_add_suffix(cb_backend_instance *inst, struct berval **bvals, int apply_mod, char *returntext)
+{
+ Slapi_DN *suffix;
+ int x;
+
+ returntext[0] = '\0';
+ for (x = 0; bvals[x]; x++) {
+ suffix=slapi_sdn_new_dn_byval(bvals[x]->bv_val);
+ if (!slapi_be_issuffix(inst->inst_be, suffix) && apply_mod) {
+ slapi_be_addsuffix(inst->inst_be, suffix);
+ }
+ slapi_sdn_free(&suffix);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int debug_on=0;
+
+int cb_debug_on()
+{
+ return debug_on;
+}
+
+void cb_set_debug(int on) {
+ debug_on=on;
+}
+
+/* this function is called when state of a backend changes */
+/* The purpose of this function is to handle the associated_be_is_disabled
+ flag in the cb instance structure. The associated database is used to
+ perform local acl evaluations. The associated database can be
+ 1) The chaining backend is the backend of a sub suffix, and the
+ parent suffix has a local backend
+ 2) Entry distribution is being used to distribute write operations to
+ a chaining backend and other operations to a local backend
+ (e.g. a replication hub or consumer)
+ If the associated local backend is being initialized (import), it will be
+ disabled, and it will be impossible to evaluate local acls. In this case,
+ we still want to be able to chain operations to a farm server or another
+ database chain. But the current code will not allow cascading without
+ local acl evaluation (cb_controls.c). associated_be_is_disabled allows
+ us to relax that restriction while the associated backend is disabled
+*/
+/*
+ The first thing we need to do is to determine what our associated backends
+ are. An associated backend is defined as a backend used by the same
+ suffix which uses this cb instance or a backend used by any
+ parent suffix of the suffix which uses this cb instance
+
+ We first see if the be_name is for a local database. If not, then just return.
+ So for the given be_name, we find the suffix which uses it, then the mapping tree
+ entry for that suffix. Then
+ get cb instances used by the suffix and set associated_be_is_disabled
+ get cb instances used by sub suffixes of this suffix and
+ set associated_be_is_disabled
+*/
+void
+cb_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state)
+{
+ const Slapi_DN *tmpsdn;
+ Slapi_DN *the_be_suffix;
+ char *cookie = NULL;
+ Slapi_Backend *chainbe;
+ Slapi_Backend *the_be = slapi_be_select_by_instance_name(be_name);
+
+ /* no backend? */
+ if (!the_be) {
+ return;
+ }
+
+ /* ignore chaining backends - associated backends must be local */
+ if (slapi_be_is_flag_set(the_be, SLAPI_BE_FLAG_REMOTE_DATA)) {
+ return;
+ }
+
+ /* get the suffix for the local backend */
+ tmpsdn = slapi_be_getsuffix(the_be, 0);
+ if (!tmpsdn) {
+ return;
+ } else {
+ the_be_suffix = slapi_sdn_dup(tmpsdn);
+ }
+
+ /* now, iterate through the chaining backends */
+ for (chainbe = slapi_get_first_backend(&cookie);
+ chainbe; chainbe = slapi_get_next_backend(cookie)) {
+ /* only look at chaining backends */
+ if (slapi_be_is_flag_set(chainbe, SLAPI_BE_FLAG_REMOTE_DATA)) {
+ /* get the suffix */
+ const Slapi_DN *tmpcbsuf = slapi_be_getsuffix(chainbe, 0);
+ if (tmpcbsuf) {
+ /* make a copy - to be safe */
+ Slapi_DN *cbsuffix = slapi_sdn_dup(tmpcbsuf);
+ /* if the suffixes are equal, or the_be_suffix is a suffix
+ of cbsuffix, apply the flag */
+ if (!slapi_sdn_compare(cbsuffix, the_be_suffix) ||
+ slapi_sdn_issuffix(cbsuffix, the_be_suffix)) {
+ cb_backend_instance *cbinst = cb_get_instance(chainbe);
+ if (cbinst) {
+ /* the backend is disabled if the state is not ON */
+ cbinst->associated_be_is_disabled = (new_be_state != SLAPI_BE_STATE_ON);
+ slapi_log_error(SLAPI_LOG_PLUGIN, "chainbe", "cb_be_state_change: set the "
+ "state of chainbe for %s to %d\n",
+ slapi_sdn_get_dn(cbsuffix), (new_be_state != SLAPI_BE_STATE_ON));
+ }
+ }
+ slapi_sdn_free(&cbsuffix);
+ }
+ }
+ }
+
+ /* clean up */
+ slapi_sdn_free(&the_be_suffix);
+ slapi_ch_free_string(&cookie);
+}