.BR poll (2)/ select (2)
following a
.BR connect (2)
-returns in case of no activity.
-The value is in seconds, and it can be specified as for
+returns in case of no activity while sending an operation to the remote target.
+The value is in milliseconds, and it can be specified as for
.BR idle\-timeout .
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B nretries {forever|never|<nretries>}
-This directive defines how many times a bind should be retried
-in case of temporary failure in contacting a target. If defined
+This directive defines how many times forwarding an operation should be retried
+in case of temporary failure in contacting a target. The number of retries
+is per operation, so if a bind to the target is necessary first, the remaining
+number is decremented. If defined
before any target specification, it applies to all targets (by default,
.BR 3
times);
for details.
.TP
-.B suffixmassage "<virtual naming context>" "<real naming context>"
-All the directives starting with "rewrite" refer to the rewrite engine
-that has been added to slapd. See
-.B slapd\-meta(5)
-for details.
+.B suffixmassage "<local suffix>" "<remote suffix>"
+.B slapd\-asyncmeta
+does not support the rewrite engine used by
+the LDAP and META backends.
+.B suffixmassage
+can be used to perform DN suffix rewriting, the same way as the obsoleted suffixmassage directive
+previously used by the LDAP backend.
.TP
.B t\-f\-support {NO|yes|discover}
## based on back-meta module for inclusion in OpenLDAP Software.
## This work was sponsored by Ericsson
-SRCS = init.c config.c search.c message_queue.c bind.c unbind.c add.c compare.c \
- delete.c modify.c modrdn.c suffixmassage.c map.c \
- conn.c candidates.c dncache.c meta_result.c abandon.c
-OBJS = init.lo config.lo search.lo message_queue.lo bind.lo unbind.lo add.lo compare.lo \
- delete.lo modify.lo modrdn.lo suffixmassage.lo map.lo \
- conn.lo candidates.lo dncache.lo meta_result.lo abandon.lo
+SRCS = init.c config.c search.c message_queue.c bind.c add.c compare.c \
+ delete.c modify.c modrdn.c map.c \
+ conn.c candidates.c dncache.c meta_result.c
+OBJS = init.lo config.lo search.lo message_queue.lo bind.lo add.lo compare.lo \
+ delete.lo modify.lo modrdn.lo map.lo \
+ conn.lo candidates.lo dncache.lo meta_result.lo
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
+++ /dev/null
-/* abandon.c - abandon request handler for back-asyncmeta */
-/* $OpenLDAP$ */
-/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
- *
- * Copyright 2016-2019 The OpenLDAP Foundation.
- * Portions Copyright 2016 Symas Corporation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* ACKNOWLEDGEMENTS:
- * This work was developed by Symas Corporation
- * based on back-meta module for inclusion in OpenLDAP Software.
- * This work was sponsored by Ericsson. */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/string.h>
-#include <ac/socket.h>
-
-#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
-#include "ldap_rq.h"
-
-/* function is unused */
-int
-asyncmeta_back_abandon( Operation *op, SlapReply *rs )
-{
- Operation *t_op;
-
- /* Find the ops being abandoned */
- ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
-
- LDAP_STAILQ_FOREACH( t_op, &op->o_conn->c_ops, o_next ) {
- if ( t_op->o_msgid == op->orn_msgid ) {
- t_op->o_abandon = 1;
- }
- }
- ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
-
- return LDAP_SUCCESS;
-}
#include <ac/string.h>
#include <ac/socket.h>
-
#include "slap.h"
+#include "../../../libraries/liblber/lber-int.h"
+#include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "ldap_rq.h"
-#include "../../../libraries/liblber/lber-int.h"
-#include "../../../libraries/libldap/ldap-int.h"
-void
-asyncmeta_sender_error(Operation *op,
- SlapReply *rs,
- slap_callback *cb)
+
+int
+asyncmeta_error_cleanup(Operation *op,
+ SlapReply *rs,
+ bm_context_t *bc,
+ a_metaconn_t *mc,
+ int candidate)
{
- if (cb != NULL) {
- op->o_callback = cb;
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) {
+ bc->bc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ return LDAP_SUCCESS;
}
+ asyncmeta_drop_bc(mc, bc);
+ slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
send_ldap_result(op, rs);
+ return LDAP_SUCCESS;
}
meta_search_candidate_t
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate)
+ int candidate,
+ int do_lock)
{
int isupdate;
Attribute *a;
int i;
LDAPMod **attrs;
- struct berval mapped;
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
- struct berval mdn;
+ struct berval mdn = {0, NULL};
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
- int rc, nretries = 1;
-
+ int rc;
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "addDN";
-
- mdn.bv_len = 0;
-
- switch (asyncmeta_dn_massage( &dc, &bc->op->o_req_dn, &mdn ) )
- {
- case LDAP_SUCCESS:
- break;
- case LDAP_UNWILLING_TO_PERFORM:
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- rs->sr_text = "Operation not allowed";
- retcode = META_SEARCH_ERR;
- goto doreturn;
- default:
- rs->sr_err = LDAP_NO_SUCH_OBJECT;
- retcode = META_SEARCH_NOT_CANDIDATE;
- goto doreturn;
- }
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
/* Count number of attributes in entry ( +1 ) */
for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );
/* Create array of LDAPMods for ldap_add() */
- attrs = ch_malloc( sizeof( LDAPMod * )*i );
+ attrs = op->o_tmpalloc(sizeof( LDAPMod * )*i, op->o_tmpmemctx);
- dc.ctx = "addAttrDN";
isupdate = be_shadow_update( op );
for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
- int j, is_oc = 0;
+ int j;
if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod )
{
continue;
}
- if ( a->a_desc == slap_schema.si_ad_objectClass
- || a->a_desc == slap_schema.si_ad_structuralObjectClass )
- {
- is_oc = 1;
- mapped = a->a_desc->ad_cname;
-
- } else {
- asyncmeta_map( &mt->mt_rwmap.rwm_at,
- &a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
- if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
- continue;
- }
- }
-
- attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
+ attrs[ i ] = op->o_tmpalloc( sizeof( LDAPMod ), op->o_tmpmemctx );
if ( attrs[ i ] == NULL ) {
continue;
}
attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
- attrs[ i ]->mod_type = mapped.bv_val;
-
- if ( is_oc ) {
- for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ );
-
- attrs[ i ]->mod_bvalues =
- (struct berval **)ch_malloc( ( j + 1 ) *
- sizeof( struct berval * ) );
- for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
- struct ldapmapping *mapping;
-
- asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
- &a->a_vals[ j ], &mapping, BACKLDAP_MAP );
-
- if ( mapping == NULL ) {
- if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
- continue;
- }
- attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
-
- } else {
- attrs[ i ]->mod_bvalues[ j ] = &mapping->dst;
- }
- j++;
- }
- attrs[ i ]->mod_bvalues[ j ] = NULL;
-
- } else {
- /*
- * FIXME: dn-valued attrs should be rewritten
- * to allow their use in ACLs at the back-ldap
- * level.
- */
- if ( a->a_desc->ad_type->sat_syntax ==
- slap_schema.si_syn_distinguishedName )
- {
- (void)asyncmeta_dnattr_rewrite( &dc, a->a_vals );
- if ( a->a_vals == NULL ) {
- continue;
- }
- }
-
- for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
- ;
-
- attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) );
- for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
- attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
- }
- attrs[ i ]->mod_bvalues[ j ] = NULL;
+ attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val;
+ j = a->a_numvals;
+ attrs[ i ]->mod_bvalues = op->o_tmpalloc( ( j + 1 ) * sizeof( struct berval * ), op->o_tmpmemctx );
+ for (j=0; j<a->a_numvals; j++) {
+ attrs[ i ]->mod_bvalues[ j ] = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
+ if ( a->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ asyncmeta_dn_massage( &dc, &a->a_vals[ j ], attrs[ i ]->mod_bvalues[ j ] );
+ else
+ *attrs[ i ]->mod_bvalues[ j ] = a->a_vals[ j ];
}
+
+ attrs[ i ]->mod_bvalues[ j ] = NULL;
i++;
}
attrs[ i ] = NULL;
-retry:;
+ asyncmeta_set_msc_time(msc);
+
ctrls = op->o_ctrls;
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
+ /* someone might have reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
ber = ldap_build_add_req( msc->msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid);
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_add_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
- mdn.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
+ mdn.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
-
+ /* fall though*/
default:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- retcode = META_SEARCH_ERR;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
}
}
-done:
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ ldap_pvt_thread_yield();
+ retcode = META_SEARCH_NEED_BIND;
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send add request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ ldap_pvt_thread_yield();
+ break;
+ }
+done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- for ( --i; i >= 0; --i ) {
- free( attrs[ i ]->mod_bvalues );
- free( attrs[ i ] );
- }
- free( attrs );
- if ( mdn.bv_val != op->ora_e->e_dn ) {
- free( mdn.bv_val );
- BER_BVZERO( &mdn );
+ if ( mdn.bv_val != op->o_req_dn.bv_val ) {
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
-doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
- OperationBuffer opbuf;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
SlapReply *candidates;
- slap_callback *cb = op->o_callback;
+ time_t current_time = slap_get_time();
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
- Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_add: %s\n",
+ Debug(LDAP_DEBUG_TRACE, "==> asyncmeta_back_add: %s\n",
op->o_req_dn.bv_val );
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ if (current_time > op->o_time) {
+ Debug(asyncmeta_debug, "==> asyncmeta_back_add[%s]: o_time:[%ld], current time: [%ld]\n",
+ op->o_log_prefix, op->o_time, current_time );
+ }
+
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
+
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ goto finish;
+ }
+
+retry:
+ current_time = slap_get_time();
+ if (bc->timeout && bc->stoptime < current_time) {
+ int timeout_err;
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ rs->sr_err = timeout_err;
+ rs->sr_text = "Operation timed out before it was sent to target";
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
}
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
+ Debug(LDAP_DEBUG_TRACE , "%s asyncmeta_back_add: "
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
- rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate);
+ rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate, 1);
if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
- break;
+ break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- }
- break;
case META_SEARCH_BINDING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- /* Todo add the context to the message queue but do not send the request
- the receiver must send this when we are done binding */
- /* question - how would do receiver know to which targets??? */
- break;
+ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING "
+ "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
+ /* add the context to the message queue but do not send the request
+ the receiver must send this when we are done binding */
+ break;
case META_SEARCH_ERR:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR "
- "cnd=\"%ldd\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- default:
- assert( 0 );
- break;
- }
+ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR "
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
+ goto finish;
+ default:
+ assert( 0 );
+ break;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
finish:
return rs->sr_err;
}
#ifndef SLAPD_ASYNCMETA_H
#define SLAPD_ASYNCMETA_H
-#ifndef ENABLE_REWRITE
-#error "--enable-rewrite is required!"
-#endif
-
#ifdef LDAP_DEVEL
#define SLAPD_META_CLIENT_PR 1
#endif /* LDAP_DEVEL */
#include "proto-asyncmeta.h"
-/* String rewrite library */
-#include "rewrite.h"
#include "ldap_rq.h"
LDAP_BEGIN_DECL
#define META_BACK_PRINT_CONNTREE 0
#endif /* !META_BACK_PRINT_CONNTREE */
-/* from back-ldap.h before rwm removal */
-struct ldapmap {
- int drop_missing;
-
- Avlnode *map;
- Avlnode *remap;
-};
-
-struct ldapmapping {
- struct berval src;
- struct berval dst;
-};
-
-struct ldaprwmap {
- /*
- * DN rewriting
- */
- struct rewrite_info *rwm_rw;
- BerVarray rwm_bva_rewrite;
-
- /*
- * Attribute/objectClass mapping
- */
- struct ldapmap rwm_oc;
- struct ldapmap rwm_at;
- BerVarray rwm_bva_map;
-};
-
-/* Whatever context asyncmeta_dn_massage needs... */
-typedef struct a_dncookie {
- struct a_metatarget_t *target;
-
- Connection *conn;
- char *ctx;
- SlapReply *rs;
-} a_dncookie;
-
-int asyncmeta_dn_massage(a_dncookie *dc, struct berval *dn,
- struct berval *res);
-
-extern int asyncmeta_conn_dup( void *c1, void *c2 );
-extern void asyncmeta_conn_free( void *c );
-
-/* attributeType/objectClass mapping */
-int asyncmeta_mapping_cmp (const void *, const void *);
-int asyncmeta_mapping_dup (void *, void *);
-
-void asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping ** );
-int asyncmeta_mapping ( struct ldapmap *map, struct berval *s,
- struct ldapmapping **m, int remap );
-void asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *m,
- int remap );
-#define BACKLDAP_MAP 0
-#define BACKLDAP_REMAP 1
-char *
-asyncmeta_map_filter(
- struct ldapmap *at_map,
- struct ldapmap *oc_map,
- struct berval *f,
- int remap );
-
-int
-asyncmeta_map_attrs(
- Operation *op,
- struct ldapmap *at_map,
- AttributeName *a,
- int remap,
- char ***mapped_attrs );
-
-extern int
-asyncmeta_filter_map_rewrite(
- a_dncookie *dc,
- Filter *f,
- struct berval *fstr,
- int remap,
- void *memctx );
-
-/* suffix massaging by means of librewrite */
-extern int
-asyncmeta_suffix_massage_config( struct rewrite_info *info,
- struct berval *pvnc,
- struct berval *nvnc,
- struct berval *prnc,
- struct berval *nrnc );
-
-extern int
-asyncmeta_back_referral_result_rewrite(
- a_dncookie *dc,
- BerVarray a_vals,
- void *memctx );
-extern int
-asyncmeta_dnattr_rewrite(
- a_dncookie *dc,
- BerVarray a_vals );
-extern int
-asyncmeta_dnattr_result_rewrite(
- a_dncookie *dc,
- BerVarray a_vals );
-
-
-/* (end of) from back-ldap.h before rwm removal */
-
/*
* A a_metasingleconn_t can be in the following, mutually exclusive states:
*
#define META_BACK_FCONN_INITED (0x00100000U)
#define META_BACK_FCONN_CREATING (0x00200000U)
+#define META_BACK_FCONN_INVALID (0x00400000U)
#define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
#define META_BACK_CONN_CREATING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING)
#define META_BACK_CONN_CREATING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING)
#define META_BACK_CONN_CREATING_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc))
+#define META_BACK_CONN_INVALID(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INVALID)
+#define META_BACK_CONN_INVALID_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INVALID)
+#define META_BACK_CONN_INVALID_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INVALID)
struct a_metainfo_t;
struct a_metaconn_t;
#define META_RETRYING ((ber_tag_t)0x4)
typedef struct bm_context_t {
- LDAP_SLIST_ENTRY(bm_context_t) bc_next;
+ LDAP_STAILQ_ENTRY(bm_context_t) bc_next;
+ struct a_metaconn_t *bc_mc;
time_t timeout;
time_t stoptime;
ldap_back_send_t sendok;
ldap_back_send_t retrying;
int candidate_match;
- int sent;
- int bc_active;
+ volatile int bc_active;
int searchtime; /* stoptime is a search timelimit */
int is_ok;
+ int is_root;
+ volatile sig_atomic_t bc_invalid;
SlapReply rs;
Operation *op;
+ Operation copy_op;
LDAPControl **ctrls;
int *msgids;
+ int *nretries; /* number of times to retry a failed send on an msc */
+ struct berval c_peer_name; /* peer name of original op->o_conn*/
SlapReply *candidates;
} bm_context_t;
LDAP *msc_ld;
LDAP *msc_ldr;
time_t msc_time;
+ time_t msc_binding_time;
+ time_t msc_result_time;
struct berval msc_bound_ndn;
struct berval msc_cred;
unsigned msc_mscflags;
+
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */
#define lc_lcflags msc_mscflags
- int msc_pending_ops;
- int msc_timeout_ops;
+ volatile int msc_active;
/* Connection for the select */
Connection *conn;
} a_metasingleconn_t;
int pending_ops;
ldap_pvt_thread_mutex_t mc_om_mutex;
/* queue for pending operations */
- LDAP_SLIST_HEAD(BCList, bm_context_t) mc_om_list;
+ LDAP_STAILQ_HEAD(BCList, bm_context_t) mc_om_list;
/* supersedes the connection stuff */
a_metasingleconn_t *mc_conns;
} a_metaconn_t;
#define META_RETRY_UNDEFINED (-2)
#define META_RETRY_FOREVER (-1)
#define META_RETRY_NEVER (0)
-#define META_RETRY_DEFAULT (10)
+#define META_RETRY_DEFAULT (2)
unsigned mc_flags;
#define META_BACK_CMN_ISSET(mc,f) ( ( (mc)->mc_flags & (f) ) == (f) )
struct berval mt_psuffix; /* pretty suffix */
struct berval mt_nsuffix; /* normalized suffix */
+ struct berval mt_lsuffixm; /* local suffix for massage */
+ struct berval mt_rsuffixm; /* remote suffix for massage */
+
struct berval mt_binddn;
struct berval mt_bindpw;
#define mt_idassert_flags mt_idassert.si_flags
#define mt_idassert_authz mt_idassert.si_authz
- struct ldaprwmap mt_rwmap;
-
sig_atomic_t mt_isquarantined;
ldap_pvt_thread_mutex_t mt_quarantine_mutex;
int mi_next_conn;
a_metaconn_t *mi_conns;
+ struct berval mi_suffix;
} a_metainfo_t;
typedef enum meta_op_type {
META_OP_REQUIRE_ALL
} meta_op_type;
+/* Whatever context asyncmeta_dn_massage needs... */
+typedef struct a_dncookie {
+ Operation *op;
+ struct a_metatarget_t *target;
+ void *memctx;
+ int to_from;
+} a_dncookie;
+
+
+#define MASSAGE_REQ 0
+#define MASSAGE_REP 1
+
+extern void
+asyncmeta_dn_massage(a_dncookie *dc, struct berval *dn,
+ struct berval *res);
+
+extern void
+asyncmeta_filter_map_rewrite(
+ a_dncookie *dc,
+ Filter *f,
+ struct berval *fstr );
+
+extern void
+asyncmeta_back_referral_result_rewrite(
+ a_dncookie *dc,
+ BerVarray a_vals );
+
extern a_metaconn_t *
asyncmeta_getconn(
Operation *op,
ldap_back_send_t sendok,
int alloc_new);
-extern int
-asyncmeta_retry(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t **mcp,
- int candidate,
- ldap_back_send_t sendok );
-
-extern void
-asyncmeta_conn_free(
- void *v_mc );
extern int
asyncmeta_init_one_conn(
SlapReply *rs,
int candidate );
-extern int
-asyncmeta_dobind(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- ldap_back_send_t sendok,
- SlapReply *candidates);
-
-extern int
-asyncmeta_single_dobind(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t **mcp,
- int candidate,
- ldap_back_send_t sendok,
- int retries,
- int dolock );
-
extern int
asyncmeta_proxy_authz_cred(
a_metaconn_t *mc,
struct berval *bindcred,
int *method );
-extern int
-asyncmeta_cancel(
- a_metaconn_t *mc,
- Operation *op,
- SlapReply *rs,
- ber_int_t msgid,
- int candidate,
- ldap_back_send_t sendok );
-
-extern int
-asyncmeta_op_result(
- a_metaconn_t *mc,
- Operation *op,
- SlapReply *rs,
- int candidate,
- ber_int_t msgid,
- time_t timeout,
- ldap_back_send_t sendok );
-
extern int
asyncmeta_controls_add(
Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
int candidate,
+ int isroot,
LDAPControl ***pctrls );
extern int
extern void
asyncmeta_dncache_free( void *entry );
-extern void
-asyncmeta_back_map_free( struct ldapmap *lm );
-
extern int
asyncmeta_subtree_destroy( a_metasubtree_t *ms );
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc);
void asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc);
+void asyncmeta_drop_bc_from_fconn(bm_context_t *bc);
bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate);
-bm_context_t *
-asyncmeta_find_message_by_opmsguid(ber_int_t msgid, a_metaconn_t *mc, int remove);
+void asyncmeta_memctx_toggle(void *thrctx);
void* asyncmeta_op_handle_result(void *ctx, void *arg);
int asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bm );
asyncmeta_clear_one_msc(
Operation *op,
a_metaconn_t *msc,
- int candidate );
+ int candidate,
+ int unbind,
+ const char * caller);
a_metaconn_t *
asyncmeta_get_next_mc( a_metainfo_t *mi );
void* asyncmeta_timeout_loop(void *ctx, void *arg);
+
int
asyncmeta_start_timeout_loop(a_metatarget_t *mt, a_metainfo_t *mi);
+
void asyncmeta_set_msc_time(a_metasingleconn_t *msc);
-void asyncmeta_clear_message_queue(a_metasingleconn_t *msc);
int asyncmeta_back_cancel(
a_metaconn_t *mc,
ber_int_t msgid,
int candidate );
-int
-asyncmeta_back_cancel_msc(
- Operation *op,
- SlapReply *rs,
- ber_int_t msgid,
- a_metasingleconn_t *msc,
- int candidate,
- ldap_back_send_t sendok );
-
-int
-asyncmeta_back_abandon_candidate(
- a_metaconn_t *mc,
- Operation *op,
- ber_int_t msgid,
- int candidate );
void
asyncmeta_send_result(bm_context_t* bc, int error, char *text);
-int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets);
+int asyncmeta_new_bm_context(Operation *op,
+ SlapReply *rs,
+ bm_context_t **new_bc,
+ int ntargets,
+ a_metainfo_t *mi);
+
int asyncmeta_start_listeners(a_metaconn_t *mc, SlapReply *candidates, bm_context_t *bc);
int asyncmeta_start_one_listener(a_metaconn_t *mc, SlapReply *candidates, bm_context_t *bc, int candidate);
bm_context_t *bc,
int candidate,
struct berval *prcookie,
- ber_int_t prsize );
+ ber_int_t prsize,
+ int do_lock);
meta_search_candidate_t
asyncmeta_dobind_init(
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate);
+ int candidate,
+ int do_lock);
meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate);
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ int do_lock);
meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate);
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ int do_lock);
meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate);
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ int do_lock);
meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate);
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ int do_lock);
+bm_context_t *
+asyncmeta_bc_in_queue(a_metaconn_t *mc,
+ bm_context_t *bc);
+
+int
+asyncmeta_error_cleanup(Operation *op,
+ SlapReply *rs,
+ bm_context_t *bc,
+ a_metaconn_t *mc,
+ int candidate);
+
+int
+asyncmeta_reset_msc(Operation *op,
+ a_metaconn_t *mc,
+ int candidate,
+ int unbind,
+ const char *caller);
+
+
+void
+asyncmeta_back_conn_free(
+ void *v_mc );
+
+void asyncmeta_log_msc(a_metasingleconn_t *msc);
+void asyncmeta_log_conns(a_metainfo_t *mi);
+
+void asyncmeta_get_timestamp(char *buf);
+
+int
+asyncmeta_dncache_update_entry(a_metadncache_t *cache,
+ struct berval *ndn,
+ int target );
+
+void
+asyncmeta_dnattr_result_rewrite(a_dncookie *dc,
+ BerVarray a_vals);
void
-asyncmeta_sender_error(Operation *op,
- SlapReply *rs,
- slap_callback *cb);
+asyncmeta_referral_result_rewrite(a_dncookie *dc,
+ BerVarray a_vals);
+
+meta_search_candidate_t
+asyncmeta_send_all_pending_ops(a_metaconn_t *mc,
+ int candidate,
+ void *ctx,
+ int dolock);
+meta_search_candidate_t
+asyncmeta_return_bind_errors(a_metaconn_t *mc,
+ int candidate,
+ SlapReply *bind_result,
+ void *ctx,
+ int dolock);
+
+/* The the maximum time in seconds after a result has been received on a connection,
+ * after which it can be reset if a sender error occurs. Should this be configurable? */
+#define META_BACK_RESULT_INTERVAL (2)
+extern int asyncmeta_debug;
LDAP_END_DECL
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
-
+#include "slap.h"
+#include "../../../libraries/libldap/ldap-int.h"
#define AVL_INTERNAL
-#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
-
#include "lutil_ldap.h"
+#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
+
static int
asyncmeta_proxy_authz_bind(
a_metaconn_t *mc,
struct timeval tv;
int rc;
int nretries = mt->mt_nretries;
- char buf[ SLAP_TEXT_BUFLEN ];
Debug( LDAP_DEBUG_TRACE,
">>> %s asyncmeta_bind_op_result[%d]\n",
ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
&rs->sr_err );
- Debug(LDAP_DEBUG_ANY,
+ Debug( LDAP_DEBUG_ANY,
"### %s asyncmeta_bind_op_result[%d]: err=%d (%s) nretries=%d.\n",
op->o_log_prefix, candidate, rs->sr_err,
ldap_err2string(rs->sr_err), nretries );
/*
* Rewrite the bind dn if needed
*/
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "bindDN";
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
- if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- rs->sr_text = "DN rewrite error";
- rs->sr_err = LDAP_OTHER;
- return rs->sr_err;
- }
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
/* don't add proxyAuthz; set the bindDN */
save_o_dn = op->o_dn;
op->o_dn = op->o_req_dn;
ctrls = op->o_ctrls;
- rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, &ctrls );
+ rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, be_isroot(op), &ctrls );
op->o_dn = save_o_dn;
op->o_do_not_cache = save_o_do_not_cache;
if ( rs->sr_err != LDAP_SUCCESS ) {
return_results:;
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
if ( META_BACK_TGT_QUARANTINE( mt ) ) {
return rs->sr_err;
}
-/*
- * asyncmeta_back_single_dobind
- */
-int
-asyncmeta_back_single_dobind(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t **mcp,
- int candidate,
- ldap_back_send_t sendok,
- int nretries,
- int dolock )
-{
- a_metaconn_t *mc = *mcp;
- a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
- int msgid;
-
- assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
-
- if ( op->o_conn != NULL &&
- !op->o_do_not_cache &&
- ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
- BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
- ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
- ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
- {
- (void)asyncmeta_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock );
-
- } else {
- char *binddn = "";
- struct berval cred = BER_BVC( "" );
-
- /* use credentials if available */
- if ( !BER_BVISNULL( &msc->msc_bound_ndn )
- && !BER_BVISNULL( &msc->msc_cred ) )
- {
- binddn = msc->msc_bound_ndn.bv_val;
- cred = msc->msc_cred;
- }
-
- for (;;) {
- rs->sr_err = ldap_sasl_bind( msc->msc_ld,
- binddn, LDAP_SASL_SIMPLE, &cred,
- NULL, NULL, &msgid );
- if ( rs->sr_err != LDAP_X_CONNECTING ) {
- break;
- }
- ldap_pvt_thread_yield();
- }
-
- rs->sr_err = asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
-
- /* if bind succeeded, but anonymous, clear msc_bound_ndn */
- if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) {
- if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
- ber_memfree( msc->msc_bound_ndn.bv_val );
- BER_BVZERO( &msc->msc_bound_ndn );
- }
-
- if ( !BER_BVISNULL( &msc->msc_cred ) ) {
- memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
- ber_memfree( msc->msc_cred.bv_val );
- BER_BVZERO( &msc->msc_cred );
- }
- }
- }
-
- if ( META_BACK_TGT_QUARANTINE( mt ) ) {
- asyncmeta_quarantine( op, mi, rs, candidate );
- }
-
- return rs->sr_err;
-}
/*
* asyncmeta_back_default_rebind
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
int rc = LDAP_OTHER;
+ struct timeval tv = { 0, 0 };
+ ber_socket_t s;
Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n",
op->o_log_prefix, candidate, msgid );
- if (msc->msc_ld == NULL) {
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n already reset",
op->o_log_prefix, candidate, msgid );
return LDAP_SUCCESS;
}
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ return rc;
+ }
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ rc = LDAP_SERVER_DOWN;
+ return rc;
+ }
/* default behavior */
if ( META_BACK_TGT_ABANDON( mt ) ) {
rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
}
-int
-asyncmeta_back_abandon_candidate(
- a_metaconn_t *mc,
- Operation *op,
- ber_int_t msgid,
- int candidate )
-{
-
- a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
-
- int rc = LDAP_OTHER;
-
- Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_abandon[%d] msgid=%d\n",
- op->o_log_prefix, candidate, msgid );
-
- rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
-
- Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_abandon[%d] err=%d\n",
- op->o_log_prefix, candidate, rc );
-
- return rc;
-}
-
-int
-asyncmeta_back_cancel_msc(
- Operation *op,
- SlapReply *rs,
- ber_int_t msgid,
- a_metasingleconn_t *msc,
- int candidate,
- ldap_back_send_t sendok )
-{
- a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private;
-
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
-
- int rc = LDAP_OTHER;
-
- Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel_msc[%d] msgid=%d\n",
- op->o_log_prefix, candidate, msgid );
-
- /* default behavior */
- if ( META_BACK_TGT_ABANDON( mt ) ) {
- rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
-
- } else if ( META_BACK_TGT_IGNORE( mt ) ) {
- rc = ldap_pvt_discard( msc->msc_ld, msgid );
-
- } else if ( META_BACK_TGT_CANCEL( mt ) ) {
- rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
-
- } else {
- assert( 0 );
- }
-
- Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_cancel_msc[%d] err=%d\n",
- op->o_log_prefix, candidate, rc );
-
- return rc;
-}
/*
- * FIXME: error return must be handled in a cleaner way ...
- */
-int
-asyncmeta_back_op_result(
- a_metaconn_t *mc,
- Operation *op,
- SlapReply *rs,
- int candidate,
- ber_int_t msgid,
- time_t timeout,
- ldap_back_send_t sendok )
-{
- a_metainfo_t *mi = mc->mc_info;
-
- const char *save_text = rs->sr_text,
- *save_matched = rs->sr_matched;
- BerVarray save_ref = rs->sr_ref;
- LDAPControl **save_ctrls = rs->sr_ctrls;
- void *matched_ctx = NULL;
-
- char *matched = NULL;
- char *text = NULL;
- char **refs = NULL;
- LDAPControl **ctrls = NULL;
-
- assert( mc != NULL );
-
- rs->sr_text = NULL;
- rs->sr_matched = NULL;
- rs->sr_ref = NULL;
- rs->sr_ctrls = NULL;
-
- if ( candidate != META_TARGET_NONE ) {
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
-
- if ( LDAP_ERR_OK( rs->sr_err ) ) {
- int rc;
- struct timeval tv;
- LDAPMessage *res = NULL;
- time_t stoptime = (time_t)(-1);
- int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
- const char *timeout_text = "Operation timed out";
-
- /* if timeout is not specified, compute and use
- * the one specific to the ongoing operation */
- if ( timeout == (time_t)(-1) ) {
- slap_op_t opidx = slap_req2op( op->o_tag );
-
- if ( opidx == SLAP_OP_SEARCH ) {
- if ( op->ors_tlimit <= 0 ) {
- timeout = 0;
-
- } else {
- timeout = op->ors_tlimit;
- timeout_err = LDAP_TIMELIMIT_EXCEEDED;
- timeout_text = NULL;
- }
-
- } else {
- timeout = mt->mt_timeout[ opidx ];
- }
- }
-
- /* better than nothing :) */
- if ( timeout == 0 ) {
- if ( mi->mi_idle_timeout ) {
- timeout = mi->mi_idle_timeout;
-
- }
- }
-
- if ( timeout ) {
- stoptime = op->o_time + timeout;
- }
-
- LDAP_BACK_TV_SET( &tv );
-
-retry:;
- rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
- switch ( rc ) {
- case 0:
- if ( timeout && slap_get_time() > stoptime ) {
- (void)asyncmeta_back_cancel( mc, op, msgid, candidate );
- rs->sr_err = timeout_err;
- rs->sr_text = timeout_text;
- break;
- }
-
- LDAP_BACK_TV_SET( &tv );
- ldap_pvt_thread_yield();
- goto retry;
-
- case -1:
- ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
- &rs->sr_err );
- break;
-
-
- /* otherwise get the result; if it is not
- * LDAP_SUCCESS, record it in the reply
- * structure (this includes
- * LDAP_COMPARE_{TRUE|FALSE}) */
- default:
- /* only touch when activity actually took place... */
- if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
- msc->msc_time = op->o_time;
- }
-
- rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
- &matched, &text, &refs, &ctrls, 1 );
- res = NULL;
- if ( rc == LDAP_SUCCESS ) {
- rs->sr_text = text;
- } else {
- rs->sr_err = rc;
- }
- rs->sr_err = slap_map_api2result( rs );
-
- /* RFC 4511: referrals can only appear
- * if result code is LDAP_REFERRAL */
- if ( refs != NULL
- && refs[ 0 ] != NULL
- && refs[ 0 ][ 0 ] != '\0' )
- {
- if ( rs->sr_err != LDAP_REFERRAL ) {
- Debug( LDAP_DEBUG_ANY,
- "%s asyncmeta_back_op_result[%d]: "
- "got referrals with err=%d\n",
- op->o_log_prefix,
- candidate, rs->sr_err );
-
- } else {
- int i;
-
- for ( i = 0; refs[ i ] != NULL; i++ )
- /* count */ ;
- rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
- op->o_tmpmemctx );
- for ( i = 0; refs[ i ] != NULL; i++ ) {
- ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
- }
- BER_BVZERO( &rs->sr_ref[ i ] );
- }
-
- } else if ( rs->sr_err == LDAP_REFERRAL ) {
- Debug( LDAP_DEBUG_ANY,
- "%s asyncmeta_back_op_result[%d]: "
- "got err=%d with null "
- "or empty referrals\n",
- op->o_log_prefix,
- candidate, rs->sr_err );
-
- rs->sr_err = LDAP_NO_SUCH_OBJECT;
- }
-
- if ( ctrls != NULL ) {
- rs->sr_ctrls = ctrls;
- }
- }
-
- assert( res == NULL );
- }
-
- /* if the error in the reply structure is not
- * LDAP_SUCCESS, try to map it from client
- * to server error */
- if ( !LDAP_ERR_OK( rs->sr_err ) ) {
- rs->sr_err = slap_map_api2result( rs );
-
- /* internal ops ( op->o_conn == NULL )
- * must not reply to client */
- if ( op->o_conn && !op->o_do_not_cache && matched ) {
-
- /* record the (massaged) matched
- * DN into the reply structure */
- rs->sr_matched = matched;
- }
- }
-
- if ( META_BACK_TGT_QUARANTINE( mt ) ) {
- asyncmeta_quarantine( op, mi, rs, candidate );
- }
-
- } else {
- int i,
- err = rs->sr_err;
-
- for ( i = 0; i < mi->mi_ntargets; i++ ) {
- a_metasingleconn_t *msc = &mc->mc_conns[ i ];
- char *xtext = NULL;
- char *xmatched = NULL;
-
- if ( msc->msc_ld == NULL ) {
- continue;
- }
-
- rs->sr_err = LDAP_SUCCESS;
-
- ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
- if ( rs->sr_err != LDAP_SUCCESS ) {
- /*
- * better check the type of error. In some cases
- * (search ?) it might be better to return a
- * success if at least one of the targets gave
- * positive result ...
- */
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
- if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
- ldap_memfree( xtext );
- xtext = NULL;
- }
-
- ldap_get_option( msc->msc_ld,
- LDAP_OPT_MATCHED_DN, &xmatched );
- if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
- ldap_memfree( xmatched );
- xmatched = NULL;
- }
-
- rs->sr_err = slap_map_api2result( rs );
-
- Debug(LDAP_DEBUG_ANY,
- "%s asyncmeta_back_op_result[%d] " "err=%d text=\"%s\" matched=\"%s\".\n",
- op->o_log_prefix, i, rs->sr_err,
- (xtext ? xtext : ""),
- (xmatched ? xmatched : "") );
-
- /*
- * FIXME: need to rewrite "match" (need rwinfo)
- */
- switch ( rs->sr_err ) {
- default:
- err = rs->sr_err;
- if ( xtext != NULL ) {
- if ( text ) {
- ldap_memfree( text );
- }
- text = xtext;
- xtext = NULL;
- }
- if ( xmatched != NULL ) {
- if ( matched ) {
- ldap_memfree( matched );
- }
- matched = xmatched;
- xmatched = NULL;
- }
- break;
- }
-
- if ( xtext ) {
- ldap_memfree( xtext );
- }
-
- if ( xmatched ) {
- ldap_memfree( xmatched );
- }
- }
-
- if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
- asyncmeta_quarantine( op, mi, rs, i );
- }
- }
-
- if ( err != LDAP_SUCCESS ) {
- rs->sr_err = err;
- }
- }
-
- if ( matched != NULL ) {
- struct berval dn, pdn;
-
- ber_str2bv( matched, 0, 0, &dn );
- if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
- ldap_memfree( matched );
- matched_ctx = op->o_tmpmemctx;
- matched = pdn.bv_val;
- }
- rs->sr_matched = matched;
- }
-
- if ( rs->sr_err == LDAP_UNAVAILABLE ) {
- if ( !( sendok & LDAP_BACK_RETRYING ) ) {
- if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
- if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
- send_ldap_result( op, rs );
- }
- }
-
- } else if ( op->o_conn &&
- ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
- || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
- {
- send_ldap_result( op, rs );
- }
- if ( matched ) {
- op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
- }
- if ( text ) {
- ldap_memfree( text );
- }
- if ( rs->sr_ref ) {
- op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
- rs->sr_ref = NULL;
- }
- if ( refs ) {
- ber_memvfree( (void **)refs );
- }
- if ( ctrls ) {
- assert( rs->sr_ctrls != NULL );
- ldap_controls_free( ctrls );
- }
-
- rs->sr_text = save_text;
- rs->sr_matched = save_matched;
- rs->sr_ref = save_ref;
- rs->sr_ctrls = save_ctrls;
-
- return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
-}
-
-/*
- * meta_back_proxy_authz_cred()
+ * asyncmeta_back_proxy_authz_cred()
*
* prepares credentials & method for meta_back_proxy_authz_bind();
* or, if method is SASL, performs the SASL bind directly.
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
struct berval ndn;
int dobind = 0;
-
+ struct timeval old_tv = {0, 0};
+ struct timeval bind_tv = { mt->mt_timeout[ SLAP_OP_BIND ], 0};
/* don't proxyAuthz if protocol is not LDAPv3 */
switch ( mt->mt_version ) {
case LDAP_VERSION3:
}
}
+ ldap_get_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv);
+
+ if (mt->mt_timeout[ SLAP_OP_BIND ] > 0 ) {
+ rs->sr_err = ldap_set_option( msc->msc_ld,
+ LDAP_OPT_TIMEOUT,
+ (void *)&bind_tv );
+
+ if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
+ rs->sr_err = LDAP_OTHER;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
+ goto done;
+ }
+ }
defaults = lutil_sasl_defaults( msc->msc_ld,
mt->mt_idassert_sasl_mech.bv_val,
mt->mt_idassert_sasl_realm.bv_val,
LDAP_SASL_QUIET, lutil_sasl_interact,
defaults );
+ /* restore the old timeout just in case */
+ ldap_set_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv );
+
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err != LDAP_SUCCESS ) {
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_back_proxy_authz_cred failed bind msc: %p\n",
+ time_buf, msc );
+ }
LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
return LDAP_BACK_CONN_ISBOUND( msc );
}
-/*
- * Add controls;
- *
- * if any needs to be added, it is prepended to existing ones,
- * in a newly allocated array. The companion function
- * mi->mi_ldap_extra->controls_free() must be used to restore the original
- * status of op->o_ctrls.
- */
-int
-asyncmeta_controls_add(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- int candidate,
- LDAPControl ***pctrls )
+
+static int
+asyncmeta_back_proxy_authz_ctrl(Operation *op,
+ SlapReply *rs,
+ struct berval *bound_ndn,
+ int version,
+ int isroot,
+ slap_idassert_t *si,
+ LDAPControl *ctrl )
{
- a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+ slap_idassert_mode_t mode;
+ struct berval assertedID,
+ ndn;
+
+ rs->sr_err = SLAP_CB_CONTINUE;
+
+ /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
+ * but if it is not set this test fails. We need a different
+ * means to detect if idassert is enabled */
+ if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
+ && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
+ && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
+ {
+ goto done;
+ }
- LDAPControl **ctrls = NULL;
- /* set to the maximum number of controls this backend can add */
- LDAPControl c[ 2 ] = {{ 0 }};
- int n = 0, i, j1 = 0, j2 = 0;
+ if ( !op->o_conn || op->o_do_not_cache || ( isroot ) ) {
+ goto done;
+ }
- *pctrls = NULL;
+ if ( op->o_tag == LDAP_REQ_BIND ) {
+ ndn = op->o_req_ndn;
- rs->sr_err = LDAP_SUCCESS;
+#if 0
+ } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ ndn = op->o_conn->c_ndn;
+#endif
+ } else {
+ ndn = op->o_ndn;
+ }
- /* don't add controls if protocol is not LDAPv3 */
- switch ( mt->mt_version ) {
- case LDAP_VERSION3:
- break;
+ if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
+ if ( op->o_proxy_authz ) {
+ /*
+ * FIXME: we do not want to perform proxyAuthz
+ * on behalf of the client, because this would
+ * be performed with "proxyauthzdn" privileges.
+ *
+ * This might actually be too strict, since
+ * the "proxyauthzdn" authzTo, and each entry's
+ * authzFrom attributes may be crafted
+ * to avoid unwanted proxyAuthz to take place.
+ */
+#if 0
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ rs->sr_text = "proxyAuthz not allowed within namingContext";
+#endif
+ goto done;
+ }
- case 0:
- if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
- break;
+ if ( !BER_BVISNULL( bound_ndn ) ) {
+ goto done;
}
- /* fall thru */
- default:
- goto done;
+ if ( BER_BVISNULL( &ndn ) ) {
+ goto done;
+ }
+
+ if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
+ goto done;
+ }
+
+ } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
+ if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
+ {
+ /* already asserted in SASL via native authz */
+ goto done;
+ }
+
+ } else if ( si->si_authz && !isroot ) {
+ int rc;
+ struct berval authcDN;
+
+ if ( BER_BVISNULL( &ndn ) ) {
+ authcDN = slap_empty_bv;
+ } else {
+ authcDN = ndn;
+ }
+ rc = slap_sasl_matches( op, si->si_authz,
+ &authcDN, &authcDN );
+ if ( rc != LDAP_SUCCESS ) {
+ if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+ /* ndn is not authorized
+ * to use idassert */
+ rs->sr_err = rc;
+ }
+ goto done;
+ }
}
- /* put controls that go __before__ existing ones here */
+ if ( op->o_proxy_authz ) {
+ /*
+ * FIXME: we can:
+ * 1) ignore the already set proxyAuthz control
+ * 2) leave it in place, and don't set ours
+ * 3) add both
+ * 4) reject the operation
+ *
+ * option (4) is very drastic
+ * option (3) will make the remote server reject
+ * the operation, thus being equivalent to (4)
+ * option (2) will likely break the idassert
+ * assumptions, so we cannot accept it;
+ * option (1) means that we are contradicting
+ * the client's reques.
+ *
+ * I think (4) is the only correct choice.
+ */
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ rs->sr_text = "proxyAuthz not allowed within namingContext";
+ }
- /* proxyAuthz for identity assertion */
- switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
- mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
- {
- case SLAP_CB_CONTINUE:
+ if ( op->o_is_auth_check ) {
+ mode = LDAP_BACK_IDASSERT_NOASSERT;
+
+ } else {
+ mode = si->si_mode;
+ }
+
+ switch ( mode ) {
+ case LDAP_BACK_IDASSERT_LEGACY:
+ /* original behavior:
+ * assert the client's identity */
+ case LDAP_BACK_IDASSERT_SELF:
+ assertedID = ndn;
break;
- case LDAP_SUCCESS:
- j1++;
+ case LDAP_BACK_IDASSERT_ANONYMOUS:
+ /* assert "anonymous" */
+ assertedID = slap_empty_bv;
+ break;
+
+ case LDAP_BACK_IDASSERT_NOASSERT:
+ /* don't assert; bind as proxyauthzdn */
+ goto done;
+
+ case LDAP_BACK_IDASSERT_OTHERID:
+ case LDAP_BACK_IDASSERT_OTHERDN:
+ /* assert idassert DN */
+ assertedID = si->si_bc.sb_authzId;
break;
default:
+ assert( 0 );
+ }
+
+ /* if we got here, "" is allowed to proxyAuthz */
+ if ( BER_BVISNULL( &assertedID ) ) {
+ assertedID = slap_empty_bv;
+ }
+
+ /* don't idassert the bound DN (ITS#4497) */
+ if ( dn_match( &assertedID, bound_ndn ) ) {
goto done;
}
- /* put controls that go __after__ existing ones here */
+ ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
+ ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL );
-#ifdef SLAP_CONTROL_X_SESSION_TRACKING
- /* session tracking */
- if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
- switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
- case SLAP_CB_CONTINUE:
- break;
+ switch ( si->si_mode ) {
+ /* already in u:ID or dn:DN form */
+ case LDAP_BACK_IDASSERT_OTHERID:
+ case LDAP_BACK_IDASSERT_OTHERDN:
+ ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
+ rs->sr_err = LDAP_SUCCESS;
+ break;
- case LDAP_SUCCESS:
- j2++;
- break;
+ /* needs the dn: prefix */
+ default:
+ ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
+ ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
+ op->o_tmpmemctx );
+ AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
+ AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
+ assertedID.bv_val, assertedID.bv_len + 1 );
+ rs->sr_err = LDAP_SUCCESS;
+ break;
+ }
- default:
- goto done;
+ /* Older versions of <draft-weltman-ldapv3-proxy> required
+ * to encode the value of the authzID (and called it proxyDN);
+ * this hack provides compatibility with those DSAs that
+ * implement it this way */
+ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
+ struct berval authzID = ctrl->ldctl_value;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ ber_tag_t tag;
+
+ ber_init2( ber, 0, LBER_USE_DER );
+ ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+ tag = ber_printf( ber, "O", &authzID );
+ if ( tag == LBER_ERROR ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber;
+ }
+
+ if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber;
}
- }
-#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
- if ( rs->sr_err == SLAP_CB_CONTINUE ) {
rs->sr_err = LDAP_SUCCESS;
- }
- /* if nothing to do, just bail out */
- if ( j1 == 0 && j2 == 0 ) {
- goto done;
- }
+free_ber:;
+ op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
+ ber_free_buf( ber );
- assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ goto done;
+ }
- if ( op->o_ctrls ) {
- for ( n = 0; op->o_ctrls[ n ]; n++ )
- /* just count ctrls */ ;
- }
+ } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
+ struct berval authzID = ctrl->ldctl_value,
+ tmp;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ ber_tag_t tag;
- ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
- op->o_tmpmemctx );
- if ( j1 ) {
- ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
- *ctrls[ 0 ] = c[ 0 ];
- for ( i = 1; i < j1; i++ ) {
- ctrls[ i ] = &ctrls[ 0 ][ i ];
- *ctrls[ i ] = c[ i ];
+ if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto done;
}
- }
- i = 0;
- if ( op->o_ctrls ) {
- for ( i = 0; op->o_ctrls[ i ]; i++ ) {
- ctrls[ i + j1 ] = op->o_ctrls[ i ];
+ tmp = authzID;
+ tmp.bv_val += STRLENOF( "dn:" );
+ tmp.bv_len -= STRLENOF( "dn:" );
+
+ ber_init2( ber, 0, LBER_USE_DER );
+ ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+ /* apparently, Mozilla API encodes this
+ * as "SEQUENCE { LDAPDN }" */
+ tag = ber_printf( ber, "{O}", &tmp );
+ if ( tag == LBER_ERROR ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber2;
}
- }
- n += j1;
- if ( j2 ) {
- ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
- *ctrls[ n ] = c[ j1 ];
- for ( i = 1; i < j2; i++ ) {
- ctrls[ n + i ] = &ctrls[ n ][ i ];
- *ctrls[ n + i ] = c[ i ];
+ if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
+ rs->sr_err = LDAP_OTHER;
+ goto free_ber2;
}
- }
- ctrls[ n + j2 ] = NULL;
+ ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
+ rs->sr_err = LDAP_SUCCESS;
-done:;
- if ( ctrls == NULL ) {
- ctrls = op->o_ctrls;
+free_ber2:;
+ op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
+ ber_free_buf( ber );
+
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ goto done;
+ }
}
- *pctrls = ctrls;
+done:;
return rs->sr_err;
}
-#if 0
/*
* Add controls;
*
- * same as asyncmeta_controls_add, but creates a new controls array
- * to be used by the operation copy
+ * if any needs to be added, it is prepended to existing ones,
+ * in a newly allocated array. The companion function
+ * mi->mi_ldap_extra->controls_free() must be used to restore the original
+ * status of op->o_ctrls.
*/
int
-asyncmeta_controls_add_copy(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- int candidate,
- LDAPControl ***pctrls )
+asyncmeta_controls_add( Operation *op,
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ int candidate,
+ int isroot,
+ LDAPControl ***pctrls )
{
- a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private;
+ a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = mc->mc_conns[ candidate ];
+ a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
LDAPControl **ctrls = NULL;
/* set to the maximum number of controls this backend can add */
/* put controls that go __before__ existing ones here */
/* proxyAuthz for identity assertion */
- switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
- mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
+ switch ( asyncmeta_back_proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
+ mt->mt_version, isroot, &mt->mt_idassert, &c[ j1 ] ) )
{
case SLAP_CB_CONTINUE:
break;
break;
default:
- goto copy;
+ goto done;
}
}
#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
rs->sr_err = LDAP_SUCCESS;
}
-copy:
+ /* if nothing to do, just bail out */
+ if ( j1 == 0 && j2 == 0 ) {
+ goto done;
+ }
+
+ assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
+
if ( op->o_ctrls ) {
for ( n = 0; op->o_ctrls[ n ]; n++ )
/* just count ctrls */ ;
}
- ctrls = ch_calloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ));
+ ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
+ op->o_tmpmemctx );
if ( j1 ) {
ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
*ctrls[ 0 ] = c[ 0 ];
ctrls[ n + j2 ] = NULL;
done:;
+ if ( ctrls == NULL ) {
+ ctrls = op->o_ctrls;
+ }
- op->o_ctrls = ctrls;
+ *pctrls = ctrls;
return rs->sr_err;
}
-#endif
+
/*
* asyncmeta_dobind_init()
a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
- ber_socket_t s;
struct berval binddn = msc->msc_bound_ndn,
cred = msc->msc_cred;
int method;
meta_search_candidate_t retcode;
- Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_search_dobind_init[%d]\n",
+ Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_dobind_init[%d]\n",
op->o_log_prefix, candidate );
if ( mc->mc_authz_target == META_BOUND_ALL ) {
return META_SEARCH_CANDIDATE;
}
+ if ( slapd_shutdown ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ return META_SEARCH_ERR;
+ }
+
retcode = META_SEARCH_BINDING;
if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
/* already bound (or anonymous) */
bound = 1;
}
- Debug(LDAP_DEBUG_ANY,
- "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n",
- op->o_log_prefix, candidate, (void *)mc,
- (void *)msc->msc_ld, bound ? " bound" : " anonymous",
- bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
+ Debug( LDAP_DEBUG_ANY,
+ "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n",
+ op->o_log_prefix, candidate, (void *)mc,
+ (void *)msc->msc_ld, bound ? " bound" : " anonymous",
+ bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
#endif /* DEBUG_205 */
retcode = META_SEARCH_CANDIDATE;
/* another thread is binding the target for this conn; wait */
#ifdef DEBUG_205
- char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
- Debug(LDAP_DEBUG_ANY,
- "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p needbind\n",
- op->o_log_prefix, candidate, (void *)mc,
- (void *)msc->msc_ld );
+ Debug( LDAP_DEBUG_ANY,
+ "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p needbind\n",
+ op->o_log_prefix, candidate, (void *)mc,
+ (void *)msc->msc_ld );
#endif /* DEBUG_205 */
candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
retcode = META_SEARCH_NEED_BIND;
-
} else {
/* we'll need to bind the target for this conn */
#ifdef DEBUG_205
- char buf[ SLAP_TEXT_BUFLEN ];
- Debug(LDAP_DEBUG_ANY,
- "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p binding\n",
- op->o_log_prefix, candidate, (void *)mc,
- (void *)msc->msc_ld );
+ Debug( LDAP_DEBUG_ANY,
+ "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p binding\n",
+ op->o_log_prefix, candidate, (void *)mc,
+ (void *)msc->msc_ld );
#endif /* DEBUG_205 */
if ( msc->msc_ld == NULL ) {
* state, with eventual connection expiration or invalidation)
* it was not initialized as expected */
- Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p ld=NULL\n",
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p ld=NULL\n",
op->o_log_prefix, candidate, (void *)mc );
rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
- LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
+ LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
+
switch ( rc ) {
case LDAP_SUCCESS:
assert( msc->msc_ld != NULL );
/* NOTE: we copy things here, even if bind didn't succeed yet,
* because the connection is not shared until bind is over */
if ( !BER_BVISNULL( &binddn ) ) {
- ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex);
-
ber_bvreplace( &msc->msc_bound_ndn, &binddn );
if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
if ( !BER_BVISNULL( &msc->msc_cred ) ) {
}
ber_bvreplace( &msc->msc_cred, &cred );
}
- ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
}
if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
/* apparently, idassert was configured with SASL bind,
if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
/* bind anonymously? */
- Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: "
"non-empty dn with empty cred; binding anonymously\n",
op->o_log_prefix, candidate, (void *)mc );
cred = slap_empty_bv;
} else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
/* error */
- Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: "
"empty dn with non-empty cred: error\n",
op->o_log_prefix, candidate, (void *)mc );
rc = LDAP_OTHER;
goto other;
}
retry_bind:
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind msc: %p\n",
+ time_buf, msc );
+ }
rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
NULL, NULL, &msgid );
ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc );
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init rc=%d msc: %p\n",
+ time_buf, rc, msc );
+ }
if (rc == LDAP_SERVER_DOWN ) {
goto down;
+ } else if (rc == LDAP_BUSY) {
+ if (rs->sr_text == NULL) {
+ rs->sr_text = "Unable to establish LDAP connection to target within the specified network timeout.";
+ }
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ goto other;
}
- candidates[ candidate ].sr_msgid = msgid;
+ /* mark as need bind so it gets send when the bind response is received */
+ candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
asyncmeta_set_msc_time(msc);
#ifdef DEBUG_205
- Debug(LDAP_DEBUG_ANY,
- "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p rc=%d\n",
- op->o_log_prefix, candidate, (void *)mc,
- (void *)mc->mc_conns[candidate].msc_ld, rc );
+ Debug( LDAP_DEBUG_ANY,
+ "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p rc=%d\n",
+ op->o_log_prefix, candidate, (void *)mc,
+ (void *)mc->mc_conns[candidate].msc_ld, rc );
#endif /* DEBUG_205 */
switch ( rc ) {
case LDAP_SUCCESS:
assert( msgid >= 0 );
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind success msc: %p\n",
+ time_buf, msc );
+ }
META_BINDING_SET( &candidates[ candidate ] );
rs->sr_err = LDAP_SUCCESS;
+ msc->msc_binding_time = slap_get_time();
return META_SEARCH_BINDING;
case LDAP_X_CONNECTING:
down:;
retcode = META_SEARCH_ERR;
rs->sr_err = LDAP_UNAVAILABLE;
+ if (rs->sr_text == NULL) {
+ rs->sr_text = "Unable to bind to remote target - target down or unavailable";
+ }
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
break;
/* fall thru */
retcode = META_SEARCH_NOT_CANDIDATE;
}
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
break;
}
asyncmeta_dobind_init_with_retry(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
{
- int rc, retries = 1;
+ int rc;
a_metasingleconn_t *msc = &mc->mc_conns[candidate];
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
- SlapReply *candidates = bc->candidates;
+
+ if (META_BACK_CONN_INVALID(msc) || (LDAP_BACK_CONN_BINDING( msc ) && msc->msc_binding_time > 0
+ && (msc->msc_binding_time + mt->mt_timeout[ SLAP_OP_BIND ]) < slap_get_time())) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ );
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, buf);
+
+ rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
+ LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ }
+
+ if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
+ return META_SEARCH_CANDIDATE;
+ }
retry_dobind:
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rs->sr_err != LDAP_UNAVAILABLE) {
+ if (rs->sr_err != LDAP_UNAVAILABLE && rs->sr_err != LDAP_BUSY) {
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return rc;
- } else if (retries <= 0) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- if (mc->mc_active < 1) {
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- }
+ } else if (bc->nretries[candidate] == 0) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ );
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, buf);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return rc;
}
/* need to retry */
- retries--;
- if ( LogTest( LDAP_DEBUG_ANY ) ) {
+ bc->nretries[candidate]--;
+ if ( LogTest( LDAP_DEBUG_TRACE ) ) {
/* this lock is required; however,
* it's invoked only when logging is on */
ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
- Debug(LDAP_DEBUG_ANY,
- "%s asyncmeta_search_dobind_init_with_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n",
- op->o_log_prefix, candidate, mt->mt_uri,
- BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val );
+ Debug( LDAP_DEBUG_ANY,
+ "%s asyncmeta_dobind_init_with_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n",
+ op->o_log_prefix, candidate, mt->mt_uri,
+ BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val );
ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
}
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- if (mc->mc_active < 1) {
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- }
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
-
- ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
-
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
if (rs->sr_err != LDAP_SUCCESS) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- if (mc->mc_active < 1) {
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- }
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return META_SEARCH_ERR;
}
-
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
goto retry_dobind;
return rc;
}
if ( candidate == META_TARGET_NONE ) {
candidate = i;
- } else {
- return META_TARGET_MULTIPLE;
}
}
}
return 0;
}
-
-int
-asyncmeta_clear_one_msc(
- Operation *op,
- a_metaconn_t *mc,
- int candidate )
-{
- a_metasingleconn_t *msc;
- if (mc == NULL) {
- return 0;
- }
- msc = &mc->mc_conns[candidate];
- if (msc->conn) {
- connection_client_stop( msc->conn );
- msc->conn = NULL;
- }
- if ( msc->msc_ld != NULL ) {
-
-#ifdef DEBUG_205
- Debug(LDAP_DEBUG_ANY,
- "### %s asyncmeta_clear_one_msc ldap_unbind_ext[%d] ld=%p\n",
- op ? op->o_log_prefix : "", candidate,
- (void *)msc->msc_ld );
-#endif /* DEBUG_205 */
-
- ldap_unbind_ext( msc->msc_ld, NULL, NULL );
- msc->msc_ld = NULL;
- ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
- msc->msc_ldr = NULL;
- }
-
- if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
- ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
- BER_BVZERO( &msc->msc_bound_ndn );
- }
-
- if ( !BER_BVISNULL( &msc->msc_cred ) ) {
- memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
- ber_memfree_x( msc->msc_cred.bv_val, NULL );
- BER_BVZERO( &msc->msc_cred );
- }
- msc->msc_time = 0;
- msc->msc_mscflags = 0;
- msc->msc_timeout_ops = 0;
- msc->msc_pending_ops = 0;
- return 0;
-}
#include <ac/string.h>
#include <ac/socket.h>
-
#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op,
- SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate)
+ SlapReply *rs,
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ int do_lock)
{
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
+ struct berval c_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mdn = BER_BVNULL;
- struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mapped_value = op->orc_ava->aa_value;
- int rc = 0, nretries = 1;
+ int rc = 0;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "compareDN";
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
- switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- case LDAP_UNWILLING_TO_PERFORM:
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- retcode = META_SEARCH_ERR;
- goto doreturn;
- default:
- break;
- }
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
- /*
- * if attr is objectClass, try to remap the value
- */
- if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
- asyncmeta_map( &mt->mt_rwmap.rwm_oc,
- &op->orc_ava->aa_value,
- &mapped_value, BACKLDAP_MAP );
-
- if ( BER_BVISNULL( &mapped_value ) || BER_BVISEMPTY( &mapped_value ) ) {
- rs->sr_err = LDAP_OTHER;
- retcode = META_SEARCH_ERR;
- goto done;
- }
-
- /*
- * else try to remap the attribute
- */
- } else {
- asyncmeta_map( &mt->mt_rwmap.rwm_at,
- &op->orc_ava->aa_desc->ad_cname,
- &mapped_attr, BACKLDAP_MAP );
- if ( BER_BVISNULL( &mapped_attr ) || BER_BVISEMPTY( &mapped_attr ) ) {
- rs->sr_err = LDAP_OTHER;
- retcode = META_SEARCH_ERR;
- goto done;
- }
+ if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value );
- if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
- {
- dc.ctx = "compareAttrDN";
-
- switch ( asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
- {
- case LDAP_UNWILLING_TO_PERFORM:
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- retcode = META_SEARCH_ERR;
- goto done;
-
- default:
- break;
- }
- }
- }
-retry:;
+ asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root,&ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
+ /* someone might have reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
- ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, mapped_attr.bv_val, &mapped_value,
+ ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, c_attr.bv_val, &mapped_value,
ctrls, NULL, &msgid);
+
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_compare_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE,
- mdn.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE,
+ mdn.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
-
+ /* fall though*/
default:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- retcode = META_SEARCH_ERR;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
}
}
+
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ retcode = META_SEARCH_NEED_BIND;
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send compare request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ break;
+ }
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
+ if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
+ op->o_tmpfree( mapped_value.bv_val, op->o_tmpmemctx );
}
- if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
- free( mapped_value.bv_val );
+ if ( mdn.bv_val != op->o_req_dn.bv_val ) {
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
-doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_compare_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
- OperationBuffer opbuf;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
SlapReply *candidates;
- slap_callback *cb = op->o_callback;
+ time_t current_time = slap_get_time();
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_compare: %s\n",
op->o_req_dn.bv_val );
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ if (current_time > op->o_time) {
+ Debug( asyncmeta_debug, "==> asyncmeta_back_compare[%s]: o_time:[%ld], current time: [%ld]\n",
+ op->o_log_prefix, op->o_time, current_time );
+ }
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
+
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ goto finish;
+ }
+
+retry:
+ if (bc->timeout && bc->stoptime < slap_get_time()) {
+ int timeout_err;
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ rs->sr_err = timeout_err;
+ rs->sr_text = "Operation timed out before it was sent to target";
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
}
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
- rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate);
+ rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate, 1);
if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
- break;
+ break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- }
- break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: BINDING "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
+ "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR "
- "cnd=\"%ldd\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
default:
assert( 0 );
break;
}
+
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
finish:
return rs->sr_err;
-
}
static ConfigLDAPadd asyncmeta_ldadd;
static ConfigCfAdd asyncmeta_cfadd;
-static int asyncmeta_map_config(
- ConfigArgs *c,
- struct ldapmap *oc_map,
- struct ldapmap *at_map );
-
/* Three sets of enums:
* 1) attrs that are only valid in the base config
* 2) attrs that are valid in base or target
LDAP_BACK_CFG_ACL_PASSWD,
LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
LDAP_BACK_CFG_IDASSERT_BIND,
- LDAP_BACK_CFG_REWRITE,
LDAP_BACK_CFG_SUFFIXM,
- LDAP_BACK_CFG_MAP,
LDAP_BACK_CFG_SUBTREE_EX,
LDAP_BACK_CFG_SUBTREE_IN,
LDAP_BACK_CFG_KEEPALIVE,
asyncmeta_back_cf_gen, "( OLcfgDbAt:0.14 "
"NAME 'olcDbURI' "
"DESC 'URI (list) for remote DSA' "
- "EQUALITY caseExactMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.1 "
"NAME 'olcDbStartTLS' "
"DESC 'StartTLS' "
- "EQUALITY caseExactMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.2 "
"NAME 'olcDbACLAuthcDn' "
"DESC 'Remote ACL administrative identity' "
- "EQUALITY distinguishedNameMatch "
"OBSOLETE "
"SYNTAX OMsDN "
"SINGLE-VALUE )",
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.7 "
"NAME 'olcDbIDAssertBind' "
"DESC 'Remote Identity Assertion administrative identity auth bind configuration' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.10 "
"NAME 'olcDbRebindAsUser' "
"DESC 'Rebind as user' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.11 "
"NAME 'olcDbChaseReferrals' "
"DESC 'Chase referrals' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.12 "
"NAME 'olcDbTFSupport' "
"DESC 'Absolute filters support' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.14 "
"NAME 'olcDbTimeout' "
"DESC 'Per-operation timeouts' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.15 "
"NAME 'olcDbIdleTimeout' "
"DESC 'connection idle timeout' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.17 "
"NAME 'olcDbNetworkTimeout' "
"DESC 'connection network timeout' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.18 "
"NAME 'olcDbProtocolVersion' "
"DESC 'protocol version' "
- "EQUALITY integerMatch "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.20 "
"NAME 'olcDbCancel' "
"DESC 'abandon/ignore/exop operations when appropriate' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.21 "
"NAME 'olcDbQuarantine' "
- "EQUALITY caseIgnoreMatch "
"DESC 'Quarantine database if connection fails and retry according to rule' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.23 "
"NAME 'olcDbConnectionPoolMax' "
"DESC 'Max size of privileged connections pool' "
- "EQUALITY integerMatch "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.24 "
"NAME 'olcDbSessionTrackingRequest' "
"DESC 'Add session tracking control to proxied requests' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.25 "
"NAME 'olcDbNoRefs' "
"DESC 'Do not return search reference responses' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.26 "
"NAME 'olcDbNoUndefFilter' "
"DESC 'Do not propagate undefined search filters' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
- { "rewrite", "arglist", 2, 0, STRLENOF( "rewrite" ),
- ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
- asyncmeta_back_cf_gen, "( OLcfgDbAt:3.101 "
- "NAME 'olcDbRewrite' "
- "DESC 'DN rewriting rules' "
- "EQUALITY caseIgnoreMatch "
- "SYNTAX OMsDirectoryString "
- "X-ORDERED 'VALUES' )",
- NULL, NULL },
- { "suffixmassage", "virtual> <real", 2, 3, 0,
+ { "suffixmassage", "local> <remote", 2, 3, 0,
ARG_MAGIC|LDAP_BACK_CFG_SUFFIXM,
- asyncmeta_back_cf_gen, NULL, NULL, NULL },
-
- { "map", "attribute|objectClass> [*|<local>] *|<remote", 3, 4, 0,
- ARG_MAGIC|LDAP_BACK_CFG_MAP,
- asyncmeta_back_cf_gen, "( OLcfgDbAt:3.102 "
- "NAME 'olcDbMap' "
- "DESC 'Map attribute and objectclass names' "
+ asyncmeta_back_cf_gen, "( OLcfgDbAt:3.117 "
+ "NAME 'olcDbSuffixMassage' "
+ "DESC 'DN suffix massage' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
- "X-ORDERED 'VALUES' )",
+ "SINGLE-VALUE )",
NULL, NULL },
{ "subtree-exclude", "pattern", 2, 2, 0,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.105 "
"NAME 'olcDbDefaultTarget' "
"DESC 'Specify the default target' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.106 "
"NAME 'olcDbDnCacheTtl' "
"DESC 'dncache ttl' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.107 "
"NAME 'olcDbBindTimeout' "
"DESC 'bind timeout' "
- "EQUALITY integerMatch "
- "SYNTAX OMsInteger "
+ "SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "onerr", "CONTINUE|report|stop", 2, 2, 0,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.108 "
"NAME 'olcDbOnErr' "
"DESC 'error handling' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.109 "
"NAME 'olcDbPseudoRootBindDefer' "
"DESC 'error handling' "
- "EQUALITY booleanMatch "
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.110 "
"NAME 'olcDbNretries' "
"DESC 'retry handling' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
ARG_MAGIC|LDAP_BACK_CFG_CLIENT_PR,
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.111 "
"NAME 'olcDbClientPr' "
- "EQUALITY caseIgnoreMatch "
"DESC 'PagedResults handling' "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.29 "
"NAME 'olcDbKeepalive' "
"DESC 'TCP keepalive' "
- "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.113 "
"NAME 'olcDbMaxPendingOps' "
"DESC 'Maximum number of pending operations' "
- "EQUALITY integerMatch "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.114 "
"NAME 'olcDbMaxTargetConns' "
"DESC 'Maximum number of open connections per target' "
- "EQUALITY integerMatch "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
asyncmeta_back_cf_gen, "( OLcfgDbAt:3.115 "
"NAME 'olcDbMaxTimeoutOps' "
"DESC 'Maximum number of consecutive timeout operations after which the connection is reset' "
- "EQUALITY integerMatch "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
"NAME 'olcAsyncMetaConfig' "
"DESC 'Asyncmeta backend configuration' "
"SUP olcDatabaseConfig "
- "MAY ( olcDbConnTtl "
- "$ olcDbDnCacheTtl "
+ "MAY ( olcDbDnCacheTtl "
"$ olcDbIdleTimeout "
"$ olcDbOnErr "
"$ olcDbPseudoRootBindDefer "
- "$ olcDbSingleConn "
- "$ olcDbUseTemporaryConn "
"$ olcDbConnectionPoolMax "
"$ olcDbMaxTimeoutOps"
"$ olcDbMaxPendingOps "
"$ olcDbACLPasswd "
"$ olcDbIDAssertAuthzFrom "
"$ olcDbIDAssertBind "
- "$ olcDbMap "
- "$ olcDbRewrite "
+ "$ olcDbSuffixMassage "
"$ olcDbSubtreeExclude "
"$ olcDbSubtreeInclude "
"$ olcDbTimeout "
return LDAP_SUCCESS;
}
-static int
-asyncmeta_rwi_init( struct rewrite_info **rwm_rw )
-{
- char *rargv[ 3 ];
-
- *rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
- if ( *rwm_rw == NULL ) {
- return -1;
- }
- /*
- * the filter rewrite as a string must be disabled
- * by default; it can be re-enabled by adding rules;
- * this creates an empty rewriteContext
- */
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "searchFilter";
- rargv[ 2 ] = NULL;
- rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "default";
- rargv[ 2 ] = NULL;
- rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
-
- return 0;
-}
-
static int
asyncmeta_back_new_target(
a_metatarget_t **mtp )
mt = ch_calloc( sizeof( a_metatarget_t ), 1 );
- if ( asyncmeta_rwi_init( &mt->mt_rwmap.rwm_rw )) {
- ch_free( mt );
- return -1;
- }
-
ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
return 0;
}
-/* Validation for suffixmassage_config */
+/* suffixmassage config */
static int
asyncmeta_suffixm_config(
ConfigArgs *c,
{
BackendDB *tmp_bd;
struct berval dn, nvnc, pvnc, nrnc, prnc;
- int j, rc;
+ int j;
/*
* syntax:
*
- * suffixmassage <suffix> <massaged suffix>
+ * suffixmassage <local suffix> <remote suffix>
*
- * the <suffix> field must be defined as a valid suffix
+ * the <local suffix> field must be defined as a valid suffix
* (or suffixAlias?) for the current database;
- * the <massaged suffix> shouldn't have already been
+ * the <remote suffix> shouldn't have already been
* defined as a valid suffix or suffixAlias for the
* current server
*/
c->log, prnc.bv_val );
}
- /*
- * The suffix massaging is emulated by means of the
- * rewrite capabilities
- */
- rc = asyncmeta_suffix_massage_config( mt->mt_rwmap.rwm_rw,
- &pvnc, &nvnc, &prnc, &nrnc );
+ mt->mt_lsuffixm = pvnc;
+ mt->mt_rsuffixm = prnc;
- free( pvnc.bv_val );
free( nvnc.bv_val );
- free( prnc.bv_val );
free( nrnc.bv_val );
- return rc;
-}
-
-static int
-slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
-{
- int i;
- BerVarray bva = NULL;
- char ibuf[32], *ptr;
- struct berval idx;
-
- assert( in != NULL );
-
- for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
- /* count'em */ ;
-
- if ( i == 0 ) {
- return 1;
- }
-
- idx.bv_val = ibuf;
-
- bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
- BER_BVZERO( &bva[ 0 ] );
-
- for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
- idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
- if ( idx.bv_len >= sizeof( ibuf ) ) {
- ber_bvarray_free( bva );
- return 1;
- }
-
- bva[i].bv_len = idx.bv_len + in[i].bv_len;
- bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
- ptr = lutil_strcopy( bva[i].bv_val, ibuf );
- ptr = lutil_strcopy( ptr, in[i].bv_val );
- *ptr = '\0';
- BER_BVZERO( &bva[ i + 1 ] );
- }
-
- *out = bva;
return 0;
}
asyncmeta_back_cf_gen( ConfigArgs *c )
{
a_metainfo_t *mi = ( a_metainfo_t * )c->be->be_private;
- a_metatarget_t *mt;
- a_metacommon_t *mc;
+ a_metatarget_t *mt = NULL;
+ a_metacommon_t *mc = NULL;
int i, rc = 0;
case LDAP_BACK_CFG_NETWORK_TIMEOUT:
if ( mc->mc_network_timeout == 0 ) {
return 1;
- } else {
- char buf[ SLAP_TEXT_BUFLEN ];
- lutil_unparse_time( buf, sizeof( buf ), mc->mc_network_timeout );
- ber_str2bv( buf, 0, 0, &bv );
- value_add_one( &c->rvalue_vals, &bv );
}
+ bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%ld",
+ mc->mc_network_timeout );
+ bv.bv_val = c->cr_msg;
+ value_add_one( &c->rvalue_vals, &bv );
break;
case LDAP_BACK_CFG_NOREFS:
break;
}
- case LDAP_BACK_CFG_SUFFIXM: /* unused */
- case LDAP_BACK_CFG_REWRITE:
- if ( mt->mt_rwmap.rwm_bva_rewrite == NULL ) {
- rc = 1;
- } else {
- rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_rewrite, &c->rvalue_vals );
- }
- break;
-
- case LDAP_BACK_CFG_MAP:
- if ( mt->mt_rwmap.rwm_bva_map == NULL ) {
+ case LDAP_BACK_CFG_SUFFIXM:
+ if ( mt->mt_lsuffixm.bv_val ) {
+ struct berval bv;
+ char *ptr;
+ bv.bv_len = mt->mt_lsuffixm.bv_len + 2 + 1 + mt->mt_rsuffixm.bv_len + 2;
+ bv.bv_val = ch_malloc( bv.bv_len + 1 );
+ ptr = bv.bv_val;
+ *ptr++ = '"';
+ ptr = lutil_strcopy(ptr, mt->mt_lsuffixm.bv_val);
+ ptr = lutil_strcopy(ptr, "\" \"");
+ ptr = lutil_strcopy(ptr, mt->mt_rsuffixm.bv_val);
+ *ptr++ = '"';
+ *ptr = '\0';
+ ber_bvarray_add( &c->rvalue_vals, &bv );
+ rc = 0;
+ } else
rc = 1;
- } else {
- rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_map, &c->rvalue_vals );
- }
break;
case LDAP_BACK_CFG_SUBTREE_EX:
memset( &mt->mt_idassert, 0, sizeof( slap_idassert_t ) );
break;
- case LDAP_BACK_CFG_SUFFIXM: /* unused */
- case LDAP_BACK_CFG_REWRITE:
- if ( mt->mt_rwmap.rwm_bva_rewrite ) {
- ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
- mt->mt_rwmap.rwm_bva_rewrite = NULL;
- }
- if ( mt->mt_rwmap.rwm_rw )
- rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
- break;
-
- case LDAP_BACK_CFG_MAP:
- if ( mt->mt_rwmap.rwm_bva_map ) {
- ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
- mt->mt_rwmap.rwm_bva_map = NULL;
+ case LDAP_BACK_CFG_SUFFIXM:
+ if ( mt->mt_lsuffixm.bv_val ) {
+ ch_free( mt->mt_lsuffixm.bv_val );
+ ch_free( mt->mt_rsuffixm.bv_val );
+ BER_BVZERO( &mt->mt_lsuffixm );
+ BER_BVZERO( &mt->mt_rsuffixm );
}
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc );
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at );
- mt->mt_rwmap.rwm_oc.drop_missing = 0;
- mt->mt_rwmap.rwm_at.drop_missing = 0;
break;
case LDAP_BACK_CFG_SUBTREE_EX:
break;
case LDAP_BACK_CFG_MAX_TARGET_CONNS:
{
- int msc_num, i;
if (c->value_int < 0) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"max-target-conns invalid value %d",
if ( strcasecmp( c->argv[ 0 ], "binddn" ) == 0 ) {
Debug( LDAP_DEBUG_ANY, "%s: "
"\"binddn\" statement is deprecated; "
- "use \"acl-authcDN\" instead\n",
- c->log );
+ "use \"acl-authcDN\" instead\n", c->log );
/* FIXME: some day we'll need to throw an error */
}
if ( strcasecmp( c->argv[ 0 ], "bindpw" ) == 0 ) {
Debug( LDAP_DEBUG_ANY, "%s "
"\"bindpw\" statement is deprecated; "
- "use \"acl-passwd\" instead\n",
- c->log );
+ "use \"acl-passwd\" instead\n", c->log );
/* FIXME: some day we'll need to throw an error */
}
break;
#endif /* SLAP_CONTROL_X_SESSION_TRACKING */
- case LDAP_BACK_CFG_SUFFIXM: /* FALLTHRU */
- case LDAP_BACK_CFG_REWRITE: {
- /* rewrite stuff ... */
- ConfigArgs ca = { 0 };
- char *line, **argv;
- struct rewrite_info *rwi;
- int cnt = 0, argc, ix = c->valx;
-
- if ( mt->mt_rwmap.rwm_bva_rewrite ) {
- for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_rewrite[ cnt ] ); cnt++ )
- /* count */ ;
- }
-
- if ( ix >= cnt || ix < 0 ) {
- ix = cnt;
- } else {
- rwi = mt->mt_rwmap.rwm_rw;
-
- mt->mt_rwmap.rwm_rw = NULL;
- rc = asyncmeta_rwi_init( &mt->mt_rwmap.rwm_rw );
-
- /* re-parse all rewrite rules, up to the one
- * that needs to be added */
- ca.be = c->be;
- ca.fname = c->fname;
- ca.lineno = c->lineno;
- for ( i = 0; i < ix; i++ ) {
- ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
- ca.argc = 0;
- config_fp_parse_line( &ca );
-
- if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
- rc = asyncmeta_suffixm_config( &ca, ca.argc, ca.argv, mt );
- } else {
- rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
- c->fname, c->lineno, ca.argc, ca.argv );
- }
- assert( rc == 0 );
- ch_free( ca.argv );
- ch_free( ca.tline );
- }
- }
- argc = c->argc;
- argv = c->argv;
- if ( c->op != SLAP_CONFIG_ADD ) {
- argc--;
- argv++;
- }
- /* add the new rule */
- if ( !strcasecmp( argv[0], "suffixmassage" )) {
- rc = asyncmeta_suffixm_config( c, argc, argv, mt );
- } else {
- rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
- c->fname, c->lineno, argc, argv );
- }
- if ( rc ) {
- if ( ix < cnt ) {
- rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
- mt->mt_rwmap.rwm_rw = rwi;
- }
- return 1;
- }
- if ( ix < cnt ) {
- for ( ; i < cnt; i++ ) {
- ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
- ca.argc = 0;
- config_fp_parse_line( &ca );
-
- if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
- rc = asyncmeta_suffixm_config( &ca, ca.argc, ca.argv, mt );
- } else {
- rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
- c->fname, c->lineno, ca.argc, argv );
- }
- assert( rc == 0 );
- ch_free( ca.argv );
- ch_free( ca.tline );
- }
- }
-
- /* save the rule info */
- line = ldap_charray2str( argv, "\" \"" );
- if ( line != NULL ) {
- struct berval bv;
- int len = strlen( argv[ 0 ] );
-
- ber_str2bv( line, 0, 0, &bv );
- AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
- bv.bv_len - ( len + 1 ));
- bv.bv_val[ bv.bv_len - 1] = '"';
- ber_bvarray_add( &mt->mt_rwmap.rwm_bva_rewrite, &bv );
- /* move it to the right slot */
- if ( ix < cnt ) {
- for ( i=cnt; i>ix; i-- )
- mt->mt_rwmap.rwm_bva_rewrite[i+1] = mt->mt_rwmap.rwm_bva_rewrite[i];
- mt->mt_rwmap.rwm_bva_rewrite[i] = bv;
-
- /* destroy old rules */
- rewrite_info_delete( &rwi );
- }
- }
- } break;
-
- case LDAP_BACK_CFG_MAP: {
- /* objectclass/attribute mapping */
- ConfigArgs ca = { 0 };
- char *argv[5];
- struct ldapmap rwm_oc;
- struct ldapmap rwm_at;
- int cnt = 0, ix = c->valx;
-
- if ( mt->mt_rwmap.rwm_bva_map ) {
- for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_map[ cnt ] ); cnt++ )
- /* count */ ;
- }
-
- if ( ix >= cnt || ix < 0 ) {
- ix = cnt;
- } else {
- rwm_oc = mt->mt_rwmap.rwm_oc;
- rwm_at = mt->mt_rwmap.rwm_at;
-
- memset( &mt->mt_rwmap.rwm_oc, 0, sizeof( mt->mt_rwmap.rwm_oc ) );
- memset( &mt->mt_rwmap.rwm_at, 0, sizeof( mt->mt_rwmap.rwm_at ) );
-
- /* re-parse all mappings, up to the one
- * that needs to be added */
- argv[0] = c->argv[0];
- ca.fname = c->fname;
- ca.lineno = c->lineno;
- for ( i = 0; i < ix; i++ ) {
- ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
- ca.argc = 0;
- config_fp_parse_line( &ca );
-
- argv[1] = ca.argv[0];
- argv[2] = ca.argv[1];
- argv[3] = ca.argv[2];
- argv[4] = ca.argv[3];
- ch_free( ca.argv );
- ca.argv = argv;
- ca.argc++;
- rc = asyncmeta_map_config( &ca, &mt->mt_rwmap.rwm_oc,
- &mt->mt_rwmap.rwm_at );
-
- ch_free( ca.tline );
- ca.tline = NULL;
- ca.argv = NULL;
-
- /* in case of failure, restore
- * the existing mapping */
- if ( rc ) {
- goto map_fail;
- }
- }
- }
- /* add the new mapping */
- rc = asyncmeta_map_config( c, &mt->mt_rwmap.rwm_oc,
- &mt->mt_rwmap.rwm_at );
- if ( rc ) {
- goto map_fail;
- }
-
- if ( ix < cnt ) {
- for ( ; i<cnt ; cnt++ ) {
- ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
- ca.argc = 0;
- config_fp_parse_line( &ca );
-
- argv[1] = ca.argv[0];
- argv[2] = ca.argv[1];
- argv[3] = ca.argv[2];
- argv[4] = ca.argv[3];
-
- ch_free( ca.argv );
- ca.argv = argv;
- ca.argc++;
- rc = asyncmeta_map_config( &ca, &mt->mt_rwmap.rwm_oc,
- &mt->mt_rwmap.rwm_at );
-
- ch_free( ca.tline );
- ca.tline = NULL;
- ca.argv = NULL;
-
- /* in case of failure, restore
- * the existing mapping */
- if ( rc ) {
- goto map_fail;
- }
- }
- }
-
- /* save the map info */
- argv[0] = ldap_charray2str( &c->argv[ 1 ], " " );
- if ( argv[0] != NULL ) {
- struct berval bv;
- ber_str2bv( argv[0], 0, 0, &bv );
- ber_bvarray_add( &mt->mt_rwmap.rwm_bva_map, &bv );
- /* move it to the right slot */
- if ( ix < cnt ) {
- for ( i=cnt; i>ix; i-- )
- mt->mt_rwmap.rwm_bva_map[i+1] = mt->mt_rwmap.rwm_bva_map[i];
- mt->mt_rwmap.rwm_bva_map[i] = bv;
-
- /* destroy old mapping */
- asyncmeta_back_map_free( &rwm_oc );
- asyncmeta_back_map_free( &rwm_at );
- }
- }
+ case LDAP_BACK_CFG_SUFFIXM:
+ rc = asyncmeta_suffixm_config( c, c->argc, c->argv, mt );
break;
-map_fail:;
- if ( ix < cnt ) {
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc );
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at );
- mt->mt_rwmap.rwm_oc = rwm_oc;
- mt->mt_rwmap.rwm_at = rwm_at;
- }
- } break;
-
case LDAP_BACK_CFG_NRETRIES: {
int nretries = META_RETRY_UNDEFINED;
if ( rc ) {
Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
"warning, unable to get \"olcDbACLPasswd\" "
- "attribute description: %d: %s\n",
- rc, text );
+ "attribute description: %d: %s\n", rc, text );
} else {
(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
ad->ad_type->sat_oid );
if ( rc ) {
Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
"warning, unable to get \"olcDbIDAssertPasswd\" "
- "attribute description: %d: %s\n",
- rc, text );
+ "attribute description: %d: %s\n", rc, text );
} else {
(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
ad->ad_type->sat_oid );
return 0;
}
-
-static int
-asyncmeta_map_config(
- ConfigArgs *c,
- struct ldapmap *oc_map,
- struct ldapmap *at_map )
-{
- struct ldapmap *map;
- struct ldapmapping *mapping;
- char *src, *dst;
- int is_oc = 0;
-
- if ( strcasecmp( c->argv[ 1 ], "objectclass" ) == 0 ) {
- map = oc_map;
- is_oc = 1;
-
- } else if ( strcasecmp( c->argv[ 1 ], "attribute" ) == 0 ) {
- map = at_map;
-
- } else {
- snprintf( c->cr_msg, sizeof(c->cr_msg),
- "%s unknown argument \"%s\"",
- c->argv[0], c->argv[1] );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- return 1;
- }
-
- if ( !is_oc && map->map == NULL ) {
- /* only init if required */
- asyncmeta_map_init( map, &mapping );
- }
-
- if ( strcmp( c->argv[ 2 ], "*" ) == 0 ) {
- if ( c->argc < 4 || strcmp( c->argv[ 3 ], "*" ) == 0 ) {
- map->drop_missing = ( c->argc < 4 );
- goto success_return;
- }
- src = dst = c->argv[ 3 ];
-
- } else if ( c->argc < 4 ) {
- src = "";
- dst = c->argv[ 2 ];
-
- } else {
- src = c->argv[ 2 ];
- dst = ( strcmp( c->argv[ 3 ], "*" ) == 0 ? src : c->argv[ 3 ] );
- }
-
- if ( ( map == at_map )
- && ( strcasecmp( src, "objectclass" ) == 0
- || strcasecmp( dst, "objectclass" ) == 0 ) )
- {
- snprintf( c->cr_msg, sizeof(c->cr_msg),
- "objectclass attribute cannot be mapped" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- return 1;
- }
-
- mapping = (struct ldapmapping *)ch_calloc( 2,
- sizeof(struct ldapmapping) );
- if ( mapping == NULL ) {
- snprintf( c->cr_msg, sizeof(c->cr_msg),
- "out of memory" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- return 1;
- }
- ber_str2bv( src, 0, 1, &mapping[ 0 ].src );
- ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst );
- mapping[ 1 ].src = mapping[ 0 ].dst;
- mapping[ 1 ].dst = mapping[ 0 ].src;
-
- /*
- * schema check
- */
- if ( is_oc ) {
- if ( src[ 0 ] != '\0' ) {
- if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: warning, source objectClass '%s' should be defined in schema\n",
- c->log, src );
-
- /*
- * FIXME: this should become an err
- */
- goto error_return;
- }
- }
-
- if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: warning, destination objectClass '%s' is not defined in schema\n",
- c->log, dst );
- }
- } else {
- int rc;
- const char *text = NULL;
- AttributeDescription *ad = NULL;
-
- if ( src[ 0 ] != '\0' ) {
- rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text );
- if ( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: warning, source attributeType '%s' should be defined in schema\n",
- c->log, src );
-
- /*
- * FIXME: this should become an err
- */
- /*
- * we create a fake "proxied" ad
- * and add it here.
- */
-
- rc = slap_bv2undef_ad( &mapping[ 0 ].src,
- &ad, &text, SLAP_AD_PROXIED );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "source attributeType \"%s\": %d (%s)",
- src, rc, text ? text : "" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto error_return;
- }
- }
-
- ad = NULL;
- }
-
- rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text );
- if ( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: warning, destination attributeType '%s' is not defined in schema\n",
- c->log, dst );
-
- /*
- * we create a fake "proxied" ad
- * and add it here.
- */
-
- rc = slap_bv2undef_ad( &mapping[ 0 ].dst,
- &ad, &text, SLAP_AD_PROXIED );
- if ( rc != LDAP_SUCCESS ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "destination attributeType \"%s\": %d (%s)\n",
- dst, rc, text ? text : "" );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- return 1;
- }
- }
- }
-
- if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], asyncmeta_mapping_cmp ) != NULL)
- || avl_find( map->remap, (caddr_t)&mapping[ 1 ], asyncmeta_mapping_cmp ) != NULL)
- {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "duplicate mapping found." );
- Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
- goto error_return;
- }
-
- if ( src[ 0 ] != '\0' ) {
- avl_insert( &map->map, (caddr_t)&mapping[ 0 ],
- asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
- }
- avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
- asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
-
-success_return:;
- return 0;
-
-error_return:;
- if ( mapping ) {
- ch_free( mapping[ 0 ].src.bv_val );
- ch_free( mapping[ 0 ].dst.bv_val );
- ch_free( mapping );
- }
-
- return 1;
-}
-
-
-static char *
-suffix_massage_regexize( const char *s )
-{
- char *res, *ptr;
- const char *p, *r;
- int i;
-
- if ( s[ 0 ] == '\0' ) {
- return ch_strdup( "^(.+)$" );
- }
-
- for ( i = 0, p = s;
- ( r = strchr( p, ',' ) ) != NULL;
- p = r + 1, i++ )
- ;
-
- res = ch_calloc( sizeof( char ),
- strlen( s )
- + STRLENOF( "((.+),)?" )
- + STRLENOF( "[ ]?" ) * i
- + STRLENOF( "$" ) + 1 );
-
- ptr = lutil_strcopy( res, "((.+),)?" );
- for ( i = 0, p = s;
- ( r = strchr( p, ',' ) ) != NULL;
- p = r + 1 , i++ ) {
- ptr = lutil_strncopy( ptr, p, r - p + 1 );
- ptr = lutil_strcopy( ptr, "[ ]?" );
-
- if ( r[ 1 ] == ' ' ) {
- r++;
- }
- }
- ptr = lutil_strcopy( ptr, p );
- ptr[ 0 ] = '$';
- ptr++;
- ptr[ 0 ] = '\0';
-
- return res;
-}
-
-static char *
-suffix_massage_patternize( const char *s, const char *p )
-{
- ber_len_t len;
- char *res, *ptr;
-
- len = strlen( p );
-
- if ( s[ 0 ] == '\0' ) {
- len++;
- }
-
- res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
- if ( res == NULL ) {
- return NULL;
- }
-
- ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
- if ( s[ 0 ] == '\0' ) {
- ptr[ 0 ] = ',';
- ptr++;
- }
- lutil_strcopy( ptr, p );
-
- return res;
-}
-
-int
-asyncmeta_suffix_massage_config(
- struct rewrite_info *info,
- struct berval *pvnc,
- struct berval *nvnc,
- struct berval *prnc,
- struct berval *nrnc
-)
-{
- char *rargv[ 5 ];
- int line = 0;
-
- rargv[ 0 ] = "rewriteEngine";
- rargv[ 1 ] = "on";
- rargv[ 2 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "default";
- rargv[ 2 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
-
- rargv[ 0 ] = "rewriteRule";
- rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
- rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
- rargv[ 3 ] = ":";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
- ch_free( rargv[ 1 ] );
- ch_free( rargv[ 2 ] );
-
- if ( BER_BVISEMPTY( pvnc ) ) {
- rargv[ 0 ] = "rewriteRule";
- rargv[ 1 ] = "^$";
- rargv[ 2 ] = prnc->bv_val;
- rargv[ 3 ] = ":";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
- }
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "searchEntryDN";
- rargv[ 2 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
-
- rargv[ 0 ] = "rewriteRule";
- rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
- rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
- rargv[ 3 ] = ":";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
- ch_free( rargv[ 1 ] );
- ch_free( rargv[ 2 ] );
-
- if ( BER_BVISEMPTY( prnc ) ) {
- rargv[ 0 ] = "rewriteRule";
- rargv[ 1 ] = "^$";
- rargv[ 2 ] = pvnc->bv_val;
- rargv[ 3 ] = ":";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
- }
-
- /* backward compatibility */
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "searchResult";
- rargv[ 2 ] = "alias";
- rargv[ 3 ] = "searchEntryDN";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "matchedDN";
- rargv[ 2 ] = "alias";
- rargv[ 3 ] = "searchEntryDN";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "searchAttrDN";
- rargv[ 2 ] = "alias";
- rargv[ 3 ] = "searchEntryDN";
- rargv[ 4 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
-
- /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
- * see servers/slapd/overlays/rwm.h for details */
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "referralAttrDN";
- rargv[ 2 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
-
- rargv[ 0 ] = "rewriteContext";
- rargv[ 1 ] = "referralDN";
- rargv[ 2 ] = NULL;
- rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
-
- return 0;
-}
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
-
-
-#define AVL_INTERNAL
#include "slap.h"
+#include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
-
-/*
- * Debug stuff (got it from libavl)
- */
-#if META_BACK_PRINT_CONNTREE > 0
-
-static void
-asyncmeta_back_ravl_print( Avlnode *root, int depth )
-{
- int i;
-
- if ( root == 0 ) {
- return;
- }
-
- asyncmeta_back_ravl_print( root->avl_right, depth + 1 );
-
- for ( i = 0; i < depth; i++ ) {
- fprintf( stderr, "-" );
- }
- fputc( ' ', stderr );
-
- asyncmeta_back_print( (a_metaconn_t *)root->avl_data,
- avl_bf2str( root->avl_bf ) );
-
- asyncmeta_back_ravl_print( root->avl_left, depth + 1 );
-}
-
-/* NOTE: duplicate from back-ldap/bind.c */
-static char* priv2str[] = {
- "privileged",
- "privileged/TLS",
- "anonymous",
- "anonymous/TLS",
- "bind",
- "bind/TLS",
- NULL
-};
-
-#endif /* META_BACK_PRINT_CONNTREE */
-/*
- * End of debug stuff
- */
-
/*
* asyncmeta_conn_alloc
*
a_dncookie dc;
int isauthz = ( candidate == mc->mc_authz_target );
int do_return = 0;
- int nretries = 2;
-
#ifdef HAVE_TLS
int is_ldaps = 0;
int do_start_tls = 0;
if ( dont_retry ) {
rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Target is quarantined";
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: Target is quarantined\n",
+ op->o_log_prefix );
if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
- rs->sr_text = "Target is quarantined";
send_ldap_result( op, rs );
}
return rs->sr_err;
}
}
msc = &mc->mc_conns[candidate];
-retry_lock:;
/*
* Already init'ed
*/
} else if ( META_BACK_CONN_CREATING( msc )
|| LDAP_BACK_CONN_BINDING( msc ) )
{
- /* sounds more appropriate */
- if (nretries >= 0) {
- nretries--;
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
- rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_err = LDAP_SUCCESS;
do_return = 1;
} else if ( META_BACK_CONN_INITED( msc ) ) {
#endif /* HAVE_TLS */
ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
if ( rs->sr_err != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: ldap_initialize failed err=%d\n",
+ op->o_log_prefix, rs->sr_err );
goto error_return;
}
msc->msc_ldr = ldap_dup(msc->msc_ld);
default:
/* only touch when activity actually took place... */
- if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
- msc->msc_time = op->o_time;
+ if ( mi->mi_idle_timeout != 0 ) {
+ asyncmeta_set_msc_time(msc);
}
break;
}
res = NULL;
if ( rs->sr_err == LDAP_SUCCESS ) {
+
rs->sr_err = err;
}
rs->sr_err = slap_map_api2result( rs );
*/
rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
-
+ if (rs->sr_err != LDAP_SUCCESS) {
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: ldap_start_tls_s failed err=%d\n",
+ op->o_log_prefix, rs->sr_err );
+ }
/* if StartTLS is requested, only attempt it if the URL
* is not "ldaps://"; this may occur not only in case
* of misconfiguration, but also when used in the chain
}
}
#endif /* HAVE_TLS */
-
/*
* Set the network timeout if set
*/
if ( mt->mt_network_timeout != 0 ) {
- struct timeval network_timeout;
-
- network_timeout.tv_usec = 0;
- network_timeout.tv_sec = mt->mt_network_timeout;
+ struct timeval network_timeout;
+ network_timeout.tv_sec = 0;
+ network_timeout.tv_usec = mt->mt_network_timeout*1000;
ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,
- (void *)&network_timeout );
+ (void *)&network_timeout );
}
/*
BER_BVZERO( &msc->msc_bound_ndn );
}
if ( !BER_BVISEMPTY( &op->o_ndn )
- && SLAP_IS_AUTHZ_BACKEND( op )
&& isauthz )
{
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "bindDN";
+ dc.memctx = NULL;
+ dc.to_from = MASSAGE_REQ;
/*
* Rewrite the bind dn if needed
*/
- if ( asyncmeta_dn_massage( &dc, &op->o_conn->c_dn,
- &msc->msc_bound_ndn ) )
- {
-
-#ifdef DEBUG_205
- Debug( LDAP_DEBUG_ANY,
- "### %s asyncmeta_init_one_conn(rewrite) "
- "ldap_unbind_ext[%d] ld=%p\n",
- op->o_log_prefix, candidate,
- (void *)msc->msc_ld );
-#endif /* DEBUG_205 */
- goto error_return;
- }
+ asyncmeta_dn_massage( &dc, &op->o_conn->c_dn, &msc->msc_bound_ndn );
/* copy the DN if needed */
if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
}
-
- assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
-
} else {
ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );
}
META_BACK_CONN_CREATING_CLEAR( msc );
}
if ( rs->sr_err == LDAP_SUCCESS && msc != NULL) {
- /*
- * Sets a cookie for the rewrite session
- */
- ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
META_BACK_CONN_INITED_SET( msc );
}
return rs->sr_err;
}
-/*
- * asyncmeta_retry
- *
- * Retries one connection
- */
-int
-asyncmeta_retry(
- Operation *op,
- SlapReply *rs,
- a_metaconn_t **mcp,
- int candidate,
- ldap_back_send_t sendok )
-{
- a_metaconn_t *mc = *mcp;
- a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
- int rc = LDAP_UNAVAILABLE,
- binding,
- quarantine = 1;
-
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- struct berval save_cred;
-
- if ( LogTest( LDAP_DEBUG_ANY ) ) {
- /* this lock is required; however,
- * it's invoked only when logging is on */
- ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
- Debug(LDAP_DEBUG_ANY,
- "%s asyncmeta_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n",
- op->o_log_prefix, candidate, mt->mt_uri,
- BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val );
- ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
- }
-
- ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
- /* mc here must be the regular mc, reset and ready for init */
- rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
- LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 );
-
- if ( rc != LDAP_SUCCESS ) {
- if ( sendok & LDAP_BACK_SENDERR ) {
- /* init_one_conn has set the result */
- send_ldap_result( op, rs );
- }
- }
-
- if ( rc == LDAP_SUCCESS ) {
- quarantine = 0;
- LDAP_BACK_CONN_BINDING_SET( msc ); binding = 1;
- /* todo this must be dobind_init */
- rc = asyncmeta_back_single_dobind( op, rs, mcp, candidate,
- sendok, mt->mt_nretries, 0 );
-
- Debug( LDAP_DEBUG_ANY,
- "%s asyncmeta_retry[%d]: "
- "asyncmeta_single_dobind=%d\n",
- op->o_log_prefix, candidate, rc );
- if ( rc == LDAP_SUCCESS ) {
- if ( !BER_BVISNULL( &msc->msc_bound_ndn ) &&
- !BER_BVISEMPTY( &msc->msc_bound_ndn ) )
- {
- LDAP_BACK_CONN_ISBOUND_SET( msc );
-
- } else {
- LDAP_BACK_CONN_ISANON_SET( msc );
- }
-
- /* when bound, dispose of the "binding" flag */
- if ( binding ) {
- LDAP_BACK_CONN_BINDING_CLEAR( msc );
- }
- }
- }
-
-
- if ( rc != LDAP_SUCCESS ) {
- if (mc->mc_active < 1) {
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- }
- if ( sendok & LDAP_BACK_SENDERR ) {
- rs->sr_err = rc;
- rs->sr_text = "Unable to retry";
- send_ldap_result( op, rs );
- }
- }
-
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) {
- asyncmeta_quarantine( op, mi, rs, candidate );
- }
-
- return rc == LDAP_SUCCESS ? 1 : 0;
-}
-
-/*
- * callback for unique candidate selection
- */
-static int
-asyncmeta_conn_cb( Operation *op, SlapReply *rs )
-{
- assert( op->o_tag == LDAP_REQ_SEARCH );
-
- switch ( rs->sr_type ) {
- case REP_SEARCH:
- ((long *)op->o_callback->sc_private)[0] = (long)op->o_private;
- break;
-
- case REP_SEARCHREF:
- case REP_RESULT:
- break;
-
- default:
- return rs->sr_err;
- }
-
- return 0;
-}
-
static int
asyncmeta_get_candidate(
rs->sr_err = LDAP_NO_SUCH_OBJECT;
rs->sr_text = "No suitable candidate target found";
- } else if ( candidate == META_TARGET_MULTIPLE ) {
- Operation op2 = *op;
- SlapReply rs2 = { REP_RESULT };
- slap_callback cb2 = { 0 };
- int rc;
-
- /* try to get a unique match for the request ndn
- * among the multiple candidates available */
- op2.o_tag = LDAP_REQ_SEARCH;
- op2.o_req_dn = *ndn;
- op2.o_req_ndn = *ndn;
- op2.ors_scope = LDAP_SCOPE_BASE;
- op2.ors_deref = LDAP_DEREF_NEVER;
- op2.ors_attrs = slap_anlist_no_attrs;
- op2.ors_attrsonly = 0;
- op2.ors_limit = NULL;
- op2.ors_slimit = 1;
- op2.ors_tlimit = SLAP_NO_LIMIT;
-
- op2.ors_filter = (Filter *)slap_filter_objectClass_pres;
- op2.ors_filterstr = *slap_filterstr_objectClass_pres;
-
- op2.o_callback = &cb2;
- cb2.sc_response = asyncmeta_conn_cb;
- cb2.sc_private = (void *)&candidate;
-
- rc = op->o_bd->be_search( &op2, &rs2 );
-
- switch ( rs2.sr_err ) {
- case LDAP_SUCCESS:
- default:
- rs->sr_err = rs2.sr_err;
- break;
-
- case LDAP_SIZELIMIT_EXCEEDED:
- /* if multiple candidates can serve the operation,
- * and a default target is defined, and it is
- * a candidate, try using it (FIXME: YMMV) */
- if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
- && asyncmeta_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ],
- ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
- {
- candidate = mi->mi_defaulttarget;
- rs->sr_err = LDAP_SUCCESS;
- rs->sr_text = NULL;
-
- } else {
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- rs->sr_text = "Unable to select unique candidate target";
- }
- break;
- }
-
} else {
rs->sr_err = LDAP_SUCCESS;
}
return candidate;
}
-static void *asyncmeta_candidates_dummy;
-
-static void
-asyncmeta_candidates_keyfree(
- void *key,
- void *data )
-{
- a_metacandidates_t *mc = (a_metacandidates_t *)data;
-
- ber_memfree_x( mc->mc_candidates, NULL );
- ber_memfree_x( data, NULL );
-}
-
/*
* asyncmeta_getconn
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
- rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
+ rs->sr_matched = mi->mi_suffix.bv_val;
}
send_ldap_result( op, rs );
rs->sr_matched = NULL;
}
if ( op_type == META_OP_REQUIRE_SINGLE ) {
- a_metatarget_t *mt = NULL;
- a_metasingleconn_t *msc = NULL;
-
int j;
for ( j = 0; j < mi->mi_ntargets; j++ ) {
if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) {
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
- rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
+ rs->sr_matched = mi->mi_suffix.bv_val;
}
send_ldap_result( op, rs );
rs->sr_matched = NULL;
*/
( void )asyncmeta_clear_unused_candidates( op, i , mc, candidates);
- mt = mi->mi_targets[ i ];
- msc = &mc->mc_conns[ i ];
-
/*
* The target is activated; if needed, it is
* also init'd. In case of error, asyncmeta_init_one_conn
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
- rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
+ rs->sr_matched = mi->mi_suffix.bv_val;
}
send_ldap_result( op, rs );
rs->sr_matched = NULL;
}
done:;
- /* clear out meta_back_init_one_conn non-fatal errors */
rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL;
asyncmeta_get_next_mc( a_metainfo_t *mi )
{
a_metaconn_t *mc = NULL;
+
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
if (mi->mi_next_conn >= mi->mi_num_conns-1) {
mi->mi_next_conn = 0;
{
a_metasingleconn_t *msc;
ber_socket_t s;
- int i;
msc = &mc->mc_conns[candidate];
- if (msc->msc_ld == NULL || !META_IS_CANDIDATE( &candidates[ candidate ] )) {
+ if ( slapd_shutdown || !META_BACK_CONN_INITED( msc ) || msc->msc_ld == NULL
+ || !META_IS_CANDIDATE( &candidates[ candidate ] )) {
return LDAP_SUCCESS;
}
bc->msgids[candidate] = candidates[candidate].sr_msgid;
- msc->msc_pending_ops++;
if ( msc->conn == NULL) {
ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
if (s < 0) {
connection_client_enable( msc->conn );
return LDAP_SUCCESS;
}
+
+int
+asyncmeta_clear_one_msc(
+ Operation *op,
+ a_metaconn_t *mc,
+ int candidate,
+ int unbind,
+ const char *caller)
+{
+ a_metasingleconn_t *msc;
+ if (mc == NULL) {
+ return 0;
+ }
+ msc = &mc->mc_conns[candidate];
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] Resetting msc: %p, msc_ld: %p, "
+ "msc_bound_ndn: %s, msc->conn: %p, %s \n",
+ time_buf, msc, msc->msc_ld, msc->msc_bound_ndn.bv_val,
+ msc->conn, caller ? caller : "" );
+ }
+ msc->msc_mscflags = 0;
+ if (msc->conn) {
+ connection_client_stop( msc->conn );
+ msc->conn = NULL;
+ }
+
+ if ( msc->msc_ld != NULL ) {
+
+#ifdef DEBUG_205
+ Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_clear_one_msc ldap_unbind_ext[%d] ld=%p\n",
+ op ? op->o_log_prefix : "", candidate, (void *)msc->msc_ld );
+#endif /* DEBUG_205 */
+
+ ldap_unbind_ext( msc->msc_ld, NULL, NULL );
+ msc->msc_ld = NULL;
+ ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
+ msc->msc_ldr = NULL;
+ }
+
+ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
+ ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );
+ BER_BVZERO( &msc->msc_bound_ndn );
+ }
+
+ if ( !BER_BVISNULL( &msc->msc_cred ) ) {
+ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
+ ber_memfree_x( msc->msc_cred.bv_val, NULL );
+ BER_BVZERO( &msc->msc_cred );
+ }
+ msc->msc_time = 0;
+ msc->msc_binding_time = 0;
+ msc->msc_result_time = 0;
+ return 0;
+}
+
+void asyncmeta_get_timestamp(char *buf)
+{
+ struct timespec tp;
+ struct tm *ttm;
+ clock_gettime(CLOCK_REALTIME, &tp);
+ ttm = gmtime(&tp.tv_sec);
+ sprintf(buf, "%d:%d:%d.%ld", ttm->tm_hour, ttm->tm_min, ttm->tm_sec, tp.tv_nsec/1000);
+}
+
+int
+asyncmeta_reset_msc(
+ Operation *op,
+ a_metaconn_t *mc,
+ int candidate,
+ int unbind,
+ const char *caller)
+{
+ a_metasingleconn_t *msc = &mc->mc_conns[candidate];
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug(asyncmeta_debug, "[%x] Will attempt to reset [%s] msc: %p, "
+ "msc->msc_binding_time: %x, msc->msc_flags:%x %s\n",
+ (unsigned int)slap_get_time(), time_buf, msc,
+ (unsigned int)msc->msc_binding_time, msc->msc_mscflags, caller );
+ }
+ if (msc->msc_active <= 1 && mc->mc_active < 1) {
+ bm_context_t *om;
+ asyncmeta_clear_one_msc(NULL, mc, candidate, 0, caller);
+ /* set whatever's in the queue to invalid, so the timeout loop cleans it up,
+ * but do not invalidate the current op*/
+ LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
+ if (om->candidates[candidate].sr_msgid >= 0 && (om->op != op)) {
+ om->bc_invalid = 1;
+ }
+ }
+ return LDAP_SUCCESS;
+ } else {
+ META_BACK_CONN_INVALID_SET(msc);
+ Debug( asyncmeta_debug, "[%x] Failed to reset msc %p, msc_active=%d, mc_active=%d, %s\n",
+ (unsigned int)slap_get_time(), msc, msc->msc_active, mc->mc_active, caller );
+ }
+ return LDAP_OTHER;
+}
+
+
+void asyncmeta_log_msc(a_metasingleconn_t *msc)
+{
+ ber_socket_t s = 0;
+ if (msc->msc_ld) {
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ }
+ Debug( asyncmeta_debug, "msc: %p, msc_ld: %p, msc_ld socket: %d, "
+ "msc_bound_ndn: %s, msc->conn: %p\n", msc, msc->msc_ld,
+ (int)s, msc->msc_bound_ndn.bv_val, msc->conn );
+}
+
+void asyncmeta_log_conns(a_metainfo_t *mi)
+{
+ a_metaconn_t *mc;
+ int i, j;
+ for (i = 0; i < mi->mi_num_conns; i++) {
+ mc = &mi->mi_conns[i];
+ Debug(asyncmeta_debug, "mc: %p, mc->pending_ops: %d\n", mc, mc->pending_ops);
+ for (j = 0; j < mi->mi_ntargets; j++ ) {
+ asyncmeta_log_msc(&mc->mc_conns[j]);
+ }
+
+ }
+}
#include "portable.h"
#include <stdio.h>
-
#include <ac/string.h>
#include <ac/socket.h>
-
#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate)
+ int candidate,
+ int do_lock)
{
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn = BER_BVNULL;
a_dncookie dc;
- int rc = 0, nretries = 1;
+ int rc = 0;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "deleteDN";
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
- if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- retcode = META_SEARCH_ERR;
- goto doreturn;
- }
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
-retry:;
+ asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
-
+ /* someone might have reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
ber = ldap_build_delete_req( msc->msc_ld, mdn.bv_val, ctrls, NULL, &msgid);
+
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_delete_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE,
- mdn.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE,
+ mdn.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
-
+ /* fall though*/
default:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- retcode = META_SEARCH_ERR;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
}
}
+
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ retcode = META_SEARCH_NEED_BIND;
+ ldap_pvt_thread_yield();
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send delete request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ ldap_pvt_thread_yield();
+ break;
+ }
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
- BER_BVZERO( &mdn );
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
-doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_delete_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
- OperationBuffer opbuf;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
SlapReply *candidates;
- slap_callback *cb = op->o_callback;
+ time_t current_time = slap_get_time();
+
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
- Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_delete: %s\n",
+ Debug(LDAP_DEBUG_TRACE, "==> asyncmeta_back_delete: %s\n",
op->o_req_dn.bv_val );
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ if (current_time > op->o_time) {
+ Debug(asyncmeta_debug, "==> asyncmeta_back_delete[%s]: o_time:[%ld], current time: [%ld]\n",
+ op->o_log_prefix, op->o_time, current_time );
+ }
+
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
+
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ goto finish;
+ }
+
+retry:
+ if (bc->timeout && bc->stoptime < slap_get_time()) {
+ int timeout_err;
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ rs->sr_err = timeout_err;
+ rs->sr_text = "Operation timed out before it was sent to target";
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
}
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
- rc = asyncmeta_back_delete_start( op, rs, mc, bc, candidate);
+ rc = asyncmeta_back_delete_start( op, rs, mc, bc, candidate, 1);
if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
- break;
+ break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NOT_CANDIDATE "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- }
- break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: BINDING "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
+ "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: ERR "
- "cnd=\"%ldd\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
default:
assert( 0 );
break;
}
+
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
finish:
return rs->sr_err;
}
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
+int asyncmeta_debug;
+
int
asyncmeta_back_open(
BackendInfo *bi )
asyncmeta_back_initialize(
BackendInfo *bi )
{
+ int rc;
+ struct berval debugbv = BER_BVC("asyncmeta");
+
+ rc = slap_loglevel_get( &debugbv, &asyncmeta_debug );
+ if ( rc ) {
+ return rc;
+ }
+
bi->bi_flags =
#if 0
/* this is not (yet) set essentially because back-meta does not
bi->bi_chk_referrals = 0;
bi->bi_connection_init = 0;
- bi->bi_connection_destroy = asyncmeta_back_conn_destroy;
+ bi->bi_connection_destroy = 0 /* asyncmeta_back_conn_destroy */;
return asyncmeta_back_init_cf( bi );
}
)
{
slap_bindconf sb = { BER_BVNULL };
- struct berval mapped;
int rc;
- int msc_num, i;
ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri );
sb.sb_version = mt->mt_version;
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_NOANON;
}
- BER_BVZERO( &mapped );
- asyncmeta_map( &mt->mt_rwmap.rwm_at,
- &slap_schema.si_ad_entryDN->ad_cname, &mapped,
- BACKLDAP_REMAP );
- if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
- mt->mt_rep_flags |= REP_NO_ENTRYDN;
- }
-
- BER_BVZERO( &mapped );
- asyncmeta_map( &mt->mt_rwmap.rwm_at,
- &slap_schema.si_ad_subschemaSubentry->ad_cname, &mapped,
- BACKLDAP_REMAP );
- if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
- mt->mt_rep_flags |= REP_NO_SUBSCHEMA;
- }
return 0;
}
ConfigReply *cr )
{
a_metainfo_t *mi = (a_metainfo_t *)be->be_private;
-
char msg[SLAP_TEXT_BUFLEN];
-
- int i, rc;
+ int i;
if ( mi->mi_ntargets == 0 ) {
/* Dynamically added, nothing to check here until
mc->mc_authz_target = META_BOUND_NONE;
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
mc->mc_info = mi;
+ LDAP_STAILQ_INIT( &mc->mc_om_list );
}
-
+ mi->mi_suffix = be->be_suffix[0];
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 0,
- asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", be->be_suffix[0].bv_val );
+ asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val );
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
return 0;
}
free( mc );
}
-static void
-mapping_free(
- void *v_mapping )
-{
- struct ldapmapping *mapping = v_mapping;
- ch_free( mapping->src.bv_val );
- ch_free( mapping->dst.bv_val );
- ch_free( mapping );
-}
-
-static void
-mapping_dst_free(
- void *v_mapping )
-{
- struct ldapmapping *mapping = v_mapping;
-
- if ( BER_BVISEMPTY( &mapping->dst ) ) {
- mapping_free( &mapping[ -1 ] );
- }
-}
-
-void
-asyncmeta_back_map_free( struct ldapmap *lm )
-{
- avl_free( lm->remap, mapping_dst_free );
- avl_free( lm->map, mapping_free );
- lm->remap = NULL;
- lm->map = NULL;
-}
-
static void
asyncmeta_back_stop_miconns( a_metainfo_t *mi )
{
mc = &mi->mi_conns[i];
/* todo clear the message queue */
for (j = 0; j < mi->mi_ntargets; j ++) {
- asyncmeta_clear_one_msc(NULL, mc, j);
+ asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
}
free(mc->mc_conns);
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
if ( mt->mt_idassert_authz != NULL ) {
ber_bvarray_free( mt->mt_idassert_authz );
}
- if ( mt->mt_rwmap.rwm_rw ) {
- rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
- if ( mt->mt_rwmap.rwm_bva_rewrite )
- ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
+ if ( !BER_BVISNULL( &mt->mt_lsuffixm )) {
+ ch_free( mt->mt_lsuffixm.bv_val );
+ }
+ if ( !BER_BVISNULL( &mt->mt_rsuffixm )) {
+ ch_free( mt->mt_rsuffixm.bv_val );
}
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc );
- asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at );
- ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
free( mt );
}
a_metainfo_t *mi;
if ( be->be_private ) {
- int i;
-
mi = ( a_metainfo_t * )be->be_private;
if ( mi->mi_task != NULL ) {
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
asyncmeta_back_stop_miconns( mi );
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
}
+ return 0;
}
int
if ( META_BACK_QUARANTINE( mi ) ) {
mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine );
}
- }
- ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
- asyncmeta_back_clear_miconns(mi);
- ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
- ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
- free( be->be_private );
+ ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
+ asyncmeta_back_clear_miconns(mi);
+ ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
+ ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
+
+ free( be->be_private );
+ }
return 0;
}
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
-int
-asyncmeta_mapping_cmp ( const void *c1, const void *c2 )
-{
- struct ldapmapping *map1 = (struct ldapmapping *)c1;
- struct ldapmapping *map2 = (struct ldapmapping *)c2;
- int rc = map1->src.bv_len - map2->src.bv_len;
- if (rc) return rc;
- return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) );
-}
-
-int
-asyncmeta_mapping_dup ( void *c1, void *c2 )
-{
- struct ldapmapping *map1 = (struct ldapmapping *)c1;
- struct ldapmapping *map2 = (struct ldapmapping *)c2;
-
- return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 );
-}
-
void
-asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping **m )
-{
- struct ldapmapping *mapping;
-
- assert( m != NULL );
-
- *m = NULL;
-
- mapping = (struct ldapmapping *)ch_calloc( 2,
- sizeof( struct ldapmapping ) );
- if ( mapping == NULL ) {
- return;
- }
-
- ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
- ber_dupbv( &mapping[0].dst, &mapping[0].src );
- mapping[1].src = mapping[0].src;
- mapping[1].dst = mapping[0].dst;
-
- avl_insert( &lm->map, (caddr_t)&mapping[0],
- asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
- avl_insert( &lm->remap, (caddr_t)&mapping[1],
- asyncmeta_mapping_cmp, asyncmeta_mapping_dup );
- *m = mapping;
-}
-
-int
-asyncmeta_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m,
- int remap )
-{
- Avlnode *tree;
- struct ldapmapping fmapping;
-
- assert( m != NULL );
-
- /* let special attrnames slip through (ITS#5760) */
- if ( bvmatch( s, slap_bv_no_attrs )
- || bvmatch( s, slap_bv_all_user_attrs )
- || bvmatch( s, slap_bv_all_operational_attrs ) )
- {
- *m = NULL;
- return 0;
- }
-
- if ( remap == BACKLDAP_REMAP ) {
- tree = map->remap;
-
- } else {
- tree = map->map;
- }
-
- fmapping.src = *s;
- *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, asyncmeta_mapping_cmp );
- if ( *m == NULL ) {
- return map->drop_missing;
- }
-
- return 0;
-}
-
-void
-asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
- int remap )
-{
- struct ldapmapping *mapping;
- int drop_missing;
-
- /* map->map may be NULL when mapping is configured,
- * but map->remap can't */
- if ( map->remap == NULL ) {
- *bv = *s;
- return;
- }
-
- BER_BVZERO( bv );
- drop_missing = asyncmeta_mapping( map, s, &mapping, remap );
- if ( mapping != NULL ) {
- if ( !BER_BVISNULL( &mapping->dst ) ) {
- *bv = mapping->dst;
- }
- return;
- }
-
- if ( !drop_missing ) {
- *bv = *s;
- }
-}
-
-int
-asyncmeta_map_attrs(
- Operation *op,
- struct ldapmap *at_map,
- AttributeName *an,
- int remap,
- char ***mapped_attrs )
-{
- int i, x, j;
- char **na;
- struct berval mapped;
-
- if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) {
- *mapped_attrs = NULL;
- return LDAP_SUCCESS;
- }
-
- i = 0;
- if ( an != NULL ) {
- for ( ; !BER_BVISNULL( &an[i].an_name ); i++ )
- /* */ ;
- }
-
- x = 0;
- if ( op->o_bd->be_extra_anlist != NULL ) {
- for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
- /* */ ;
- }
-
- assert( i > 0 || x > 0 );
-
- na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx );
- if ( na == NULL ) {
- *mapped_attrs = NULL;
- return LDAP_NO_MEMORY;
- }
-
- j = 0;
- if ( i > 0 ) {
- for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
- asyncmeta_map( at_map, &an[i].an_name, &mapped, remap );
- if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
- na[j++] = mapped.bv_val;
- }
- }
- }
-
- if ( x > 0 ) {
- for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) {
- if ( op->o_bd->be_extra_anlist[x].an_desc &&
- ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) )
- {
- continue;
- }
-
- asyncmeta_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap );
- if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) {
- na[j++] = mapped.bv_val;
- }
- }
- }
-
- if ( j == 0 && ( i > 0 || x > 0 ) ) {
- na[j++] = LDAP_NO_ATTRS;
- }
- na[j] = NULL;
-
- *mapped_attrs = na;
-
- return LDAP_SUCCESS;
-}
-
-static int
-map_attr_value(
- a_dncookie *dc,
- AttributeDescription *ad,
- struct berval *mapped_attr,
- struct berval *value,
- struct berval *mapped_value,
- int remap,
- void *memctx )
-{
- struct berval vtmp;
- int freeval = 0;
-
- asyncmeta_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap );
- if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
-#if 0
- /*
- * FIXME: are we sure we need to search oc_map if at_map fails?
- */
- asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap );
- if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) {
- *mapped_attr = ad->ad_cname;
- }
-#endif
- if ( dc->target->mt_rwmap.rwm_at.drop_missing ) {
- return -1;
- }
-
- *mapped_attr = ad->ad_cname;
- }
-
- if ( value == NULL ) {
- return 0;
- }
-
- if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
- {
- a_dncookie fdc = *dc;
-
- fdc.ctx = "searchFilterAttrDN";
-
- switch ( asyncmeta_dn_massage( &fdc, value, &vtmp ) ) {
- case LDAP_SUCCESS:
- if ( vtmp.bv_val != value->bv_val ) {
- freeval = 1;
- }
- break;
-
- case LDAP_UNWILLING_TO_PERFORM:
- return -1;
-
- case LDAP_OTHER:
- return -1;
- }
-
- } else if ( ad->ad_type->sat_equality &&
- ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER )
- {
- if ( ad->ad_type->sat_equality->smr_normalize(
- (SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX),
- NULL, NULL, value, &vtmp, memctx ) )
- {
- return -1;
- }
- freeval = 2;
-
- } else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) {
- asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, value, &vtmp, remap );
- if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) {
- vtmp = *value;
- }
-
- } else {
- vtmp = *value;
- }
-
- filter_escape_value_x( &vtmp, mapped_value, memctx );
-
- switch ( freeval ) {
- case 1:
- ber_memfree( vtmp.bv_val );
- break;
- case 2:
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
- }
-
- return 0;
-}
-
-static int
-asyncmeta_int_filter_map_rewrite(
- a_dncookie *dc,
- Filter *f,
- struct berval *fstr,
- int remap,
- void *memctx )
-{
- int i;
- Filter *p;
- struct berval atmp,
- vtmp,
- *tmp;
- static struct berval
- /* better than nothing... */
- ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
- ber_bvtf_false = BER_BVC( "(|)" ),
- /* better than nothing... */
- ber_bvtrue = BER_BVC( "(objectClass=*)" ),
- ber_bvtf_true = BER_BVC( "(&)" ),
-#if 0
- /* no longer needed; preserved for completeness */
- ber_bvundefined = BER_BVC( "(?=undefined)" ),
-#endif
- ber_bverror = BER_BVC( "(?=error)" ),
- ber_bvunknown = BER_BVC( "(?=unknown)" ),
- ber_bvnone = BER_BVC( "(?=none)" );
- ber_len_t len;
-
- assert( fstr != NULL );
- BER_BVZERO( fstr );
-
- if ( f == NULL ) {
- ber_dupbv_x( fstr, &ber_bvnone, memctx );
- return LDAP_OTHER;
- }
-
- switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) {
- case LDAP_FILTER_EQUALITY:
- if ( map_attr_value( dc, f->f_av_desc, &atmp,
- &f->f_av_value, &vtmp, remap, memctx ) )
- {
- goto computed;
- }
-
- fstr->bv_len = atmp.bv_len + vtmp.bv_len
- + ( sizeof("(=)") - 1 );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
- atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
-
- case LDAP_FILTER_GE:
- if ( map_attr_value( dc, f->f_av_desc, &atmp,
- &f->f_av_value, &vtmp, remap, memctx ) )
- {
- goto computed;
- }
-
- fstr->bv_len = atmp.bv_len + vtmp.bv_len
- + ( sizeof("(>=)") - 1 );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
- atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
-
- case LDAP_FILTER_LE:
- if ( map_attr_value( dc, f->f_av_desc, &atmp,
- &f->f_av_value, &vtmp, remap, memctx ) )
- {
- goto computed;
- }
-
- fstr->bv_len = atmp.bv_len + vtmp.bv_len
- + ( sizeof("(<=)") - 1 );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
- atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
-
- case LDAP_FILTER_APPROX:
- if ( map_attr_value( dc, f->f_av_desc, &atmp,
- &f->f_av_value, &vtmp, remap, memctx ) )
- {
- goto computed;
- }
-
- fstr->bv_len = atmp.bv_len + vtmp.bv_len
- + ( sizeof("(~=)") - 1 );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
- atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
-
- case LDAP_FILTER_SUBSTRINGS:
- if ( map_attr_value( dc, f->f_sub_desc, &atmp,
- NULL, NULL, remap, memctx ) )
- {
- goto computed;
- }
-
- /* cannot be a DN ... */
-
- fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
- atmp.bv_val );
-
- if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
- len = fstr->bv_len;
-
- filter_escape_value_x( &f->f_sub_initial, &vtmp, memctx );
-
- fstr->bv_len += vtmp.bv_len;
- fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
-
- snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3,
- /* "(attr=" */ "%s*)",
- vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- }
-
- if ( f->f_sub_any != NULL ) {
- for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
- len = fstr->bv_len;
- filter_escape_value_x( &f->f_sub_any[i], &vtmp, memctx );
-
- fstr->bv_len += vtmp.bv_len + 1;
- fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
-
- snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
- /* "(attr=[init]*[any*]" */ "%s*)",
- vtmp.bv_len ? vtmp.bv_val : "" );
- ber_memfree_x( vtmp.bv_val, memctx );
- }
- }
-
- if ( !BER_BVISNULL( &f->f_sub_final ) ) {
- len = fstr->bv_len;
-
- filter_escape_value_x( &f->f_sub_final, &vtmp, memctx );
-
- fstr->bv_len += vtmp.bv_len;
- fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
-
- snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3,
- /* "(attr=[init*][any*]" */ "%s)",
- vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- }
-
- break;
-
- case LDAP_FILTER_PRESENT:
- if ( map_attr_value( dc, f->f_desc, &atmp,
- NULL, NULL, remap, memctx ) )
- {
- goto computed;
- }
-
- fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
- atmp.bv_val );
- break;
-
- case LDAP_FILTER_AND:
- case LDAP_FILTER_OR:
- case LDAP_FILTER_NOT:
- fstr->bv_len = STRLENOF( "(%)" );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
- f->f_choice == LDAP_FILTER_AND ? '&' :
- f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
-
- for ( p = f->f_list; p != NULL; p = p->f_next ) {
- int rc;
-
- len = fstr->bv_len;
-
- rc = asyncmeta_int_filter_map_rewrite( dc, p, &vtmp, remap, memctx );
- if ( rc != LDAP_SUCCESS ) {
- return rc;
- }
-
- fstr->bv_len += vtmp.bv_len;
- fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
-
- snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
- /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
-
- ber_memfree_x( vtmp.bv_val, memctx );
- }
-
- break;
-
- case LDAP_FILTER_EXT:
- if ( f->f_mr_desc ) {
- if ( map_attr_value( dc, f->f_mr_desc, &atmp,
- &f->f_mr_value, &vtmp, remap, memctx ) )
- {
- goto computed;
- }
-
- } else {
- BER_BVSTR( &atmp, "" );
- filter_escape_value_x( &f->f_mr_value, &vtmp, memctx );
- }
-
- /* FIXME: cleanup (less ?: operators...) */
- fstr->bv_len = atmp.bv_len +
- ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
- ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
- vtmp.bv_len + ( STRLENOF( "(:=)" ) );
- fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
-
- snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
- atmp.bv_val,
- f->f_mr_dnattrs ? ":dn" : "",
- !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
- !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
- vtmp.bv_len ? vtmp.bv_val : "" );
- ber_memfree_x( vtmp.bv_val, memctx );
- break;
-
- case SLAPD_FILTER_COMPUTED:
- switch ( f->f_result ) {
- /* FIXME: treat UNDEFINED as FALSE */
- case SLAPD_COMPARE_UNDEFINED:
-computed:;
- if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) {
- return LDAP_COMPARE_FALSE;
- }
- /* fallthru */
-
- case LDAP_COMPARE_FALSE:
- if ( META_BACK_TGT_T_F( dc->target ) ) {
- tmp = &ber_bvtf_false;
- break;
- }
- tmp = &ber_bvfalse;
- break;
-
- case LDAP_COMPARE_TRUE:
- if ( META_BACK_TGT_T_F( dc->target ) ) {
- tmp = &ber_bvtf_true;
- break;
- }
-
- tmp = &ber_bvtrue;
- break;
-
- default:
- tmp = &ber_bverror;
- break;
- }
-
- ber_dupbv_x( fstr, tmp, memctx );
- break;
-
- default:
- ber_dupbv_x( fstr, &ber_bvunknown, memctx );
- break;
- }
-
- return 0;
-}
-
-int
-asyncmeta_filter_map_rewrite(
- a_dncookie *dc,
- Filter *f,
- struct berval *fstr,
- int remap,
- void *memctx )
-{
- int rc;
- a_dncookie fdc;
- struct berval ftmp;
- static char *dmy = "";
-
- rc = asyncmeta_int_filter_map_rewrite( dc, f, fstr, remap, memctx );
-
- if ( rc != LDAP_SUCCESS ) {
- return rc;
- }
-
- fdc = *dc;
- ftmp = *fstr;
-
- fdc.ctx = "searchFilter";
-
- switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx,
- ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ),
- fdc.conn, &fstr->bv_val ) )
- {
- case REWRITE_REGEXEC_OK:
- if ( !BER_BVISNULL( fstr ) ) {
- fstr->bv_len = strlen( fstr->bv_val );
-
- } else {
- *fstr = ftmp;
- }
- Debug( LDAP_DEBUG_ARGS,
- "[rw] %s: \"%s\" -> \"%s\"\n",
- fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val,
- BER_BVISNULL( fstr ) ? "" : fstr->bv_val );
- rc = LDAP_SUCCESS;
- break;
-
- case REWRITE_REGEXEC_UNWILLING:
- if ( fdc.rs ) {
- fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- fdc.rs->sr_text = "Operation not allowed";
- }
- rc = LDAP_UNWILLING_TO_PERFORM;
- break;
-
- case REWRITE_REGEXEC_ERR:
- if ( fdc.rs ) {
- fdc.rs->sr_err = LDAP_OTHER;
- fdc.rs->sr_text = "Rewrite error";
- }
- rc = LDAP_OTHER;
- break;
- }
-
- if ( fstr->bv_val == dmy ) {
- BER_BVZERO( fstr );
-
- } else if ( fstr->bv_val != ftmp.bv_val ) {
- /* NOTE: need to realloc mapped filter on slab
- * and free the original one, until librewrite
- * becomes slab-aware
- */
- ber_dupbv_x( &ftmp, fstr, memctx );
- ch_free( fstr->bv_val );
- *fstr = ftmp;
- }
-
- return rc;
-}
-
-int
asyncmeta_referral_result_rewrite(
a_dncookie *dc,
- BerVarray a_vals,
- void *memctx
+ BerVarray a_vals
)
{
int i, last;
ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
- rc = asyncmeta_dn_massage( dc, &olddn, &dn );
- switch ( rc ) {
- case LDAP_UNWILLING_TO_PERFORM:
- /*
- * FIXME: need to check if it may be considered
- * legal to trim values when adding/modifying;
- * it should be when searching (e.g. ACLs).
- */
- ber_memfree( a_vals[ i ].bv_val );
- if ( last > i ) {
- a_vals[ i ] = a_vals[ last ];
- }
- BER_BVZERO( &a_vals[ last ] );
- last--;
- i--;
- break;
+ asyncmeta_dn_massage( dc, &olddn, &dn );
+ /* leave attr untouched if massage did nothing */
+ if ( olddn.bv_val != dn.bv_val )
+ {
+ char *newurl;
- default:
- /* leave attr untouched if massage failed */
- if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
+ ludp->lud_dn = dn.bv_val;
+ newurl = ldap_url_desc2str( ludp );
+ dc->op->o_tmpfree( dn.bv_val, dc->memctx );
+ if ( newurl )
{
- char *newurl;
-
- ludp->lud_dn = dn.bv_val;
- newurl = ldap_url_desc2str( ludp );
- free( dn.bv_val );
- if ( newurl == NULL ) {
- /* FIXME: leave attr untouched
- * even if ldap_url_desc2str failed...
- */
- break;
- }
+ /* FIXME: leave attr untouched
+ * even if ldap_url_desc2str failed...
+ */
- ber_memfree_x( a_vals[ i ].bv_val, memctx );
- ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx );
+ ber_memfree_x( a_vals[ i ].bv_val, dc->op->o_tmpmemctx );
+ ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], dc->memctx );
ber_memfree( newurl );
ludp->lud_dn = olddn.bv_val;
}
- break;
}
-
ldap_free_urldesc( ludp );
}
-
- return 0;
}
-/*
- * I don't like this much, but we need two different
- * functions because different heap managers may be
- * in use in back-ldap/meta to reduce the amount of
- * calls to malloc routines, and some of the free()
- * routines may be macros with args
- */
-int
-asyncmeta_dnattr_rewrite(
+void
+asyncmeta_dnattr_result_rewrite(
a_dncookie *dc,
BerVarray a_vals
)
{
struct berval bv;
- int i, last;
+ int i;
assert( a_vals != NULL );
- for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
- ;
- last--;
-
for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
- switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
- case LDAP_UNWILLING_TO_PERFORM:
- /*
- * FIXME: need to check if it may be considered
- * legal to trim values when adding/modifying;
- * it should be when searching (e.g. ACLs).
- */
- ch_free( a_vals[i].bv_val );
- if ( last > i ) {
- a_vals[i] = a_vals[last];
- }
- BER_BVZERO( &a_vals[last] );
- last--;
- break;
-
- default:
- /* leave attr untouched if massage failed */
- if ( !BER_BVISNULL( &bv ) && bv.bv_val != a_vals[i].bv_val ) {
- ch_free( a_vals[i].bv_val );
- a_vals[i] = bv;
- }
- break;
+ asyncmeta_dn_massage( dc, &a_vals[i], &bv );
+ if ( bv.bv_val != a_vals[i].bv_val ) {
+ ber_memfree_x( a_vals[i].bv_val, dc->memctx );
+ a_vals[i] = bv;
}
}
-
- return 0;
}
-int
-asyncmeta_dnattr_result_rewrite(
- a_dncookie *dc,
- BerVarray a_vals
+/*
+ * asyncmeta_dn_massage
+ *
+ * Aliases the suffix.
+ */
+void
+asyncmeta_dn_massage(
+ a_dncookie *dc,
+ struct berval *odn,
+ struct berval *res
)
{
- struct berval bv;
- int i, last;
+ struct berval pretty = {0,NULL}, *dn = odn;
+ struct berval *osuff, *nsuff;
+ int diff;
- assert( a_vals != NULL );
+ assert( res );
- for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
- ;
- last--;
+ BER_BVZERO(res);
+ if ( dn == NULL )
+ return;
- for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
- switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) {
- case LDAP_UNWILLING_TO_PERFORM:
- /*
- * FIXME: need to check if it may be considered
- * legal to trim values when adding/modifying;
- * it should be when searching (e.g. ACLs).
- */
- ber_memfree( a_vals[i].bv_val );
- if ( last > i ) {
- a_vals[i] = a_vals[last];
- }
- BER_BVZERO( &a_vals[last] );
- last--;
- break;
+ /* no suffix massage configured */
+ if ( !dc->target->mt_lsuffixm.bv_val ) {
+ *res = *dn;
+ return;
+ }
- default:
- /* leave attr untouched if massage failed */
- if ( !BER_BVISNULL( &bv ) && a_vals[i].bv_val != bv.bv_val ) {
- ber_memfree( a_vals[i].bv_val );
- a_vals[i] = bv;
- }
- break;
- }
+ if ( dc->to_from == MASSAGE_REQ ) {
+ osuff = &dc->target->mt_lsuffixm;
+ nsuff = &dc->target->mt_rsuffixm;
+ } else {
+ osuff = &dc->target->mt_rsuffixm;
+ nsuff = &dc->target->mt_lsuffixm;
+ /* DN from remote server may be in arbitrary form.
+ * Pretty it so we can parse reliably.
+ */
+ dnPretty( NULL, dn, &pretty, dc->op->o_tmpmemctx );
+ if (pretty.bv_val) dn = &pretty;
+ }
+
+ diff = dn->bv_len - osuff->bv_len;
+ /* DN is shorter than suffix - ignore */
+ if ( diff < 0 ) {
+ignore:
+ *res = *odn;
+ if (pretty.bv_val)
+ dc->op->o_tmpfree( pretty.bv_val, dc->op->o_tmpmemctx );
+ return;
}
- return 0;
+ /* DN longer than our suffix and doesn't match */
+ if ( diff > 0 && !DN_SEPARATOR(dn->bv_val[diff-1]))
+ goto ignore;
+
+ /* suffix is same length as ours, but doesn't match */
+ if ( strcasecmp( osuff->bv_val, &dn->bv_val[diff] ))
+ goto ignore;
+
+ res->bv_len = diff + nsuff->bv_len;
+ res->bv_val = dc->op->o_tmpalloc( res->bv_len + 1, dc->memctx );
+ strncpy( res->bv_val, dn->bv_val, diff );
+ strcpy( &res->bv_val[diff], nsuff->bv_val );
+
+ if (pretty.bv_val)
+ dc->op->o_tmpfree( pretty.bv_val, dc->op->o_tmpmemctx );
}
#include "lutil.h"
-LDAPControl **asyncmeta_copy_controls(Operation *op)
-{
- LDAPControl **new_controls = NULL;
- LDAPControl **c;
- LDAPControl *tmp_ctl = NULL;
- int i, length = 1;
-
-
- if (op->o_ctrls == NULL) {
- return NULL;
- }
- for (c = op->o_ctrls; *c != NULL; c++) {
- length++;
- }
-
- new_controls = op->o_tmpalloc( sizeof(LDAPControl*)*length, op->o_tmpmemctx );
- for (i = 0; i < length-1; i ++) {
- new_controls[i] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
- if (op->o_ctrls[i]->ldctl_value.bv_len > 0) {
- ber_dupbv_x( &new_controls[i]->ldctl_value, &op->o_ctrls[i]->ldctl_value, op->o_tmpmemctx);
- }
- if (op->o_ctrls[i]->ldctl_oid) {
- new_controls[i]->ldctl_oid = ber_strdup_x(op->o_ctrls[i]->ldctl_oid, op->o_tmpmemctx);
- }
- new_controls[i]->ldctl_iscritical = op->o_ctrls[i]->ldctl_iscritical;
- }
- new_controls[length-1] = NULL;
- return new_controls;
-}
-
-static
-void asyncmeta_free_op_controls(Operation *op)
-{
- LDAPControl **c;
- for (c = op->o_ctrls; *c != NULL; c++) {
- if ((*c)->ldctl_value.bv_len > 0) {
- free((*c)->ldctl_value.bv_val);
- }
- if ((*c)->ldctl_oid) {
- free((*c)->ldctl_oid);
- }
- free(*c);
- }
- free(op->o_ctrls);
-}
-
-
-static
-Modifications* asyncmeta_copy_modlist(Operation *op, Modifications *modlist)
-{
- Modifications *ml;
- Modifications *new_mods = NULL;
- for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
- Modifications *mod = op->o_tmpalloc( sizeof( Modifications ), op->o_tmpmemctx );
- *mod = *ml;
- if ( ml->sml_values ) {
- ber_bvarray_dup_x( &mod->sml_values, ml->sml_values, op->o_tmpmemctx );
- if ( ml->sml_nvalues ) {
- ber_bvarray_dup_x( &mod->sml_nvalues, ml->sml_nvalues, op->o_tmpmemctx );
- }
- }
- mod->sml_next = NULL;
- if (new_mods == NULL) {
- new_mods = mod;
- } else {
- new_mods->sml_next = mod;
- }
- }
- return new_mods;
-}
-
-Operation *asyncmeta_copy_op(Operation *op)
-{
- const char *text;
- int rc;
- char txtbuf[SLAP_TEXT_BUFLEN];
- size_t textlen = sizeof txtbuf;
- Entry *e;
- Operation *new_op = op->o_tmpcalloc( 1, sizeof(OperationBuffer), op->o_tmpmemctx );
- *new_op = *op;
- new_op->o_hdr = &((OperationBuffer *) new_op)->ob_hdr;
- *(new_op->o_hdr) = *(op->o_hdr);
- new_op->o_controls = ((OperationBuffer *) new_op)->ob_controls;
- new_op->o_callback = op->o_callback;
- new_op->o_ber = NULL;
- new_op->o_bd = op->o_bd->bd_self;
-
- ber_dupbv_x( &new_op->o_req_dn, &op->o_req_dn, op->o_tmpmemctx );
- ber_dupbv_x( &new_op->o_req_ndn, &op->o_req_ndn, op->o_tmpmemctx );
- op->o_callback = NULL;
-
- if (op->o_ndn.bv_len > 0) {
- ber_dupbv_x( &new_op->o_ndn, &op->o_ndn, op->o_tmpmemctx );
- }
- if (op->o_dn.bv_len > 0) {
- ber_dupbv_x( &new_op->o_dn, &op->o_dn, op->o_tmpmemctx );
- }
-
- new_op->o_ctrls = asyncmeta_copy_controls(op);
- switch (op->o_tag) {
- case LDAP_REQ_SEARCH:
- {
- AttributeName *at_names;
- int i;
- for (i=0; op->ors_attrs && !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++);
- if (i > 0) {
- at_names = op->o_tmpcalloc( i+1, sizeof( AttributeName ), op->o_tmpmemctx );
- at_names[i].an_name.bv_len = 0;
- i--;
- for (i; i >= 0; i--) {
- at_names[i] = op->ors_attrs[i];
- ber_dupbv_x( &at_names[i].an_name, &op->ors_attrs[i].an_name, op->o_tmpmemctx );
- }
- } else {
- at_names = NULL;
- }
- ber_dupbv_x( &new_op->ors_filterstr, &op->ors_filterstr, op->o_tmpmemctx );
- new_op->ors_filter = filter_dup( op->ors_filter, op->o_tmpmemctx );
- new_op->ors_attrs = at_names;
- }
- break;
- case LDAP_REQ_ADD:
- {
- slap_entry2mods(op->ora_e, &new_op->ora_modlist, &text, txtbuf, textlen);
- e = entry_alloc();
- new_op->ora_e = e;
- ber_dupbv_x( &e->e_name, &op->o_req_dn, op->o_tmpmemctx );
- ber_dupbv_x( &e->e_nname, &op->o_req_ndn, op->o_tmpmemctx );
- rc = slap_mods2entry( new_op->ora_modlist, &new_op->ora_e, 1, 0, &text, txtbuf, textlen);
- }
- break;
- case LDAP_REQ_MODIFY:
- {
- new_op->orm_modlist = asyncmeta_copy_modlist(op, op->orm_modlist);
- }
- break;
- case LDAP_REQ_COMPARE:
- new_op->orc_ava = (AttributeAssertion *)ch_calloc( 1, sizeof( AttributeAssertion ));
- *new_op->orc_ava = *op->orc_ava;
- if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
- ber_dupbv_x( &new_op->orc_ava->aa_value, &op->orc_ava->aa_value, op->o_tmpmemctx);
- }
- break;
- case LDAP_REQ_MODRDN:
-
- if (op->orr_newrdn.bv_len > 0) {
- ber_dupbv_x( &new_op->orr_newrdn, &op->orr_newrdn, op->o_tmpmemctx );
- }
- if (op->orr_nnewrdn.bv_len > 0) {
- ber_dupbv_x( &new_op->orr_nnewrdn, &op->orr_nnewrdn, op->o_tmpmemctx );
- }
- if (op->orr_newSup != NULL) {
- new_op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
- new_op->orr_newSup->bv_len = 0;
- if (op->orr_newSup->bv_len > 0) {
- ber_dupbv_x( new_op->orr_newSup, op->orr_newSup, op->o_tmpmemctx );
- }
- }
-
- if (op->orr_nnewSup != NULL) {
- new_op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
- new_op->orr_nnewSup->bv_len = 0;
- if (op->orr_nnewSup->bv_len > 0) {
- ber_dupbv_x( new_op->orr_nnewSup, op->orr_nnewSup, op->o_tmpmemctx );
- }
- }
- new_op->orr_modlist = asyncmeta_copy_modlist(op, op->orr_modlist);
- break;
- case LDAP_REQ_DELETE:
- default:
- break;
- }
- return new_op;
-}
-
-
typedef struct listptr {
void *reserved;
struct listptr *next;
int cnt;
} listhead;
-static void *asyncmeta_memctx_destroy(void *key, void *data)
-{
- listhead *lh = data;
- listptr *lp;
- while (lp = lh->list) {
- lh->list = lp->next;
- slap_sl_mem_destroy((void *)1, lp);
- }
- ch_free(lh);
-}
-
#ifndef LH_MAX
#define LH_MAX 16
#endif
static void *asyncmeta_memctx_get(void *threadctx)
{
- listhead *lh = NULL;
- listptr *lp = NULL;
- ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
- if (!lh) {
- lh = ch_malloc(sizeof(listhead));
- lh->cnt = 0;
- lh->list = NULL;
- ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
- }
- if (lh->list) {
- lp = lh->list;
- lh->list = lp->next;
- lh->cnt--;
- slap_sl_mem_setctx(threadctx, lp);
- }
return slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, threadctx, 1);
}
static void asyncmeta_memctx_put(void *threadctx, void *memctx)
{
- listhead *lh = NULL;
- ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
- if (!lh) {
- lh = ch_malloc(sizeof(listhead));
- lh->cnt = 0;
- lh->list = NULL;
- ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
- }
- if (lh->cnt < LH_MAX) {
- listptr *lp = memctx;
- lp->next = lh->list;
- lh->list = lp;
- lh->cnt++;
- } else {
- slap_sl_mem_destroy((void *)1, memctx);
- }
+ slap_sl_mem_setctx(threadctx, NULL);
+ slap_sl_mem_destroy((void *)1, memctx);
}
-int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets)
+void asyncmeta_memctx_toggle(void *thrctx)
+{
+ asyncmeta_memctx_get(thrctx);
+}
+
+int asyncmeta_new_bm_context(Operation *op,
+ SlapReply *rs,
+ bm_context_t **new_bc,
+ int ntargets,
+ a_metainfo_t *mi)
{
- void *oldctx = op->o_tmpmemctx;
int i;
- /* prevent old memctx from being destroyed */
- slap_sl_mem_setctx(op->o_threadctx, NULL);
- /* create new memctx */
- op->o_tmpmemctx = asyncmeta_memctx_get( op->o_threadctx );
*new_bc = op->o_tmpcalloc( 1, sizeof( bm_context_t ), op->o_tmpmemctx );
- (*new_bc)->op = asyncmeta_copy_op(op);
+ (*new_bc)->op = op;
+ (*new_bc)->copy_op = *op;
(*new_bc)->candidates = op->o_tmpcalloc(ntargets, sizeof(SlapReply),op->o_tmpmemctx);
(*new_bc)->msgids = op->o_tmpcalloc(ntargets, sizeof(int),op->o_tmpmemctx);
+ (*new_bc)->nretries = op->o_tmpcalloc(ntargets, sizeof(int),op->o_tmpmemctx);
+ (*new_bc)->c_peer_name = op->o_conn->c_peer_name;
+ (*new_bc)->is_root = be_isroot( op );
+
+ switch(op->o_tag) {
+ case LDAP_REQ_COMPARE:
+ {
+ AttributeAssertion *ava = op->o_tmpcalloc( 1, sizeof(AttributeAssertion), op->o_tmpmemctx );
+ *ava = *op->orc_ava;
+ op->orc_ava = ava;
+ }
+ break;
+ case LDAP_REQ_MODRDN:
+ if (op->orr_newSup != NULL) {
+ struct berval *bv = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
+ *bv = *op->orr_newSup;
+ op->orr_newSup = bv;
+ }
+
+ if (op->orr_nnewSup != NULL) {
+ struct berval *bv = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
+ *bv = *op->orr_nnewSup;
+ op->orr_nnewSup = bv;
+ }
+ break;
+ default:
+ break;
+ }
for (i = 0; i < ntargets; i++) {
(*new_bc)->msgids[i] = META_MSGID_UNDEFINED;
}
- /* restore original memctx */
- slap_sl_mem_setctx(op->o_threadctx, oldctx);
- op->o_tmpmemctx = oldctx;
+ for (i = 0; i < ntargets; i++) {
+ (*new_bc)->nretries[i] = mi->mi_targets[i]->mt_nretries;
+ }
return LDAP_SUCCESS;
}
assert (op != NULL);
switch (op->o_tag) {
case LDAP_REQ_SEARCH:
- if (op->ors_filterstr.bv_len != 0) {
- free(op->ors_filterstr.bv_val);
- }
- if (op->ors_filter) {
- filter_free(op->ors_filter);
- }
- if (op->ors_attrs) {
- free(op->ors_attrs);
- }
break;
case LDAP_REQ_ADD:
if ( op->ora_modlist != NULL ) {
}
break;
case LDAP_REQ_MODRDN:
- if (op->orr_newrdn.bv_len > 0) {
- free(op->orr_newrdn.bv_val);
- }
- if (op->orr_nnewrdn.bv_len > 0) {
- free(op->orr_nnewrdn.bv_val);
- }
-
- if (op->orr_nnewSup != NULL ) {
- if (op->orr_nnewSup->bv_len > 0) {
- free(op->orr_nnewSup->bv_val);
- }
- free (op->orr_nnewSup);
- }
-
- if (op->orr_newSup != NULL ) {
- if (op->orr_newSup->bv_len > 0) {
- free(op->orr_newSup->bv_val);
- }
- free (op->orr_newSup);
- }
-
if ( op->orr_modlist != NULL ) {
slap_mods_free(op->orr_modlist, 1 );
}
break;
case LDAP_REQ_COMPARE:
- if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
- free(op->orc_ava->aa_value.bv_val);
- }
- free(op->orc_ava);
break;
case LDAP_REQ_DELETE:
break;
Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type" );
}
- if (op->o_ctrls != NULL) {
- asyncmeta_free_op_controls(op);
- }
- if (op->o_ndn.bv_len > 0) {
- free(op->o_ndn.bv_val);
- }
- if (op->o_dn.bv_len > 0) {
- free( op->o_dn.bv_val );
- }
- if (op->o_req_dn.bv_len > 0) {
- free(op->o_req_dn.bv_val);
- }
- if (op->o_req_dn.bv_len > 0) {
- free(op->o_req_ndn.bv_val);
- }
- free(op);
+ connection_op_finish( op );
+ slap_op_free( op, op->o_threadctx );
}
{
Operation *op = bc->op;
-#if 0
- bm_candidates_t *cl;
- a_metainfo_t *mi;
- int i = 0;
- if (bmc == NULL) {
- return;
- } else if (bmc->cl == NULL) {
- free(bmc);
- return;
- }
- cl = bmc->cl;
- op = cl->op;
- switch (op->o_tag) {
- case LDAP_REQ_SEARCH:
- break;
- case LDAP_REQ_ADD:
- if ( (bmc->mdn.bv_len != 0) &&
- (bmc->mdn.bv_val != op->o_req_dn.bv_val) ) {
- free( bmc->mdn.bv_val );
- }
-
- if (bmc->data.add_d.attrs != NULL ) {
- while (bmc->data.add_d.attrs[i] != NULL) {
- free( bmc->data.add_d.attrs[i]->mod_bvalues );
- free( bmc->data.add_d.attrs[i] );
- i++;
- }
- free( bmc->data.add_d.attrs );
- }
- break;
- case LDAP_REQ_MODIFY:
- if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
- free( bmc->mdn.bv_val );
- }
- if ( bmc->data.mod_d.modv != NULL ) {
- for ( i = 0; bmc->data.mod_d.modv[ i ]; i++ ) {
- free( bmc->data.mod_d.modv[ i ]->mod_bvalues );
- }
- }
- free( bmc->data.mod_d.mods );
- free( bmc->data.mod_d.modv );
-
- break;
- case LDAP_REQ_MODRDN:
- if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
- free( bmc->mdn.bv_val );
- }
-
- if ( bmc->data.modrdn_d.newSuperior.bv_len != 0 &&
- bmc->data.modrdn_d.newSuperior.bv_val != op->orr_newSup->bv_val )
- {
- free( bmc->data.modrdn_d.newSuperior.bv_val );
-
- }
-
- if ( bmc->data.modrdn_d.newrdn.bv_len != 0 &&
- bmc->data.modrdn_d.newrdn.bv_val != op->orr_newrdn.bv_val )
- {
- free( bmc->data.modrdn_d.newrdn.bv_val );
+ void *thrctx, *memctx;
+ int i;
- }
- break;
- case LDAP_REQ_COMPARE:
- if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
- free( bmc->mdn.bv_val );
- }
- if ( op->orc_ava->aa_value.bv_val != bmc->data.comp_d.mapped_value.bv_val ) {
- free( bmc->data.comp_d.mapped_value.bv_val );
+ if ( bc->bc_mc && bc->bc_mc->mc_info ) {
+ for (i = 0; i < bc->bc_mc->mc_info->mi_ntargets; i++) {
+ if (bc->candidates[ i ].sr_text != NULL) {
+ ch_free( (char *)bc->candidates[ i ].sr_text );
+ bc->candidates[ i ].sr_text = NULL;
}
- break;
- case LDAP_REQ_DELETE:
- if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
- free( bmc->mdn.bv_val );
}
- break;
- default:
- Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: other message type" );
}
- if (bmc->dc != NULL) {
- free (bmc->dc);
- }
- free(bmc);
- if (clear_cl > 0) {
- asyncmeta_free_candidate_list(cl, lock);
- Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: free_cl_list\n" );
- }
-#else
- asyncmeta_memctx_put(op->o_threadctx, op->o_tmpmemctx);
-#endif
+ if (op->o_conn->c_conn_idx == -1)
+ return;
+ memctx = op->o_tmpmemctx;
+ thrctx = op->o_threadctx;
+ while (op->o_bd == bc->copy_op.o_bd)
+ ldap_pvt_thread_yield();
+ asyncmeta_free_op(op);
+ asyncmeta_memctx_put(thrctx, memctx);
}
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc)
Debug( LDAP_DEBUG_TRACE, "add_message_queue: mc %p, pending_ops %d, max_pending %d\n",
mc, mc->pending_ops, max_pending_ops );
+ assert(bc->bc_mc == NULL);
if (mc->pending_ops >= max_pending_ops) {
return LDAP_BUSY;
}
+ bc->bc_mc = mc;
- LDAP_SLIST_INSERT_HEAD( &mc->mc_om_list, bc, bc_next);
+ slap_sl_mem_setctx(bc->op->o_threadctx, NULL);
+ LDAP_STAILQ_INSERT_TAIL( &mc->mc_om_list, bc, bc_next);
mc->pending_ops++;
return LDAP_SUCCESS;
}
+
void
asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc)
{
bm_context_t *om;
- int i;
- LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
+ LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om == bc) {
- for (i = 0; i < mc->mc_info->mi_ntargets; i++)
- {
- if (bc->msgids[i] >= 0) {
- mc->mc_conns[i].msc_pending_ops--;
- }
- }
- LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
mc->pending_ops--;
break;
}
}
+ assert(om == bc);
+ assert(bc->bc_mc == mc);
}
+
bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate)
{
bm_context_t *om;
- LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
- if (om->candidates[candidate].sr_msgid == msgid) {
+ LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
+ if (om->candidates[candidate].sr_msgid == msgid && !om->bc_invalid) {
break;
}
}
return om;
}
-
-
bm_context_t *
-asyncmeta_find_message_by_opmsguid (ber_int_t msgid, a_metaconn_t *mc, int remove)
+asyncmeta_bc_in_queue(a_metaconn_t *mc, bm_context_t *bc)
{
bm_context_t *om;
- LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
- if (om->op->o_msgid == msgid) {
- break;
+ LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
+ if (om == bc) {
+ return bc;
}
}
- if (remove && om) {
- LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
- mc->pending_ops--;
- }
- return om;
+ return NULL;
}
#include "ldap_rq.h"
#include "../../../libraries/liblber/lber-int.h"
+static void
+asyncmeta_send_ldap_result(bm_context_t *bc, Operation *op, SlapReply *rs)
+{
+ if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !bc->op->o_abandon ) {
+ send_ldap_result(&bc->copy_op, rs);
+ bc->op->o_callback = bc->copy_op.o_callback;
+ bc->op->o_extra = bc->copy_op.o_extra;
+ bc->op->o_ctrls = bc->copy_op.o_ctrls;
+ }
+}
+
static int
asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate)
{
a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- int i,found = 0;
+ int i;
SlapReply *candidates = bc->candidates;
for ( i = 0; i < mi->mi_ntargets; i++ ) {
if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
meta_search_candidate_t
asyncmeta_dobind_result(
- Operation *op,
- SlapReply *rs,
a_metaconn_t *mc,
int candidate,
- SlapReply *candidates,
+ SlapReply *bind_result,
LDAPMessage *res )
{
a_metainfo_t *mi = mc->mc_info;
assert( msc->msc_ldr != NULL );
+ if ( mi->mi_idle_timeout != 0 ) {
+ asyncmeta_set_msc_time(msc);
+ }
+
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%x] [%s] asyncmeta_dobind_result msc: %p, "
+ "msc->msc_binding_time: %x, msc->msc_flags:%x\n ",
+ (unsigned int)slap_get_time(), time_buf, msc,
+ (unsigned int)msc->msc_binding_time, msc->msc_mscflags );
+ }
/* FIXME: matched? referrals? response controls? */
rc = ldap_parse_result( msc->msc_ldr, res,
- &candidates[ candidate ].sr_err,
- NULL, NULL, NULL, NULL, 0 );
+ &(bind_result->sr_err),
+ (char **)&(bind_result->sr_matched),
+ (char **)&(bind_result->sr_text),
+ NULL, NULL, 0 );
+
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug,
+ "[%s] asyncmeta_dobind_result error=%d msc: %p\n",
+ time_buf,bind_result->sr_err, msc );
+ }
+
if ( rc != LDAP_SUCCESS ) {
- candidates[ candidate ].sr_err = rc;
+ bind_result->sr_err = rc;
}
- rc = slap_map_api2result( &candidates[ candidate ] );
+ rc = slap_map_api2result( bind_result );
LDAP_BACK_CONN_BINDING_CLEAR( msc );
if ( rc != LDAP_SUCCESS ) {
- candidates[ candidate ].sr_err = rc;
- if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) {
- asyncmeta_clear_one_msc(op, mc, candidate);
- retcode = META_SEARCH_ERR;
- rs->sr_err = rc;
- }
-
+ bind_result->sr_err = rc;
} else {
/* FIXME: check if bound as idassert authcDN! */
if ( BER_BVISNULL( &msc->msc_bound_ndn )
|| BER_BVISEMPTY( &msc->msc_bound_ndn ) )
{
LDAP_BACK_CONN_ISANON_SET( msc );
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result anonymous msc: %p\n",
+ time_buf, msc );
+ }
} else {
if ( META_BACK_TGT_SAVECRED( mt ) &&
{
ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc );
}
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result success msc: %p\n",
+ time_buf, msc );
+ }
LDAP_BACK_CONN_ISBOUND_SET( msc );
}
retcode = META_SEARCH_CANDIDATE;
-
- /* connect must be async */
- //ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
}
-
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- META_BINDING_CLEAR( &candidates[ candidate ] );
-
return retcode;
}
LDAPMessage *e )
{
a_metainfo_t *mi = mc->mc_info;
- struct berval a, mapped;
- int check_duplicate_attrs = 0;
+ struct berval a, mapped = BER_BVNULL;
int check_sorted_attrs = 0;
Entry ent = {0};
BerElement ber = *ldap_get_message_ber( e );
a_dncookie dc;
ber_len_t len;
int rc;
+ void *mem_mark;
+
+ mem_mark = slap_sl_mark( op->o_tmpmemctx );
+ ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
return LDAP_DECODING_ERROR;
/*
* Rewrite the dn of the result, if needed
*/
+ dc.op = op;
dc.target = mi->mi_targets[ target ];
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "searchResult";
-
- rs->sr_err = asyncmeta_dn_massage( &dc, &bdn, &dn );
- if ( rs->sr_err != LDAP_SUCCESS) {
- return rs->sr_err;
- }
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REP;
+ asyncmeta_dn_massage( &dc, &bdn, &dn );
/*
* Note: this may fail if the target host(s) schema differs
rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
op->o_tmpmemctx );
if ( dn.bv_val != bdn.bv_val ) {
- free( dn.bv_val );
+ op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
}
BER_BVZERO( &dn );
attrp = &ent.e_attrs;
- dc.ctx = "searchAttrDN";
while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
int last = 0;
slap_syntax_validate_func *validate;
break;
}
- asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at,
- &a, &mapped, BACKLDAP_REMAP );
- if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
- ( void )ber_scanf( &ber, "x" /* [W] */ );
- continue;
- }
- if ( mapped.bv_val != a.bv_val ) {
- /* will need to check for duplicate attrs */
- check_duplicate_attrs++;
- }
attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx );
- if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
+ if ( slap_bv2ad( &a, &attr->a_desc, &text )
!= LDAP_SUCCESS) {
- if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
+ if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
SLAP_AD_PROXIED ) != LDAP_SUCCESS )
{
- char buf[ SLAP_TEXT_BUFLEN ];
-
Debug(LDAP_DEBUG_ANY,
"%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n",
op->o_log_prefix, ent.e_name.bv_val,
pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
if ( !validate && !pretty ) {
- attr_clean( attr );
+ ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
op->o_tmpfree( attr, op->o_tmpmemctx );
goto next_attr;
}
- if ( attr->a_desc == slap_schema.si_ad_objectClass
- || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
- {
- struct berval *bv;
-
- for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
- ObjectClass *oc;
-
- asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
- bv, &mapped, BACKLDAP_REMAP );
- if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
-remove_oc:;
- free( bv->bv_val );
- BER_BVZERO( bv );
- if ( --last < 0 ) {
- break;
- }
- *bv = attr->a_vals[ last ];
- BER_BVZERO( &attr->a_vals[ last ] );
- bv--;
-
- } else if ( mapped.bv_val != bv->bv_val ) {
- int i;
-
- for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
- if ( &attr->a_vals[ i ] == bv ) {
- continue;
- }
-
- if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
- break;
- }
- }
-
- if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
- goto remove_oc;
- }
-
- ber_bvreplace( bv, &mapped );
-
- } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) {
- goto remove_oc;
-
- } else {
- ber_bvreplace( bv, &oc->soc_cname );
- }
- }
/*
* It is necessary to try to rewrite attributes with
* dn syntax because they might be used in ACLs as
* ACLs to the target directory server, and letting
* everything pass thru the ldap backend.
*/
- } else {
+ {
int i;
if ( attr->a_desc->ad_type->sat_syntax ==
asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals );
} else if ( attr->a_desc == slap_schema.si_ad_ref ) {
- asyncmeta_referral_result_rewrite( &dc, attr->a_vals, NULL );
+ asyncmeta_referral_result_rewrite( &dc, attr->a_vals );
}
if ( pretty ) {
rc = ordered_value_pretty( attr->a_desc,
- &attr->a_vals[i], &pval, NULL );
+ &attr->a_vals[i], &pval, op->o_tmpmemctx );
} else {
rc = ordered_value_validate( attr->a_desc,
}
if ( rc ) {
- ber_memfree( attr->a_vals[i].bv_val );
+ ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
if ( --last == i ) {
BER_BVZERO( &attr->a_vals[ i ] );
break;
}
if ( pretty ) {
- ber_memfree( attr->a_vals[i].bv_val );
+ ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
attr->a_vals[i] = pval;
}
}
if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
- attr_clean( attr );
+ ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
op->o_tmpfree( attr, op->o_tmpmemctx );
goto next_attr;
}
{
int i;
- attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
+ attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
for ( i = 0; i<last; i++ ) {
/* if normalizer fails, drop this value */
if ( ordered_value_normalize(
attr->a_desc,
attr->a_desc->ad_type->sat_equality,
&attr->a_vals[i], &attr->a_nvals[i],
- NULL )) {
- ber_memfree( attr->a_vals[i].bv_val );
+ op->o_tmpmemctx )) {
+ ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
if ( --last == i ) {
BER_BVZERO( &attr->a_vals[ i ] );
break;
}
BER_BVZERO( &attr->a_nvals[i] );
if ( last == 0 ) {
- attr_clean( attr );
+ ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
+ ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
op->o_tmpfree( attr, op->o_tmpmemctx );
goto next_attr;
}
next_attr:;
}
- /* only check if some mapping occurred */
- if ( check_duplicate_attrs ) {
- Attribute **ap;
-
- for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
- Attribute **tap;
-
- for ( tap = &(*ap)->a_next; *tap != NULL; ) {
- if ( (*tap)->a_desc == (*ap)->a_desc ) {
- Entry e = { 0 };
- Modification mod = { 0 };
- const char *text = NULL;
- char textbuf[ SLAP_TEXT_BUFLEN ];
- Attribute *next = (*tap)->a_next;
-
- BER_BVSTR( &e.e_name, "" );
- BER_BVSTR( &e.e_nname, "" );
- e.e_attrs = *ap;
- mod.sm_op = LDAP_MOD_ADD;
- mod.sm_desc = (*ap)->a_desc;
- mod.sm_type = mod.sm_desc->ad_cname;
- mod.sm_numvals = (*ap)->a_numvals;
- mod.sm_values = (*tap)->a_vals;
- if ( (*tap)->a_nvals != (*tap)->a_vals ) {
- mod.sm_nvalues = (*tap)->a_nvals;
- }
-
- (void)modify_add_values( &e, &mod,
- /* permissive */ 1,
- &text, textbuf, sizeof( textbuf ) );
-
- /* should not insert new attrs! */
- assert( e.e_attrs == *ap );
-
- attr_clean( *tap );
- op->o_tmpfree( *tap, op->o_tmpmemctx );
- *tap = next;
-
- } else {
- tap = &(*tap)->a_next;
- }
- }
- }
- }
-
/* Check for sorted attributes */
if ( check_sorted_attrs ) {
for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
/* Strip duplicate values */
if ( attr->a_nvals != attr->a_vals )
- ber_memfree( attr->a_nvals[i].bv_val );
- ber_memfree( attr->a_vals[i].bv_val );
+ ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx );
+ ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
attr->a_numvals--;
if ( (unsigned)i < attr->a_numvals ) {
attr->a_vals[i] = attr->a_vals[attr->a_numvals];
ldap_controls_free( rs->sr_ctrls );
rs->sr_ctrls = NULL;
}
+#if 0
while ( ent.e_attrs ) {
attr = ent.e_attrs;
ent.e_attrs = attr->a_next;
- attr_clean( attr );
+ if ( attr->a_nvals != attr->a_vals )
+ ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
+ ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
op->o_tmpfree( attr, op->o_tmpmemctx );
}
+ if (ent.e_name.bv_val != NULL) {
+ op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
+ }
+
+ if (ent.e_nname.bv_val != NULL) {
+ op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
+ }
if (rs->sr_entry && rs->sr_entry != &ent) {
entry_free( rs->sr_entry );
}
+#endif
+ slap_sl_release( mem_mark, op->o_tmpmemctx );
rs->sr_entry = NULL;
rs->sr_attrs = NULL;
return rc;
}
-int
+static void
asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, int sres)
{
a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
Operation *op = bc->op;
SlapReply *rs = &bc->rs;
- int rc, i;
+ int i;
SlapReply *candidates = bc->candidates;
char *matched = NULL;
}
} else if ( sres == LDAP_NO_SUCH_OBJECT ) {
- matched = op->o_bd->be_suffix[ 0 ].bv_val;
+ matched = mi->mi_suffix.bv_val;
}
/*
}
}
Debug( LDAP_DEBUG_TRACE,
- "%s asyncmeta_search_last_result(\"%s\"): "
+ "%s asyncmeta_search_last_result(\"%d\"): "
".\n",
- op->o_log_prefix, 0 );
+ op->o_log_prefix, candidate );
rs->sr_err = sres;
rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
+ rs->sr_text = ( sres == LDAP_SUCCESS ? NULL : candidates[candidate].sr_text );
rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
- send_ldap_result(op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
+ rs->sr_text = NULL;
rs->sr_matched = NULL;
rs->sr_ref = NULL;
}
+static meta_search_candidate_t
+asyncmeta_send_pending_op(bm_context_t *bc, int candidate)
+{
+ meta_search_candidate_t retcode;
+ switch (bc->op->o_tag) {
+ case LDAP_REQ_SEARCH:
+ retcode = asyncmeta_back_search_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, NULL, 0 , 0);
+ break;
+ case LDAP_REQ_ADD:
+ retcode = asyncmeta_back_add_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
+ break;
+ case LDAP_REQ_MODIFY:
+ retcode = asyncmeta_back_modify_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
+ break;
+ case LDAP_REQ_MODRDN:
+ retcode = asyncmeta_back_modrdn_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
+ break;
+ case LDAP_REQ_COMPARE:
+ retcode = asyncmeta_back_compare_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
+ break;
+ case LDAP_REQ_DELETE:
+ retcode = asyncmeta_back_delete_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
+ break;
+ default:
+ retcode = META_SEARCH_NOT_CANDIDATE;
+ }
+ return retcode;
+}
-int
-asyncmeta_search_finish(a_metaconn_t *mc, bm_context_t *bc, int candidate, char *matched)
+
+meta_search_candidate_t
+asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock)
{
a_metainfo_t *mi = mc->mc_info;
- a_metatarget_t *mt = mi->mi_targets[ candidate ];
- Operation *op = bc->op;
- SlapReply *rs = &bc->rs;
- SlapReply *candidates = bc->candidates;
- int i;
- int do_taint = 0;
- if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
- op->o_tmpfree( matched, op->o_tmpmemctx );
- }
+ bm_context_t *bc, *onext;
+ a_metasingleconn_t *msc = &mc->mc_conns[candidate];
- if ( rs->sr_v2ref ) {
- ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx );
- }
+ if ( dolock )
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- for ( i = 0; i < mi->mi_ntargets; i++ ) {
- if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
+ msc->msc_active++;
+ for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
+ meta_search_candidate_t ret;
+ onext = LDAP_STAILQ_NEXT(bc, bc_next);
+ if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) {
continue;
}
-
- if ( META_IS_BINDING( &candidates[ i ] )
- || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
- {
- if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
- || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
- {
- assert( candidates[ i ].sr_msgid >= 0
- || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
- assert( mc->mc_conns[ i ].msc_ldr != NULL );
-
-#ifdef DEBUG_205
- Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_finish "
- "ldap_unbind_ext[%ld] ld=%p\n",
- op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ldr );
-#endif /* DEBUG_205 */
-
- }
- META_BINDING_CLEAR( &candidates[ i ] );
-
- } else if ( candidates[ i ].sr_msgid >= 0 ) {
- (void)asyncmeta_back_cancel( mc, op,
- candidates[ i ].sr_msgid, i );
+ bc->op->o_threadctx = ctx;
+ bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
+ slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
+ bc->bc_active++;
+ ret = asyncmeta_send_pending_op(bc, candidate);
+ if (ret != META_SEARCH_CANDIDATE) {
+ bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ bc->candidates[ candidate ].sr_type = REP_RESULT;
+ bc->candidates[ candidate ].sr_err = bc->rs.sr_err;
+ if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) ||
+ (asyncmeta_is_last_result(mc, bc, candidate) == 0)) {
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+ mc->pending_ops--;
+ asyncmeta_send_ldap_result(bc, bc->op, &bc->rs);
+ asyncmeta_clear_bm_context(bc);
}
-
- if ( candidates[ i ].sr_matched ) {
- free( (char *)candidates[ i ].sr_matched );
- candidates[ i ].sr_matched = NULL;
+ } else {
+ bc->bc_active--;
}
+ }
+ msc->msc_active--;
- if ( candidates[ i ].sr_text ) {
- ldap_memfree( (char *)candidates[ i ].sr_text );
- candidates[ i ].sr_text = NULL;
- }
+ if ( dolock )
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- if ( candidates[ i ].sr_ref ) {
- ber_bvarray_free( candidates[ i ].sr_ref );
- candidates[ i ].sr_ref = NULL;
- }
+ return META_SEARCH_CANDIDATE;
+}
- if ( candidates[ i ].sr_ctrls ) {
- ldap_controls_free( candidates[ i ].sr_ctrls );
- candidates[ i ].sr_ctrls = NULL;
- }
+meta_search_candidate_t
+asyncmeta_return_bind_errors(a_metaconn_t *mc, int candidate, SlapReply *bind_result, void *ctx, int dolock)
+{
+ a_metainfo_t *mi = mc->mc_info;
+ bm_context_t *bc, *onext;
+
+ if ( dolock )
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
- asyncmeta_quarantine( op, mi, &candidates[ i ], i );
+ for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
+ onext = LDAP_STAILQ_NEXT(bc, bc_next);
+ if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND
+ || bc->bc_active > 0 || bc->op->o_abandon > 0) {
+ continue;
}
- /* this remains as it is only for explicitly bound connections, for the time being */
- /* only in case of timelimit exceeded, if the timelimit exceeded because
- * one contacted target never responded, invalidate the connection
- * NOTE: should we quarantine the target as well? right now, the connection
- * is invalidated; the next time it will be recreated and the target
- * will be quarantined if it cannot be contacted */
- if ( mi->mi_idle_timeout != 0
- && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
- && op->o_time > mc->mc_conns[ i ].msc_time )
- {
- /* don't let anyone else use this expired connection */
- do_taint++;
+ bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ bc->candidates[ candidate ].sr_type = REP_RESULT;
+ bc->candidates[ candidate ].sr_err = bind_result->sr_err;
+ if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) ||
+ (asyncmeta_is_last_result(mc, bc, candidate) == 0)) {
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+ bc->op->o_threadctx = ctx;
+ bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
+ slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
+ bc->rs.sr_err = bind_result->sr_err;
+ bc->rs.sr_text = bind_result->sr_text;
+ mc->pending_ops--;
+ asyncmeta_send_ldap_result(bc, bc->op, &bc->rs);
+ asyncmeta_clear_bm_context(bc);
}
}
- if ( mc && do_taint) {
- LDAP_BACK_CONN_TAINTED_SET( mc );
- }
+ if ( dolock )
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- return rs->sr_err;
+ return META_SEARCH_CANDIDATE;
}
-
-int
-asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate)
+static meta_search_candidate_t
+asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, int candidate, void *ctx)
{
meta_search_candidate_t retcode;
- a_metainfo_t *mi;
- a_metatarget_t *mt;
- Operation *op;
- SlapReply *rs;
- int rc;
- SlapReply *candidates;
-
- mi = mc->mc_info;
- mt = mi->mi_targets[ candidate ];
- op = bc->op;
- rs = &bc->rs;
- candidates = bc->candidates;
- Debug( LDAP_DEBUG_TRACE,
- "%s asyncmeta_handle_bind_result[%d]\n",
- op->o_log_prefix, candidate );
- retcode = asyncmeta_dobind_result( op, rs, mc, candidate, candidates, msg );
+ SlapReply bind_result = {0};
+ /* could modify the msc, safer to lock it */
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ retcode = asyncmeta_dobind_result( mc, candidate, &bind_result, msg );
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
if ( retcode == META_SEARCH_CANDIDATE ) {
- switch (op->o_tag) {
- case LDAP_REQ_SEARCH:
- retcode = asyncmeta_back_search_start( op, rs, mc, bc, candidate, NULL, 0 );
- break;
- case LDAP_REQ_ADD:
- retcode = asyncmeta_back_add_start( op, rs, mc, bc, candidate);
- break;
- case LDAP_REQ_MODIFY:
- retcode = asyncmeta_back_modify_start( op, rs, mc, bc, candidate);
- break;
- case LDAP_REQ_MODRDN:
- retcode = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate);
- break;
- case LDAP_REQ_COMPARE:
- retcode = asyncmeta_back_compare_start( op, rs, mc, bc, candidate);
- break;
- case LDAP_REQ_DELETE:
- retcode = asyncmeta_back_delete_start( op, rs, mc, bc, candidate);
- break;
- default:
- retcode = META_SEARCH_NOT_CANDIDATE;
- }
- }
-
- switch ( retcode ) {
- case META_SEARCH_CANDIDATE:
- break;
- /* means that failed but onerr == continue */
- case META_SEARCH_NOT_CANDIDATE:
- case META_SEARCH_ERR:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- candidates[ candidate ].sr_err = rs->sr_err;
- if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) {
- send_ldap_result(op, rs);
- }
- if (op->o_tag != LDAP_REQ_SEARCH) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- asyncmeta_drop_bc( mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- asyncmeta_clear_bm_context(bc);
- return retcode;
- }
- break;
- default:
- assert( 0 );
- break;
+ /* send the remaining pending ops */
+ asyncmeta_send_all_pending_ops(mc, candidate, ctx, 1);
+ } else {
+ asyncmeta_return_bind_errors(mc, candidate, &bind_result, ctx, 1);
}
- bc->bc_active = 0;
return retcode;
}
a_metainfo_t *mi;
a_metatarget_t *mt;
a_metasingleconn_t *msc;
- Operation op;
+ Operation *op = bc->op;
SlapReply *rs;
- int i, j, rc, sres;
+ int i, rc = LDAP_SUCCESS, sres;
SlapReply *candidates;
char **references = NULL;
LDAPControl **ctrls = NULL;
LDAPMessage *msg;
ber_int_t id;
- op = *bc->op;
rs = &bc->rs;
mi = mc->mc_info;
mt = mi->mi_targets[ candidate ];
msc = &mc->mc_conns[ candidate ];
+ dc.op = op;
dc.target = mt;
- dc.conn = op.o_conn;
- dc.rs = rs;
+ dc.to_from = MASSAGE_REP;
id = ldap_msgid(res);
+
candidates = bc->candidates;
i = candidate;
- while (res) {
+ while (res && !META_BACK_CONN_INVALID(msc)) {
for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
switch(ldap_msgtype(msg)) {
case LDAP_RES_SEARCH_ENTRY:
Debug( LDAP_DEBUG_TRACE,
"%s asyncmeta_handle_search_msg: msc %p entry\n",
- op.o_log_prefix, msc );
+ op->o_log_prefix, msc );
if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
/* don't retry any more... */
candidates[ i ].sr_type = REP_RESULT;
}
/* count entries returned by target */
candidates[ i ].sr_nentries++;
- rs->sr_err = asyncmeta_send_entry( &op, rs, mc, i, msg );
+ if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) {
+ rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg );
+ } else {
+ goto err_cleanup;
+ }
switch ( rs->sr_err ) {
case LDAP_SIZELIMIT_EXCEEDED:
- send_ldap_result(&op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
rs->sr_err = LDAP_SUCCESS;
goto err_cleanup;
case LDAP_UNAVAILABLE:
rs->sr_err = LDAP_OTHER;
+ break;
+ default:
+ break;
}
bc->is_ok++;
break;
case LDAP_RES_SEARCH_REFERENCE:
- if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) {
+ if ( META_BACK_TGT_NOREFS( mt ) ) {
rs->sr_err = LDAP_OTHER;
- send_ldap_result(&op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
goto err_cleanup;
}
if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
if ( rc != LDAP_SUCCESS || references == NULL ) {
rs->sr_err = LDAP_OTHER;
- send_ldap_result(&op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
goto err_cleanup;
}
;
rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
- op.o_tmpmemctx );
+ op->o_tmpmemctx );
for ( cnt = 0; references[ cnt ]; cnt++ ) {
ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
- op.o_tmpmemctx );
+ op->o_tmpmemctx );
}
BER_BVZERO( &rs->sr_ref[ cnt ] );
}
{
- dc.ctx = "referralDN";
- ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref,
- op.o_tmpmemctx );
+ dc.memctx = op->o_tmpmemctx;
+ ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref );
}
if ( rs->sr_ref != NULL ) {
if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
/* ignore return value by now */
- ( void )send_search_reference( &op, rs );
+ ( void )send_search_reference( op, rs );
}
- ber_bvarray_free_x( rs->sr_ref, op.o_tmpmemctx );
+ ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
rs->sr_ref = NULL;
}
if ( rs->sr_err != LDAP_SUCCESS ) {
candidates[ i ].sr_type = REP_RESULT;
rs->sr_err = LDAP_OTHER;
- send_ldap_result(&op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
goto err_cleanup;
}
- slap_send_ldap_intermediate( &op, rs );
+ slap_send_ldap_intermediate( op, rs );
if ( rs->sr_rspoid != NULL ) {
ber_memfree( (char *)rs->sr_rspoid );
break;
case LDAP_RES_SEARCH_RESULT:
+ if ( mi->mi_idle_timeout != 0 ) {
+ asyncmeta_set_msc_time(msc);
+ }
Debug( LDAP_DEBUG_TRACE,
- "%s asyncmeta_handle_search_msg: msc %p result\n",
- op.o_log_prefix, msc );
+ "%s asyncmeta_handle_search_msg: msc %p result\n",
+ op->o_log_prefix, msc );
candidates[ i ].sr_type = REP_RESULT;
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
/* NOTE: ignores response controls
0, 0, &match );
candidates[ i ].sr_matched = NULL;
- dc.ctx = "matchedDN";
- dc.target = mi->mi_targets[ i ];
- if ( !asyncmeta_dn_massage( &dc, &match, &mmatch ) ) {
- if ( mmatch.bv_val == match.bv_val ) {
- candidates[ i ].sr_matched
- = ch_strdup( mmatch.bv_val );
-
- } else {
- candidates[ i ].sr_matched = mmatch.bv_val;
- }
+ dc.memctx = NULL;
+ asyncmeta_dn_massage( &dc, &match, &mmatch );
+ if ( mmatch.bv_val == match.bv_val ) {
+ candidates[ i ].sr_matched
+ = ch_strdup( mmatch.bv_val );
- bc->candidate_match++;
+ } else {
+ candidates[ i ].sr_matched = mmatch.bv_val;
}
+
+ bc->candidate_match++;
ldap_memfree( match.bv_val );
}
Debug( LDAP_DEBUG_ANY,
"%s asncmeta_search_result[%d]: "
"got referrals with err=%d\n",
- op.o_log_prefix,
+ op->o_log_prefix,
i, rs->sr_err );
} else {
;
sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
- op.o_tmpmemctx );
+ op->o_tmpmemctx );
for ( cnt = 0; references[ cnt ]; cnt++ ) {
ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
- op.o_tmpmemctx );
+ op->o_tmpmemctx );
}
BER_BVZERO( &sr_ref[ cnt ] );
- ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref,
- op.o_tmpmemctx );
+ dc.memctx = op->o_tmpmemctx;
+ ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref );
if ( rs->sr_v2ref == NULL ) {
rs->sr_v2ref = sr_ref;
} else {
for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
- op.o_tmpmemctx );
+ op->o_tmpmemctx );
}
- ber_memfree_x( sr_ref, op.o_tmpmemctx );
+ ber_memfree_x( sr_ref, op->o_tmpmemctx );
}
}
} else if ( rs->sr_err == LDAP_REFERRAL ) {
- Debug( LDAP_DEBUG_ANY,
+ Debug( LDAP_DEBUG_TRACE,
"%s asyncmeta_search_result[%d]: "
"got err=%d with null "
"or empty referrals\n",
- op.o_log_prefix,
+ op->o_log_prefix,
i, rs->sr_err );
rs->sr_err = LDAP_NO_SUCH_OBJECT;
sres = slap_map_api2result( rs );
- if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
- char buf[ SLAP_TEXT_BUFLEN ];
- snprintf( buf, sizeof( buf ),
- "%s asyncmeta_search_result[%ld] "
- "match=\"%s\" err=%d",
- op.o_log_prefix, i,
- candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
- (long) candidates[ i ].sr_err );
- if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_TRACE, "%s.\n", buf );
-
- } else {
- Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
- buf, ldap_err2string( candidates[ i ].sr_err ) );
- }
+ if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] "
+ "match=\"%s\" err=%ld",
+ op->o_log_prefix, i,
+ candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
+ (long) candidates[ i ].sr_err );
+ } else {
+ Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_result[%d] "
+ "match=\"%s\" err=%ld (%s)",
+ op->o_log_prefix, i,
+ candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
+ (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) );
}
switch ( sres ) {
struct berval prcookie;
/* unsolicited, do not accept */
- if ( mi->mi_targets[i]->mt_ps == 0 ) {
+ if ( mt->mt_ps == 0 ) {
rs->sr_err = LDAP_OTHER;
goto err_pr;
}
/* more pages? new search request */
if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
- if ( mi->mi_targets[i]->mt_ps > 0 ) {
+ if ( mt->mt_ps > 0 ) {
/* ignore size if specified */
prsize = 0;
assert( candidates[ i ].sr_text == NULL );
assert( candidates[ i ].sr_ref == NULL );
- switch ( asyncmeta_back_search_start( &op, rs, mc, bc, i, &prcookie, prsize ) )
+ switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) )
{
case META_SEARCH_CANDIDATE:
assert( candidates[ i ].sr_msgid >= 0 );
// goto free_message;
case META_SEARCH_ERR:
+ case META_SEARCH_NEED_BIND:
err_pr:;
candidates[ i ].sr_err = rs->sr_err;
candidates[ i ].sr_type = REP_RESULT;
if ( META_BACK_ONERR_STOP( mi ) ) {
- send_ldap_result(&op, rs);
+ asyncmeta_send_ldap_result(bc, op, rs);
ldap_controls_free( ctrls );
goto err_cleanup;
}
* than what requested by the proxy;
* ignore it */
candidates[ i ].sr_err = rs->sr_err;
- if ( rs->sr_nentries == op.ors_slimit
+ if ( rs->sr_nentries == op->ors_slimit
|| META_BACK_ONERR_STOP( mi ) )
{
const char *save_text;
got_err:
save_text = rs->sr_text;
rs->sr_text = candidates[ i ].sr_text;
- send_ldap_result(&op, rs);
- ch_free( candidates[ i ].sr_text );
- candidates[ i ].sr_text = NULL;
+ asyncmeta_send_ldap_result(bc, op, rs);
+ if (candidates[ i ].sr_text != NULL) {
+ ch_free( (char *)candidates[ i ].sr_text );
+ candidates[ i ].sr_text = NULL;
+ }
rs->sr_text = save_text;
ldap_controls_free( ctrls );
goto err_cleanup;
if (asyncmeta_is_last_result(mc, bc, i) == 0) {
Debug( LDAP_DEBUG_TRACE,
"%s asyncmeta_handle_search_msg: msc %p last result\n",
- op.o_log_prefix, msc );
+ op->o_log_prefix, msc );
asyncmeta_search_last_result(mc, bc, i, sres);
err_cleanup:
rc = rs->sr_err;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
asyncmeta_drop_bc( mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
asyncmeta_clear_bm_context(bc);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
ldap_msgfree(res);
return rc;
}
if (candidates[ i ].sr_type != REP_RESULT) {
struct timeval tv = {0};
rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
+ if (res != NULL) {
+ msc->msc_result_time = slap_get_time();
+ }
}
}
- bc->bc_active = 0;
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ bc->bc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return rc;
}
rs->sr_ctrls = NULL;
/* only touch when activity actually took place... */
- if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
- msc->msc_time = op->o_time;
+ if ( mi->mi_idle_timeout != 0 ) {
+ asyncmeta_set_msc_time(msc);
}
rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err,
rs->sr_matched = matched;
}
- if ( rs->sr_err == LDAP_UNAVAILABLE ) {
- if ( !( bc->sendok & LDAP_BACK_RETRYING ) ) {
- if ( op->o_conn && ( bc->sendok & LDAP_BACK_SENDERR ) ) {
- if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
- send_ldap_result( op, rs );
+ if ( rs->sr_err == LDAP_UNAVAILABLE || rs->sr_err == LDAP_SERVER_DOWN ) {
+ if ( rs->sr_text == NULL ) {
+ rs->sr_text = "Target is unavailable";
}
- }
+ }
- } else if ( op->o_conn &&
- ( ( ( bc->sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
- || ( ( bc->sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
- {
- send_ldap_result( op, rs );
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ asyncmeta_drop_bc( mc, bc);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+
+ if ( op->o_conn ) {
+ asyncmeta_send_ldap_result(bc, op, rs);
}
+
if ( matched ) {
op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
}
rs->sr_ctrls = save_ctrls;
rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err);
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- asyncmeta_drop_bc( mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
asyncmeta_clear_bm_context(bc);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return rc;
}
/* This takes care to clean out the outbound queue in case we have a read error
* sending back responses to the client */
int
-asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error)
+asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx)
{
bm_context_t *bc, *onext;
- int rc, cleanup;
+ int cleanup;
Operation *op;
SlapReply *rs;
SlapReply *candidates;
/* no outstanding ops, nothing to do but log */
- Debug( LDAP_DEBUG_ANY,
- "asyncmeta_op_read_error: %x\n",
- error );
-#if 0
- if (mc->mc_conns[candidate].conn) {
- Connection *conn = mc->mc_conns[candidate].conn;
- mc->mc_conns[candidate].conn = NULL;
- connection_client_stop(conn);
- }
-#endif
+ Debug( LDAP_DEBUG_TRACE,
+ "asyncmeta_op_read_error: ldr=%p\n",
+ mc->mc_conns[candidate].msc_ldr );
+
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- asyncmeta_clear_one_msc(NULL, mc, candidate);
+ /*someone may be trying to write */
+ if (mc->mc_conns[candidate].msc_active <= 1) {
+ asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ } else {
+ META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]);
+ }
+
if (mc->pending_ops <= 0) {
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
return LDAP_SUCCESS;
}
- for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) {
- onext = LDAP_SLIST_NEXT(bc, bc_next);
+ for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
+ onext = LDAP_STAILQ_NEXT(bc, bc_next);
cleanup = 0;
candidates = bc->candidates;
/* was this op affected? */
if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) )
continue;
- if (bc->op->o_abandon == 1) {
+ if (bc->op->o_abandon) {
+ bc->bc_invalid = 1;
continue;
}
+ if (bc->bc_active > 0) {
+ continue;
+ }
+
+ bc->op->o_threadctx = ctx;
+ bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
+ slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
+
op = bc->op;
rs = &bc->rs;
switch (op->o_tag) {
case LDAP_REQ_COMPARE:
case LDAP_REQ_DELETE:
rs->sr_err = LDAP_UNAVAILABLE;
- send_ldap_error( op, rs, rs->sr_err , "Read error on connection to target" );
+ rs->sr_text = "Read error on connection to target";
+ asyncmeta_send_ldap_result( bc, op, rs );
cleanup = 1;
break;
case LDAP_REQ_SEARCH:
{
a_metainfo_t *mi = mc->mc_info;
rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Read error on connection to target";
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
candidates[ candidate ].sr_type = REP_RESULT;
- if ( META_BACK_ONERR_STOP( mi ) ||
- asyncmeta_is_last_result(mc, bc, candidate) && op->o_conn) {
- send_ldap_error(op, rs, rs->sr_err, "Read error on connection to target");
+ if ( (META_BACK_ONERR_STOP( mi ) ||
+ asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) {
+ asyncmeta_send_ldap_result( bc, op, rs );
cleanup = 1;
}
}
for (j=0; j<mi->mi_ntargets; j++) {
if (j != candidate && bc->candidates[j].sr_msgid >= 0
&& mc->mc_conns[j].msc_ld != NULL) {
- asyncmeta_back_abandon_candidate( mc, op,
- bc->candidates[ j ].sr_msgid, j );
+ asyncmeta_back_cancel( mc, op,
+ bc->candidates[ j ].sr_msgid, j );
}
}
- asyncmeta_drop_bc( mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+ mc->pending_ops--;
asyncmeta_clear_bm_context(bc);
}
}
asyncmeta_op_handle_result(void *ctx, void *arg)
{
a_metaconn_t *mc = arg;
- int i, j, rc, ntargets, processed;
+ int i, j, rc, ntargets;
struct timeval tv = {0};
LDAPMessage *msg;
a_metasingleconn_t *msc;
oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); /* get existing memctx */
again:
- processed = 0;
for (j=0; j<ntargets; j++) {
i++;
if (i >= ntargets) i = 0;
- if (!mc->mc_conns[i].msc_ldr || mc->mc_conns[i].msc_pending_ops <= 0) continue;
- rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
msc = &mc->mc_conns[i];
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ if (!mc->mc_conns[i].msc_ldr ||
+ META_BACK_CONN_CREATING( &mc->mc_conns[i] ) ||
+ META_BACK_CONN_INVALID(&mc->mc_conns[i])) {
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ continue;
+ }
+
+ msc->msc_active++;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+
+ rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
if (rc < 1) {
if (rc < 0) {
- asyncmeta_op_read_error(mc, i, rc);
+ ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc);
+ asyncmeta_op_read_error(mc, i, rc, ctx);
+ }
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ msc->msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ continue;
+ }
+ rc = ldap_msgtype( msg );
+ if (rc == LDAP_RES_BIND) {
+ if ( LogTest( asyncmeta_debug ) ) {
+ char time_buf[ SLAP_TEXT_BUFLEN ];
+ asyncmeta_get_timestamp(time_buf);
+ Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n",
+ time_buf, ldap_msgid(msg), msc );
}
+ asyncmeta_handle_bind_result(msg, mc, i, ctx);
+ mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
+ msc->msc_result_time = slap_get_time();
+ msc->msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ if (msg)
+ ldap_msgfree(msg);
+
continue;
}
- Debug(LDAP_DEBUG_TRACE, "asyncmeta_op_handle_result: got msgid %d on msc %p\n",
- ldap_msgid(msg), msc );
+retry_bc:
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
bc = asyncmeta_find_message(ldap_msgid(msg), mc, i);
+/* The sender might not be yet done with the context. On error it might also remove it
+ * so it's best to try and find it again after a wait */
+ if (bc && bc->bc_active > 0) {
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_bc;
+ }
+ if (bc) {
+ bc->bc_active++;
+ }
- if (bc)
- bc->bc_active = 1;
+ msc->msc_result_time = slap_get_time();
+ msc->msc_active--;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
if (!bc) {
- Debug( LDAP_DEBUG_ANY,
- "asyncmeta_op_handle_result: Unable to find bc for msguid %d\n", ldap_msgid(msg) );
+ Debug( asyncmeta_debug,
+ "asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc );
ldap_msgfree(msg);
continue;
}
bc->op->o_threadctx = ctx;
bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
- if (bc->op->o_abandon == 1) {
+ if (bc->op->o_abandon) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
asyncmeta_drop_bc( mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+ if ( bc->op->o_tag == LDAP_REQ_SEARCH ) {
+ int j;
+ for (j=0; j<ntargets; j++) {
+ if (bc->candidates[j].sr_msgid >= 0) {
+ a_metasingleconn_t *tmp_msc = &mc->mc_conns[j];
+ tmp_msc->msc_active++;
+ asyncmeta_back_cancel( mc, bc->op,
+ bc->candidates[ j ].sr_msgid, j );
+ tmp_msc->msc_active--;
+ }
+ }
+ }
asyncmeta_clear_bm_context(bc);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
if (msg)
ldap_msgfree(msg);
continue;
}
- rc = ldap_msgtype( msg );
switch (rc) {
- case LDAP_RES_BIND:
- asyncmeta_handle_bind_result(msg, mc, bc, i);
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- LDAP_SLIST_FOREACH( bc, &mc->mc_om_list, bc_next ) {
- if (bc->candidates[i].sr_msgid == META_MSGID_NEED_BIND) {
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- asyncmeta_handle_bind_result(msg, mc, bc, i);
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- }
- }
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
- msc->msc_timeout_ops = 0;
- mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
- break;
case LDAP_RES_SEARCH_ENTRY:
case LDAP_RES_SEARCH_REFERENCE:
case LDAP_RES_SEARCH_RESULT:
case LDAP_RES_INTERMEDIATE:
asyncmeta_handle_search_msg(msg, mc, bc, i);
- msc->msc_timeout_ops = 0;
mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
msg = NULL;
break;
case LDAP_RES_COMPARE:
case LDAP_RES_MODIFY:
rc = asyncmeta_handle_common_result(msg, mc, bc, i);
- msc->msc_timeout_ops = 0;
mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
break;
default:
- Debug( LDAP_DEBUG_ANY,
- "asyncmeta_op_handle_result: "
- "unrecognized response message tag=%d\n",
- rc );
+ {
+ Debug( asyncmeta_debug,
+ "asyncmeta_op_handle_result: "
+ "unrecognized response message tag=%d\n",
+ rc );
+
+ }
}
if (msg)
ldap_msgfree(msg);
}
slap_sl_mem_setctx(ctx, oldctx);
if (mc->mc_conns) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
for (i=0; i<ntargets; i++)
if (mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn)
connection_client_enable(mc->mc_conns[i].conn);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
}
return NULL;
}
{
struct re_s* rtask = arg;
a_metainfo_t *mi = rtask->arg;
- a_metaconn_t *mc;
bm_context_t *bc, *onext;
time_t current_time = slap_get_time();
int i, j;
+ LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list;
+ LDAP_STAILQ_INIT( &timeout_list );
+ Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
+ void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
for (i=0; i<mi->mi_num_conns; i++) {
- mc = &mi->mi_conns[i];
+ a_metaconn_t * mc= &mi->mi_conns[i];
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
- for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) {
- onext = LDAP_SLIST_NEXT(bc, bc_next);
- if (!bc->bc_active && bc->timeout && bc->stoptime <= current_time) {
+ for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
+ onext = LDAP_STAILQ_NEXT(bc, bc_next);
+ if (bc->bc_active > 0) {
+ continue;
+ }
+
+ if (bc->op->o_abandon ) {
+ /* set our memctx */
+ bc->op->o_threadctx = ctx;
+ bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
+ slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
Operation *op = bc->op;
- SlapReply *rs = &bc->rs;
- int timeout_err;
- const char *timeout_text;
- LDAP_SLIST_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
mc->pending_ops--;
+ for (j=0; j<mi->mi_ntargets; j++) {
+ if (bc->candidates[j].sr_msgid >= 0) {
+ a_metasingleconn_t *msc = &mc->mc_conns[j];
+ if ( op->o_tag == LDAP_REQ_SEARCH ) {
+ msc->msc_active++;
+ asyncmeta_back_cancel( mc, op,
+ bc->candidates[ j ].sr_msgid, j );
+ msc->msc_active--;
+ }
+ }
+ }
+ asyncmeta_clear_bm_context(bc);
+ continue;
+ }
+ if (bc->bc_invalid) {
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+ mc->pending_ops--;
+ LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
+ continue;
+ }
+
+ if (bc->timeout && bc->stoptime < current_time) {
+ Operation *op = bc->op;
+ LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
+ mc->pending_ops--;
+ LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
+ for (j=0; j<mi->mi_ntargets; j++) {
+ if (bc->candidates[j].sr_msgid >= 0) {
+ a_metasingleconn_t *msc = &mc->mc_conns[j];
+ asyncmeta_set_msc_time(msc);
+ if ( op->o_tag == LDAP_REQ_SEARCH ) {
+ msc->msc_active++;
+ asyncmeta_back_cancel( mc, op,
+ bc->candidates[ j ].sr_msgid, j );
+ msc->msc_active--;
+ }
+ }
+ }
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
+
+ for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) {
+ Operation *op = bc->op;
+ SlapReply *rs = &bc->rs;
+ int timeout_err;
+ const char *timeout_text;
+
+ onext = LDAP_STAILQ_NEXT(bc, bc_next);
+ LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next);
+ /* set our memctx */
+ bc->op->o_threadctx = ctx;
+ bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
+ slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
+
+ if (bc->searchtime) {
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ } else {
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ }
+
+ if ( bc->bc_invalid ) {
+ timeout_text = "Operation is invalid - target connection has been reset";
+ } else {
+ a_metasingleconn_t *log_msc = &mc->mc_conns[0];
+ Debug( asyncmeta_debug,
+ "asyncmeta_timeout_loop:Timeout op %s loop[%p], "
+ "current_time:%ld, op->o_time:%ld msc: %p, "
+ "msc->msc_binding_time: %x, msc->msc_flags:%x \n",
+ bc->op->o_log_prefix, rtask, current_time, bc->op->o_time,
+ log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags );
if (bc->searchtime) {
- timeout_err = LDAP_TIMELIMIT_EXCEEDED;
timeout_text = NULL;
} else {
- timeout_err = op->o_protocol >= LDAP_VERSION3 ?
- LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
timeout_text = "Operation timed out";
}
+
for (j=0; j<mi->mi_ntargets; j++) {
if (bc->candidates[j].sr_msgid >= 0) {
- a_metasingleconn_t *msc = &mc->mc_conns[j];
a_metatarget_t *mt = mi->mi_targets[j];
- msc->msc_timeout_ops++;
- if (bc->msgids[j] >= 0) {
- msc->msc_pending_ops--;
- }
- asyncmeta_back_cancel( mc, op,
- bc->candidates[ j ].sr_msgid, j );
if (!META_BACK_TGT_QUARANTINE( mt ) ||
bc->candidates[j].sr_type == REP_RESULT) {
continue;
}
}
}
- send_ldap_error( op, rs, timeout_err, timeout_text );
- asyncmeta_clear_bm_context(bc);
}
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
+ if (!bc->op->o_abandon ) {
+ asyncmeta_send_ldap_result( bc, bc->op, &bc->rs );
+ }
+ asyncmeta_clear_bm_context(bc);
}
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
if (mi->mi_idle_timeout) {
for (j=0; j<mi->mi_ntargets; j++) {
a_metasingleconn_t *msc = &mc->mc_conns[j];
- if (msc->msc_pending_ops > 0) {
+ if ( msc->msc_active > 0 ) {
continue;
}
- if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout <= current_time) {
- asyncmeta_clear_one_msc(NULL, mc, j);
+ if (mc->pending_ops > 0) {
+ continue;
+ }
+ current_time = slap_get_time();
+ if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) {
+ asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
}
}
}
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
}
+ slap_sl_mem_setctx(ctx, oldctx);
+ current_time = slap_get_time();
+ Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time );
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
return NULL;
}
-#if 0
-int
-asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bc )
-{
- if (bc->ctrls != NULL && bc->cl != NULL && bc->cl->mc != NULL) {
- a_metainfo_t *mi = bc->cl->mc->mc_info;
- (void)mi->mi_ldap_extra->controls_free(op, rs, &bc->ctrls );
- }
- asyncmeta_clear_bm_context(bc, 1, 1);
- return rs->sr_err;
-}
-#endif
#include <ac/string.h>
#include <ac/socket.h>
-
#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate)
+ int candidate,
+ int do_lock)
{
- int i, isupdate, rc = 0, nretries = 1;
+ int i, isupdate, rc = 0;
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ];
LDAPMod *mods = NULL;
struct berval mdn;
Modifications *ml;
- struct berval mapped;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
/*
* Rewrite the modify dn, if needed
*/
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
- dc.ctx = "modifyDN";
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
- switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) )
- {
- case LDAP_SUCCESS:
- break;
- case LDAP_UNWILLING_TO_PERFORM:
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- rs->sr_text = "Operation not allowed";
- retcode = META_SEARCH_ERR;
- goto doreturn;
- default:
- rs->sr_err = LDAP_NO_SUCH_OBJECT;
- retcode = META_SEARCH_NOT_CANDIDATE;
- goto doreturn;
- }
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next )
;
+ if (i > 0) {
+ mods = op->o_tmpalloc( sizeof( LDAPMod )*i, op->o_tmpmemctx );
+ }
- mods = ch_malloc( sizeof( LDAPMod )*i );
if ( mods == NULL ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto doreturn;
}
- modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
+ modv = ( LDAPMod ** )op->o_tmpalloc( ( i + 1 )*sizeof( LDAPMod * ), op->o_tmpmemctx );
if ( modv == NULL ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto doreturn;
}
- dc.ctx = "modifyAttrDN";
isupdate = be_shadow_update( op );
for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
- int j, is_oc = 0;
+ int j;
if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
{
continue;
}
- if ( ml->sml_desc == slap_schema.si_ad_objectClass
- || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
- {
- is_oc = 1;
- mapped = ml->sml_desc->ad_cname;
-
- } else {
- asyncmeta_map( &mt->mt_rwmap.rwm_at,
- &ml->sml_desc->ad_cname, &mapped,
- BACKLDAP_MAP );
- if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
- continue;
- }
- }
-
modv[ i ] = &mods[ i ];
mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
- mods[ i ].mod_type = mapped.bv_val;
+ mods[ i ].mod_type = ml->sml_desc->ad_cname.bv_val;
- /*
- * FIXME: dn-valued attrs should be rewritten
- * to allow their use in ACLs at the back-ldap
- * level.
- */
if ( ml->sml_values != NULL ) {
- if ( is_oc ) {
- for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
- ;
- mods[ i ].mod_bvalues =
- (struct berval **)ch_malloc( ( j + 1 ) *
- sizeof( struct berval * ) );
- for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) {
- struct ldapmapping *mapping;
-
- asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
- &ml->sml_values[ j ], &mapping, BACKLDAP_MAP );
-
- if ( mapping == NULL ) {
- if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
- continue;
- }
- mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
-
- } else {
- mods[ i ].mod_bvalues[ j ] = &mapping->dst;
- }
- j++;
- }
- mods[ i ].mod_bvalues[ j ] = NULL;
-
- } else {
- if ( ml->sml_desc->ad_type->sat_syntax ==
- slap_schema.si_syn_distinguishedName )
- {
- ( void )asyncmeta_dnattr_rewrite( &dc, ml->sml_values );
- if ( ml->sml_values == NULL ) {
- continue;
- }
- }
-
- for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
- ;
- mods[ i ].mod_bvalues =
- (struct berval **)ch_malloc( ( j + 1 ) *
- sizeof( struct berval * ) );
- for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
- mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
- }
- mods[ i ].mod_bvalues[ j ] = NULL;
+ j = ml->sml_numvals;
+ mods[ i ].mod_bvalues =(struct berval **)op->o_tmpalloc( ( j + 1 ) *sizeof( struct berval * ), op->o_tmpmemctx );
+ for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
+ mods[ i ].mod_bvalues[ j ] = op->o_tmpalloc(sizeof( struct berval ), op->o_tmpmemctx );
+ if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ asyncmeta_dn_massage( &dc, &ml->sml_values[ j ], mods[ i ].mod_bvalues[ j ] );
+ else
+ *mods[ i ].mod_bvalues[ j ] = ml->sml_values[ j ];
}
+ mods[ i ].mod_bvalues[ j ] = NULL;
} else {
mods[ i ].mod_bvalues = NULL;
}
modv[ i ] = 0;
-retry:;
+ asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
+ /* someone reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug , "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
ber = ldap_build_modify_req( msc->msc_ld, mdn.bv_val, modv, ctrls, NULL, &msgid);
+
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_modify_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY,
- mdn.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY,
+ mdn.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
-
+ /* fall though*/
default:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- retcode = META_SEARCH_ERR;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
}
}
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ ldap_pvt_thread_yield();
+ retcode = META_SEARCH_NEED_BIND;
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send modify request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ ldap_pvt_thread_yield();
+ break;
+ }
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
- BER_BVZERO( &mdn );
- }
- if ( modv != NULL ) {
- for ( i = 0; modv[ i ]; i++ ) {
- free( modv[ i ]->mod_bvalues );
- }
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
- free( mods );
- free( modv );
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
- OperationBuffer opbuf;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
SlapReply *candidates;
- slap_callback *cb = op->o_callback;
+ time_t current_time = slap_get_time();
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modify: %s\n",
op->o_req_dn.bv_val );
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ if (current_time > op->o_time) {
+ Debug(asyncmeta_debug, "==> asyncmeta_back_modify[%s]: o_time:[%ld], current time: [%ld]\n",
+ op->o_log_prefix, op->o_time, current_time );
+ }
+
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
+
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
+ ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
+ goto finish;
+ }
+
+retry:
+ if (bc->timeout && bc->stoptime < slap_get_time()) {
+ int timeout_err;
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ rs->sr_err = timeout_err;
+ rs->sr_text = "Operation timed out before it was sent to target";
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
}
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
- rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate);
+ rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate, 1);
if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
- break;
+ break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- }
- break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: BINDING "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
+ "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
- /* question - how would do receiver know to which targets??? */
break;
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR "
- "cnd=\"%ldd\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
default:
assert( 0 );
break;
}
+
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
+
finish:
return rs->sr_err;
}
#include <ac/socket.h>
#include <ac/string.h>
-
#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate)
+ int candidate,
+ int do_lock)
{
a_dncookie dc;
a_metainfo_t *mi = mc->mc_info;
struct berval mdn = BER_BVNULL,
mnewSuperior = BER_BVNULL,
newrdn = BER_BVNULL;
- int rc = 0, nretries = 1;
+ int rc = 0;
LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL;
SlapReply *candidates = bc->candidates;
ber_int_t msgid;
+ dc.op = op;
dc.target = mt;
- dc.conn = op->o_conn;
- dc.rs = rs;
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
if ( op->orr_newSup ) {
/*
* Rewrite the new superior, if defined and required
*/
- dc.ctx = "newSuperiorDN";
- if ( asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
- rs->sr_err = LDAP_OTHER;
- retcode = META_SEARCH_ERR;
- goto done;
- }
+ asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior );
}
/*
* Rewrite the modrdn dn, if required
*/
- dc.ctx = "modrDN";
- if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- rs->sr_err = LDAP_OTHER;
- retcode = META_SEARCH_ERR;
- goto done;
- }
+ asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
/* NOTE: we need to copy the newRDN in case it was formed
* from a DN by simply changing the length (ITS#5397) */
if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) {
ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx );
}
-retry:;
+
+ asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR;
goto done;
}
-
+ /* someone might have reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
ber = ldap_build_moddn_req( msc->msc_ld, mdn.bv_val, newrdn.bv_val,
mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid);
+
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_modrdn_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN,
- mdn.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN,
+ mdn.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_clear_one_msc(NULL, mc, candidate);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__ );
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
-
+ /* fall though*/
default:
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- retcode = META_SEARCH_ERR;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
}
}
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ retcode = META_SEARCH_NEED_BIND;
+ ldap_pvt_thread_yield();
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send modrdn request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ ldap_pvt_thread_yield();
+ break;
+ }
done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
- free( mdn.bv_val );
- BER_BVZERO( &mdn );
+ op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
}
if ( !BER_BVISNULL( &mnewSuperior )
&& mnewSuperior.bv_val != op->orr_newSup->bv_val )
{
- free( mnewSuperior.bv_val );
- BER_BVZERO( &mnewSuperior );
+ op->o_tmpfree( mnewSuperior.bv_val, op->o_tmpmemctx );
}
if ( newrdn.bv_val != op->orr_newrdn.bv_val ) {
op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx );
}
-doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modrdn_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode;
}
a_metatarget_t *mt;
a_metaconn_t *mc;
int rc, candidate = -1;
- OperationBuffer opbuf;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
SlapReply *candidates;
- slap_callback *cb = op->o_callback;
+ time_t current_time = slap_get_time();
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modrdn: %s\n",
op->o_req_dn.bv_val );
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ if (current_time > op->o_time) {
+ Debug(asyncmeta_debug, "==> asyncmeta_back_modrdn[%s]: o_time:[%ld], current time: [%ld]\n",
+ op->o_log_prefix, op->o_time, current_time );
+ }
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ send_ldap_result(op, rs);
return rs->sr_err;
}
bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
+
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
+ }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- asyncmeta_sender_error(op, rs, cb);
+ send_ldap_result(op, rs);
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
goto finish;
}
+retry:
+ if (bc->timeout && bc->stoptime < slap_get_time()) {
+ int timeout_err;
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ rs->sr_err = timeout_err;
+ rs->sr_text = "Operation timed out before it was sent to target";
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
+ goto finish;
+
+ }
+
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc)
{
case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
- rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate);
+ rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate, 1);
if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
- break;
+ break;
case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE "
- "cnd=\"%ld\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
- rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
- if (rc == META_SEARCH_ERR) {
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
- goto finish;
- }
- break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: BINDING "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
+ "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
/* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR "
- "cnd=\"%ldd\"\n", op->o_log_prefix, candidate );
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- candidates[ candidate ].sr_type = REP_RESULT;
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- asyncmeta_sender_error(op, rs, cb);
- asyncmeta_clear_bm_context(bc);
+ "cnd=\"%d\"\n", op->o_log_prefix, candidate );
+ asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
goto finish;
default:
assert( 0 );
break;
}
+
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
finish:
return rs->sr_err;
}
extern BI_op_modrdn asyncmeta_back_modrdn;
extern BI_op_add asyncmeta_back_add;
extern BI_op_delete asyncmeta_back_delete;
-extern BI_op_abandon asyncmeta_back_abandon;
extern BI_connection_destroy asyncmeta_back_conn_destroy;
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
-
-#include "lutil.h"
#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h"
-
#include "../../../libraries/libldap/ldap-int.h"
-#undef ldap_debug
-#define ldap_debug slap_debug
+#include "lutil.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
static void
asyncmeta_handle_onerr_stop(Operation *op,
SlapReply *rs,
a_metaconn_t *mc,
bm_context_t *bc,
- int candidate,
- slap_callback *cb)
+ int candidate)
{
a_metainfo_t *mi = mc->mc_info;
int j;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- if (bc->bc_active > 0) {
+ if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) {
+ bc->bc_active--;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
return;
}
- bc->bc_active = 1;
asyncmeta_drop_bc(mc, bc);
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
-
for (j=0; j<mi->mi_ntargets; j++) {
if (j != candidate && bc->candidates[j].sr_msgid >= 0
- && mc->mc_conns[j].msc_ld != NULL) {
- asyncmeta_back_abandon_candidate( mc, op,
+ && mc->mc_conns[j].msc_ld != NULL && !META_BACK_CONN_CREATING( &mc->mc_conns[j] )) {
+ asyncmeta_back_cancel( mc, op,
bc->candidates[ j ].sr_msgid, j );
}
}
- if (cb != NULL) {
- op->o_callback = cb;
- }
+ slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
send_ldap_result(op, rs);
- asyncmeta_clear_bm_context(bc);
}
+static int
+asyncmeta_int_filter2bv( a_dncookie *dc,
+ Filter *f,
+ struct berval *fstr )
+{
+ int i;
+ Filter *p;
+ struct berval atmp,
+ vtmp,
+ ntmp,
+ *tmp;
+ static struct berval
+ /* better than nothing... */
+ ber_bvfalse = BER_BVC( "(!(objectClass=*))" ),
+ ber_bvtf_false = BER_BVC( "(|)" ),
+ /* better than nothing... */
+ ber_bvtrue = BER_BVC( "(objectClass=*)" ),
+ ber_bvtf_true = BER_BVC( "(&)" ),
+ ber_bverror = BER_BVC( "(?=error)" ),
+ ber_bvunknown = BER_BVC( "(?=unknown)" ),
+ ber_bvnone = BER_BVC( "(?=none)" );
+ ber_len_t len;
+ void *memctx = dc->memctx;
+
+ assert( fstr != NULL );
+ BER_BVZERO( fstr );
+
+ if ( f == NULL ) {
+ ber_dupbv_x( fstr, &ber_bvnone, memctx );
+ return LDAP_OTHER;
+ }
+
+ switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) {
+ case LDAP_FILTER_EQUALITY:
+ if ( f->f_av_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
+ asyncmeta_dn_massage( dc, &f->f_av_value, &vtmp );
+ } else {
+ vtmp = f->f_av_value;
+ }
+
+ filter_escape_value_x( &vtmp, &ntmp, memctx );
+ fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len
+ + ( sizeof("(=)") - 1 );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)",
+ f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ break;
+
+ case LDAP_FILTER_GE:
+ filter_escape_value_x( &f->f_av_value, &ntmp, memctx );
+ fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len
+ + ( sizeof("(>=)") - 1 );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)",
+ f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ break;
+
+ case LDAP_FILTER_LE:
+ filter_escape_value_x( &f->f_av_value, &ntmp, memctx );
+ fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len
+ + ( sizeof("(<=)") - 1 );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)",
+ f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ break;
+
+ case LDAP_FILTER_APPROX:
+ filter_escape_value_x( &f->f_av_value, &ntmp, memctx );
+ fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len
+ + ( sizeof("(~=)") - 1 );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)",
+ f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ fstr->bv_len = f->f_sub_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
+ f->f_sub_desc->ad_cname.bv_val );
+
+ if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
+ len = fstr->bv_len;
+
+ filter_escape_value_x( &f->f_sub_initial, &ntmp, memctx );
+
+ fstr->bv_len += ntmp.bv_len;
+ fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
+
+ snprintf( &fstr->bv_val[len - 2], ntmp.bv_len + 3,
+ /* "(attr=" */ "%s*)",
+ ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ }
+
+ if ( f->f_sub_any != NULL ) {
+ for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) {
+ len = fstr->bv_len;
+ filter_escape_value_x( &f->f_sub_any[i], &ntmp, memctx );
+
+ fstr->bv_len += ntmp.bv_len + 1;
+ fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
+
+ snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3,
+ /* "(attr=[init]*[any*]" */ "%s*)",
+ ntmp.bv_len ? ntmp.bv_val : "" );
+ ber_memfree_x( ntmp.bv_val, memctx );
+ }
+ }
+
+ if ( !BER_BVISNULL( &f->f_sub_final ) ) {
+ len = fstr->bv_len;
+
+ filter_escape_value_x( &f->f_sub_final, &ntmp, memctx );
+
+ fstr->bv_len += ntmp.bv_len;
+ fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
+
+ snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3,
+ /* "(attr=[init*][any*]" */ "%s)",
+ ntmp.bv_len ? ntmp.bv_val : "" );
+
+ ber_memfree_x( ntmp.bv_val, memctx );
+ }
+
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ fstr->bv_len = f->f_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)",
+ f->f_desc->ad_cname.bv_val );
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ fstr->bv_len = STRLENOF( "(%)" );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)",
+ f->f_choice == LDAP_FILTER_AND ? '&' :
+ f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
+
+ for ( p = f->f_list; p != NULL; p = p->f_next ) {
+ int rc;
+
+ len = fstr->bv_len;
+
+ rc = asyncmeta_int_filter2bv( dc, p, &vtmp );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ fstr->bv_len += vtmp.bv_len;
+ fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx );
+
+ snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2,
+ /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" );
+
+ ber_memfree_x( vtmp.bv_val, memctx );
+ }
+
+ break;
+
+ case LDAP_FILTER_EXT:
+ if ( f->f_mr_desc ) {
+ atmp = f->f_mr_desc->ad_cname;
+
+ } else {
+ BER_BVSTR( &atmp, "" );
+ }
+ filter_escape_value_x( &f->f_mr_value, &ntmp, memctx );
+
+ /* FIXME: cleanup (less ?: operators...) */
+ fstr->bv_len = atmp.bv_len +
+ ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) +
+ ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) +
+ ntmp.bv_len + ( STRLENOF( "(:=)" ) );
+ fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx );
+
+ snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
+ atmp.bv_val,
+ f->f_mr_dnattrs ? ":dn" : "",
+ !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "",
+ !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "",
+ ntmp.bv_len ? ntmp.bv_val : "" );
+ ber_memfree_x( ntmp.bv_val, memctx );
+ break;
+
+ case SLAPD_FILTER_COMPUTED:
+ switch ( f->f_result ) {
+ /* FIXME: treat UNDEFINED as FALSE */
+ case SLAPD_COMPARE_UNDEFINED:
+ if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) {
+ return LDAP_COMPARE_FALSE;
+ }
+ /* fallthru */
+
+ case LDAP_COMPARE_FALSE:
+ if ( META_BACK_TGT_T_F( dc->target ) ) {
+ tmp = &ber_bvtf_false;
+ break;
+ }
+ tmp = &ber_bvfalse;
+ break;
+
+ case LDAP_COMPARE_TRUE:
+ if ( META_BACK_TGT_T_F( dc->target ) ) {
+ tmp = &ber_bvtf_true;
+ break;
+ }
+
+ tmp = &ber_bvtrue;
+ break;
+
+ default:
+ tmp = &ber_bverror;
+ break;
+ }
+
+ ber_dupbv_x( fstr, tmp, memctx );
+ break;
+
+ default:
+ ber_dupbv_x( fstr, &ber_bvunknown, memctx );
+ break;
+ }
+
+ return 0;
+}
meta_search_candidate_t
asyncmeta_back_search_start(
Operation *op,
SlapReply *rs,
- a_metaconn_t *mc,
- bm_context_t *bc,
- int candidate,
- struct berval *prcookie,
- ber_int_t prsize )
+ a_metaconn_t *mc,
+ bm_context_t *bc,
+ int candidate,
+ struct berval *prcookie,
+ ber_int_t prsize,
+ int do_lock)
{
SlapReply *candidates = bc->candidates;
a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
a_dncookie dc;
struct berval realbase = op->o_req_dn;
+ char **attrs;
int realscope = op->ors_scope;
struct berval mbase = BER_BVNULL;
- struct berval mfilter = BER_BVNULL;
- char **mapped_attrs = NULL;
int rc;
+ struct berval filterbv = BER_BVNULL;
meta_search_candidate_t retcode;
int timelimit;
- int nretries = 1;
LDAPControl **ctrls = NULL;
- BerElement *ber;
+ BerElement *ber = NULL;
ber_int_t msgid;
#ifdef SLAPD_META_CLIENT_PR
LDAPControl **save_ctrls = NULL;
return META_SEARCH_NOT_CANDIDATE;
}
- Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_back_search_start[%d]\n", op->o_log_prefix, candidate );
+ Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_back_search_start: dn=%s filter=%s\n",
+ op->o_log_prefix, op->o_req_dn.bv_val, op->ors_filterstr.bv_val );
/*
* modifies the base according to the scope, if required
*/
/*
* Rewrite the search base, if required
*/
+ dc.op = op;
dc.target = mt;
- dc.ctx = "searchBase";
- dc.conn = op->o_conn;
- dc.rs = rs;
- switch ( asyncmeta_dn_massage( &dc, &realbase, &mbase ) ) {
- case LDAP_SUCCESS:
- break;
-
- case LDAP_UNWILLING_TO_PERFORM:
- rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- rs->sr_text = "Operation not allowed";
- retcode = META_SEARCH_ERR;
- goto doreturn;
+ dc.memctx = op->o_tmpmemctx;
+ dc.to_from = MASSAGE_REQ;
+ asyncmeta_dn_massage( &dc, &realbase, &mbase );
- default:
-
- /*
- * this target is no longer candidate
- */
- retcode = META_SEARCH_NOT_CANDIDATE;
- goto doreturn;
- }
-
- /*
- * Maps filter
- */
- rc = asyncmeta_filter_map_rewrite( &dc, op->ors_filter,
- &mfilter, BACKLDAP_MAP, NULL );
- switch ( rc ) {
- case LDAP_SUCCESS:
- break;
-
- case LDAP_COMPARE_FALSE:
- default:
- /*
- * this target is no longer candidate
- */
- retcode = META_SEARCH_NOT_CANDIDATE;
- goto done;
- }
-
- /*
- * Maps required attributes
- */
- rc = asyncmeta_map_attrs( op, &mt->mt_rwmap.rwm_at,
- op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
- if ( rc != LDAP_SUCCESS ) {
- /*
- * this target is no longer candidate
- */
- retcode = META_SEARCH_NOT_CANDIDATE;
- goto done;
- }
+ attrs = anlist2charray_x( op->ors_attrs, 0, op->o_tmpmemctx );
if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
}
#endif /* SLAPD_META_CLIENT_PR */
-retry:;
asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls;
- if (nretries == 0)
- {
- if (rc != LDAP_SUCCESS)
- {
- rs->sr_err = LDAP_BUSY;
- retcode = META_SEARCH_ERR;
- candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
- goto done;
- }
- }
- if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls )
+ if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls )
!= LDAP_SUCCESS )
{
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
/*
* Starts the search
*/
+ /* someone reset the connection */
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+ rc = asyncmeta_int_filter2bv( &dc, op->ors_filter, &filterbv );
+ if ( rc ) {
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
ber = ldap_build_search_req( msc->msc_ld,
- mbase.bv_val, realscope, mfilter.bv_val,
- mapped_attrs, op->ors_attrsonly,
+ mbase.bv_val, realscope, filterbv.bv_val,
+ attrs, op->ors_attrsonly,
ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref,
&msgid );
+ if (!ber) {
+ Debug( asyncmeta_debug, "%s asyncmeta_back_search_start: Operation encoding failed with errno %d\n",
+ op->o_log_prefix, msc->msc_ld->ld_errno );
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ rs->sr_text = "Failed to encode proxied request";
+ retcode = META_SEARCH_ERR;
+ goto done;
+ }
+
if (ber) {
- candidates[ candidate ].sr_msgid = msgid;
- rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH,
- mbase.bv_val, ber, msgid );
- if (rc == msgid)
- rc = LDAP_SUCCESS;
- else
- rc = LDAP_SERVER_DOWN;
+ struct timeval tv = {0, mt->mt_network_timeout*1000};
+ ber_socket_t s;
+
+ if (!( LDAP_BACK_CONN_ISBOUND( msc )
+ || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
+ if (s < 0) {
+ Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+ }
+
+ rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
+ if (rc < 0) {
+ Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
+ if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
+ rc = LDAP_SERVER_DOWN;
+ } else {
+ goto error_unavailable;
+ }
+ } else {
+ candidates[ candidate ].sr_msgid = msgid;
+ rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH,
+ mbase.bv_val, ber, msgid );
+ if (rc == msgid)
+ rc = LDAP_SUCCESS;
+ else
+ rc = LDAP_SERVER_DOWN;
+ ber = NULL;
+ }
+
switch ( rc ) {
case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc);
- break;
+ goto done;
case LDAP_SERVER_DOWN:
- ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
- if (mc->mc_active < 1) {
- asyncmeta_clear_one_msc(NULL, mc, candidate);
+ /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
+ if (do_lock > 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
- ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
- nretries = 0;
- /* if the identity changed, there might be need to re-authz */
- (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
- goto retry;
- }
- rs->sr_err = LDAP_UNAVAILABLE;
- retcode = META_SEARCH_ERR;
- break;
+ Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
+ goto error_unavailable;
+
default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE;
+ goto done;
}
}
+error_unavailable:
+ if (ber)
+ ber_free(ber, 1);
+ switch (bc->nretries[candidate]) {
+ case -1: /* nretries = forever */
+ retcode = META_SEARCH_NEED_BIND;
+ ldap_pvt_thread_yield();
+ break;
+ case 0: /* no retries left */
+ candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "Unable to send search request to target";
+ retcode = META_SEARCH_ERR;
+ break;
+ default: /* more retries left - try to rebind and go again */
+ retcode = META_SEARCH_NEED_BIND;
+ bc->nretries[candidate]--;
+ ldap_pvt_thread_yield();
+ break;
+ }
done:;
+#if 0
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
+#endif
#ifdef SLAPD_META_CLIENT_PR
if ( save_ctrls != op->o_ctrls ) {
op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
}
#endif /* SLAPD_META_CLIENT_PR */
- if ( mapped_attrs ) {
- ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
- }
- if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
- ber_memfree_x( mfilter.bv_val, NULL );
- }
if ( mbase.bv_val != realbase.bv_val ) {
- free( mbase.bv_val );
+ op->o_tmpfree( mbase.bv_val, op->o_tmpmemctx );
}
doreturn:;
asyncmeta_back_search( Operation *op, SlapReply *rs )
{
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
- struct timeval save_tv = { 0, 0 },
- tv;
- time_t stoptime = (time_t)(-1),
- lastres_time = slap_get_time(),
- timeout = 0;
- int rc = 0, sres = LDAP_SUCCESS;
- char *matched = NULL;
- int last = 0, ncandidates = 0,
- initial_candidates = 0, candidate_match = 0,
- needbind = 0;
- ldap_back_send_t sendok = LDAP_BACK_SENDERR;
- long i,j;
- int is_ok = 0;
- void *savepriv;
+ time_t timeout = 0;
+ int rc = 0;
+ int ncandidates = 0, initial_candidates = 0;
+ long i;
SlapReply *candidates = NULL;
- int do_taint = 0;
+ void *thrctx = op->o_threadctx;
bm_context_t *bc;
a_metaconn_t *mc;
- slap_callback *cb = op->o_callback;
+ int msc_decr = 0;
+ int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
rs_assert_ready( rs );
rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
* to map attrs and maybe rewrite value
*/
- asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
+ asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
if (bc == NULL) {
rs->sr_err = LDAP_OTHER;
send_ldap_result(op, rs);
candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) {
- op->o_callback = cb;
send_ldap_result(op, rs);
- asyncmeta_clear_bm_context(bc);
return rs->sr_err;
}
}
}
- bc->timeout = timeout;
+ if ( op->ors_tlimit != SLAP_NO_LIMIT && (timeout == 0 || op->ors_tlimit < timeout)) {
+ bc->searchtime = 1;
+ bc->timeout = op->ors_tlimit;
+ } else {
+ bc->timeout = timeout;
+ }
+
bc->stoptime = op->o_time + bc->timeout;
+ bc->bc_active = 1;
- if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
- stoptime = op->o_time + op->ors_tlimit;
- if (stoptime < bc->stoptime) {
- bc->stoptime = stoptime;
- bc->searchtime = 1;
- bc->timeout = op->ors_tlimit;
- }
+ if (mc->pending_ops >= max_pending_ops) {
+ rs->sr_err = LDAP_BUSY;
+ rs->sr_text = "Maximum pending ops limit exceeded";
+ send_ldap_result(op, rs);
+ return rs->sr_err;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc);
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ mc->mc_conns[i].msc_active++;
+ }
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded";
- asyncmeta_clear_bm_context(bc);
- op->o_callback = cb;
send_ldap_result(op, rs);
goto finish;
}
{
continue;
}
+retry:
+ if (bc->timeout && bc->stoptime < slap_get_time() && META_BACK_ONERR_STOP( mi )) {
+ int timeout_err;
+ const char *timeout_text;
+ if (bc->searchtime) {
+ timeout_err = LDAP_TIMELIMIT_EXCEEDED;
+ timeout_text = NULL;
+ } else {
+ timeout_err = op->o_protocol >= LDAP_VERSION3 ?
+ LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
+ timeout_text = "Operation timed out before it was sent to target";
+ }
+ rs->sr_err = timeout_err;
+ rs->sr_text = timeout_text;
+ asyncmeta_handle_onerr_stop(op,rs,mc,bc,i);
+ goto finish;
+
+ }
+
+ if (op->o_abandon) {
+ rs->sr_err = SLAPD_ABANDON;
+ asyncmeta_handle_onerr_stop(op,rs,mc,bc,i);
+ goto finish;
+ }
rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, i);
switch (rc)
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, i );
- rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 );
+ rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 , 1);
if (rc == META_SEARCH_ERR) {
META_CANDIDATE_CLEAR(&candidates[i]);
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
if ( META_BACK_ONERR_STOP( mi ) ) {
- asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
+ asyncmeta_handle_onerr_stop(op,rs,mc,bc,i);
goto finish;
}
else {
continue;
}
+ } else if (rc == META_SEARCH_NEED_BIND) {
+ goto retry;
}
break;
case META_SEARCH_NOT_CANDIDATE:
break;
case META_SEARCH_NEED_BIND:
- case META_SEARCH_CONNECTING:
- Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: NEED_BIND "
- "cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]);
- ncandidates++;
- rc = asyncmeta_dobind_init(op, rs, bc, mc, i);
- if (rc == META_SEARCH_ERR) {
- candidates[ i ].sr_msgid = META_MSGID_IGNORE;
- if ( META_BACK_ONERR_STOP( mi ) ) {
- asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
- goto finish;
- }
- else {
- continue;
- }
- }
- break;
case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]);
candidates[ i ].sr_type = REP_RESULT;
if ( META_BACK_ONERR_STOP( mi ) ) {
- asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb);
+ asyncmeta_handle_onerr_stop(op,rs,mc,bc,i);
goto finish;
}
else {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
- op->o_callback = cb;
send_ldap_result(op, rs);
- asyncmeta_clear_bm_context(bc);
goto finish;
}
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ mc->mc_conns[i].msc_active--;
+ }
+ msc_decr = 1;
+
asyncmeta_start_listeners(mc, candidates, bc);
+ bc->bc_active--;
+ asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ rs->sr_err = SLAPD_ASYNCOP;
+
finish:
+ /* we ended up straight here due to error and need to reset the msc_active*/
+ if (msc_decr == 0) {
+ ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
+ for ( i = 0; i < mi->mi_ntargets; i++ ) {
+ mc->mc_conns[i].msc_active--;
+ }
+ ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
+ }
return rs->sr_err;
}
+++ /dev/null
-/* suffixmassage.c - massages ldap backend dns */
-/* $OpenLDAP$ */
-/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
- *
- * Copyright 2016-2019 The OpenLDAP Foundation.
- * Portions Copyright 2016 Symas Corporation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* ACKNOWLEDGEMENTS:
- * This work was developed by Symas Corporation
- * based on back-meta module for inclusion in OpenLDAP Software.
- * This work was sponsored by Ericsson. */
-
-/* This is an altered version */
-
-/*
- * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
- * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
- *
- * Module back-ldap, originally developed by Howard Chu
- *
- * has been modified by Pierangelo Masarati. The original copyright
- * notice has been maintained.
- *
- * Permission is granted to anyone to use this software for any purpose
- * on any computer system, and to alter it and redistribute it, subject
- * to the following restrictions:
- *
- * 1. The author is not responsible for the consequences of use of this
- * software, no matter how awful, even if they arise from flaws in it.
- *
- * 2. The origin of this software must not be misrepresented, either by
- * explicit claim or by omission. Since few users ever read sources,
- * credits should appear in the documentation.
- *
- * 3. Altered versions must be plainly marked as such, and must not be
- * misrepresented as being the original software. Since few users
- * ever read sources, credits should appear in the documentation.
- *
- * 4. This notice may not be removed or altered.
- */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/string.h>
-#include <ac/socket.h>
-
-#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
-
-int
-asyncmeta_dn_massage(
- a_dncookie *dc,
- struct berval *dn,
- struct berval *res )
-{
- int rc = 0;
- static char *dmy = "";
-
- switch ( rewrite_session( dc->target->mt_rwmap.rwm_rw, dc->ctx,
- ( dn->bv_val ? dn->bv_val : dmy ),
- dc->conn, &res->bv_val ) )
- {
- case REWRITE_REGEXEC_OK:
- if ( res->bv_val != NULL ) {
- res->bv_len = strlen( res->bv_val );
- } else {
- *res = *dn;
- }
- Debug( LDAP_DEBUG_ARGS,
- "[rw] %s: \"%s\" -> \"%s\"\n",
- dc->ctx,
- BER_BVISNULL( dn ) ? "" : dn->bv_val,
- BER_BVISNULL( res ) ? "" : res->bv_val );
- rc = LDAP_SUCCESS;
- break;
-
- case REWRITE_REGEXEC_UNWILLING:
- if ( dc->rs ) {
- dc->rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
- dc->rs->sr_text = "Operation not allowed";
- }
- rc = LDAP_UNWILLING_TO_PERFORM;
- break;
-
- case REWRITE_REGEXEC_ERR:
- if ( dc->rs ) {
- dc->rs->sr_err = LDAP_OTHER;
- dc->rs->sr_text = "Rewrite error";
- }
- rc = LDAP_OTHER;
- break;
- }
-
- if ( res->bv_val == dmy ) {
- BER_BVZERO( res );
- }
-
- return rc;
-}
+++ /dev/null
-/* unbind.c - unbind handler for back-asyncmeta */
-/* $OpenLDAP$ */
-/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
- *
- * Copyright 2016-2019 The OpenLDAP Foundation.
- * Portions Copyright 2016 Symas Corporation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-
-/* ACKNOWLEDGEMENTS:
- * This work was developed by Symas Corporation
- * based on back-meta module for inclusion in OpenLDAP Software.
- * This work was sponsored by Ericsson. */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/errno.h>
-#include <ac/socket.h>
-#include <ac/string.h>
-
-#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-#include "back-asyncmeta.h"
-
-int
-asyncmeta_back_conn_destroy(
- Backend *be,
- Connection *conn )
-{
- a_metainfo_t *mi = ( a_metainfo_t * )be->be_private;
- int i;
-
- Debug( LDAP_DEBUG_TRACE,
- "=>asyncmeta_back_conn_destroy: fetching conn=%ld DN=\"%s\"\n",
- conn->c_connid,
- BER_BVISNULL( &conn->c_ndn ) ? "" : conn->c_ndn.bv_val );
- /*
- * Cleanup rewrite session
- */
- for ( i = 0; i < mi->mi_ntargets; ++i ) {
- rewrite_session_delete( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, conn );
- }
-
- return 0;
-}
--- /dev/null
+# master slapd config -- for testing
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+include @SCHEMADIR@/core.schema
+include @SCHEMADIR@/cosine.schema
+include @SCHEMADIR@/inetorgperson.schema
+include @SCHEMADIR@/openldap.schema
+include @SCHEMADIR@/nis.schema
+include @SCHEMADIR@/ppolicy.schema
+pidfile @TESTDIR@/slapd.m.pid
+argsfile @TESTDIR@/slapd.m.args
+
+#ldapmod#modulepath ../servers/slapd/back-ldap/
+#ldapmod#moduleload back_ldap.la
+#metamod#modulepath ../servers/slapd/back-meta/
+#metamod#moduleload back_meta.la
+#monitormod#modulepath ../servers/slapd/back-monitor/
+#monitormod#moduleload back_monitor.la
+
+# seems to improve behavior under very heavy load
+# (i.e. it alleviates load on target systems)
+threads 8
+
+#######################################################################
+# database definitions
+#######################################################################
+
+database asyncmeta
+suffix "o=Example,c=US"
+rootdn "cn=Manager,o=Example,c=US"
+rootpw secret
+chase-referrals no
+#nretries forever
+nretries 100
+#norefs true
+network-timeout 500
+#max-timeout-ops 50
+#max-pending-ops 128
+#max-target-conns 16
+
+# local
+uri "@URI2@ou=Meta,o=Example,c=US"
+subtree-exclude "ou=Excluded,ou=Meta,o=Example,c=US"
+suffixmassage "ou=Meta,o=Example,c=US" "ou=Meta,dc=example,dc=com"
+###pseudorootdn "cn=manager,ou=meta,dc=example,dc=com"
+###pseudorootpw secret
+idassert-bind bindmethod=simple
+ binddn="cn=manager,ou=meta,dc=example,dc=com"
+ credentials="secret"
+ mode=self
+ flags=non-prescriptive
+idassert-authzFrom "dn.exact:cn=Manager,o=Local"
+
+# remote
+uri "@URI1@o=Example,c=US"
+subtree-include "dn.subtree:o=Example,c=US"
+suffixmassage "o=Example,c=US" "dc=example,dc=com"
+###pseudorootdn "cn=manager,dc=example,dc=com"
+###pseudorootpw secret
+idassert-bind bindmethod=simple
+ binddn="cn=manager,dc=example,dc=com"
+ credentials="secret"
+ mode=self
+ flags=non-prescriptive
+idassert-authzFrom "dn.exact:cn=Manager,o=Local"
+
+limits dn.exact="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Example,c=US" time=1 size=8
+
+# This is only for binding as the rootdn
+database asyncmeta
+suffix "o=Local"
+rootdn "cn=Manager,o=Local"
+rootpw secret
+uri "@URI6@o=Local"
+
+#monitor#database monitor
# other backends
AC_ldap=ldap@BUILD_LDAP@
AC_meta=meta@BUILD_META@
+AC_asyncmeta=asyncmeta@BUILD_ASYNCMETA@
AC_monitor=@BUILD_MONITOR@
AC_relay=relay@BUILD_RELAY@
AC_sql=sql@BUILD_SQL@
if test "${AC_meta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then
AC_meta="metano"
fi
-
-export AC_bdb AC_hdb AC_ldap AC_mdb AC_meta AC_monitor AC_null AC_relay AC_sql \
+if test "${AC_asyncmeta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then
+ AC_meta="asyncmetano"
+fi
+export AC_bdb AC_hdb AC_ldap AC_mdb AC_meta AC_asyncmeta AC_monitor AC_null AC_relay AC_sql \
AC_accesslog AC_autoca AC_constraint AC_dds AC_dynlist AC_memberof AC_pcache AC_ppolicy \
AC_refint AC_retcode AC_rwm AC_unique AC_syncprov AC_translucent \
AC_valsort \
MONITORDB=${AC_monitor-no}
BACKLDAP=${AC_ldap-ldapno}
BACKMETA=${AC_meta-metano}
+BACKASYNCMETA=${AC_asyncmeta-asyncmetano}
BACKRELAY=${AC_relay-relayno}
BACKSQL=${AC_sql-sqlno}
RDBMS=${SLAPD_USE_SQL-rdbmsno}
METACONF=$DATADIR/slapd-meta.conf
METACONF1=$DATADIR/slapd-meta-target1.conf
METACONF2=$DATADIR/slapd-meta-target2.conf
+ASYNCMETACONF=$DATADIR/slapd-asyncmeta.conf
GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf
ACICONF=$DATADIR/slapd-aci.conf
VALSORTCONF=$DATADIR/slapd-valsort.conf
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+echo ""
+
+if test $BACKASYNCMETA = asyncmetano ; then
+ echo "asyncmeta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND $MONITORDB < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND $MONITORDB < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL $TIMING > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -h $LOCALHOST -p $PORT2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND $MONITORDB < $ASYNCMETACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL $TIMING > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# ITS#4195: spurious matchedDN when the search scopes the main target,
+# and the searchBase is not present, so that target returns noSuchObject
+BASEDN="ou=Meta,o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Do some modifications
+#
+
+BASEDN="o=Example,c=US"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -h $LOCALHOST -p $PORT3 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+# These operations (updates with objectClass mapping) triggered ITS#3499
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+objectClass: uidObject
+cn: Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+uid: added
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+cn: Another Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+member: cn=Another Added Group,ou=Groups,$BASEDN
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: modify
+add: objectClass
+objectClass: uidObject
+-
+add: uid
+uid: added
+-
+
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: modify
+delete: objectClass
+objectClass: uidObject
+-
+delete: uid
+-
+
+dn: ou=Meta,$BASEDN
+changetype: modify
+add: description
+description: added to "ou=Meta,$BASEDN"
+-
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: delete
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: cn=Added User,ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: inetOrgPerson
+cn: Added User
+sn: User
+userPassword: secret
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: delete
+EOMODS
+
+RC=$?
+#if test $RC != 0 ; then
+# echo "Modify failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"seeAlso\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"seeAlso\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" "$FILTER" seeAlso \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"member\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Waiting 10 seconds for cached connections to timeout..."
+sleep 10
+
+echo "Searching with a timed out connection..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"" >> $SEARCHOUT
+echo "# with a timed out connection..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking server-enforced size limit..."
+echo "# Checking server-enforced size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit -1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking client-requested size limit..."
+echo "# Checking client-requested size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -h $LOCALHOST -p $PORT3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" -z 2 "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit -1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METAOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - meta search/modification didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Binding as newly added user to database \"$BASEDN\"..."
+$LDAPWHOAMI -h $LOCALHOST -p $PORT3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+
+echo "Binding with incorrect password to database \"$BASEDN\"..."
+$LDAPWHOAMI -h $LOCALHOST -p $PORT3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit -1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Binding with non-existing user to database \"$BASEDN\"..."
+$LDAPWHOAMI -h $LOCALHOST -p $PORT3 \
+ -D "cn=Non-existing User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit -1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2019 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+echo ""
+
+if test $BACKASYNCMETA = asyncmetano ; then
+ echo "asyncmeta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+if test x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+if test x$TESTCHILDREN = x ; then
+ TESTCHILDREN=20
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+# NOTE: this could be added to all tests...
+if test "$BACKEND" = "bdb" || test "$BACKEND" = "hdb" ; then
+ if test "x$DB_CONFIG" != "x" ; then \
+ if test -f $DB_CONFIG ; then
+ echo "==> using DB_CONFIG \"$DB_CONFIG\""
+ cp $DB_CONFIG $DBDIR1
+ cp $DB_CONFIG $DBDIR2
+ else
+ echo "==> DB_CONFIG must point to a valid file (ignored)"
+ fi
+ else
+ echo "==> set \"DB_CONFIG\" to the DB_CONFIG file you want to use for the test."
+ fi
+ echo ""
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND $MONITORDB < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND $MONITORDB < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL $TIMING > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -h $LOCALHOST -p $PORT2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND $MONITORDB < $ASYNCMETACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL $TIMING > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT
+
+mkdir -p $TESTDIR/$DATADIR
+METABASEDN="o=Example,c=US"
+for f in $DATADIR/do_* ; do
+ sed -e "s;$BASEDN;$METABASEDN;" $f > $TESTDIR/$f
+done
+
+# add a read that matches only the local database, but selects
+# also the remote as candidate; this should be removed to compare
+# execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "ou=Meta,$METABASEDN" >> $f
+done
+
+# add a read that matches a referral in the local database only,
+# but selects also the remote as candidate; this should be removed
+# to compare execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "cn=Somewhere,ou=Meta,$METABASEDN" >> $f
+done
+
+# add a bind that resolves to a referral
+for f in $TESTDIR/$DATADIR/do_bind.* ; do
+ echo "cn=Foo,ou=Meta,$METABASEDN" >> $f
+ echo "bar" >> $f
+ echo "" >> $f
+ echo "" >> $f
+done
+
+# fix test data to include back-monitor, if available
+# NOTE: copies do_* files from $TESTDIR/$DATADIR to $TESTDIR
+$MONITORDATA "$MONITORDB" "$TESTDIR/$DATADIR" "$TESTDIR"
+
+BINDDN="cn=Manager,o=Local"
+PASSWD="secret"
+echo "Using tester for concurrent server access..."
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" -h $LOCALHOST -p $PORT3 \
+ -D "$BINDDN" -w $PASSWD -l $TESTLOOPS -j $TESTCHILDREN \
+ -r 20 -i '!REFERRAL' -i '*INVALID_CREDENTIALS' -SS
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$METABASEDN" -h $LOCALHOST -p $PORT3 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METACONCURRENCYOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - slapd-asyncmeta search/modification didn't succeed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0