ITS#8734 Fixes for many back-asyncmeta issues

Includes all the changes necessary to fix back-asyncmeta issues
discovered during on-site testing since the start of 2016.
These include:
Issues with stability - crashes and assetion failures
Incorrect behavior during unstable network conditions, such as inability to reset connections
or process responses, or "hanging" to wait for a response that would never be received.
Memory leaks and memory management fixes - major redesign of the way back-asyncmeta
works with memory contexts.
Rewrite was replaced with suffix-massage in configuration, and the network-timeout value was changed to milliseconds.
Incorrect behavior when SASL is used to bind to a target.
Many problems caused by race conditions
Fixes for compiler warnings, and tests.
Cleanup of unused code.
This commit is contained in:
Nadezhda Ivanova 2019-02-18 17:08:52 +02:00 committed by Quanah Gibson-Mount
parent 06d289f985
commit bb7e14d201
26 changed files with 3691 additions and 4760 deletions

View file

@ -376,16 +376,18 @@ Sets the network timeout value after which
.BR poll (2)/ select (2) .BR poll (2)/ select (2)
following a following a
.BR connect (2) .BR connect (2)
returns in case of no activity. returns in case of no activity while sending an operation to the remote target.
The value is in seconds, and it can be specified as for The value is in milliseconds, and it can be specified as for
.BR idle\-timeout . .BR idle\-timeout .
If set before any target specification, it affects all targets, unless If set before any target specification, it affects all targets, unless
overridden by any per-target directive. overridden by any per-target directive.
.TP .TP
.B nretries {forever|never|<nretries>} .B nretries {forever|never|<nretries>}
This directive defines how many times a bind should be retried This directive defines how many times forwarding an operation should be retried
in case of temporary failure in contacting a target. If defined 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, before any target specification, it applies to all targets (by default,
.BR 3 .BR 3
times); times);
@ -409,11 +411,13 @@ by a target. See
for details. for details.
.TP .TP
.B suffixmassage "<virtual naming context>" "<real naming context>" .B suffixmassage "<local suffix>" "<remote suffix>"
All the directives starting with "rewrite" refer to the rewrite engine .B slapd\-asyncmeta
that has been added to slapd. See does not support the rewrite engine used by
.B slapd\-meta(5) the LDAP and META backends.
for details. .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 .TP
.B t\-f\-support {NO|yes|discover} .B t\-f\-support {NO|yes|discover}

View file

@ -19,12 +19,12 @@
## based on back-meta module for inclusion in OpenLDAP Software. ## based on back-meta module for inclusion in OpenLDAP Software.
## This work was sponsored by Ericsson ## This work was sponsored by Ericsson
SRCS = init.c config.c search.c message_queue.c bind.c unbind.c add.c compare.c \ SRCS = init.c config.c search.c message_queue.c bind.c add.c compare.c \
delete.c modify.c modrdn.c suffixmassage.c map.c \ delete.c modify.c modrdn.c map.c \
conn.c candidates.c dncache.c meta_result.c abandon.c conn.c candidates.c dncache.c meta_result.c
OBJS = init.lo config.lo search.lo message_queue.lo bind.lo unbind.lo add.lo compare.lo \ OBJS = init.lo config.lo search.lo message_queue.lo bind.lo add.lo compare.lo \
delete.lo modify.lo modrdn.lo suffixmassage.lo map.lo \ delete.lo modify.lo modrdn.lo map.lo \
conn.lo candidates.lo dncache.lo meta_result.lo abandon.lo conn.lo candidates.lo dncache.lo meta_result.lo
LDAP_INCDIR= ../../../include LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries LDAP_LIBDIR= ../../../libraries

View file

@ -1,52 +0,0 @@
/* 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;
}

View file

@ -27,23 +27,33 @@
#include <ac/string.h> #include <ac/string.h>
#include <ac/socket.h> #include <ac/socket.h>
#include "slap.h" #include "slap.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h" #include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h" #include "back-asyncmeta.h"
#include "ldap_rq.h" #include "ldap_rq.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
void
asyncmeta_sender_error(Operation *op, int
asyncmeta_error_cleanup(Operation *op,
SlapReply *rs, SlapReply *rs,
slap_callback *cb) bm_context_t *bc,
a_metaconn_t *mc,
int candidate)
{ {
if (cb != NULL) { ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
op->o_callback = cb; 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); send_ldap_result(op, rs);
return LDAP_SUCCESS;
} }
meta_search_candidate_t meta_search_candidate_t
@ -51,149 +61,116 @@ asyncmeta_back_add_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate) int candidate,
int do_lock)
{ {
int isupdate; int isupdate;
Attribute *a; Attribute *a;
int i; int i;
LDAPMod **attrs; LDAPMod **attrs;
struct berval mapped;
a_dncookie dc; a_dncookie dc;
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ]; a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn; struct berval mdn = {0, NULL};
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL; BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
SlapReply *candidates = bc->candidates; SlapReply *candidates = bc->candidates;
ber_int_t msgid; ber_int_t msgid;
LDAPControl **ctrls = NULL; LDAPControl **ctrls = NULL;
int rc, nretries = 1; int rc;
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = op->o_tmpmemctx;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
dc.ctx = "addDN"; asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
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;
}
/* Count number of attributes in entry ( +1 ) */ /* Count number of attributes in entry ( +1 ) */
for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next ); for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );
/* Create array of LDAPMods for ldap_add() */ /* 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 ); isupdate = be_shadow_update( op );
for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) { 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 ) if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod )
{ {
continue; continue;
} }
if ( a->a_desc == slap_schema.si_ad_objectClass attrs[ i ] = op->o_tmpalloc( sizeof( LDAPMod ), op->o_tmpmemctx );
|| 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 ) );
if ( attrs[ i ] == NULL ) { if ( attrs[ i ] == NULL ) {
continue; continue;
} }
attrs[ i ]->mod_op = LDAP_MOD_BVALUES; attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
attrs[ i ]->mod_type = mapped.bv_val; attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val;
j = a->a_numvals;
if ( is_oc ) { attrs[ i ]->mod_bvalues = op->o_tmpalloc( ( j + 1 ) * sizeof( struct berval * ), op->o_tmpmemctx );
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ); for (j=0; j<a->a_numvals; j++) {
attrs[ i ]->mod_bvalues[ j ] = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
attrs[ i ]->mod_bvalues = if ( a->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
(struct berval **)ch_malloc( ( j + 1 ) * asyncmeta_dn_massage( &dc, &a->a_vals[ j ], attrs[ i ]->mod_bvalues[ j ] );
sizeof( struct berval * ) ); else
for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) { *attrs[ i ]->mod_bvalues[ j ] = 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; 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;
}
i++; i++;
} }
attrs[ i ] = NULL; attrs[ i ] = NULL;
retry:; asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls; 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; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto done; 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); 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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
mdn.bv_val, ber, msgid ); mdn.bv_val, ber, msgid );
@ -201,45 +178,57 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate); 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; /* fall though*/
/* if the identity changed, there might be need to re-authz */ default:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
goto retry; goto error_unavailable;
}
} }
default: 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; 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; 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: done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
for ( --i; i >= 0; --i ) { if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( attrs[ i ]->mod_bvalues ); op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
free( attrs[ i ] );
}
free( attrs );
if ( mdn.bv_val != op->ora_e->e_dn ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
} }
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode; return retcode;
} }
@ -252,26 +241,31 @@ asyncmeta_back_add( Operation *op, SlapReply *rs )
a_metatarget_t *mt; a_metatarget_t *mt;
a_metaconn_t *mc; a_metaconn_t *mc;
int rc, candidate = -1; int rc, candidate = -1;
OperationBuffer opbuf; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
SlapReply *candidates; 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 ); 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
return rs->sr_err; return rs->sr_err;
} }
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -280,16 +274,39 @@ asyncmeta_back_add( Operation *op, SlapReply *rs )
bc->retrying = LDAP_BACK_RETRYING; bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout; 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); rc = asyncmeta_add_message_queue(mc, bc);
mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc); send_ldap_result(op, rs);
asyncmeta_sender_error(op, rs, cb); 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; goto finish;
} }
@ -299,62 +316,35 @@ asyncmeta_back_add( Operation *op, SlapReply *rs )
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */ /* target is already bound, just send the request */
Debug(LDAP_DEBUG_TRACE , "%s asyncmeta_back_add: " Debug(LDAP_DEBUG_TRACE , "%s asyncmeta_back_add: "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "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) { if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: 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 /* add the context to the message queue but do not send the request
the receiver must send this when we are done binding */ the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break; break;
case META_SEARCH_ERR: case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
default: default:
assert( 0 ); assert( 0 );
@ -362,8 +352,12 @@ asyncmeta_back_add( Operation *op, SlapReply *rs )
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate); asyncmeta_start_one_listener(mc, candidates, bc, candidate);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: finish:
return rs->sr_err; return rs->sr_err;
} }

View file

@ -27,18 +27,12 @@
#ifndef SLAPD_ASYNCMETA_H #ifndef SLAPD_ASYNCMETA_H
#define SLAPD_ASYNCMETA_H #define SLAPD_ASYNCMETA_H
#ifndef ENABLE_REWRITE
#error "--enable-rewrite is required!"
#endif
#ifdef LDAP_DEVEL #ifdef LDAP_DEVEL
#define SLAPD_META_CLIENT_PR 1 #define SLAPD_META_CLIENT_PR 1
#endif /* LDAP_DEVEL */ #endif /* LDAP_DEVEL */
#include "proto-asyncmeta.h" #include "proto-asyncmeta.h"
/* String rewrite library */
#include "rewrite.h"
#include "ldap_rq.h" #include "ldap_rq.h"
LDAP_BEGIN_DECL LDAP_BEGIN_DECL
@ -50,108 +44,6 @@ LDAP_BEGIN_DECL
#define META_BACK_PRINT_CONNTREE 0 #define META_BACK_PRINT_CONNTREE 0
#endif /* !META_BACK_PRINT_CONNTREE */ #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: * A a_metasingleconn_t can be in the following, mutually exclusive states:
* *
@ -171,6 +63,7 @@ asyncmeta_dnattr_result_rewrite(
#define META_BACK_FCONN_INITED (0x00100000U) #define META_BACK_FCONN_INITED (0x00100000U)
#define META_BACK_FCONN_CREATING (0x00200000U) #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(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_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
@ -180,6 +73,9 @@ asyncmeta_dnattr_result_rewrite(
#define META_BACK_CONN_CREATING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING) #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_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_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_metainfo_t;
struct a_metaconn_t; struct a_metaconn_t;
@ -190,20 +86,25 @@ struct a_metatarget_t;
#define META_RETRYING ((ber_tag_t)0x4) #define META_RETRYING ((ber_tag_t)0x4)
typedef struct bm_context_t { 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 timeout;
time_t stoptime; time_t stoptime;
ldap_back_send_t sendok; ldap_back_send_t sendok;
ldap_back_send_t retrying; ldap_back_send_t retrying;
int candidate_match; int candidate_match;
int sent; volatile int bc_active;
int bc_active;
int searchtime; /* stoptime is a search timelimit */ int searchtime; /* stoptime is a search timelimit */
int is_ok; int is_ok;
int is_root;
volatile sig_atomic_t bc_invalid;
SlapReply rs; SlapReply rs;
Operation *op; Operation *op;
Operation copy_op;
LDAPControl **ctrls; LDAPControl **ctrls;
int *msgids; 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; SlapReply *candidates;
} bm_context_t; } bm_context_t;
@ -226,14 +127,16 @@ typedef struct a_metasingleconn_t {
LDAP *msc_ld; LDAP *msc_ld;
LDAP *msc_ldr; LDAP *msc_ldr;
time_t msc_time; time_t msc_time;
time_t msc_binding_time;
time_t msc_result_time;
struct berval msc_bound_ndn; struct berval msc_bound_ndn;
struct berval msc_cred; struct berval msc_cred;
unsigned msc_mscflags; unsigned msc_mscflags;
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros /* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */ * defined for back-ldap */
#define lc_lcflags msc_mscflags #define lc_lcflags msc_mscflags
int msc_pending_ops; volatile int msc_active;
int msc_timeout_ops;
/* Connection for the select */ /* Connection for the select */
Connection *conn; Connection *conn;
} a_metasingleconn_t; } a_metasingleconn_t;
@ -267,7 +170,7 @@ typedef struct a_metaconn_t {
int pending_ops; int pending_ops;
ldap_pvt_thread_mutex_t mc_om_mutex; ldap_pvt_thread_mutex_t mc_om_mutex;
/* queue for pending operations */ /* 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 */ /* supersedes the connection stuff */
a_metasingleconn_t *mc_conns; a_metasingleconn_t *mc_conns;
} a_metaconn_t; } a_metaconn_t;
@ -309,7 +212,7 @@ typedef struct a_metacommon_t {
#define META_RETRY_UNDEFINED (-2) #define META_RETRY_UNDEFINED (-2)
#define META_RETRY_FOREVER (-1) #define META_RETRY_FOREVER (-1)
#define META_RETRY_NEVER (0) #define META_RETRY_NEVER (0)
#define META_RETRY_DEFAULT (10) #define META_RETRY_DEFAULT (2)
unsigned mc_flags; unsigned mc_flags;
#define META_BACK_CMN_ISSET(mc,f) ( ( (mc)->mc_flags & (f) ) == (f) ) #define META_BACK_CMN_ISSET(mc,f) ( ( (mc)->mc_flags & (f) ) == (f) )
@ -359,6 +262,9 @@ typedef struct a_metatarget_t {
struct berval mt_psuffix; /* pretty suffix */ struct berval mt_psuffix; /* pretty suffix */
struct berval mt_nsuffix; /* normalized 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_binddn;
struct berval mt_bindpw; struct berval mt_bindpw;
@ -379,8 +285,6 @@ typedef struct a_metatarget_t {
#define mt_idassert_flags mt_idassert.si_flags #define mt_idassert_flags mt_idassert.si_flags
#define mt_idassert_authz mt_idassert.si_authz #define mt_idassert_authz mt_idassert.si_authz
struct ldaprwmap mt_rwmap;
sig_atomic_t mt_isquarantined; sig_atomic_t mt_isquarantined;
ldap_pvt_thread_mutex_t mt_quarantine_mutex; ldap_pvt_thread_mutex_t mt_quarantine_mutex;
@ -520,6 +424,7 @@ typedef struct a_metainfo_t {
int mi_next_conn; int mi_next_conn;
a_metaconn_t *mi_conns; a_metaconn_t *mi_conns;
struct berval mi_suffix;
} a_metainfo_t; } a_metainfo_t;
typedef enum meta_op_type { typedef enum meta_op_type {
@ -528,6 +433,33 @@ typedef enum meta_op_type {
META_OP_REQUIRE_ALL META_OP_REQUIRE_ALL
} meta_op_type; } 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 * extern a_metaconn_t *
asyncmeta_getconn( asyncmeta_getconn(
Operation *op, Operation *op,
@ -537,17 +469,6 @@ asyncmeta_getconn(
ldap_back_send_t sendok, ldap_back_send_t sendok,
int alloc_new); 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 extern int
asyncmeta_init_one_conn( asyncmeta_init_one_conn(
@ -566,24 +487,6 @@ asyncmeta_quarantine(
SlapReply *rs, SlapReply *rs,
int candidate ); 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 extern int
asyncmeta_proxy_authz_cred( asyncmeta_proxy_authz_cred(
a_metaconn_t *mc, a_metaconn_t *mc,
@ -595,31 +498,13 @@ asyncmeta_proxy_authz_cred(
struct berval *bindcred, struct berval *bindcred,
int *method ); 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 extern int
asyncmeta_controls_add( asyncmeta_controls_add(
Operation *op, Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
int candidate, int candidate,
int isroot,
LDAPControl ***pctrls ); LDAPControl ***pctrls );
extern int extern int
@ -682,9 +567,6 @@ asyncmeta_dncache_delete_entry(
extern void extern void
asyncmeta_dncache_free( void *entry ); asyncmeta_dncache_free( void *entry );
extern void
asyncmeta_back_map_free( struct ldapmap *lm );
extern int extern int
asyncmeta_subtree_destroy( a_metasubtree_t *ms ); asyncmeta_subtree_destroy( a_metasubtree_t *ms );
@ -724,12 +606,12 @@ void asyncmeta_clear_bm_context(bm_context_t *bc);
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc); 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(a_metaconn_t *mc, bm_context_t *bc);
void asyncmeta_drop_bc_from_fconn(bm_context_t *bc);
bm_context_t * bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate); asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate);
bm_context_t * void asyncmeta_memctx_toggle(void *thrctx);
asyncmeta_find_message_by_opmsguid(ber_int_t msgid, a_metaconn_t *mc, int remove);
void* asyncmeta_op_handle_result(void *ctx, void *arg); void* asyncmeta_op_handle_result(void *ctx, void *arg);
int asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bm ); int asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bm );
@ -738,16 +620,19 @@ int
asyncmeta_clear_one_msc( asyncmeta_clear_one_msc(
Operation *op, Operation *op,
a_metaconn_t *msc, a_metaconn_t *msc,
int candidate ); int candidate,
int unbind,
const char * caller);
a_metaconn_t * a_metaconn_t *
asyncmeta_get_next_mc( a_metainfo_t *mi ); asyncmeta_get_next_mc( a_metainfo_t *mi );
void* asyncmeta_timeout_loop(void *ctx, void *arg); void* asyncmeta_timeout_loop(void *ctx, void *arg);
int int
asyncmeta_start_timeout_loop(a_metatarget_t *mt, a_metainfo_t *mi); asyncmeta_start_timeout_loop(a_metatarget_t *mt, a_metainfo_t *mi);
void asyncmeta_set_msc_time(a_metasingleconn_t *msc); void asyncmeta_set_msc_time(a_metasingleconn_t *msc);
void asyncmeta_clear_message_queue(a_metasingleconn_t *msc);
int asyncmeta_back_cancel( int asyncmeta_back_cancel(
a_metaconn_t *mc, a_metaconn_t *mc,
@ -755,25 +640,15 @@ int asyncmeta_back_cancel(
ber_int_t msgid, ber_int_t msgid,
int candidate ); 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 void
asyncmeta_send_result(bm_context_t* bc, int error, char *text); 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_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); int asyncmeta_start_one_listener(a_metaconn_t *mc, SlapReply *candidates, bm_context_t *bc, int candidate);
@ -785,7 +660,8 @@ asyncmeta_back_search_start(
bm_context_t *bc, bm_context_t *bc,
int candidate, int candidate,
struct berval *prcookie, struct berval *prcookie,
ber_int_t prsize ); ber_int_t prsize,
int do_lock);
meta_search_candidate_t meta_search_candidate_t
asyncmeta_dobind_init( asyncmeta_dobind_init(
@ -808,40 +684,97 @@ asyncmeta_back_add_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate); int candidate,
int do_lock);
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op, asyncmeta_back_modify_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate); int candidate,
int do_lock);
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op, asyncmeta_back_modrdn_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate); int candidate,
int do_lock);
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op, asyncmeta_back_delete_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate); int candidate,
int do_lock);
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op, asyncmeta_back_compare_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, 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 candidate);
int
asyncmeta_reset_msc(Operation *op,
a_metaconn_t *mc,
int candidate,
int unbind,
const char *caller);
void void
asyncmeta_sender_error(Operation *op, asyncmeta_back_conn_free(
SlapReply *rs, void *v_mc );
slap_callback *cb);
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_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 LDAP_END_DECL

File diff suppressed because it is too large Load diff

View file

@ -206,8 +206,6 @@ asyncmeta_select_unique_candidate(
if ( candidate == META_TARGET_NONE ) { if ( candidate == META_TARGET_NONE ) {
candidate = i; candidate = i;
} else {
return META_TARGET_MULTIPLE;
} }
} }
} }
@ -239,50 +237,3 @@ asyncmeta_clear_unused_candidates(
return 0; 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;
}

View file

@ -26,27 +26,27 @@
#include <ac/string.h> #include <ac/string.h>
#include <ac/socket.h> #include <ac/socket.h>
#include "slap.h" #include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h" #include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_compare_start(Operation *op, asyncmeta_back_compare_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate) int candidate,
int do_lock)
{ {
a_dncookie dc; a_dncookie dc;
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ]; 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 mdn = BER_BVNULL;
struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
struct berval mapped_value = op->orc_ava->aa_value; struct berval mapped_value = op->orc_ava->aa_value;
int rc = 0, nretries = 1; int rc = 0;
LDAPControl **ctrls = NULL; LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL; BerElement *ber = NULL;
@ -54,75 +54,66 @@ asyncmeta_back_compare_start(Operation *op,
SlapReply *candidates = bc->candidates; SlapReply *candidates = bc->candidates;
ber_int_t msgid; ber_int_t msgid;
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = op->o_tmpmemctx;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
dc.ctx = "compareDN";
switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { 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;
}
/*
* 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 ) 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 );
dc.ctx = "compareAttrDN";
switch ( asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) ) asyncmeta_set_msc_time(msc);
{
case LDAP_UNWILLING_TO_PERFORM:
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto done;
default:
break;
}
}
}
retry:;
ctrls = op->o_ctrls; 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; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto done; 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); 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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE,
mdn.bv_val, ber, msgid ); mdn.bv_val, ber, msgid );
@ -130,41 +121,58 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate); 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; /* fall though*/
/* if the identity changed, there might be need to re-authz */ default:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
goto retry; goto error_unavailable;
}
} }
default: 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; 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; 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: done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (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 ) { if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) {
free( mapped_value.bv_val ); op->o_tmpfree( mapped_value.bv_val, op->o_tmpmemctx );
}
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 ); Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_compare_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode; return retcode;
} }
@ -176,26 +184,30 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs )
a_metatarget_t *mt; a_metatarget_t *mt;
a_metaconn_t *mc; a_metaconn_t *mc;
int rc, candidate = -1; int rc, candidate = -1;
OperationBuffer opbuf; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
SlapReply *candidates; 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", Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_compare: %s\n",
op->o_req_dn.bv_val ); 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
return rs->sr_err; return rs->sr_err;
} }
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -204,16 +216,38 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs )
bc->retrying = LDAP_BACK_RETRYING; bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout; 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); rc = asyncmeta_add_message_queue(mc, bc);
mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc); send_ldap_result(op, rs);
asyncmeta_sender_error(op, rs, cb); 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; goto finish;
} }
@ -223,47 +257,27 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs )
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */ /* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: " 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) { if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: 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 /* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */ the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */ /* question - how would do receiver know to which targets??? */
@ -271,23 +285,21 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs )
case META_SEARCH_ERR: case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
default: default:
assert( 0 ); assert( 0 );
break; break;
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate); asyncmeta_start_one_listener(mc, candidates, bc, candidate);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: finish:
return rs->sr_err; return rs->sr_err;
} }

File diff suppressed because it is too large Load diff

View file

@ -27,57 +27,11 @@
#include <ac/errno.h> #include <ac/errno.h>
#include <ac/socket.h> #include <ac/socket.h>
#include <ac/string.h> #include <ac/string.h>
#define AVL_INTERNAL
#include "slap.h" #include "slap.h"
#include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h" #include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.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 * asyncmeta_conn_alloc
* *
@ -127,8 +81,6 @@ asyncmeta_init_one_conn(
a_dncookie dc; a_dncookie dc;
int isauthz = ( candidate == mc->mc_authz_target ); int isauthz = ( candidate == mc->mc_authz_target );
int do_return = 0; int do_return = 0;
int nretries = 2;
#ifdef HAVE_TLS #ifdef HAVE_TLS
int is_ldaps = 0; int is_ldaps = 0;
int do_start_tls = 0; int do_start_tls = 0;
@ -164,15 +116,16 @@ asyncmeta_init_one_conn(
if ( dont_retry ) { if ( dont_retry ) {
rs->sr_err = LDAP_UNAVAILABLE; rs->sr_err = LDAP_UNAVAILABLE;
if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
rs->sr_text = "Target is quarantined"; 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 ) ) {
send_ldap_result( op, rs ); send_ldap_result( op, rs );
} }
return rs->sr_err; return rs->sr_err;
} }
} }
msc = &mc->mc_conns[candidate]; msc = &mc->mc_conns[candidate];
retry_lock:;
/* /*
* Already init'ed * Already init'ed
*/ */
@ -186,13 +139,7 @@ retry_lock:;
} else if ( META_BACK_CONN_CREATING( msc ) } else if ( META_BACK_CONN_CREATING( msc )
|| LDAP_BACK_CONN_BINDING( msc ) ) || LDAP_BACK_CONN_BINDING( msc ) )
{ {
/* sounds more appropriate */ rs->sr_err = LDAP_SUCCESS;
if (nretries >= 0) {
nretries--;
ldap_pvt_thread_yield();
goto retry_lock;
}
rs->sr_err = LDAP_UNAVAILABLE;
do_return = 1; do_return = 1;
} else if ( META_BACK_CONN_INITED( msc ) ) { } else if ( META_BACK_CONN_INITED( msc ) ) {
@ -231,6 +178,8 @@ retry_lock:;
#endif /* HAVE_TLS */ #endif /* HAVE_TLS */
ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
if ( rs->sr_err != LDAP_SUCCESS ) { 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; goto error_return;
} }
msc->msc_ldr = ldap_dup(msc->msc_ld); msc->msc_ldr = ldap_dup(msc->msc_ld);
@ -327,8 +276,8 @@ retry:;
default: default:
/* only touch when activity actually took place... */ /* only touch when activity actually took place... */
if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { if ( mi->mi_idle_timeout != 0 ) {
msc->msc_time = op->o_time; asyncmeta_set_msc_time(msc);
} }
break; break;
} }
@ -348,6 +297,7 @@ retry:;
res = NULL; res = NULL;
if ( rs->sr_err == LDAP_SUCCESS ) { if ( rs->sr_err == LDAP_SUCCESS ) {
rs->sr_err = err; rs->sr_err = err;
} }
rs->sr_err = slap_map_api2result( rs ); rs->sr_err = slap_map_api2result( rs );
@ -385,7 +335,10 @@ retry:;
*/ */
rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL ); rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ #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 /* if StartTLS is requested, only attempt it if the URL
* is not "ldaps://"; this may occur not only in case * is not "ldaps://"; this may occur not only in case
* of misconfiguration, but also when used in the chain * of misconfiguration, but also when used in the chain
@ -407,15 +360,13 @@ retry:;
} }
} }
#endif /* HAVE_TLS */ #endif /* HAVE_TLS */
/* /*
* Set the network timeout if set * Set the network timeout if set
*/ */
if ( mt->mt_network_timeout != 0 ) { if ( mt->mt_network_timeout != 0 ) {
struct timeval network_timeout; struct timeval network_timeout;
network_timeout.tv_sec = 0;
network_timeout.tv_usec = 0; network_timeout.tv_usec = mt->mt_network_timeout*1000;
network_timeout.tv_sec = mt->mt_network_timeout;
ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,
(void *)&network_timeout ); (void *)&network_timeout );
@ -452,38 +403,22 @@ retry:;
BER_BVZERO( &msc->msc_bound_ndn ); BER_BVZERO( &msc->msc_bound_ndn );
} }
if ( !BER_BVISEMPTY( &op->o_ndn ) if ( !BER_BVISEMPTY( &op->o_ndn )
&& SLAP_IS_AUTHZ_BACKEND( op )
&& isauthz ) && isauthz )
{ {
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = NULL;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
dc.ctx = "bindDN";
/* /*
* Rewrite the bind dn if needed * Rewrite the bind dn if needed
*/ */
if ( asyncmeta_dn_massage( &dc, &op->o_conn->c_dn, asyncmeta_dn_massage( &dc, &op->o_conn->c_dn, &msc->msc_bound_ndn );
&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;
}
/* copy the DN if needed */ /* copy the DN if needed */
if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { 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 ); ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
} }
assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
} else { } else {
ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv ); ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );
} }
@ -496,10 +431,6 @@ error_return:;
META_BACK_CONN_CREATING_CLEAR( msc ); META_BACK_CONN_CREATING_CLEAR( msc );
} }
if ( rs->sr_err == LDAP_SUCCESS && msc != NULL) { 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 ); META_BACK_CONN_INITED_SET( msc );
} }
@ -512,125 +443,6 @@ error_return:;
return rs->sr_err; 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 static int
asyncmeta_get_candidate( asyncmeta_get_candidate(
@ -654,59 +466,6 @@ asyncmeta_get_candidate(
rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_err = LDAP_NO_SUCH_OBJECT;
rs->sr_text = "No suitable candidate target found"; 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 { } else {
rs->sr_err = LDAP_SUCCESS; rs->sr_err = LDAP_SUCCESS;
} }
@ -714,19 +473,6 @@ asyncmeta_get_candidate(
return candidate; 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 * asyncmeta_getconn
@ -910,7 +656,7 @@ asyncmeta_getconn(
if ( sendok & LDAP_BACK_SENDERR ) { if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 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 ); send_ldap_result( op, rs );
rs->sr_matched = NULL; rs->sr_matched = NULL;
@ -933,9 +679,6 @@ asyncmeta_getconn(
} }
if ( op_type == META_OP_REQUIRE_SINGLE ) { if ( op_type == META_OP_REQUIRE_SINGLE ) {
a_metatarget_t *mt = NULL;
a_metasingleconn_t *msc = NULL;
int j; int j;
for ( j = 0; j < mi->mi_ntargets; j++ ) { for ( j = 0; j < mi->mi_ntargets; j++ ) {
@ -956,7 +699,7 @@ asyncmeta_getconn(
if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) { if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) {
if ( sendok & LDAP_BACK_SENDERR ) { if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 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 ); send_ldap_result( op, rs );
rs->sr_matched = NULL; rs->sr_matched = NULL;
@ -998,9 +741,6 @@ asyncmeta_getconn(
*/ */
( void )asyncmeta_clear_unused_candidates( op, i , mc, candidates); ( 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 * The target is activated; if needed, it is
* also init'd. In case of error, asyncmeta_init_one_conn * also init'd. In case of error, asyncmeta_init_one_conn
@ -1118,7 +858,7 @@ asyncmeta_getconn(
if ( sendok & LDAP_BACK_SENDERR ) { if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 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 ); send_ldap_result( op, rs );
rs->sr_matched = NULL; rs->sr_matched = NULL;
@ -1133,7 +873,6 @@ asyncmeta_getconn(
} }
done:; done:;
/* clear out meta_back_init_one_conn non-fatal errors */
rs->sr_err = LDAP_SUCCESS; rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL; rs->sr_text = NULL;
@ -1266,6 +1005,7 @@ a_metaconn_t *
asyncmeta_get_next_mc( a_metainfo_t *mi ) asyncmeta_get_next_mc( a_metainfo_t *mi )
{ {
a_metaconn_t *mc = NULL; a_metaconn_t *mc = NULL;
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
if (mi->mi_next_conn >= mi->mi_num_conns-1) { if (mi->mi_next_conn >= mi->mi_num_conns-1) {
mi->mi_next_conn = 0; mi->mi_next_conn = 0;
@ -1294,14 +1034,13 @@ int asyncmeta_start_one_listener(a_metaconn_t *mc,
{ {
a_metasingleconn_t *msc; a_metasingleconn_t *msc;
ber_socket_t s; ber_socket_t s;
int i;
msc = &mc->mc_conns[candidate]; 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; return LDAP_SUCCESS;
} }
bc->msgids[candidate] = candidates[candidate].sr_msgid; bc->msgids[candidate] = candidates[candidate].sr_msgid;
msc->msc_pending_ops++;
if ( msc->conn == NULL) { if ( msc->conn == NULL) {
ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
if (s < 0) { if (s < 0) {
@ -1313,3 +1052,130 @@ int asyncmeta_start_one_listener(a_metaconn_t *mc,
connection_client_enable( msc->conn ); connection_client_enable( msc->conn );
return LDAP_SUCCESS; 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]);
}
}
}

View file

@ -23,28 +23,27 @@
#include "portable.h" #include "portable.h"
#include <stdio.h> #include <stdio.h>
#include <ac/string.h> #include <ac/string.h>
#include <ac/socket.h> #include <ac/socket.h>
#include "slap.h" #include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h" #include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_delete_start(Operation *op, asyncmeta_back_delete_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate) int candidate,
int do_lock)
{ {
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ]; a_metatarget_t *mt = mi->mi_targets[ candidate ];
struct berval mdn = BER_BVNULL; struct berval mdn = BER_BVNULL;
a_dncookie dc; a_dncookie dc;
int rc = 0, nretries = 1; int rc = 0;
LDAPControl **ctrls = NULL; LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL; BerElement *ber = NULL;
@ -52,28 +51,62 @@ asyncmeta_back_delete_start(Operation *op,
SlapReply *candidates = bc->candidates; SlapReply *candidates = bc->candidates;
ber_int_t msgid; ber_int_t msgid;
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = op->o_tmpmemctx;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
dc.ctx = "deleteDN";
if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
retcode = META_SEARCH_ERR;
goto doreturn;
}
retry:; asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls; 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; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto done; 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); 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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE,
mdn.bv_val, ber, msgid ); mdn.bv_val, ber, msgid );
@ -81,38 +114,56 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate); 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; /* fall though*/
/* if the identity changed, there might be need to re-authz */ default:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
goto retry; goto error_unavailable;
}
} }
default: 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; 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; 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: done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) { if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val ); op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &mdn );
} }
doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_delete_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_delete_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode; return retcode;
} }
@ -124,26 +175,32 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs )
a_metatarget_t *mt; a_metatarget_t *mt;
a_metaconn_t *mc; a_metaconn_t *mc;
int rc, candidate = -1; int rc, candidate = -1;
OperationBuffer opbuf; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
SlapReply *candidates; SlapReply *candidates;
slap_callback *cb = op->o_callback; time_t current_time = slap_get_time();
Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_delete: %s\n", int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
Debug(LDAP_DEBUG_TRACE, "==> asyncmeta_back_delete: %s\n",
op->o_req_dn.bv_val ); 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
return rs->sr_err; return rs->sr_err;
} }
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -152,16 +209,38 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs )
bc->retrying = LDAP_BACK_RETRYING; bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout; 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); rc = asyncmeta_add_message_queue(mc, bc);
mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc); send_ldap_result(op, rs);
asyncmeta_sender_error(op, rs, cb); 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; goto finish;
} }
@ -171,47 +250,27 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs )
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */ /* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: " 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) { if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NOT_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: 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 /* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */ the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */ /* question - how would do receiver know to which targets??? */
@ -219,22 +278,21 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs )
case META_SEARCH_ERR: case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: ERR " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
default: default:
assert( 0 ); assert( 0 );
break; break;
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate); asyncmeta_start_one_listener(mc, candidates, bc, candidate);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: finish:
return rs->sr_err; return rs->sr_err;
} }

View file

@ -32,6 +32,8 @@
#include "../back-ldap/back-ldap.h" #include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h" #include "back-asyncmeta.h"
int asyncmeta_debug;
int int
asyncmeta_back_open( asyncmeta_back_open(
BackendInfo *bi ) BackendInfo *bi )
@ -46,6 +48,14 @@ int
asyncmeta_back_initialize( asyncmeta_back_initialize(
BackendInfo *bi ) BackendInfo *bi )
{ {
int rc;
struct berval debugbv = BER_BVC("asyncmeta");
rc = slap_loglevel_get( &debugbv, &asyncmeta_debug );
if ( rc ) {
return rc;
}
bi->bi_flags = bi->bi_flags =
#if 0 #if 0
/* this is not (yet) set essentially because back-meta does not /* this is not (yet) set essentially because back-meta does not
@ -89,7 +99,7 @@ asyncmeta_back_initialize(
bi->bi_chk_referrals = 0; bi->bi_chk_referrals = 0;
bi->bi_connection_init = 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 ); return asyncmeta_back_init_cf( bi );
} }
@ -164,9 +174,7 @@ asyncmeta_target_finish(
) )
{ {
slap_bindconf sb = { BER_BVNULL }; slap_bindconf sb = { BER_BVNULL };
struct berval mapped;
int rc; int rc;
int msc_num, i;
ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri ); ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri );
sb.sb_version = mt->mt_version; sb.sb_version = mt->mt_version;
@ -216,21 +224,6 @@ asyncmeta_target_finish(
mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_NOANON; 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; return 0;
} }
@ -240,10 +233,8 @@ asyncmeta_back_db_open(
ConfigReply *cr ) ConfigReply *cr )
{ {
a_metainfo_t *mi = (a_metainfo_t *)be->be_private; a_metainfo_t *mi = (a_metainfo_t *)be->be_private;
char msg[SLAP_TEXT_BUFLEN]; char msg[SLAP_TEXT_BUFLEN];
int i;
int i, rc;
if ( mi->mi_ntargets == 0 ) { if ( mi->mi_ntargets == 0 ) {
/* Dynamically added, nothing to check here until /* Dynamically added, nothing to check here until
@ -272,11 +263,12 @@ asyncmeta_back_db_open(
mc->mc_authz_target = META_BOUND_NONE; mc->mc_authz_target = META_BOUND_NONE;
mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t )); mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
mc->mc_info = mi; 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 ); ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 0, 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 ); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
return 0; return 0;
} }
@ -298,36 +290,6 @@ asyncmeta_back_conn_free(
free( mc ); 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 static void
asyncmeta_back_stop_miconns( a_metainfo_t *mi ) asyncmeta_back_stop_miconns( a_metainfo_t *mi )
{ {
@ -344,7 +306,7 @@ asyncmeta_back_clear_miconns( a_metainfo_t *mi )
mc = &mi->mi_conns[i]; mc = &mi->mi_conns[i];
/* todo clear the message queue */ /* todo clear the message queue */
for (j = 0; j < mi->mi_ntargets; j ++) { 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); free(mc->mc_conns);
ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex ); ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
@ -401,14 +363,12 @@ asyncmeta_target_free(
if ( mt->mt_idassert_authz != NULL ) { if ( mt->mt_idassert_authz != NULL ) {
ber_bvarray_free( mt->mt_idassert_authz ); ber_bvarray_free( mt->mt_idassert_authz );
} }
if ( mt->mt_rwmap.rwm_rw ) { if ( !BER_BVISNULL( &mt->mt_lsuffixm )) {
rewrite_info_delete( &mt->mt_rwmap.rwm_rw ); ch_free( mt->mt_lsuffixm.bv_val );
if ( mt->mt_rwmap.rwm_bva_rewrite ) }
ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite ); 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 ); free( mt );
} }
@ -420,8 +380,6 @@ asyncmeta_back_db_close(
a_metainfo_t *mi; a_metainfo_t *mi;
if ( be->be_private ) { if ( be->be_private ) {
int i;
mi = ( a_metainfo_t * )be->be_private; mi = ( a_metainfo_t * )be->be_private;
if ( mi->mi_task != NULL ) { if ( mi->mi_task != NULL ) {
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
@ -435,6 +393,7 @@ asyncmeta_back_db_close(
asyncmeta_back_stop_miconns( mi ); asyncmeta_back_stop_miconns( mi );
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
} }
return 0;
} }
int int
@ -486,13 +445,14 @@ asyncmeta_back_db_destroy(
if ( META_BACK_QUARANTINE( mi ) ) { if ( META_BACK_QUARANTINE( mi ) ) {
mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine ); mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine );
} }
}
ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
asyncmeta_back_clear_miconns(mi); asyncmeta_back_clear_miconns(mi);
ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex ); ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
free( be->be_private ); free( be->be_private );
}
return 0; return 0;
} }

View file

@ -63,641 +63,10 @@
#include "../back-ldap/back-ldap.h" #include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.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 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( asyncmeta_referral_result_rewrite(
a_dncookie *dc, a_dncookie *dc,
BerVarray a_vals, BerVarray a_vals
void *memctx
) )
{ {
int i, last; int i, last;
@ -731,144 +100,115 @@ asyncmeta_referral_result_rewrite(
ber_str2bv( ludp->lud_dn, 0, 0, &olddn ); ber_str2bv( ludp->lud_dn, 0, 0, &olddn );
rc = asyncmeta_dn_massage( dc, &olddn, &dn ); asyncmeta_dn_massage( dc, &olddn, &dn );
switch ( rc ) { /* leave attr untouched if massage did nothing */
case LDAP_UNWILLING_TO_PERFORM: if ( olddn.bv_val != dn.bv_val )
/*
* 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;
default:
/* leave attr untouched if massage failed */
if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val )
{ {
char *newurl; char *newurl;
ludp->lud_dn = dn.bv_val; ludp->lud_dn = dn.bv_val;
newurl = ldap_url_desc2str( ludp ); newurl = ldap_url_desc2str( ludp );
free( dn.bv_val ); dc->op->o_tmpfree( dn.bv_val, dc->memctx );
if ( newurl == NULL ) { if ( newurl )
{
/* FIXME: leave attr untouched /* FIXME: leave attr untouched
* even if ldap_url_desc2str failed... * even if ldap_url_desc2str failed...
*/ */
break;
}
ber_memfree_x( a_vals[ i ].bv_val, memctx ); ber_memfree_x( a_vals[ i ].bv_val, dc->op->o_tmpmemctx );
ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx ); ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], dc->memctx );
ber_memfree( newurl ); ber_memfree( newurl );
ludp->lud_dn = olddn.bv_val; ludp->lud_dn = olddn.bv_val;
} }
break;
} }
ldap_free_urldesc( ludp ); ldap_free_urldesc( ludp );
} }
return 0;
} }
/* void
* 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(
a_dncookie *dc,
BerVarray a_vals
)
{
struct berval bv;
int i, last;
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;
}
}
return 0;
}
int
asyncmeta_dnattr_result_rewrite( asyncmeta_dnattr_result_rewrite(
a_dncookie *dc, a_dncookie *dc,
BerVarray a_vals BerVarray a_vals
) )
{ {
struct berval bv; struct berval bv;
int i, last; int i;
assert( a_vals != NULL ); assert( a_vals != NULL );
for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ )
;
last--;
for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) { for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) {
switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) { asyncmeta_dn_massage( dc, &a_vals[i], &bv );
case LDAP_UNWILLING_TO_PERFORM: if ( bv.bv_val != a_vals[i].bv_val ) {
/* ber_memfree_x( a_vals[i].bv_val, dc->memctx );
* 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;
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; a_vals[i] = bv;
} }
break;
} }
} }
return 0; /*
* asyncmeta_dn_massage
*
* Aliases the suffix.
*/
void
asyncmeta_dn_massage(
a_dncookie *dc,
struct berval *odn,
struct berval *res
)
{
struct berval pretty = {0,NULL}, *dn = odn;
struct berval *osuff, *nsuff;
int diff;
assert( res );
BER_BVZERO(res);
if ( dn == NULL )
return;
/* no suffix massage configured */
if ( !dc->target->mt_lsuffixm.bv_val ) {
*res = *dn;
return;
}
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;
}
/* 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 );
} }

View file

@ -37,182 +37,6 @@
#include "lutil.h" #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 { typedef struct listptr {
void *reserved; void *reserved;
struct listptr *next; struct listptr *next;
@ -223,80 +47,73 @@ typedef struct listhead {
int cnt; int cnt;
} listhead; } 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 #ifndef LH_MAX
#define LH_MAX 16 #define LH_MAX 16
#endif #endif
static void *asyncmeta_memctx_get(void *threadctx) 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); return slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, threadctx, 1);
} }
static void asyncmeta_memctx_put(void *threadctx, void *memctx) static void asyncmeta_memctx_put(void *threadctx, void *memctx)
{ {
listhead *lh = NULL; slap_sl_mem_setctx(threadctx, 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_destroy((void *)1, memctx);
} }
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) 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; 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->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)->candidates = op->o_tmpcalloc(ntargets, sizeof(SlapReply),op->o_tmpmemctx);
(*new_bc)->msgids = op->o_tmpcalloc(ntargets, sizeof(int),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++) { for (i = 0; i < ntargets; i++) {
(*new_bc)->msgids[i] = META_MSGID_UNDEFINED; (*new_bc)->msgids[i] = META_MSGID_UNDEFINED;
} }
/* restore original memctx */ for (i = 0; i < ntargets; i++) {
slap_sl_mem_setctx(op->o_threadctx, oldctx); (*new_bc)->nretries[i] = mi->mi_targets[i]->mt_nretries;
op->o_tmpmemctx = oldctx; }
return LDAP_SUCCESS; return LDAP_SUCCESS;
} }
@ -305,15 +122,6 @@ void asyncmeta_free_op(Operation *op)
assert (op != NULL); assert (op != NULL);
switch (op->o_tag) { switch (op->o_tag) {
case LDAP_REQ_SEARCH: 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; break;
case LDAP_REQ_ADD: case LDAP_REQ_ADD:
if ( op->ora_modlist != NULL ) { if ( op->ora_modlist != NULL ) {
@ -331,36 +139,11 @@ void asyncmeta_free_op(Operation *op)
} }
break; break;
case LDAP_REQ_MODRDN: 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 ) { if ( op->orr_modlist != NULL ) {
slap_mods_free(op->orr_modlist, 1 ); slap_mods_free(op->orr_modlist, 1 );
} }
break; break;
case LDAP_REQ_COMPARE: 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; break;
case LDAP_REQ_DELETE: case LDAP_REQ_DELETE:
break; break;
@ -368,22 +151,8 @@ void asyncmeta_free_op(Operation *op)
Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type" ); Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type" );
} }
if (op->o_ctrls != NULL) { connection_op_finish( op );
asyncmeta_free_op_controls(op); slap_op_free( op, op->o_threadctx );
}
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);
} }
@ -393,96 +162,26 @@ void asyncmeta_clear_bm_context(bm_context_t *bc)
{ {
Operation *op = bc->op; Operation *op = bc->op;
#if 0 void *thrctx, *memctx;
bm_candidates_t *cl; int i;
a_metainfo_t *mi;
int i = 0; if ( bc->bc_mc && bc->bc_mc->mc_info ) {
if (bmc == NULL) { 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;
}
}
}
if (op->o_conn->c_conn_idx == -1)
return; return;
} else if (bmc->cl == NULL) { memctx = op->o_tmpmemctx;
free(bmc); thrctx = op->o_threadctx;
return; while (op->o_bd == bc->copy_op.o_bd)
} ldap_pvt_thread_yield();
cl = bmc->cl; asyncmeta_free_op(op);
op = cl->op; asyncmeta_memctx_put(thrctx, memctx);
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 );
}
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 );
}
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
} }
int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc) int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc)
@ -493,61 +192,55 @@ 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", Debug( LDAP_DEBUG_TRACE, "add_message_queue: mc %p, pending_ops %d, max_pending %d\n",
mc, mc->pending_ops, max_pending_ops ); mc, mc->pending_ops, max_pending_ops );
assert(bc->bc_mc == NULL);
if (mc->pending_ops >= max_pending_ops) { if (mc->pending_ops >= max_pending_ops) {
return LDAP_BUSY; 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++; mc->pending_ops++;
return LDAP_SUCCESS; return LDAP_SUCCESS;
} }
void void
asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc) asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc)
{ {
bm_context_t *om; bm_context_t *om;
int i; LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om == bc) { if (om == bc) {
for (i = 0; i < mc->mc_info->mi_ntargets; i++) LDAP_STAILQ_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
{
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);
mc->pending_ops--; mc->pending_ops--;
break; break;
} }
} }
assert(om == bc);
assert(bc->bc_mc == mc);
} }
bm_context_t * bm_context_t *
asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate) asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate)
{ {
bm_context_t *om; bm_context_t *om;
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) { LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om->candidates[candidate].sr_msgid == msgid) { if (om->candidates[candidate].sr_msgid == msgid && !om->bc_invalid) {
break; break;
} }
} }
return om; return om;
} }
bm_context_t * 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; bm_context_t *om;
LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) { LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) {
if (om->op->o_msgid == msgid) { if (om == bc) {
break; return bc;
} }
} }
if (remove && om) { return NULL;
LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
mc->pending_ops--;
}
return om;
} }

File diff suppressed because it is too large Load diff

View file

@ -26,21 +26,21 @@
#include <ac/string.h> #include <ac/string.h>
#include <ac/socket.h> #include <ac/socket.h>
#include "slap.h" #include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h" #include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_modify_start(Operation *op, asyncmeta_back_modify_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, 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_dncookie dc;
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
a_metatarget_t *mt = mi->mi_targets[ candidate ]; a_metatarget_t *mt = mi->mi_targets[ candidate ];
@ -48,7 +48,6 @@ asyncmeta_back_modify_start(Operation *op,
LDAPMod *mods = NULL; LDAPMod *mods = NULL;
struct berval mdn; struct berval mdn;
Modifications *ml; Modifications *ml;
struct berval mapped;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL; BerElement *ber = NULL;
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
@ -59,122 +58,55 @@ asyncmeta_back_modify_start(Operation *op,
/* /*
* Rewrite the modify dn, if needed * Rewrite the modify dn, if needed
*/ */
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = op->o_tmpmemctx;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
dc.ctx = "modifyDN";
switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) 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;
}
for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next ) 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 ) { if ( mods == NULL ) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto doreturn; 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 ) { if ( modv == NULL ) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto doreturn; goto doreturn;
} }
dc.ctx = "modifyAttrDN";
isupdate = be_shadow_update( op ); isupdate = be_shadow_update( op );
for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) { 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 ) if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
{ {
continue; 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 ]; modv[ i ] = &mods[ i ];
mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES; 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 ( ml->sml_values != NULL ) {
if ( is_oc ) { j = ml->sml_numvals;
for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) mods[ i ].mod_bvalues =(struct berval **)op->o_tmpalloc( ( j + 1 ) *sizeof( struct berval * ), op->o_tmpmemctx );
;
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++ ) { for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ 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; mods[ i ].mod_bvalues[ j ] = NULL;
}
} else { } else {
mods[ i ].mod_bvalues = NULL; mods[ i ].mod_bvalues = NULL;
@ -184,17 +116,57 @@ asyncmeta_back_modify_start(Operation *op,
} }
modv[ i ] = 0; modv[ i ] = 0;
retry:; asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls; 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; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto done; 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); 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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY,
mdn.bv_val, ber, msgid ); mdn.bv_val, ber, msgid );
@ -202,44 +174,55 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate); 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;
} }
/* fall though*/
default: default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
retcode = META_SEARCH_ERR; 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: done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) { if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val ); op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &mdn );
} }
if ( modv != NULL ) {
for ( i = 0; modv[ i ]; i++ ) {
free( modv[ i ]->mod_bvalues );
}
}
free( mods );
free( modv );
doreturn:; doreturn:;
Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
@ -253,26 +236,31 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs )
a_metatarget_t *mt; a_metatarget_t *mt;
a_metaconn_t *mc; a_metaconn_t *mc;
int rc, candidate = -1; int rc, candidate = -1;
OperationBuffer opbuf; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
SlapReply *candidates; 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", Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modify: %s\n",
op->o_req_dn.bv_val ); 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
return rs->sr_err; return rs->sr_err;
} }
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -281,16 +269,38 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs )
bc->retrying = LDAP_BACK_RETRYING; bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout; 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); rc = asyncmeta_add_message_queue(mc, bc);
mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc); send_ldap_result(op, rs);
asyncmeta_sender_error(op, rs, cb); 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; goto finish;
} }
@ -300,70 +310,49 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs )
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */ /* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: " 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) { if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: 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 /* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */ the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */
break; break;
case META_SEARCH_ERR: case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
default: default:
assert( 0 ); assert( 0 );
break; break;
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate); asyncmeta_start_one_listener(mc, candidates, bc, candidate);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: finish:
return rs->sr_err; return rs->sr_err;
} }

View file

@ -26,19 +26,19 @@
#include <ac/socket.h> #include <ac/socket.h>
#include <ac/string.h> #include <ac/string.h>
#include "slap.h" #include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
#include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h" #include "../../../libraries/libldap/ldap-int.h"
#include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.h"
meta_search_candidate_t meta_search_candidate_t
asyncmeta_back_modrdn_start(Operation *op, asyncmeta_back_modrdn_start(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate) int candidate,
int do_lock)
{ {
a_dncookie dc; a_dncookie dc;
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
@ -46,7 +46,7 @@ asyncmeta_back_modrdn_start(Operation *op,
struct berval mdn = BER_BVNULL, struct berval mdn = BER_BVNULL,
mnewSuperior = BER_BVNULL, mnewSuperior = BER_BVNULL,
newrdn = BER_BVNULL; newrdn = BER_BVNULL;
int rc = 0, nretries = 1; int rc = 0;
LDAPControl **ctrls = NULL; LDAPControl **ctrls = NULL;
meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
BerElement *ber = NULL; BerElement *ber = NULL;
@ -54,9 +54,10 @@ asyncmeta_back_modrdn_start(Operation *op,
SlapReply *candidates = bc->candidates; SlapReply *candidates = bc->candidates;
ber_int_t msgid; ber_int_t msgid;
dc.op = op;
dc.target = mt; dc.target = mt;
dc.conn = op->o_conn; dc.memctx = op->o_tmpmemctx;
dc.rs = rs; dc.to_from = MASSAGE_REQ;
if ( op->orr_newSup ) { if ( op->orr_newSup ) {
@ -101,23 +102,13 @@ asyncmeta_back_modrdn_start(Operation *op,
/* /*
* Rewrite the new superior, if defined and required * Rewrite the new superior, if defined and required
*/ */
dc.ctx = "newSuperiorDN"; asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior );
if ( asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
} }
/* /*
* Rewrite the modrdn dn, if required * Rewrite the modrdn dn, if required
*/ */
dc.ctx = "modrDN"; asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
rs->sr_err = LDAP_OTHER;
retcode = META_SEARCH_ERR;
goto done;
}
/* NOTE: we need to copy the newRDN in case it was formed /* NOTE: we need to copy the newRDN in case it was formed
* from a DN by simply changing the length (ITS#5397) */ * from a DN by simply changing the length (ITS#5397) */
@ -125,18 +116,58 @@ asyncmeta_back_modrdn_start(Operation *op,
if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) { if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) {
ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx ); ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx );
} }
retry:;
asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls; 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; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_ERR; retcode = META_SEARCH_ERR;
goto done; 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, ber = ldap_build_moddn_req( msc->msc_ld, mdn.bv_val, newrdn.bv_val,
mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid); 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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN,
mdn.bv_val, ber, msgid ); mdn.bv_val, ber, msgid );
@ -144,50 +175,66 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_clear_one_msc(NULL, mc, candidate); 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;
} }
/* fall though*/
default: default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
retcode = META_SEARCH_ERR; 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: done:
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
if ( mdn.bv_val != op->o_req_dn.bv_val ) { if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val ); op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &mdn );
} }
if ( !BER_BVISNULL( &mnewSuperior ) if ( !BER_BVISNULL( &mnewSuperior )
&& mnewSuperior.bv_val != op->orr_newSup->bv_val ) && mnewSuperior.bv_val != op->orr_newSup->bv_val )
{ {
free( mnewSuperior.bv_val ); op->o_tmpfree( mnewSuperior.bv_val, op->o_tmpmemctx );
BER_BVZERO( &mnewSuperior );
} }
if ( newrdn.bv_val != op->orr_newrdn.bv_val ) { if ( newrdn.bv_val != op->orr_newrdn.bv_val ) {
op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx ); 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 ); Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modrdn_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
return retcode; return retcode;
} }
@ -199,26 +246,30 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs )
a_metatarget_t *mt; a_metatarget_t *mt;
a_metaconn_t *mc; a_metaconn_t *mc;
int rc, candidate = -1; int rc, candidate = -1;
OperationBuffer opbuf; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
SlapReply *candidates; 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", Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modrdn: %s\n",
op->o_req_dn.bv_val ); 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
return rs->sr_err; return rs->sr_err;
} }
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
asyncmeta_sender_error(op, rs, cb); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -227,66 +278,69 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs )
bc->retrying = LDAP_BACK_RETRYING; bc->retrying = LDAP_BACK_RETRYING;
bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
bc->stoptime = op->o_time + bc->timeout; 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); rc = asyncmeta_add_message_queue(mc, bc);
mc->mc_conns[candidate].msc_active++;
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc); send_ldap_result(op, rs);
asyncmeta_sender_error(op, rs, cb); 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; 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); rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
switch (rc) switch (rc)
{ {
case META_SEARCH_CANDIDATE: case META_SEARCH_CANDIDATE:
/* target is already bound, just send the request */ /* target is already bound, just send the request */
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: " 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) { if (rc == META_SEARCH_ERR) {
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: 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 /* Todo add the context to the message queue but do not send the request
the receiver must send this when we are done binding */ the receiver must send this when we are done binding */
/* question - how would do receiver know to which targets??? */ /* question - how would do receiver know to which targets??? */
@ -294,22 +348,21 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs )
case META_SEARCH_ERR: case META_SEARCH_ERR:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR "
"cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); "cnd=\"%d\"\n", op->o_log_prefix, candidate );
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
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; goto finish;
default: default:
assert( 0 ); assert( 0 );
break; break;
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
mc->mc_conns[candidate].msc_active--;
asyncmeta_start_one_listener(mc, candidates, bc, candidate); asyncmeta_start_one_listener(mc, candidates, bc, candidate);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: finish:
return rs->sr_err; return rs->sr_err;
} }

View file

@ -43,7 +43,6 @@ extern BI_op_modify asyncmeta_back_modify;
extern BI_op_modrdn asyncmeta_back_modrdn; extern BI_op_modrdn asyncmeta_back_modrdn;
extern BI_op_add asyncmeta_back_add; extern BI_op_add asyncmeta_back_add;
extern BI_op_delete asyncmeta_back_delete; extern BI_op_delete asyncmeta_back_delete;
extern BI_op_abandon asyncmeta_back_abandon;
extern BI_connection_destroy asyncmeta_back_conn_destroy; extern BI_connection_destroy asyncmeta_back_conn_destroy;

View file

@ -27,50 +27,287 @@
#include <ac/socket.h> #include <ac/socket.h>
#include <ac/string.h> #include <ac/string.h>
#include <ac/time.h> #include <ac/time.h>
#include "lutil.h"
#include "slap.h" #include "slap.h"
#include "../../../libraries/liblber/lber-int.h"
#include "../../../libraries/libldap/ldap-int.h"
#include "lutil.h"
#include "../back-ldap/back-ldap.h" #include "../back-ldap/back-ldap.h"
#include "back-asyncmeta.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
static void static void
asyncmeta_handle_onerr_stop(Operation *op, asyncmeta_handle_onerr_stop(Operation *op,
SlapReply *rs, SlapReply *rs,
a_metaconn_t *mc, a_metaconn_t *mc,
bm_context_t *bc, bm_context_t *bc,
int candidate, int candidate)
slap_callback *cb)
{ {
a_metainfo_t *mi = mc->mc_info; a_metainfo_t *mi = mc->mc_info;
int j; int j;
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 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); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
return; return;
} }
bc->bc_active = 1;
asyncmeta_drop_bc(mc, bc); asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
for (j=0; j<mi->mi_ntargets; j++) { for (j=0; j<mi->mi_ntargets; j++) {
if (j != candidate && bc->candidates[j].sr_msgid >= 0 if (j != candidate && bc->candidates[j].sr_msgid >= 0
&& mc->mc_conns[j].msc_ld != NULL) { && mc->mc_conns[j].msc_ld != NULL && !META_BACK_CONN_CREATING( &mc->mc_conns[j] )) {
asyncmeta_back_abandon_candidate( mc, op, asyncmeta_back_cancel( mc, op,
bc->candidates[ j ].sr_msgid, j ); bc->candidates[ j ].sr_msgid, j );
} }
} }
if (cb != NULL) { slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx);
op->o_callback = cb; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
}
send_ldap_result(op, rs); 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 meta_search_candidate_t
asyncmeta_back_search_start( asyncmeta_back_search_start(
Operation *op, Operation *op,
@ -79,7 +316,8 @@ asyncmeta_back_search_start(
bm_context_t *bc, bm_context_t *bc,
int candidate, int candidate,
struct berval *prcookie, struct berval *prcookie,
ber_int_t prsize ) ber_int_t prsize,
int do_lock)
{ {
SlapReply *candidates = bc->candidates; SlapReply *candidates = bc->candidates;
a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info; a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
@ -87,16 +325,15 @@ asyncmeta_back_search_start(
a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
a_dncookie dc; a_dncookie dc;
struct berval realbase = op->o_req_dn; struct berval realbase = op->o_req_dn;
char **attrs;
int realscope = op->ors_scope; int realscope = op->ors_scope;
struct berval mbase = BER_BVNULL; struct berval mbase = BER_BVNULL;
struct berval mfilter = BER_BVNULL;
char **mapped_attrs = NULL;
int rc; int rc;
struct berval filterbv = BER_BVNULL;
meta_search_candidate_t retcode; meta_search_candidate_t retcode;
int timelimit; int timelimit;
int nretries = 1;
LDAPControl **ctrls = NULL; LDAPControl **ctrls = NULL;
BerElement *ber; BerElement *ber = NULL;
ber_int_t msgid; ber_int_t msgid;
#ifdef SLAPD_META_CLIENT_PR #ifdef SLAPD_META_CLIENT_PR
LDAPControl **save_ctrls = NULL; LDAPControl **save_ctrls = NULL;
@ -116,7 +353,8 @@ asyncmeta_back_search_start(
return META_SEARCH_NOT_CANDIDATE; 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 * modifies the base according to the scope, if required
*/ */
@ -199,59 +437,13 @@ asyncmeta_back_search_start(
/* /*
* Rewrite the search base, if required * Rewrite the search base, if required
*/ */
dc.op = op;
dc.target = mt; dc.target = mt;
dc.ctx = "searchBase"; dc.memctx = op->o_tmpmemctx;
dc.conn = op->o_conn; dc.to_from = MASSAGE_REQ;
dc.rs = rs; asyncmeta_dn_massage( &dc, &realbase, &mbase );
switch ( asyncmeta_dn_massage( &dc, &realbase, &mbase ) ) {
case LDAP_SUCCESS:
break;
case LDAP_UNWILLING_TO_PERFORM: attrs = anlist2charray_x( op->ors_attrs, 0, op->o_tmpmemctx );
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Operation not allowed";
retcode = META_SEARCH_ERR;
goto doreturn;
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;
}
if ( op->ors_tlimit != SLAP_NO_LIMIT ) { if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1; timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
@ -338,21 +530,10 @@ done_pr:;
} }
#endif /* SLAPD_META_CLIENT_PR */ #endif /* SLAPD_META_CLIENT_PR */
retry:;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
ctrls = op->o_ctrls; 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 ) != LDAP_SUCCESS )
{ {
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
@ -363,12 +544,57 @@ retry:;
/* /*
* Starts the search * 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, ber = ldap_build_search_req( msc->msc_ld,
mbase.bv_val, realscope, mfilter.bv_val, mbase.bv_val, realscope, filterbv.bv_val,
mapped_attrs, op->ors_attrsonly, attrs, op->ors_attrsonly,
ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref, ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref,
&msgid ); &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) { if (ber) {
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; candidates[ candidate ].sr_msgid = msgid;
rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH, rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH,
mbase.bv_val, ber, msgid ); mbase.bv_val, ber, msgid );
@ -376,35 +602,56 @@ retry:;
rc = LDAP_SUCCESS; rc = LDAP_SUCCESS;
else else
rc = LDAP_SERVER_DOWN; rc = LDAP_SERVER_DOWN;
ber = NULL;
}
switch ( rc ) { switch ( rc ) {
case LDAP_SUCCESS: case LDAP_SUCCESS:
retcode = META_SEARCH_CANDIDATE; retcode = META_SEARCH_CANDIDATE;
asyncmeta_set_msc_time(msc); asyncmeta_set_msc_time(msc);
break; goto done;
case LDAP_SERVER_DOWN: case LDAP_SERVER_DOWN:
/* 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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
if (mc->mc_active < 1) { asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
asyncmeta_clear_one_msc(NULL, mc, candidate);
}
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; Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
retcode = META_SEARCH_ERR; goto error_unavailable;
break;
default: default:
candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
retcode = META_SEARCH_NOT_CANDIDATE; 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:; done:;
#if 0
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
#endif
#ifdef SLAPD_META_CLIENT_PR #ifdef SLAPD_META_CLIENT_PR
if ( save_ctrls != op->o_ctrls ) { if ( save_ctrls != op->o_ctrls ) {
op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
@ -412,14 +659,8 @@ done:;
} }
#endif /* SLAPD_META_CLIENT_PR */ #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 ) { if ( mbase.bv_val != realbase.bv_val ) {
free( mbase.bv_val ); op->o_tmpfree( mbase.bv_val, op->o_tmpmemctx );
} }
doreturn:; doreturn:;
@ -431,25 +672,16 @@ int
asyncmeta_back_search( Operation *op, SlapReply *rs ) asyncmeta_back_search( Operation *op, SlapReply *rs )
{ {
a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private; a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
struct timeval save_tv = { 0, 0 }, time_t timeout = 0;
tv; int rc = 0;
time_t stoptime = (time_t)(-1), int ncandidates = 0, initial_candidates = 0;
lastres_time = slap_get_time(), long i;
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;
SlapReply *candidates = NULL; SlapReply *candidates = NULL;
int do_taint = 0; void *thrctx = op->o_threadctx;
bm_context_t *bc; bm_context_t *bc;
a_metaconn_t *mc; 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_assert_ready( rs );
rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */ rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
@ -461,7 +693,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
* to map attrs and maybe rewrite value * 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) { if (bc == NULL) {
rs->sr_err = LDAP_OTHER; rs->sr_err = LDAP_OTHER;
send_ldap_result(op, rs); send_ldap_result(op, rs);
@ -471,9 +703,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
candidates = bc->candidates; candidates = bc->candidates;
mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0); mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0);
if ( !mc || rs->sr_err != LDAP_SUCCESS) { if ( !mc || rs->sr_err != LDAP_SUCCESS) {
op->o_callback = cb;
send_ldap_result(op, rs); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
return rs->sr_err; return rs->sr_err;
} }
@ -511,27 +741,33 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
} }
} }
bc->timeout = timeout; if ( op->ors_tlimit != SLAP_NO_LIMIT && (timeout == 0 || op->ors_tlimit < timeout)) {
bc->stoptime = op->o_time + bc->timeout;
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->searchtime = 1;
bc->timeout = op->ors_tlimit; bc->timeout = op->ors_tlimit;
} else {
bc->timeout = timeout;
} }
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); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
rc = asyncmeta_add_message_queue(mc, bc); 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); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
rs->sr_err = LDAP_BUSY; rs->sr_err = LDAP_BUSY;
rs->sr_text = "Maximum pending ops limit exceeded"; rs->sr_text = "Maximum pending ops limit exceeded";
asyncmeta_clear_bm_context(bc);
op->o_callback = cb;
send_ldap_result(op, rs); send_ldap_result(op, rs);
goto finish; goto finish;
} }
@ -542,6 +778,30 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
{ {
continue; 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); rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, i);
switch (rc) switch (rc)
@ -552,17 +812,19 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE "
"cnd=\"%ld\"\n", op->o_log_prefix, i ); "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) { if (rc == META_SEARCH_ERR) {
META_CANDIDATE_CLEAR(&candidates[i]); META_CANDIDATE_CLEAR(&candidates[i]);
candidates[ i ].sr_msgid = META_MSGID_IGNORE; candidates[ i ].sr_msgid = META_MSGID_IGNORE;
if ( META_BACK_ONERR_STOP( mi ) ) { 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; goto finish;
} }
else { else {
continue; continue;
} }
} else if (rc == META_SEARCH_NEED_BIND) {
goto retry;
} }
break; break;
case META_SEARCH_NOT_CANDIDATE: case META_SEARCH_NOT_CANDIDATE:
@ -572,22 +834,6 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
break; break;
case META_SEARCH_NEED_BIND: 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: case META_SEARCH_BINDING:
Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING " Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING "
"cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]); "cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]);
@ -604,7 +850,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
candidates[ i ].sr_type = REP_RESULT; candidates[ i ].sr_type = REP_RESULT;
if ( META_BACK_ONERR_STOP( mi ) ) { 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; goto finish;
} }
else { else {
@ -666,14 +912,29 @@ asyncmeta_back_search( Operation *op, SlapReply *rs )
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
asyncmeta_drop_bc(mc, bc); asyncmeta_drop_bc(mc, bc);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
op->o_callback = cb;
send_ldap_result(op, rs); send_ldap_result(op, rs);
asyncmeta_clear_bm_context(bc);
goto finish; goto finish;
} }
ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 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); asyncmeta_start_listeners(mc, candidates, bc);
bc->bc_active--;
asyncmeta_memctx_toggle(thrctx);
ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
rs->sr_err = SLAPD_ASYNCOP;
finish: 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; return rs->sr_err;
} }

View file

@ -1,112 +0,0 @@
/* 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;
}

View file

@ -1,55 +0,0 @@
/* 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;
}

View file

@ -0,0 +1,88 @@
# 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

View file

@ -33,6 +33,7 @@ AC_null=@BUILD_NULL@
# other backends # other backends
AC_ldap=ldap@BUILD_LDAP@ AC_ldap=ldap@BUILD_LDAP@
AC_meta=meta@BUILD_META@ AC_meta=meta@BUILD_META@
AC_asyncmeta=asyncmeta@BUILD_ASYNCMETA@
AC_monitor=@BUILD_MONITOR@ AC_monitor=@BUILD_MONITOR@
AC_relay=relay@BUILD_RELAY@ AC_relay=relay@BUILD_RELAY@
AC_sql=sql@BUILD_SQL@ AC_sql=sql@BUILD_SQL@
@ -70,8 +71,10 @@ fi
if test "${AC_meta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then if test "${AC_meta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then
AC_meta="metano" AC_meta="metano"
fi fi
if test "${AC_asyncmeta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then
export AC_bdb AC_hdb AC_ldap AC_mdb AC_meta AC_monitor AC_null AC_relay AC_sql \ 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_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_refint AC_retcode AC_rwm AC_unique AC_syncprov AC_translucent \
AC_valsort \ AC_valsort \

View file

@ -21,6 +21,7 @@ TESTWD=`pwd`
MONITORDB=${AC_monitor-no} MONITORDB=${AC_monitor-no}
BACKLDAP=${AC_ldap-ldapno} BACKLDAP=${AC_ldap-ldapno}
BACKMETA=${AC_meta-metano} BACKMETA=${AC_meta-metano}
BACKASYNCMETA=${AC_asyncmeta-asyncmetano}
BACKRELAY=${AC_relay-relayno} BACKRELAY=${AC_relay-relayno}
BACKSQL=${AC_sql-sqlno} BACKSQL=${AC_sql-sqlno}
RDBMS=${SLAPD_USE_SQL-rdbmsno} RDBMS=${SLAPD_USE_SQL-rdbmsno}
@ -134,6 +135,7 @@ TRANSLUCENTREMOTECONF=$DATADIR/slapd-translucent-remote.conf
METACONF=$DATADIR/slapd-meta.conf METACONF=$DATADIR/slapd-meta.conf
METACONF1=$DATADIR/slapd-meta-target1.conf METACONF1=$DATADIR/slapd-meta-target1.conf
METACONF2=$DATADIR/slapd-meta-target2.conf METACONF2=$DATADIR/slapd-meta-target2.conf
ASYNCMETACONF=$DATADIR/slapd-asyncmeta.conf
GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf
ACICONF=$DATADIR/slapd-aci.conf ACICONF=$DATADIR/slapd-aci.conf
VALSORTCONF=$DATADIR/slapd-valsort.conf VALSORTCONF=$DATADIR/slapd-valsort.conf

620
tests/scripts/test073-asyncmeta Executable file
View file

@ -0,0 +1,620 @@
#! /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

View file

@ -0,0 +1,242 @@
#! /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