diff --git a/doc/man/man5/slapd-asyncmeta.5 b/doc/man/man5/slapd-asyncmeta.5 index 2b88c5b99f..6ab6f4c19b 100644 --- a/doc/man/man5/slapd-asyncmeta.5 +++ b/doc/man/man5/slapd-asyncmeta.5 @@ -376,16 +376,18 @@ Sets the network timeout value after which .BR poll (2)/ select (2) following a .BR connect (2) -returns in case of no activity. -The value is in seconds, and it can be specified as for +returns in case of no activity while sending an operation to the remote target. +The value is in milliseconds, and it can be specified as for .BR idle\-timeout . If set before any target specification, it affects all targets, unless overridden by any per-target directive. .TP .B nretries {forever|never|} -This directive defines how many times a bind should be retried -in case of temporary failure in contacting a target. If defined +This directive defines how many times forwarding an operation should be retried +in case of temporary failure in contacting a target. The number of retries +is per operation, so if a bind to the target is necessary first, the remaining +number is decremented. If defined before any target specification, it applies to all targets (by default, .BR 3 times); @@ -409,11 +411,13 @@ by a target. See for details. .TP -.B suffixmassage "" "" -All the directives starting with "rewrite" refer to the rewrite engine -that has been added to slapd. See -.B slapd\-meta(5) -for details. +.B suffixmassage "" "" +.B slapd\-asyncmeta +does not support the rewrite engine used by +the LDAP and META backends. +.B suffixmassage +can be used to perform DN suffix rewriting, the same way as the obsoleted suffixmassage directive +previously used by the LDAP backend. .TP .B t\-f\-support {NO|yes|discover} diff --git a/servers/slapd/back-asyncmeta/Makefile.in b/servers/slapd/back-asyncmeta/Makefile.in index 26a19384bf..5d64e6f493 100644 --- a/servers/slapd/back-asyncmeta/Makefile.in +++ b/servers/slapd/back-asyncmeta/Makefile.in @@ -19,12 +19,12 @@ ## based on back-meta module for inclusion in OpenLDAP Software. ## This work was sponsored by Ericsson -SRCS = init.c config.c search.c message_queue.c bind.c unbind.c add.c compare.c \ - delete.c modify.c modrdn.c suffixmassage.c map.c \ - conn.c candidates.c dncache.c meta_result.c abandon.c -OBJS = init.lo config.lo search.lo message_queue.lo bind.lo unbind.lo add.lo compare.lo \ - delete.lo modify.lo modrdn.lo suffixmassage.lo map.lo \ - conn.lo candidates.lo dncache.lo meta_result.lo abandon.lo +SRCS = init.c config.c search.c message_queue.c bind.c add.c compare.c \ + delete.c modify.c modrdn.c map.c \ + conn.c candidates.c dncache.c meta_result.c +OBJS = init.lo config.lo search.lo message_queue.lo bind.lo add.lo compare.lo \ + delete.lo modify.lo modrdn.lo map.lo \ + conn.lo candidates.lo dncache.lo meta_result.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-asyncmeta/abandon.c b/servers/slapd/back-asyncmeta/abandon.c deleted file mode 100644 index 62001dbc21..0000000000 --- a/servers/slapd/back-asyncmeta/abandon.c +++ /dev/null @@ -1,52 +0,0 @@ -/* abandon.c - abandon request handler for back-asyncmeta */ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * 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 - * . - */ - -/* 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 - -#include -#include - -#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; -} diff --git a/servers/slapd/back-asyncmeta/add.c b/servers/slapd/back-asyncmeta/add.c index 600138a0f5..12290a51bd 100644 --- a/servers/slapd/back-asyncmeta/add.c +++ b/servers/slapd/back-asyncmeta/add.c @@ -27,23 +27,33 @@ #include #include - #include "slap.h" +#include "../../../libraries/liblber/lber-int.h" +#include "../../../libraries/libldap/ldap-int.h" #include "../back-ldap/back-ldap.h" #include "back-asyncmeta.h" #include "ldap_rq.h" -#include "../../../libraries/liblber/lber-int.h" -#include "../../../libraries/libldap/ldap-int.h" -void -asyncmeta_sender_error(Operation *op, - SlapReply *rs, - slap_callback *cb) + +int +asyncmeta_error_cleanup(Operation *op, + SlapReply *rs, + bm_context_t *bc, + a_metaconn_t *mc, + int candidate) { - if (cb != NULL) { - op->o_callback = cb; + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) { + bc->bc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + return LDAP_SUCCESS; } + asyncmeta_drop_bc(mc, bc); + slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); send_ldap_result(op, rs); + return LDAP_SUCCESS; } meta_search_candidate_t @@ -51,195 +61,174 @@ asyncmeta_back_add_start(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate) + int candidate, + int do_lock) { int isupdate; Attribute *a; int i; LDAPMod **attrs; - struct berval mapped; a_dncookie dc; a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; - struct berval mdn; + struct berval mdn = {0, NULL}; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; BerElement *ber = NULL; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; SlapReply *candidates = bc->candidates; ber_int_t msgid; LDAPControl **ctrls = NULL; - int rc, nretries = 1; - + int rc; + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "addDN"; - - mdn.bv_len = 0; - - switch (asyncmeta_dn_massage( &dc, &bc->op->o_req_dn, &mdn ) ) - { - case LDAP_SUCCESS: - break; - case LDAP_UNWILLING_TO_PERFORM: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "Operation not allowed"; - retcode = META_SEARCH_ERR; - goto doreturn; - default: - rs->sr_err = LDAP_NO_SUCH_OBJECT; - retcode = META_SEARCH_NOT_CANDIDATE; - goto doreturn; - } + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); /* Count number of attributes in entry ( +1 ) */ for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next ); /* Create array of LDAPMods for ldap_add() */ - attrs = ch_malloc( sizeof( LDAPMod * )*i ); + attrs = op->o_tmpalloc(sizeof( LDAPMod * )*i, op->o_tmpmemctx); - dc.ctx = "addAttrDN"; isupdate = be_shadow_update( op ); for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) { - int j, is_oc = 0; + int j; if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod ) { continue; } - if ( a->a_desc == slap_schema.si_ad_objectClass - || a->a_desc == slap_schema.si_ad_structuralObjectClass ) - { - is_oc = 1; - mapped = a->a_desc->ad_cname; - - } else { - asyncmeta_map( &mt->mt_rwmap.rwm_at, - &a->a_desc->ad_cname, &mapped, BACKLDAP_MAP ); - if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) { - continue; - } - } - - attrs[ i ] = ch_malloc( sizeof( LDAPMod ) ); + attrs[ i ] = op->o_tmpalloc( sizeof( LDAPMod ), op->o_tmpmemctx ); if ( attrs[ i ] == NULL ) { continue; } attrs[ i ]->mod_op = LDAP_MOD_BVALUES; - attrs[ i ]->mod_type = mapped.bv_val; - - if ( is_oc ) { - for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ); - - attrs[ i ]->mod_bvalues = - (struct berval **)ch_malloc( ( j + 1 ) * - sizeof( struct berval * ) ); - for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) { - struct ldapmapping *mapping; - - asyncmeta_mapping( &mt->mt_rwmap.rwm_oc, - &a->a_vals[ j ], &mapping, BACKLDAP_MAP ); - - if ( mapping == NULL ) { - if ( mt->mt_rwmap.rwm_oc.drop_missing ) { - continue; - } - attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ]; - - } else { - attrs[ i ]->mod_bvalues[ j ] = &mapping->dst; - } - j++; - } - attrs[ i ]->mod_bvalues[ j ] = NULL; - - } else { - /* - * FIXME: dn-valued attrs should be rewritten - * to allow their use in ACLs at the back-ldap - * level. - */ - if ( a->a_desc->ad_type->sat_syntax == - slap_schema.si_syn_distinguishedName ) - { - (void)asyncmeta_dnattr_rewrite( &dc, a->a_vals ); - if ( a->a_vals == NULL ) { - continue; - } - } - - for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) - ; - - attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) ); - for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) { - attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ]; - } - attrs[ i ]->mod_bvalues[ j ] = NULL; + attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val; + j = a->a_numvals; + attrs[ i ]->mod_bvalues = op->o_tmpalloc( ( j + 1 ) * sizeof( struct berval * ), op->o_tmpmemctx ); + for (j=0; ja_numvals; j++) { + attrs[ i ]->mod_bvalues[ j ] = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx ); + if ( a->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) + asyncmeta_dn_massage( &dc, &a->a_vals[ j ], attrs[ i ]->mod_bvalues[ j ] ); + else + *attrs[ i ]->mod_bvalues[ j ] = a->a_vals[ j ]; } + + attrs[ i ]->mod_bvalues[ j ] = NULL; i++; } attrs[ i ] = NULL; -retry:; + asyncmeta_set_msc_time(msc); + ctrls = op->o_ctrls; - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_ERR; goto done; } + /* someone might have reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } ber = ldap_build_add_req( msc->msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid); + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_add_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD, - mdn.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD, + mdn.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_clear_one_msc(NULL, mc, candidate); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - + /* fall though*/ default: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - retcode = META_SEARCH_ERR; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; } } -done: +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + ldap_pvt_thread_yield(); + retcode = META_SEARCH_NEED_BIND; + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send add request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + ldap_pvt_thread_yield(); + break; + } +done: (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - for ( --i; i >= 0; --i ) { - free( attrs[ i ]->mod_bvalues ); - free( attrs[ i ] ); - } - free( attrs ); - if ( mdn.bv_val != op->ora_e->e_dn ) { - free( mdn.bv_val ); - BER_BVZERO( &mdn ); + if ( mdn.bv_val != op->o_req_dn.bv_val ) { + op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); } -doreturn:; Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); return retcode; } @@ -252,26 +241,31 @@ asyncmeta_back_add( Operation *op, SlapReply *rs ) a_metatarget_t *mt; a_metaconn_t *mc; int rc, candidate = -1; - OperationBuffer opbuf; + void *thrctx = op->o_threadctx; bm_context_t *bc; SlapReply *candidates; - slap_callback *cb = op->o_callback; + time_t current_time = slap_get_time(); + int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; - Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_add: %s\n", + Debug(LDAP_DEBUG_TRACE, "==> asyncmeta_back_add: %s\n", op->o_req_dn.bv_val ); - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + if (current_time > op->o_time) { + Debug(asyncmeta_debug, "==> asyncmeta_back_add[%s]: o_time:[%ld], current time: [%ld]\n", + op->o_log_prefix, op->o_time, current_time ); + } + + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); return rs->sr_err; } candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + send_ldap_result(op, rs); return rs->sr_err; } @@ -280,16 +274,39 @@ asyncmeta_back_add( Operation *op, SlapReply *rs ) bc->retrying = LDAP_BACK_RETRYING; bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + mc->mc_conns[candidate].msc_active++; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + goto finish; + } + +retry: + current_time = slap_get_time(); + if (bc->timeout && bc->stoptime < current_time) { + int timeout_err; + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + rs->sr_err = timeout_err; + rs->sr_text = "Operation timed out before it was sent to target"; + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; } @@ -298,72 +315,49 @@ asyncmeta_back_add( Operation *op, SlapReply *rs ) { case META_SEARCH_CANDIDATE: /* target is already bound, just send the request */ - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); + Debug(LDAP_DEBUG_TRACE , "%s asyncmeta_back_add: " + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); - rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate); + rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate, 1); if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } - break; + break; case META_SEARCH_NOT_CANDIDATE: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - } - break; case META_SEARCH_BINDING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - /* Todo add the context to the message queue but do not send the request - the receiver must send this when we are done binding */ - /* question - how would do receiver know to which targets??? */ - break; + Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING " + "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); + /* add the context to the message queue but do not send the request + the receiver must send this when we are done binding */ + break; case META_SEARCH_ERR: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR " - "cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - default: - assert( 0 ); - break; - } + Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR " + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); + goto finish; + default: + assert( 0 ); + break; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; asyncmeta_start_one_listener(mc, candidates, bc, candidate); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; finish: return rs->sr_err; } diff --git a/servers/slapd/back-asyncmeta/back-asyncmeta.h b/servers/slapd/back-asyncmeta/back-asyncmeta.h index 53d57f6052..ab1f03619f 100644 --- a/servers/slapd/back-asyncmeta/back-asyncmeta.h +++ b/servers/slapd/back-asyncmeta/back-asyncmeta.h @@ -27,18 +27,12 @@ #ifndef SLAPD_ASYNCMETA_H #define SLAPD_ASYNCMETA_H -#ifndef ENABLE_REWRITE -#error "--enable-rewrite is required!" -#endif - #ifdef LDAP_DEVEL #define SLAPD_META_CLIENT_PR 1 #endif /* LDAP_DEVEL */ #include "proto-asyncmeta.h" -/* String rewrite library */ -#include "rewrite.h" #include "ldap_rq.h" LDAP_BEGIN_DECL @@ -50,108 +44,6 @@ LDAP_BEGIN_DECL #define META_BACK_PRINT_CONNTREE 0 #endif /* !META_BACK_PRINT_CONNTREE */ -/* from back-ldap.h before rwm removal */ -struct ldapmap { - int drop_missing; - - Avlnode *map; - Avlnode *remap; -}; - -struct ldapmapping { - struct berval src; - struct berval dst; -}; - -struct ldaprwmap { - /* - * DN rewriting - */ - struct rewrite_info *rwm_rw; - BerVarray rwm_bva_rewrite; - - /* - * Attribute/objectClass mapping - */ - struct ldapmap rwm_oc; - struct ldapmap rwm_at; - BerVarray rwm_bva_map; -}; - -/* Whatever context asyncmeta_dn_massage needs... */ -typedef struct a_dncookie { - struct a_metatarget_t *target; - - Connection *conn; - char *ctx; - SlapReply *rs; -} a_dncookie; - -int asyncmeta_dn_massage(a_dncookie *dc, struct berval *dn, - struct berval *res); - -extern int asyncmeta_conn_dup( void *c1, void *c2 ); -extern void asyncmeta_conn_free( void *c ); - -/* attributeType/objectClass mapping */ -int asyncmeta_mapping_cmp (const void *, const void *); -int asyncmeta_mapping_dup (void *, void *); - -void asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping ** ); -int asyncmeta_mapping ( struct ldapmap *map, struct berval *s, - struct ldapmapping **m, int remap ); -void asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *m, - int remap ); -#define BACKLDAP_MAP 0 -#define BACKLDAP_REMAP 1 -char * -asyncmeta_map_filter( - struct ldapmap *at_map, - struct ldapmap *oc_map, - struct berval *f, - int remap ); - -int -asyncmeta_map_attrs( - Operation *op, - struct ldapmap *at_map, - AttributeName *a, - int remap, - char ***mapped_attrs ); - -extern int -asyncmeta_filter_map_rewrite( - a_dncookie *dc, - Filter *f, - struct berval *fstr, - int remap, - void *memctx ); - -/* suffix massaging by means of librewrite */ -extern int -asyncmeta_suffix_massage_config( struct rewrite_info *info, - struct berval *pvnc, - struct berval *nvnc, - struct berval *prnc, - struct berval *nrnc ); - -extern int -asyncmeta_back_referral_result_rewrite( - a_dncookie *dc, - BerVarray a_vals, - void *memctx ); -extern int -asyncmeta_dnattr_rewrite( - a_dncookie *dc, - BerVarray a_vals ); -extern int -asyncmeta_dnattr_result_rewrite( - a_dncookie *dc, - BerVarray a_vals ); - - -/* (end of) from back-ldap.h before rwm removal */ - /* * A a_metasingleconn_t can be in the following, mutually exclusive states: * @@ -171,6 +63,7 @@ asyncmeta_dnattr_result_rewrite( #define META_BACK_FCONN_INITED (0x00100000U) #define META_BACK_FCONN_CREATING (0x00200000U) +#define META_BACK_FCONN_INVALID (0x00400000U) #define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED) #define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED) @@ -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_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING) #define META_BACK_CONN_CREATING_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc)) +#define META_BACK_CONN_INVALID(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INVALID) +#define META_BACK_CONN_INVALID_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INVALID) +#define META_BACK_CONN_INVALID_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INVALID) struct a_metainfo_t; struct a_metaconn_t; @@ -190,20 +86,25 @@ struct a_metatarget_t; #define META_RETRYING ((ber_tag_t)0x4) typedef struct bm_context_t { - LDAP_SLIST_ENTRY(bm_context_t) bc_next; + LDAP_STAILQ_ENTRY(bm_context_t) bc_next; + struct a_metaconn_t *bc_mc; time_t timeout; time_t stoptime; ldap_back_send_t sendok; ldap_back_send_t retrying; int candidate_match; - int sent; - int bc_active; + volatile int bc_active; int searchtime; /* stoptime is a search timelimit */ int is_ok; + int is_root; + volatile sig_atomic_t bc_invalid; SlapReply rs; Operation *op; + Operation copy_op; LDAPControl **ctrls; int *msgids; + int *nretries; /* number of times to retry a failed send on an msc */ + struct berval c_peer_name; /* peer name of original op->o_conn*/ SlapReply *candidates; } bm_context_t; @@ -226,14 +127,16 @@ typedef struct a_metasingleconn_t { LDAP *msc_ld; LDAP *msc_ldr; time_t msc_time; + time_t msc_binding_time; + time_t msc_result_time; struct berval msc_bound_ndn; struct berval msc_cred; unsigned msc_mscflags; + /* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros * defined for back-ldap */ #define lc_lcflags msc_mscflags - int msc_pending_ops; - int msc_timeout_ops; + volatile int msc_active; /* Connection for the select */ Connection *conn; } a_metasingleconn_t; @@ -267,7 +170,7 @@ typedef struct a_metaconn_t { int pending_ops; ldap_pvt_thread_mutex_t mc_om_mutex; /* queue for pending operations */ - LDAP_SLIST_HEAD(BCList, bm_context_t) mc_om_list; + LDAP_STAILQ_HEAD(BCList, bm_context_t) mc_om_list; /* supersedes the connection stuff */ a_metasingleconn_t *mc_conns; } a_metaconn_t; @@ -309,7 +212,7 @@ typedef struct a_metacommon_t { #define META_RETRY_UNDEFINED (-2) #define META_RETRY_FOREVER (-1) #define META_RETRY_NEVER (0) -#define META_RETRY_DEFAULT (10) +#define META_RETRY_DEFAULT (2) unsigned mc_flags; #define META_BACK_CMN_ISSET(mc,f) ( ( (mc)->mc_flags & (f) ) == (f) ) @@ -359,6 +262,9 @@ typedef struct a_metatarget_t { struct berval mt_psuffix; /* pretty suffix */ struct berval mt_nsuffix; /* normalized suffix */ + struct berval mt_lsuffixm; /* local suffix for massage */ + struct berval mt_rsuffixm; /* remote suffix for massage */ + struct berval mt_binddn; struct berval mt_bindpw; @@ -379,8 +285,6 @@ typedef struct a_metatarget_t { #define mt_idassert_flags mt_idassert.si_flags #define mt_idassert_authz mt_idassert.si_authz - struct ldaprwmap mt_rwmap; - sig_atomic_t mt_isquarantined; ldap_pvt_thread_mutex_t mt_quarantine_mutex; @@ -520,6 +424,7 @@ typedef struct a_metainfo_t { int mi_next_conn; a_metaconn_t *mi_conns; + struct berval mi_suffix; } a_metainfo_t; typedef enum meta_op_type { @@ -528,6 +433,33 @@ typedef enum meta_op_type { META_OP_REQUIRE_ALL } meta_op_type; +/* Whatever context asyncmeta_dn_massage needs... */ +typedef struct a_dncookie { + Operation *op; + struct a_metatarget_t *target; + void *memctx; + int to_from; +} a_dncookie; + + +#define MASSAGE_REQ 0 +#define MASSAGE_REP 1 + +extern void +asyncmeta_dn_massage(a_dncookie *dc, struct berval *dn, + struct berval *res); + +extern void +asyncmeta_filter_map_rewrite( + a_dncookie *dc, + Filter *f, + struct berval *fstr ); + +extern void +asyncmeta_back_referral_result_rewrite( + a_dncookie *dc, + BerVarray a_vals ); + extern a_metaconn_t * asyncmeta_getconn( Operation *op, @@ -537,17 +469,6 @@ asyncmeta_getconn( ldap_back_send_t sendok, int alloc_new); -extern int -asyncmeta_retry( - Operation *op, - SlapReply *rs, - a_metaconn_t **mcp, - int candidate, - ldap_back_send_t sendok ); - -extern void -asyncmeta_conn_free( - void *v_mc ); extern int asyncmeta_init_one_conn( @@ -566,24 +487,6 @@ asyncmeta_quarantine( SlapReply *rs, int candidate ); -extern int -asyncmeta_dobind( - Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - ldap_back_send_t sendok, - SlapReply *candidates); - -extern int -asyncmeta_single_dobind( - Operation *op, - SlapReply *rs, - a_metaconn_t **mcp, - int candidate, - ldap_back_send_t sendok, - int retries, - int dolock ); - extern int asyncmeta_proxy_authz_cred( a_metaconn_t *mc, @@ -595,31 +498,13 @@ asyncmeta_proxy_authz_cred( struct berval *bindcred, int *method ); -extern int -asyncmeta_cancel( - a_metaconn_t *mc, - Operation *op, - SlapReply *rs, - ber_int_t msgid, - int candidate, - ldap_back_send_t sendok ); - -extern int -asyncmeta_op_result( - a_metaconn_t *mc, - Operation *op, - SlapReply *rs, - int candidate, - ber_int_t msgid, - time_t timeout, - ldap_back_send_t sendok ); - extern int asyncmeta_controls_add( Operation *op, SlapReply *rs, a_metaconn_t *mc, int candidate, + int isroot, LDAPControl ***pctrls ); extern int @@ -682,9 +567,6 @@ asyncmeta_dncache_delete_entry( extern void asyncmeta_dncache_free( void *entry ); -extern void -asyncmeta_back_map_free( struct ldapmap *lm ); - extern int asyncmeta_subtree_destroy( a_metasubtree_t *ms ); @@ -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); void asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc); +void asyncmeta_drop_bc_from_fconn(bm_context_t *bc); bm_context_t * asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate); -bm_context_t * -asyncmeta_find_message_by_opmsguid(ber_int_t msgid, a_metaconn_t *mc, int remove); +void asyncmeta_memctx_toggle(void *thrctx); void* asyncmeta_op_handle_result(void *ctx, void *arg); int asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bm ); @@ -738,16 +620,19 @@ int asyncmeta_clear_one_msc( Operation *op, a_metaconn_t *msc, - int candidate ); + int candidate, + int unbind, + const char * caller); a_metaconn_t * asyncmeta_get_next_mc( a_metainfo_t *mi ); void* asyncmeta_timeout_loop(void *ctx, void *arg); + int asyncmeta_start_timeout_loop(a_metatarget_t *mt, a_metainfo_t *mi); + void asyncmeta_set_msc_time(a_metasingleconn_t *msc); -void asyncmeta_clear_message_queue(a_metasingleconn_t *msc); int asyncmeta_back_cancel( a_metaconn_t *mc, @@ -755,25 +640,15 @@ int asyncmeta_back_cancel( ber_int_t msgid, int candidate ); -int -asyncmeta_back_cancel_msc( - Operation *op, - SlapReply *rs, - ber_int_t msgid, - a_metasingleconn_t *msc, - int candidate, - ldap_back_send_t sendok ); - -int -asyncmeta_back_abandon_candidate( - a_metaconn_t *mc, - Operation *op, - ber_int_t msgid, - int candidate ); void asyncmeta_send_result(bm_context_t* bc, int error, char *text); -int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets); +int asyncmeta_new_bm_context(Operation *op, + SlapReply *rs, + bm_context_t **new_bc, + int ntargets, + a_metainfo_t *mi); + int asyncmeta_start_listeners(a_metaconn_t *mc, SlapReply *candidates, bm_context_t *bc); int asyncmeta_start_one_listener(a_metaconn_t *mc, SlapReply *candidates, bm_context_t *bc, int candidate); @@ -785,7 +660,8 @@ asyncmeta_back_search_start( bm_context_t *bc, int candidate, struct berval *prcookie, - ber_int_t prsize ); + ber_int_t prsize, + int do_lock); meta_search_candidate_t asyncmeta_dobind_init( @@ -808,40 +684,97 @@ asyncmeta_back_add_start(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate); + int candidate, + int do_lock); meta_search_candidate_t asyncmeta_back_modify_start(Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate); + SlapReply *rs, + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + int do_lock); meta_search_candidate_t asyncmeta_back_modrdn_start(Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate); + SlapReply *rs, + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + int do_lock); meta_search_candidate_t asyncmeta_back_delete_start(Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate); + SlapReply *rs, + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + int do_lock); meta_search_candidate_t asyncmeta_back_compare_start(Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate); + SlapReply *rs, + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + int do_lock); + +bm_context_t * +asyncmeta_bc_in_queue(a_metaconn_t *mc, + bm_context_t *bc); + +int +asyncmeta_error_cleanup(Operation *op, + SlapReply *rs, + bm_context_t *bc, + a_metaconn_t *mc, + int candidate); + +int +asyncmeta_reset_msc(Operation *op, + a_metaconn_t *mc, + int candidate, + int unbind, + const char *caller); void -asyncmeta_sender_error(Operation *op, - SlapReply *rs, - slap_callback *cb); +asyncmeta_back_conn_free( + void *v_mc ); +void asyncmeta_log_msc(a_metasingleconn_t *msc); +void asyncmeta_log_conns(a_metainfo_t *mi); + +void asyncmeta_get_timestamp(char *buf); + +int +asyncmeta_dncache_update_entry(a_metadncache_t *cache, + struct berval *ndn, + int target ); + +void +asyncmeta_dnattr_result_rewrite(a_dncookie *dc, + BerVarray a_vals); + +void +asyncmeta_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 diff --git a/servers/slapd/back-asyncmeta/bind.c b/servers/slapd/back-asyncmeta/bind.c index 6e4aec380c..8b33b8b294 100644 --- a/servers/slapd/back-asyncmeta/bind.c +++ b/servers/slapd/back-asyncmeta/bind.c @@ -28,15 +28,16 @@ #include #include #include - +#include "slap.h" +#include "../../../libraries/libldap/ldap-int.h" #define AVL_INTERNAL -#include "slap.h" #include "../back-ldap/back-ldap.h" #include "back-asyncmeta.h" - #include "lutil_ldap.h" +#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12" + static int asyncmeta_proxy_authz_bind( a_metaconn_t *mc, @@ -250,7 +251,6 @@ asyncmeta_bind_op_result( struct timeval tv; int rc; int nretries = mt->mt_nretries; - char buf[ SLAP_TEXT_BUFLEN ]; Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_bind_op_result[%d]\n", @@ -333,7 +333,7 @@ retry:; ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); - Debug(LDAP_DEBUG_ANY, + Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_bind_op_result[%d]: err=%d (%s) nretries=%d.\n", op->o_log_prefix, candidate, rs->sr_err, ldap_err2string(rs->sr_err), nretries ); @@ -401,16 +401,12 @@ asyncmeta_single_bind( /* * Rewrite the bind dn if needed */ + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "bindDN"; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; - if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - rs->sr_text = "DN rewrite error"; - rs->sr_err = LDAP_OTHER; - return rs->sr_err; - } + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); /* don't add proxyAuthz; set the bindDN */ save_o_dn = op->o_dn; @@ -419,7 +415,7 @@ asyncmeta_single_bind( op->o_dn = op->o_req_dn; ctrls = op->o_ctrls; - rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ); + rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, be_isroot(op), &ctrls ); op->o_dn = save_o_dn; op->o_do_not_cache = save_o_do_not_cache; if ( rs->sr_err != LDAP_SUCCESS ) { @@ -484,7 +480,7 @@ cache_refresh:; return_results:; if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); + op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); } if ( META_BACK_TGT_QUARANTINE( mt ) ) { @@ -497,81 +493,6 @@ return_results:; return rs->sr_err; } -/* - * asyncmeta_back_single_dobind - */ -int -asyncmeta_back_single_dobind( - Operation *op, - SlapReply *rs, - a_metaconn_t **mcp, - int candidate, - ldap_back_send_t sendok, - int nretries, - int dolock ) -{ - a_metaconn_t *mc = *mcp; - a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - int msgid; - - assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); - - if ( op->o_conn != NULL && - !op->o_do_not_cache && - ( BER_BVISNULL( &msc->msc_bound_ndn ) || - BER_BVISEMPTY( &msc->msc_bound_ndn ) || - ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || - ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) - { - (void)asyncmeta_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock ); - - } else { - char *binddn = ""; - struct berval cred = BER_BVC( "" ); - - /* use credentials if available */ - if ( !BER_BVISNULL( &msc->msc_bound_ndn ) - && !BER_BVISNULL( &msc->msc_cred ) ) - { - binddn = msc->msc_bound_ndn.bv_val; - cred = msc->msc_cred; - } - - for (;;) { - rs->sr_err = ldap_sasl_bind( msc->msc_ld, - binddn, LDAP_SASL_SIMPLE, &cred, - NULL, NULL, &msgid ); - if ( rs->sr_err != LDAP_X_CONNECTING ) { - break; - } - ldap_pvt_thread_yield(); - } - - rs->sr_err = asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); - - /* if bind succeeded, but anonymous, clear msc_bound_ndn */ - if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) { - if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { - ber_memfree( msc->msc_bound_ndn.bv_val ); - BER_BVZERO( &msc->msc_bound_ndn ); - } - - if ( !BER_BVISNULL( &msc->msc_cred ) ) { - memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); - ber_memfree( msc->msc_cred.bv_val ); - BER_BVZERO( &msc->msc_cred ); - } - } - } - - if ( META_BACK_TGT_QUARANTINE( mt ) ) { - asyncmeta_quarantine( op, mi, rs, candidate ); - } - - return rs->sr_err; -} /* * asyncmeta_back_default_rebind @@ -644,16 +565,28 @@ asyncmeta_back_cancel( a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int rc = LDAP_OTHER; + struct timeval tv = { 0, 0 }; + ber_socket_t s; Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n", op->o_log_prefix, candidate, msgid ); - if (msc->msc_ld == NULL) { + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n already reset", op->o_log_prefix, candidate, msgid ); return LDAP_SUCCESS; } + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + return rc; + } + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + rc = LDAP_SERVER_DOWN; + return rc; + } /* default behavior */ if ( META_BACK_TGT_ABANDON( mt ) ) { rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL ); @@ -675,396 +608,9 @@ asyncmeta_back_cancel( } -int -asyncmeta_back_abandon_candidate( - a_metaconn_t *mc, - Operation *op, - ber_int_t msgid, - int candidate ) -{ - - a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - - int rc = LDAP_OTHER; - - Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_abandon[%d] msgid=%d\n", - op->o_log_prefix, candidate, msgid ); - - rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL ); - - Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_abandon[%d] err=%d\n", - op->o_log_prefix, candidate, rc ); - - return rc; -} - -int -asyncmeta_back_cancel_msc( - Operation *op, - SlapReply *rs, - ber_int_t msgid, - a_metasingleconn_t *msc, - int candidate, - ldap_back_send_t sendok ) -{ - a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private; - - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - - int rc = LDAP_OTHER; - - Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel_msc[%d] msgid=%d\n", - op->o_log_prefix, candidate, msgid ); - - /* default behavior */ - if ( META_BACK_TGT_ABANDON( mt ) ) { - rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL ); - - } else if ( META_BACK_TGT_IGNORE( mt ) ) { - rc = ldap_pvt_discard( msc->msc_ld, msgid ); - - } else if ( META_BACK_TGT_CANCEL( mt ) ) { - rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL ); - - } else { - assert( 0 ); - } - - Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_cancel_msc[%d] err=%d\n", - op->o_log_prefix, candidate, rc ); - - return rc; -} /* - * FIXME: error return must be handled in a cleaner way ... - */ -int -asyncmeta_back_op_result( - a_metaconn_t *mc, - Operation *op, - SlapReply *rs, - int candidate, - ber_int_t msgid, - time_t timeout, - ldap_back_send_t sendok ) -{ - a_metainfo_t *mi = mc->mc_info; - - const char *save_text = rs->sr_text, - *save_matched = rs->sr_matched; - BerVarray save_ref = rs->sr_ref; - LDAPControl **save_ctrls = rs->sr_ctrls; - void *matched_ctx = NULL; - - char *matched = NULL; - char *text = NULL; - char **refs = NULL; - LDAPControl **ctrls = NULL; - - assert( mc != NULL ); - - rs->sr_text = NULL; - rs->sr_matched = NULL; - rs->sr_ref = NULL; - rs->sr_ctrls = NULL; - - if ( candidate != META_TARGET_NONE ) { - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - - if ( LDAP_ERR_OK( rs->sr_err ) ) { - int rc; - struct timeval tv; - LDAPMessage *res = NULL; - time_t stoptime = (time_t)(-1); - int timeout_err = op->o_protocol >= LDAP_VERSION3 ? - LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; - const char *timeout_text = "Operation timed out"; - - /* if timeout is not specified, compute and use - * the one specific to the ongoing operation */ - if ( timeout == (time_t)(-1) ) { - slap_op_t opidx = slap_req2op( op->o_tag ); - - if ( opidx == SLAP_OP_SEARCH ) { - if ( op->ors_tlimit <= 0 ) { - timeout = 0; - - } else { - timeout = op->ors_tlimit; - timeout_err = LDAP_TIMELIMIT_EXCEEDED; - timeout_text = NULL; - } - - } else { - timeout = mt->mt_timeout[ opidx ]; - } - } - - /* better than nothing :) */ - if ( timeout == 0 ) { - if ( mi->mi_idle_timeout ) { - timeout = mi->mi_idle_timeout; - - } - } - - if ( timeout ) { - stoptime = op->o_time + timeout; - } - - LDAP_BACK_TV_SET( &tv ); - -retry:; - rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); - switch ( rc ) { - case 0: - if ( timeout && slap_get_time() > stoptime ) { - (void)asyncmeta_back_cancel( mc, op, msgid, candidate ); - rs->sr_err = timeout_err; - rs->sr_text = timeout_text; - break; - } - - LDAP_BACK_TV_SET( &tv ); - ldap_pvt_thread_yield(); - goto retry; - - case -1: - ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, - &rs->sr_err ); - break; - - - /* otherwise get the result; if it is not - * LDAP_SUCCESS, record it in the reply - * structure (this includes - * LDAP_COMPARE_{TRUE|FALSE}) */ - default: - /* only touch when activity actually took place... */ - if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { - msc->msc_time = op->o_time; - } - - rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, - &matched, &text, &refs, &ctrls, 1 ); - res = NULL; - if ( rc == LDAP_SUCCESS ) { - rs->sr_text = text; - } else { - rs->sr_err = rc; - } - rs->sr_err = slap_map_api2result( rs ); - - /* RFC 4511: referrals can only appear - * if result code is LDAP_REFERRAL */ - if ( refs != NULL - && refs[ 0 ] != NULL - && refs[ 0 ][ 0 ] != '\0' ) - { - if ( rs->sr_err != LDAP_REFERRAL ) { - Debug( LDAP_DEBUG_ANY, - "%s asyncmeta_back_op_result[%d]: " - "got referrals with err=%d\n", - op->o_log_prefix, - candidate, rs->sr_err ); - - } else { - int i; - - for ( i = 0; refs[ i ] != NULL; i++ ) - /* count */ ; - rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), - op->o_tmpmemctx ); - for ( i = 0; refs[ i ] != NULL; i++ ) { - ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); - } - BER_BVZERO( &rs->sr_ref[ i ] ); - } - - } else if ( rs->sr_err == LDAP_REFERRAL ) { - Debug( LDAP_DEBUG_ANY, - "%s asyncmeta_back_op_result[%d]: " - "got err=%d with null " - "or empty referrals\n", - op->o_log_prefix, - candidate, rs->sr_err ); - - rs->sr_err = LDAP_NO_SUCH_OBJECT; - } - - if ( ctrls != NULL ) { - rs->sr_ctrls = ctrls; - } - } - - assert( res == NULL ); - } - - /* if the error in the reply structure is not - * LDAP_SUCCESS, try to map it from client - * to server error */ - if ( !LDAP_ERR_OK( rs->sr_err ) ) { - rs->sr_err = slap_map_api2result( rs ); - - /* internal ops ( op->o_conn == NULL ) - * must not reply to client */ - if ( op->o_conn && !op->o_do_not_cache && matched ) { - - /* record the (massaged) matched - * DN into the reply structure */ - rs->sr_matched = matched; - } - } - - if ( META_BACK_TGT_QUARANTINE( mt ) ) { - asyncmeta_quarantine( op, mi, rs, candidate ); - } - - } else { - int i, - err = rs->sr_err; - - for ( i = 0; i < mi->mi_ntargets; i++ ) { - a_metasingleconn_t *msc = &mc->mc_conns[ i ]; - char *xtext = NULL; - char *xmatched = NULL; - - if ( msc->msc_ld == NULL ) { - continue; - } - - rs->sr_err = LDAP_SUCCESS; - - ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); - if ( rs->sr_err != LDAP_SUCCESS ) { - /* - * better check the type of error. In some cases - * (search ?) it might be better to return a - * success if at least one of the targets gave - * positive result ... - */ - ldap_get_option( msc->msc_ld, - LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext ); - if ( xtext != NULL && xtext [ 0 ] == '\0' ) { - ldap_memfree( xtext ); - xtext = NULL; - } - - ldap_get_option( msc->msc_ld, - LDAP_OPT_MATCHED_DN, &xmatched ); - if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) { - ldap_memfree( xmatched ); - xmatched = NULL; - } - - rs->sr_err = slap_map_api2result( rs ); - - Debug(LDAP_DEBUG_ANY, - "%s asyncmeta_back_op_result[%d] " "err=%d text=\"%s\" matched=\"%s\".\n", - op->o_log_prefix, i, rs->sr_err, - (xtext ? xtext : ""), - (xmatched ? xmatched : "") ); - - /* - * FIXME: need to rewrite "match" (need rwinfo) - */ - switch ( rs->sr_err ) { - default: - err = rs->sr_err; - if ( xtext != NULL ) { - if ( text ) { - ldap_memfree( text ); - } - text = xtext; - xtext = NULL; - } - if ( xmatched != NULL ) { - if ( matched ) { - ldap_memfree( matched ); - } - matched = xmatched; - xmatched = NULL; - } - break; - } - - if ( xtext ) { - ldap_memfree( xtext ); - } - - if ( xmatched ) { - ldap_memfree( xmatched ); - } - } - - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) { - asyncmeta_quarantine( op, mi, rs, i ); - } - } - - if ( err != LDAP_SUCCESS ) { - rs->sr_err = err; - } - } - - if ( matched != NULL ) { - struct berval dn, pdn; - - ber_str2bv( matched, 0, 0, &dn ); - if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) { - ldap_memfree( matched ); - matched_ctx = op->o_tmpmemctx; - matched = pdn.bv_val; - } - rs->sr_matched = matched; - } - - if ( rs->sr_err == LDAP_UNAVAILABLE ) { - if ( !( sendok & LDAP_BACK_RETRYING ) ) { - if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { - if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; - send_ldap_result( op, rs ); - } - } - - } else if ( op->o_conn && - ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) - || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) - { - send_ldap_result( op, rs ); - } - if ( matched ) { - op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); - } - if ( text ) { - ldap_memfree( text ); - } - if ( rs->sr_ref ) { - op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); - rs->sr_ref = NULL; - } - if ( refs ) { - ber_memvfree( (void **)refs ); - } - if ( ctrls ) { - assert( rs->sr_ctrls != NULL ); - ldap_controls_free( ctrls ); - } - - rs->sr_text = save_text; - rs->sr_matched = save_matched; - rs->sr_ref = save_ref; - rs->sr_ctrls = save_ctrls; - - return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); -} - -/* - * meta_back_proxy_authz_cred() + * asyncmeta_back_proxy_authz_cred() * * prepares credentials & method for meta_back_proxy_authz_bind(); * or, if method is SASL, performs the SASL bind directly. @@ -1085,7 +631,8 @@ asyncmeta_back_proxy_authz_cred( a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; struct berval ndn; int dobind = 0; - + struct timeval old_tv = {0, 0}; + struct timeval bind_tv = { mt->mt_timeout[ SLAP_OP_BIND ], 0}; /* don't proxyAuthz if protocol is not LDAPv3 */ switch ( mt->mt_version ) { case LDAP_VERSION3: @@ -1260,6 +807,22 @@ asyncmeta_back_proxy_authz_cred( } } + ldap_get_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv); + + if (mt->mt_timeout[ SLAP_OP_BIND ] > 0 ) { + rs->sr_err = ldap_set_option( msc->msc_ld, + LDAP_OPT_TIMEOUT, + (void *)&bind_tv ); + + if ( rs->sr_err != LDAP_OPT_SUCCESS ) { + rs->sr_err = LDAP_OTHER; + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); + goto done; + } + } defaults = lutil_sasl_defaults( msc->msc_ld, mt->mt_idassert_sasl_mech.bv_val, mt->mt_idassert_sasl_realm.bv_val, @@ -1280,8 +843,17 @@ asyncmeta_back_proxy_authz_cred( LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); + /* restore the old timeout just in case */ + ldap_set_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv ); + rs->sr_err = slap_map_api2result( rs ); if ( rs->sr_err != LDAP_SUCCESS ) { + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_back_proxy_authz_cred failed bind msc: %p\n", + time_buf, msc ); + } LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); @@ -1391,6 +963,278 @@ asyncmeta_proxy_authz_bind( return LDAP_BACK_CONN_ISBOUND( msc ); } + +static int +asyncmeta_back_proxy_authz_ctrl(Operation *op, + SlapReply *rs, + struct berval *bound_ndn, + int version, + int isroot, + slap_idassert_t *si, + LDAPControl *ctrl ) +{ + slap_idassert_mode_t mode; + struct berval assertedID, + ndn; + + rs->sr_err = SLAP_CB_CONTINUE; + + /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID, + * but if it is not set this test fails. We need a different + * means to detect if idassert is enabled */ + if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) ) + && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) + && BER_BVISNULL( &si->si_bc.sb_saslmech ) ) + { + goto done; + } + + if ( !op->o_conn || op->o_do_not_cache || ( isroot ) ) { + goto done; + } + + if ( op->o_tag == LDAP_REQ_BIND ) { + ndn = op->o_req_ndn; + +#if 0 + } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { + ndn = op->o_conn->c_ndn; +#endif + } else { + ndn = op->o_ndn; + } + + if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) { + if ( op->o_proxy_authz ) { + /* + * FIXME: we do not want to perform proxyAuthz + * on behalf of the client, because this would + * be performed with "proxyauthzdn" privileges. + * + * This might actually be too strict, since + * the "proxyauthzdn" authzTo, and each entry's + * authzFrom attributes may be crafted + * to avoid unwanted proxyAuthz to take place. + */ +#if 0 + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "proxyAuthz not allowed within namingContext"; +#endif + goto done; + } + + if ( !BER_BVISNULL( bound_ndn ) ) { + goto done; + } + + if ( BER_BVISNULL( &ndn ) ) { + goto done; + } + + if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) { + goto done; + } + + } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) { + if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) + { + /* already asserted in SASL via native authz */ + goto done; + } + + } else if ( si->si_authz && !isroot ) { + int rc; + struct berval authcDN; + + if ( BER_BVISNULL( &ndn ) ) { + authcDN = slap_empty_bv; + } else { + authcDN = ndn; + } + rc = slap_sasl_matches( op, si->si_authz, + &authcDN, &authcDN ); + if ( rc != LDAP_SUCCESS ) { + if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { + /* ndn is not authorized + * to use idassert */ + rs->sr_err = rc; + } + goto done; + } + } + + if ( op->o_proxy_authz ) { + /* + * FIXME: we can: + * 1) ignore the already set proxyAuthz control + * 2) leave it in place, and don't set ours + * 3) add both + * 4) reject the operation + * + * option (4) is very drastic + * option (3) will make the remote server reject + * the operation, thus being equivalent to (4) + * option (2) will likely break the idassert + * assumptions, so we cannot accept it; + * option (1) means that we are contradicting + * the client's reques. + * + * I think (4) is the only correct choice. + */ + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "proxyAuthz not allowed within namingContext"; + } + + if ( op->o_is_auth_check ) { + mode = LDAP_BACK_IDASSERT_NOASSERT; + + } else { + mode = si->si_mode; + } + + switch ( mode ) { + case LDAP_BACK_IDASSERT_LEGACY: + /* original behavior: + * assert the client's identity */ + case LDAP_BACK_IDASSERT_SELF: + assertedID = ndn; + break; + + case LDAP_BACK_IDASSERT_ANONYMOUS: + /* assert "anonymous" */ + assertedID = slap_empty_bv; + break; + + case LDAP_BACK_IDASSERT_NOASSERT: + /* don't assert; bind as proxyauthzdn */ + goto done; + + case LDAP_BACK_IDASSERT_OTHERID: + case LDAP_BACK_IDASSERT_OTHERDN: + /* assert idassert DN */ + assertedID = si->si_bc.sb_authzId; + break; + + default: + assert( 0 ); + } + + /* if we got here, "" is allowed to proxyAuthz */ + if ( BER_BVISNULL( &assertedID ) ) { + assertedID = slap_empty_bv; + } + + /* don't idassert the bound DN (ITS#4497) */ + if ( dn_match( &assertedID, bound_ndn ) ) { + goto done; + } + + ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; + ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ); + + switch ( si->si_mode ) { + /* already in u:ID or dn:DN form */ + case LDAP_BACK_IDASSERT_OTHERID: + case LDAP_BACK_IDASSERT_OTHERDN: + ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx ); + rs->sr_err = LDAP_SUCCESS; + break; + + /* needs the dn: prefix */ + default: + ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" ); + ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1, + op->o_tmpmemctx ); + AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) ); + AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ], + assertedID.bv_val, assertedID.bv_len + 1 ); + rs->sr_err = LDAP_SUCCESS; + break; + } + + /* Older versions of required + * to encode the value of the authzID (and called it proxyDN); + * this hack provides compatibility with those DSAs that + * implement it this way */ + if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { + struct berval authzID = ctrl->ldctl_value; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + + ber_init2( ber, 0, LBER_USE_DER ); + ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); + + tag = ber_printf( ber, "O", &authzID ); + if ( tag == LBER_ERROR ) { + rs->sr_err = LDAP_OTHER; + goto free_ber; + } + + if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { + rs->sr_err = LDAP_OTHER; + goto free_ber; + } + + rs->sr_err = LDAP_SUCCESS; + +free_ber:; + op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); + ber_free_buf( ber ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + goto done; + } + + } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { + struct berval authzID = ctrl->ldctl_value, + tmp; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + + if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) { + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + + tmp = authzID; + tmp.bv_val += STRLENOF( "dn:" ); + tmp.bv_len -= STRLENOF( "dn:" ); + + ber_init2( ber, 0, LBER_USE_DER ); + ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); + + /* apparently, Mozilla API encodes this + * as "SEQUENCE { LDAPDN }" */ + tag = ber_printf( ber, "{O}", &tmp ); + if ( tag == LBER_ERROR ) { + rs->sr_err = LDAP_OTHER; + goto free_ber2; + } + + if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { + rs->sr_err = LDAP_OTHER; + goto free_ber2; + } + + ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ; + rs->sr_err = LDAP_SUCCESS; + +free_ber2:; + op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); + ber_free_buf( ber ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + goto done; + } + } + +done:; + + return rs->sr_err; +} + /* * Add controls; * @@ -1400,12 +1244,12 @@ asyncmeta_proxy_authz_bind( * status of op->o_ctrls. */ int -asyncmeta_controls_add( - Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - int candidate, - LDAPControl ***pctrls ) +asyncmeta_controls_add( Operation *op, + SlapReply *rs, + a_metaconn_t *mc, + int candidate, + int isroot, + LDAPControl ***pctrls ) { a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -1438,8 +1282,8 @@ asyncmeta_controls_add( /* put controls that go __before__ existing ones here */ /* proxyAuthz for identity assertion */ - switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) ) + switch ( asyncmeta_back_proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, + mt->mt_version, isroot, &mt->mt_idassert, &c[ j1 ] ) ) { case SLAP_CB_CONTINUE: break; @@ -1527,131 +1371,6 @@ done:; return rs->sr_err; } -#if 0 -/* - * Add controls; - * - * same as asyncmeta_controls_add, but creates a new controls array - * to be used by the operation copy - */ -int -asyncmeta_controls_add_copy( - Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - int candidate, - LDAPControl ***pctrls ) -{ - a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - a_metasingleconn_t *msc = mc->mc_conns[ candidate ]; - - LDAPControl **ctrls = NULL; - /* set to the maximum number of controls this backend can add */ - LDAPControl c[ 2 ] = {{ 0 }}; - int n = 0, i, j1 = 0, j2 = 0; - - *pctrls = NULL; - - rs->sr_err = LDAP_SUCCESS; - - /* don't add controls if protocol is not LDAPv3 */ - switch ( mt->mt_version ) { - case LDAP_VERSION3: - break; - - case 0: - if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { - break; - } - /* fall thru */ - - default: - goto done; - } - - /* put controls that go __before__ existing ones here */ - - /* proxyAuthz for identity assertion */ - switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) ) - { - case SLAP_CB_CONTINUE: - break; - - case LDAP_SUCCESS: - j1++; - break; - - default: - goto done; - } - - /* put controls that go __after__ existing ones here */ - -#ifdef SLAP_CONTROL_X_SESSION_TRACKING - /* session tracking */ - if ( META_BACK_TGT_ST_REQUEST( mt ) ) { - switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) { - case SLAP_CB_CONTINUE: - break; - - case LDAP_SUCCESS: - j2++; - break; - - default: - goto copy; - } - } -#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ - - if ( rs->sr_err == SLAP_CB_CONTINUE ) { - rs->sr_err = LDAP_SUCCESS; - } - -copy: - if ( op->o_ctrls ) { - for ( n = 0; op->o_ctrls[ n ]; n++ ) - /* just count ctrls */ ; - } - - ctrls = ch_calloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl )); - if ( j1 ) { - ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ]; - *ctrls[ 0 ] = c[ 0 ]; - for ( i = 1; i < j1; i++ ) { - ctrls[ i ] = &ctrls[ 0 ][ i ]; - *ctrls[ i ] = c[ i ]; - } - } - - i = 0; - if ( op->o_ctrls ) { - for ( i = 0; op->o_ctrls[ i ]; i++ ) { - ctrls[ i + j1 ] = op->o_ctrls[ i ]; - } - } - - n += j1; - if ( j2 ) { - ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1; - *ctrls[ n ] = c[ j1 ]; - for ( i = 1; i < j2; i++ ) { - ctrls[ n + i ] = &ctrls[ n ][ i ]; - *ctrls[ n + i ] = c[ i ]; - } - } - - ctrls[ n + j2 ] = NULL; - -done:; - - op->o_ctrls = ctrls; - - return rs->sr_err; -} -#endif /* * asyncmeta_dobind_init() @@ -1665,7 +1384,6 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - ber_socket_t s; struct berval binddn = msc->msc_bound_ndn, cred = msc->msc_cred; int method; @@ -1675,13 +1393,18 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn meta_search_candidate_t retcode; - Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_search_dobind_init[%d]\n", + Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_dobind_init[%d]\n", op->o_log_prefix, candidate ); if ( mc->mc_authz_target == META_BOUND_ALL ) { return META_SEARCH_CANDIDATE; } + if ( slapd_shutdown ) { + rs->sr_err = LDAP_UNAVAILABLE; + return META_SEARCH_ERR; + } + retcode = META_SEARCH_BINDING; if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { /* already bound (or anonymous) */ @@ -1694,11 +1417,11 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn bound = 1; } - Debug(LDAP_DEBUG_ANY, - "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n", - op->o_log_prefix, candidate, (void *)mc, - (void *)msc->msc_ld, bound ? " bound" : " anonymous", - bound == 0 ? "" : msc->msc_bound_ndn.bv_val ); + Debug( LDAP_DEBUG_ANY, + "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n", + op->o_log_prefix, candidate, (void *)mc, + (void *)msc->msc_ld, bound ? " bound" : " anonymous", + bound == 0 ? "" : msc->msc_bound_ndn.bv_val ); #endif /* DEBUG_205 */ retcode = META_SEARCH_CANDIDATE; @@ -1707,27 +1430,24 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn /* another thread is binding the target for this conn; wait */ #ifdef DEBUG_205 - char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; - Debug(LDAP_DEBUG_ANY, - "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p needbind\n", - op->o_log_prefix, candidate, (void *)mc, - (void *)msc->msc_ld ); + Debug( LDAP_DEBUG_ANY, + "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p needbind\n", + op->o_log_prefix, candidate, (void *)mc, + (void *)msc->msc_ld ); #endif /* DEBUG_205 */ candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND; retcode = META_SEARCH_NEED_BIND; - } else { /* we'll need to bind the target for this conn */ #ifdef DEBUG_205 - char buf[ SLAP_TEXT_BUFLEN ]; - Debug(LDAP_DEBUG_ANY, - "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p binding\n", - op->o_log_prefix, candidate, (void *)mc, - (void *)msc->msc_ld ); + Debug( LDAP_DEBUG_ANY, + "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p binding\n", + op->o_log_prefix, candidate, (void *)mc, + (void *)msc->msc_ld ); #endif /* DEBUG_205 */ if ( msc->msc_ld == NULL ) { @@ -1735,11 +1455,12 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn * state, with eventual connection expiration or invalidation) * it was not initialized as expected */ - Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p ld=NULL\n", + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p ld=NULL\n", op->o_log_prefix, candidate, (void *)mc ); rc = asyncmeta_init_one_conn( op, rs, mc, candidate, - LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 ); + LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 ); + switch ( rc ) { case LDAP_SUCCESS: assert( msc->msc_ld != NULL ); @@ -1780,8 +1501,6 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn /* NOTE: we copy things here, even if bind didn't succeed yet, * because the connection is not shared until bind is over */ if ( !BER_BVISNULL( &binddn ) ) { - ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex); - ber_bvreplace( &msc->msc_bound_ndn, &binddn ); if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { @@ -1790,7 +1509,6 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn } ber_bvreplace( &msc->msc_cred, &cred ); } - ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex); } if ( LDAP_BACK_CONN_ISBOUND( msc ) ) { /* apparently, idassert was configured with SASL bind, @@ -1816,41 +1534,67 @@ asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) { /* bind anonymously? */ - Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: " + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: " "non-empty dn with empty cred; binding anonymously\n", op->o_log_prefix, candidate, (void *)mc ); cred = slap_empty_bv; } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) { /* error */ - Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: " + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: " "empty dn with non-empty cred: error\n", op->o_log_prefix, candidate, (void *)mc ); rc = LDAP_OTHER; goto other; } retry_bind: + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind msc: %p\n", + time_buf, msc ); + } rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid ); ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc ); + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init rc=%d msc: %p\n", + time_buf, rc, msc ); + } if (rc == LDAP_SERVER_DOWN ) { goto down; + } else if (rc == LDAP_BUSY) { + if (rs->sr_text == NULL) { + rs->sr_text = "Unable to establish LDAP connection to target within the specified network timeout."; + } + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + goto other; } - candidates[ candidate ].sr_msgid = msgid; + /* mark as need bind so it gets send when the bind response is received */ + candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND; asyncmeta_set_msc_time(msc); #ifdef DEBUG_205 - Debug(LDAP_DEBUG_ANY, - "### %s asyncmeta_search_dobind_init[%d] mc=%p ld=%p rc=%d\n", - op->o_log_prefix, candidate, (void *)mc, - (void *)mc->mc_conns[candidate].msc_ld, rc ); + Debug( LDAP_DEBUG_ANY, + "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p rc=%d\n", + op->o_log_prefix, candidate, (void *)mc, + (void *)mc->mc_conns[candidate].msc_ld, rc ); #endif /* DEBUG_205 */ switch ( rc ) { case LDAP_SUCCESS: assert( msgid >= 0 ); + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind success msc: %p\n", + time_buf, msc ); + } META_BINDING_SET( &candidates[ candidate ] ); rs->sr_err = LDAP_SUCCESS; + msc->msc_binding_time = slap_get_time(); return META_SEARCH_BINDING; case LDAP_X_CONNECTING: @@ -1863,7 +1607,11 @@ retry_bind: down:; retcode = META_SEARCH_ERR; rs->sr_err = LDAP_UNAVAILABLE; + if (rs->sr_text == NULL) { + rs->sr_text = "Unable to bind to remote target - target down or unavailable"; + } candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + LDAP_BACK_CONN_BINDING_CLEAR( msc ); break; /* fall thru */ @@ -1880,6 +1628,7 @@ other:; retcode = META_SEARCH_NOT_CANDIDATE; } candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + LDAP_BACK_CONN_BINDING_CLEAR( msc ); break; } @@ -1893,57 +1642,63 @@ meta_search_candidate_t asyncmeta_dobind_init_with_retry(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate) { - int rc, retries = 1; + int rc; a_metasingleconn_t *msc = &mc->mc_conns[candidate]; a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; - SlapReply *candidates = bc->candidates; + + if (META_BACK_CONN_INVALID(msc) || (LDAP_BACK_CONN_BINDING( msc ) && msc->msc_binding_time > 0 + && (msc->msc_binding_time + mt->mt_timeout[ SLAP_OP_BIND ]) < slap_get_time())) { + char buf[ SLAP_TEXT_BUFLEN ]; + snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ ); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + asyncmeta_reset_msc(NULL, mc, candidate, 0, buf); + + rc = asyncmeta_init_one_conn( op, rs, mc, candidate, + LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 ); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + } + + if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { + return META_SEARCH_CANDIDATE; + } retry_dobind: + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rs->sr_err != LDAP_UNAVAILABLE) { + if (rs->sr_err != LDAP_UNAVAILABLE && rs->sr_err != LDAP_BUSY) { + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; - } else if (retries <= 0) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - if (mc->mc_active < 1) { - asyncmeta_clear_one_msc(NULL, mc, candidate); - } + } else if (bc->nretries[candidate] == 0) { + char buf[ SLAP_TEXT_BUFLEN ]; + snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ ); + asyncmeta_reset_msc(NULL, mc, candidate, 0, buf); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; } /* need to retry */ - retries--; - if ( LogTest( LDAP_DEBUG_ANY ) ) { + bc->nretries[candidate]--; + if ( LogTest( LDAP_DEBUG_TRACE ) ) { /* this lock is required; however, * it's invoked only when logging is on */ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); - Debug(LDAP_DEBUG_ANY, - "%s asyncmeta_search_dobind_init_with_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n", - op->o_log_prefix, candidate, mt->mt_uri, - BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val ); + Debug( LDAP_DEBUG_ANY, + "%s asyncmeta_dobind_init_with_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n", + op->o_log_prefix, candidate, mt->mt_uri, + BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val ); ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); } - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - if (mc->mc_active < 1) { - asyncmeta_clear_one_msc(NULL, mc, candidate); - } - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); - - ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); - + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); rc = asyncmeta_init_one_conn( op, rs, mc, candidate, LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 ); if (rs->sr_err != LDAP_SUCCESS) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - if (mc->mc_active < 1) { - asyncmeta_clear_one_msc(NULL, mc, candidate); - } + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return META_SEARCH_ERR; } - + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); goto retry_dobind; return rc; } diff --git a/servers/slapd/back-asyncmeta/candidates.c b/servers/slapd/back-asyncmeta/candidates.c index b25832a7ac..1ab0639bd5 100644 --- a/servers/slapd/back-asyncmeta/candidates.c +++ b/servers/slapd/back-asyncmeta/candidates.c @@ -206,8 +206,6 @@ asyncmeta_select_unique_candidate( if ( candidate == META_TARGET_NONE ) { candidate = i; - } else { - return META_TARGET_MULTIPLE; } } } @@ -239,50 +237,3 @@ asyncmeta_clear_unused_candidates( 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; -} diff --git a/servers/slapd/back-asyncmeta/compare.c b/servers/slapd/back-asyncmeta/compare.c index d511103b53..8c77a3d506 100644 --- a/servers/slapd/back-asyncmeta/compare.c +++ b/servers/slapd/back-asyncmeta/compare.c @@ -26,27 +26,27 @@ #include #include - #include "slap.h" -#include "../back-ldap/back-ldap.h" -#include "back-asyncmeta.h" #include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/libldap/ldap-int.h" +#include "../back-ldap/back-ldap.h" +#include "back-asyncmeta.h" meta_search_candidate_t asyncmeta_back_compare_start(Operation *op, - SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate) + SlapReply *rs, + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + int do_lock) { a_dncookie dc; a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; + struct berval c_attr = op->orc_ava->aa_desc->ad_cname; struct berval mdn = BER_BVNULL; - struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname; struct berval mapped_value = op->orc_ava->aa_value; - int rc = 0, nretries = 1; + int rc = 0; LDAPControl **ctrls = NULL; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; BerElement *ber = NULL; @@ -54,117 +54,125 @@ asyncmeta_back_compare_start(Operation *op, SlapReply *candidates = bc->candidates; ber_int_t msgid; + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "compareDN"; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; - switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - case LDAP_UNWILLING_TO_PERFORM: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - retcode = META_SEARCH_ERR; - goto doreturn; - default: - break; - } + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); - /* - * if attr is objectClass, try to remap the value - */ - if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) { - asyncmeta_map( &mt->mt_rwmap.rwm_oc, - &op->orc_ava->aa_value, - &mapped_value, BACKLDAP_MAP ); + if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) + asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ); - if ( 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 ) - { - dc.ctx = "compareAttrDN"; - - switch ( asyncmeta_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) ) - { - case LDAP_UNWILLING_TO_PERFORM: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - retcode = META_SEARCH_ERR; - goto done; - - default: - break; - } - } - } -retry:; + asyncmeta_set_msc_time(msc); ctrls = op->o_ctrls; - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root,&ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_ERR; goto done; } + /* someone might have reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } - ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, mapped_attr.bv_val, &mapped_value, + ber = ldap_build_compare_req( msc->msc_ld, mdn.bv_val, c_attr.bv_val, &mapped_value, ctrls, NULL, &msgid); + + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_compare_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE, - mdn.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_COMPARE, + mdn.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_clear_one_msc(NULL, mc, candidate); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - + /* fall though*/ default: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - retcode = META_SEARCH_ERR; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; } } + +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + retcode = META_SEARCH_NEED_BIND; + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send compare request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + break; + } done: (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); - } - if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) { - 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 ); return retcode; } @@ -176,26 +184,30 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs ) a_metatarget_t *mt; a_metaconn_t *mc; int rc, candidate = -1; - OperationBuffer opbuf; + void *thrctx = op->o_threadctx; bm_context_t *bc; SlapReply *candidates; - slap_callback *cb = op->o_callback; + time_t current_time = slap_get_time(); + int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_compare: %s\n", op->o_req_dn.bv_val ); - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + if (current_time > op->o_time) { + Debug( asyncmeta_debug, "==> asyncmeta_back_compare[%s]: o_time:[%ld], current time: [%ld]\n", + op->o_log_prefix, op->o_time, current_time ); + } + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); return rs->sr_err; } candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + send_ldap_result(op, rs); return rs->sr_err; } @@ -204,16 +216,38 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs ) bc->retrying = LDAP_BACK_RETRYING; bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + mc->mc_conns[candidate].msc_active++; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + goto finish; + } + +retry: + if (bc->timeout && bc->stoptime < slap_get_time()) { + int timeout_err; + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + rs->sr_err = timeout_err; + rs->sr_text = "Operation timed out before it was sent to target"; + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; } @@ -223,47 +257,27 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs ) case META_SEARCH_CANDIDATE: /* target is already bound, just send the request */ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); - rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate); + rc = asyncmeta_back_compare_start( op, rs, mc, bc, candidate, 1); if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } - break; + break; case META_SEARCH_NOT_CANDIDATE: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NOT_CANDIDATE " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - } - break; case META_SEARCH_BINDING: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: BINDING " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); + "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); /* Todo add the context to the message queue but do not send the request the receiver must send this when we are done binding */ /* question - how would do receiver know to which targets??? */ @@ -271,23 +285,21 @@ asyncmeta_back_compare( Operation *op, SlapReply *rs ) case META_SEARCH_ERR: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_compare: ERR " - "cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; default: assert( 0 ); break; } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; asyncmeta_start_one_listener(mc, candidates, bc, candidate); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; finish: return rs->sr_err; - } diff --git a/servers/slapd/back-asyncmeta/config.c b/servers/slapd/back-asyncmeta/config.c index 9e368d633a..bfa5b7a29f 100644 --- a/servers/slapd/back-asyncmeta/config.c +++ b/servers/slapd/back-asyncmeta/config.c @@ -43,11 +43,6 @@ static ConfigDriver asyncmeta_back_cf_gen; static ConfigLDAPadd asyncmeta_ldadd; static ConfigCfAdd asyncmeta_cfadd; -static int asyncmeta_map_config( - ConfigArgs *c, - struct ldapmap *oc_map, - struct ldapmap *at_map ); - /* Three sets of enums: * 1) attrs that are only valid in the base config * 2) attrs that are valid in base or target @@ -95,9 +90,7 @@ enum { LDAP_BACK_CFG_ACL_PASSWD, LDAP_BACK_CFG_IDASSERT_AUTHZFROM, LDAP_BACK_CFG_IDASSERT_BIND, - LDAP_BACK_CFG_REWRITE, LDAP_BACK_CFG_SUFFIXM, - LDAP_BACK_CFG_MAP, LDAP_BACK_CFG_SUBTREE_EX, LDAP_BACK_CFG_SUBTREE_IN, LDAP_BACK_CFG_KEEPALIVE, @@ -111,7 +104,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:0.14 " "NAME 'olcDbURI' " "DESC 'URI (list) for remote DSA' " - "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -120,7 +112,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.1 " "NAME 'olcDbStartTLS' " "DESC 'StartTLS' " - "EQUALITY caseExactMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -129,7 +120,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.2 " "NAME 'olcDbACLAuthcDn' " "DESC 'Remote ACL administrative identity' " - "EQUALITY distinguishedNameMatch " "OBSOLETE " "SYNTAX OMsDN " "SINGLE-VALUE )", @@ -156,7 +146,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.7 " "NAME 'olcDbIDAssertBind' " "DESC 'Remote Identity Assertion administrative identity auth bind configuration' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -174,7 +163,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.10 " "NAME 'olcDbRebindAsUser' " "DESC 'Rebind as user' " - "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, @@ -183,7 +171,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.11 " "NAME 'olcDbChaseReferrals' " "DESC 'Chase referrals' " - "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, @@ -192,7 +179,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.12 " "NAME 'olcDbTFSupport' " "DESC 'Absolute filters support' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -201,7 +187,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.14 " "NAME 'olcDbTimeout' " "DESC 'Per-operation timeouts' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -210,7 +195,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.15 " "NAME 'olcDbIdleTimeout' " "DESC 'connection idle timeout' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -219,7 +203,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.17 " "NAME 'olcDbNetworkTimeout' " "DESC 'connection network timeout' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -228,7 +211,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.18 " "NAME 'olcDbProtocolVersion' " "DESC 'protocol version' " - "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, @@ -238,7 +220,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.20 " "NAME 'olcDbCancel' " "DESC 'abandon/ignore/exop operations when appropriate' " - "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, @@ -246,7 +227,6 @@ static ConfigTable a_metacfg[] = { ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE, asyncmeta_back_cf_gen, "( OLcfgDbAt:3.21 " "NAME 'olcDbQuarantine' " - "EQUALITY caseIgnoreMatch " "DESC 'Quarantine database if connection fails and retry according to rule' " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", @@ -257,7 +237,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.23 " "NAME 'olcDbConnectionPoolMax' " "DESC 'Max size of privileged connections pool' " - "EQUALITY integerMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, @@ -267,7 +246,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.24 " "NAME 'olcDbSessionTrackingRequest' " "DESC 'Add session tracking control to proxied requests' " - "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, @@ -277,7 +255,6 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.25 " "NAME 'olcDbNoRefs' " "DESC 'Do not return search reference responses' " - "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, @@ -286,32 +263,18 @@ static ConfigTable a_metacfg[] = { asyncmeta_back_cf_gen, "( OLcfgDbAt:3.26 " "NAME 'olcDbNoUndefFilter' " "DESC 'Do not propagate undefined search filters' " - "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, - { "rewrite", "arglist", 2, 0, STRLENOF( "rewrite" ), - ARG_MAGIC|LDAP_BACK_CFG_REWRITE, - asyncmeta_back_cf_gen, "( OLcfgDbAt:3.101 " - "NAME 'olcDbRewrite' " - "DESC 'DN rewriting rules' " - "EQUALITY caseIgnoreMatch " - "SYNTAX OMsDirectoryString " - "X-ORDERED 'VALUES' )", - NULL, NULL }, - { "suffixmassage", "virtual> [*|] *|", 1, 2, rargv ); - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "default"; - rargv[ 2 ] = NULL; - rewrite_parse( *rwm_rw, "", 1, 2, rargv ); - - return 0; -} - static int asyncmeta_back_new_target( a_metatarget_t **mtp ) @@ -592,11 +513,6 @@ asyncmeta_back_new_target( mt = ch_calloc( sizeof( a_metatarget_t ), 1 ); - if ( asyncmeta_rwi_init( &mt->mt_rwmap.rwm_rw )) { - ch_free( mt ); - return -1; - } - ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex ); mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY; @@ -610,7 +526,7 @@ asyncmeta_back_new_target( return 0; } -/* Validation for suffixmassage_config */ +/* suffixmassage config */ static int asyncmeta_suffixm_config( ConfigArgs *c, @@ -621,16 +537,16 @@ asyncmeta_suffixm_config( { BackendDB *tmp_bd; struct berval dn, nvnc, pvnc, nrnc, prnc; - int j, rc; + int j; /* * syntax: * - * suffixmassage + * suffixmassage * - * the field must be defined as a valid suffix + * the field must be defined as a valid suffix * (or suffixAlias?) for the current database; - * the shouldn't have already been + * the shouldn't have already been * defined as a valid suffix or suffixAlias for the * current server */ @@ -679,59 +595,12 @@ asyncmeta_suffixm_config( c->log, prnc.bv_val ); } - /* - * The suffix massaging is emulated by means of the - * rewrite capabilities - */ - rc = asyncmeta_suffix_massage_config( mt->mt_rwmap.rwm_rw, - &pvnc, &nvnc, &prnc, &nrnc ); + mt->mt_lsuffixm = pvnc; + mt->mt_rsuffixm = prnc; - free( pvnc.bv_val ); free( nvnc.bv_val ); - free( prnc.bv_val ); free( nrnc.bv_val ); - return rc; -} - -static int -slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out ) -{ - int i; - BerVarray bva = NULL; - char ibuf[32], *ptr; - struct berval idx; - - assert( in != NULL ); - - for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) - /* count'em */ ; - - if ( i == 0 ) { - return 1; - } - - idx.bv_val = ibuf; - - bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) ); - BER_BVZERO( &bva[ 0 ] ); - - for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) { - idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i ); - if ( idx.bv_len >= sizeof( ibuf ) ) { - ber_bvarray_free( bva ); - return 1; - } - - bva[i].bv_len = idx.bv_len + in[i].bv_len; - bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 ); - ptr = lutil_strcopy( bva[i].bv_val, ibuf ); - ptr = lutil_strcopy( ptr, in[i].bv_val ); - *ptr = '\0'; - BER_BVZERO( &bva[ i + 1 ] ); - } - - *out = bva; return 0; } @@ -1156,8 +1025,8 @@ static int asyncmeta_back_cf_gen( ConfigArgs *c ) { a_metainfo_t *mi = ( a_metainfo_t * )c->be->be_private; - a_metatarget_t *mt; - a_metacommon_t *mc; + a_metatarget_t *mt = NULL; + a_metacommon_t *mc = NULL; int i, rc = 0; @@ -1282,12 +1151,11 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) case LDAP_BACK_CFG_NETWORK_TIMEOUT: if ( mc->mc_network_timeout == 0 ) { return 1; - } else { - char buf[ SLAP_TEXT_BUFLEN ]; - lutil_unparse_time( buf, sizeof( buf ), mc->mc_network_timeout ); - ber_str2bv( buf, 0, 0, &bv ); - value_add_one( &c->rvalue_vals, &bv ); } + bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%ld", + mc->mc_network_timeout ); + bv.bv_val = c->cr_msg; + value_add_one( &c->rvalue_vals, &bv ); break; case LDAP_BACK_CFG_NOREFS: @@ -1617,21 +1485,23 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) break; } - case LDAP_BACK_CFG_SUFFIXM: /* unused */ - case LDAP_BACK_CFG_REWRITE: - if ( mt->mt_rwmap.rwm_bva_rewrite == NULL ) { + case LDAP_BACK_CFG_SUFFIXM: + if ( mt->mt_lsuffixm.bv_val ) { + struct berval bv; + char *ptr; + bv.bv_len = mt->mt_lsuffixm.bv_len + 2 + 1 + mt->mt_rsuffixm.bv_len + 2; + bv.bv_val = ch_malloc( bv.bv_len + 1 ); + ptr = bv.bv_val; + *ptr++ = '"'; + ptr = lutil_strcopy(ptr, mt->mt_lsuffixm.bv_val); + ptr = lutil_strcopy(ptr, "\" \""); + ptr = lutil_strcopy(ptr, mt->mt_rsuffixm.bv_val); + *ptr++ = '"'; + *ptr = '\0'; + ber_bvarray_add( &c->rvalue_vals, &bv ); + rc = 0; + } else rc = 1; - } else { - rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_rewrite, &c->rvalue_vals ); - } - break; - - case LDAP_BACK_CFG_MAP: - if ( mt->mt_rwmap.rwm_bva_map == NULL ) { - rc = 1; - } else { - rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_map, &c->rvalue_vals ); - } break; case LDAP_BACK_CFG_SUBTREE_EX: @@ -1824,25 +1694,13 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) memset( &mt->mt_idassert, 0, sizeof( slap_idassert_t ) ); break; - case LDAP_BACK_CFG_SUFFIXM: /* unused */ - case LDAP_BACK_CFG_REWRITE: - if ( mt->mt_rwmap.rwm_bva_rewrite ) { - ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite ); - mt->mt_rwmap.rwm_bva_rewrite = NULL; + case LDAP_BACK_CFG_SUFFIXM: + if ( mt->mt_lsuffixm.bv_val ) { + ch_free( mt->mt_lsuffixm.bv_val ); + ch_free( mt->mt_rsuffixm.bv_val ); + BER_BVZERO( &mt->mt_lsuffixm ); + BER_BVZERO( &mt->mt_rsuffixm ); } - if ( mt->mt_rwmap.rwm_rw ) - rewrite_info_delete( &mt->mt_rwmap.rwm_rw ); - break; - - case LDAP_BACK_CFG_MAP: - if ( mt->mt_rwmap.rwm_bva_map ) { - ber_bvarray_free( mt->mt_rwmap.rwm_bva_map ); - mt->mt_rwmap.rwm_bva_map = NULL; - } - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc ); - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at ); - mt->mt_rwmap.rwm_oc.drop_missing = 0; - mt->mt_rwmap.rwm_at.drop_missing = 0; break; case LDAP_BACK_CFG_SUBTREE_EX: @@ -2179,7 +2037,6 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) break; case LDAP_BACK_CFG_MAX_TARGET_CONNS: { - int msc_num, i; if (c->value_int < 0) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "max-target-conns invalid value %d", @@ -2301,8 +2158,7 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) if ( strcasecmp( c->argv[ 0 ], "binddn" ) == 0 ) { Debug( LDAP_DEBUG_ANY, "%s: " "\"binddn\" statement is deprecated; " - "use \"acl-authcDN\" instead\n", - c->log ); + "use \"acl-authcDN\" instead\n", c->log ); /* FIXME: some day we'll need to throw an error */ } @@ -2317,8 +2173,7 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) if ( strcasecmp( c->argv[ 0 ], "bindpw" ) == 0 ) { Debug( LDAP_DEBUG_ANY, "%s " "\"bindpw\" statement is deprecated; " - "use \"acl-passwd\" instead\n", - c->log ); + "use \"acl-passwd\" instead\n", c->log ); /* FIXME: some day we'll need to throw an error */ } @@ -2524,226 +2379,10 @@ asyncmeta_back_cf_gen( ConfigArgs *c ) break; #endif /* SLAP_CONTROL_X_SESSION_TRACKING */ - case LDAP_BACK_CFG_SUFFIXM: /* FALLTHRU */ - case LDAP_BACK_CFG_REWRITE: { - /* rewrite stuff ... */ - ConfigArgs ca = { 0 }; - char *line, **argv; - struct rewrite_info *rwi; - int cnt = 0, argc, ix = c->valx; - - if ( mt->mt_rwmap.rwm_bva_rewrite ) { - for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_rewrite[ cnt ] ); cnt++ ) - /* count */ ; - } - - if ( ix >= cnt || ix < 0 ) { - ix = cnt; - } else { - rwi = mt->mt_rwmap.rwm_rw; - - mt->mt_rwmap.rwm_rw = NULL; - rc = asyncmeta_rwi_init( &mt->mt_rwmap.rwm_rw ); - - /* re-parse all rewrite rules, up to the one - * that needs to be added */ - ca.be = c->be; - ca.fname = c->fname; - ca.lineno = c->lineno; - for ( i = 0; i < ix; i++ ) { - ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val; - ca.argc = 0; - config_fp_parse_line( &ca ); - - if ( !strcasecmp( ca.argv[0], "suffixmassage" )) { - rc = asyncmeta_suffixm_config( &ca, ca.argc, ca.argv, mt ); - } else { - rc = rewrite_parse( mt->mt_rwmap.rwm_rw, - c->fname, c->lineno, ca.argc, ca.argv ); - } - assert( rc == 0 ); - ch_free( ca.argv ); - ch_free( ca.tline ); - } - } - argc = c->argc; - argv = c->argv; - if ( c->op != SLAP_CONFIG_ADD ) { - argc--; - argv++; - } - /* add the new rule */ - if ( !strcasecmp( argv[0], "suffixmassage" )) { - rc = asyncmeta_suffixm_config( c, argc, argv, mt ); - } else { - rc = rewrite_parse( mt->mt_rwmap.rwm_rw, - c->fname, c->lineno, argc, argv ); - } - if ( rc ) { - if ( ix < cnt ) { - rewrite_info_delete( &mt->mt_rwmap.rwm_rw ); - mt->mt_rwmap.rwm_rw = rwi; - } - return 1; - } - if ( ix < cnt ) { - for ( ; i < cnt; i++ ) { - ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val; - ca.argc = 0; - config_fp_parse_line( &ca ); - - if ( !strcasecmp( ca.argv[0], "suffixmassage" )) { - rc = asyncmeta_suffixm_config( &ca, ca.argc, ca.argv, mt ); - } else { - rc = rewrite_parse( mt->mt_rwmap.rwm_rw, - c->fname, c->lineno, ca.argc, argv ); - } - assert( rc == 0 ); - ch_free( ca.argv ); - ch_free( ca.tline ); - } - } - - /* save the rule info */ - line = ldap_charray2str( argv, "\" \"" ); - if ( line != NULL ) { - struct berval bv; - int len = strlen( argv[ 0 ] ); - - ber_str2bv( line, 0, 0, &bv ); - AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ], - bv.bv_len - ( len + 1 )); - bv.bv_val[ bv.bv_len - 1] = '"'; - ber_bvarray_add( &mt->mt_rwmap.rwm_bva_rewrite, &bv ); - /* move it to the right slot */ - if ( ix < cnt ) { - for ( i=cnt; i>ix; i-- ) - mt->mt_rwmap.rwm_bva_rewrite[i+1] = mt->mt_rwmap.rwm_bva_rewrite[i]; - mt->mt_rwmap.rwm_bva_rewrite[i] = bv; - - /* destroy old rules */ - rewrite_info_delete( &rwi ); - } - } - } break; - - case LDAP_BACK_CFG_MAP: { - /* objectclass/attribute mapping */ - ConfigArgs ca = { 0 }; - char *argv[5]; - struct ldapmap rwm_oc; - struct ldapmap rwm_at; - int cnt = 0, ix = c->valx; - - if ( mt->mt_rwmap.rwm_bva_map ) { - for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_map[ cnt ] ); cnt++ ) - /* count */ ; - } - - if ( ix >= cnt || ix < 0 ) { - ix = cnt; - } else { - rwm_oc = mt->mt_rwmap.rwm_oc; - rwm_at = mt->mt_rwmap.rwm_at; - - memset( &mt->mt_rwmap.rwm_oc, 0, sizeof( mt->mt_rwmap.rwm_oc ) ); - memset( &mt->mt_rwmap.rwm_at, 0, sizeof( mt->mt_rwmap.rwm_at ) ); - - /* re-parse all mappings, up to the one - * that needs to be added */ - argv[0] = c->argv[0]; - ca.fname = c->fname; - ca.lineno = c->lineno; - for ( i = 0; i < ix; i++ ) { - ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val; - ca.argc = 0; - config_fp_parse_line( &ca ); - - argv[1] = ca.argv[0]; - argv[2] = ca.argv[1]; - argv[3] = ca.argv[2]; - argv[4] = ca.argv[3]; - ch_free( ca.argv ); - ca.argv = argv; - ca.argc++; - rc = asyncmeta_map_config( &ca, &mt->mt_rwmap.rwm_oc, - &mt->mt_rwmap.rwm_at ); - - ch_free( ca.tline ); - ca.tline = NULL; - ca.argv = NULL; - - /* in case of failure, restore - * the existing mapping */ - if ( rc ) { - goto map_fail; - } - } - } - /* add the new mapping */ - rc = asyncmeta_map_config( c, &mt->mt_rwmap.rwm_oc, - &mt->mt_rwmap.rwm_at ); - if ( rc ) { - goto map_fail; - } - - if ( ix < cnt ) { - for ( ; imt_rwmap.rwm_bva_map[ i ].bv_val; - ca.argc = 0; - config_fp_parse_line( &ca ); - - argv[1] = ca.argv[0]; - argv[2] = ca.argv[1]; - argv[3] = ca.argv[2]; - argv[4] = ca.argv[3]; - - ch_free( ca.argv ); - ca.argv = argv; - ca.argc++; - rc = asyncmeta_map_config( &ca, &mt->mt_rwmap.rwm_oc, - &mt->mt_rwmap.rwm_at ); - - ch_free( ca.tline ); - ca.tline = NULL; - ca.argv = NULL; - - /* in case of failure, restore - * the existing mapping */ - if ( rc ) { - goto map_fail; - } - } - } - - /* save the map info */ - argv[0] = ldap_charray2str( &c->argv[ 1 ], " " ); - if ( argv[0] != NULL ) { - struct berval bv; - ber_str2bv( argv[0], 0, 0, &bv ); - ber_bvarray_add( &mt->mt_rwmap.rwm_bva_map, &bv ); - /* move it to the right slot */ - if ( ix < cnt ) { - for ( i=cnt; i>ix; i-- ) - mt->mt_rwmap.rwm_bva_map[i+1] = mt->mt_rwmap.rwm_bva_map[i]; - mt->mt_rwmap.rwm_bva_map[i] = bv; - - /* destroy old mapping */ - asyncmeta_back_map_free( &rwm_oc ); - asyncmeta_back_map_free( &rwm_at ); - } - } + case LDAP_BACK_CFG_SUFFIXM: + rc = asyncmeta_suffixm_config( c, c->argc, c->argv, mt ); break; -map_fail:; - if ( ix < cnt ) { - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc ); - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at ); - mt->mt_rwmap.rwm_oc = rwm_oc; - mt->mt_rwmap.rwm_at = rwm_at; - } - } break; - case LDAP_BACK_CFG_NRETRIES: { int nretries = META_RETRY_UNDEFINED; @@ -2850,8 +2489,7 @@ asyncmeta_back_init_cf( BackendInfo *bi ) if ( rc ) { Debug( LDAP_DEBUG_ANY, "config_back_initialize: " "warning, unable to get \"olcDbACLPasswd\" " - "attribute description: %d: %s\n", - rc, text ); + "attribute description: %d: %s\n", rc, text ); } else { (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val, ad->ad_type->sat_oid ); @@ -2862,8 +2500,7 @@ asyncmeta_back_init_cf( BackendInfo *bi ) if ( rc ) { Debug( LDAP_DEBUG_ANY, "config_back_initialize: " "warning, unable to get \"olcDbIDAssertPasswd\" " - "attribute description: %d: %s\n", - rc, text ); + "attribute description: %d: %s\n", rc, text ); } else { (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val, ad->ad_type->sat_oid ); @@ -2871,350 +2508,3 @@ asyncmeta_back_init_cf( BackendInfo *bi ) return 0; } - -static int -asyncmeta_map_config( - ConfigArgs *c, - struct ldapmap *oc_map, - struct ldapmap *at_map ) -{ - struct ldapmap *map; - struct ldapmapping *mapping; - char *src, *dst; - int is_oc = 0; - - if ( strcasecmp( c->argv[ 1 ], "objectclass" ) == 0 ) { - map = oc_map; - is_oc = 1; - - } else if ( strcasecmp( c->argv[ 1 ], "attribute" ) == 0 ) { - map = at_map; - - } else { - snprintf( c->cr_msg, sizeof(c->cr_msg), - "%s unknown argument \"%s\"", - c->argv[0], c->argv[1] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - return 1; - } - - if ( !is_oc && map->map == NULL ) { - /* only init if required */ - asyncmeta_map_init( map, &mapping ); - } - - if ( strcmp( c->argv[ 2 ], "*" ) == 0 ) { - if ( c->argc < 4 || strcmp( c->argv[ 3 ], "*" ) == 0 ) { - map->drop_missing = ( c->argc < 4 ); - goto success_return; - } - src = dst = c->argv[ 3 ]; - - } else if ( c->argc < 4 ) { - src = ""; - dst = c->argv[ 2 ]; - - } else { - src = c->argv[ 2 ]; - dst = ( strcmp( c->argv[ 3 ], "*" ) == 0 ? src : c->argv[ 3 ] ); - } - - if ( ( map == at_map ) - && ( strcasecmp( src, "objectclass" ) == 0 - || strcasecmp( dst, "objectclass" ) == 0 ) ) - { - snprintf( c->cr_msg, sizeof(c->cr_msg), - "objectclass attribute cannot be mapped" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - return 1; - } - - mapping = (struct ldapmapping *)ch_calloc( 2, - sizeof(struct ldapmapping) ); - if ( mapping == NULL ) { - snprintf( c->cr_msg, sizeof(c->cr_msg), - "out of memory" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - return 1; - } - ber_str2bv( src, 0, 1, &mapping[ 0 ].src ); - ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst ); - mapping[ 1 ].src = mapping[ 0 ].dst; - mapping[ 1 ].dst = mapping[ 0 ].src; - - /* - * schema check - */ - if ( is_oc ) { - if ( src[ 0 ] != '\0' ) { - if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) { - Debug( LDAP_DEBUG_ANY, - "%s: warning, source objectClass '%s' should be defined in schema\n", - c->log, src ); - - /* - * FIXME: this should become an err - */ - goto error_return; - } - } - - if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) { - Debug( LDAP_DEBUG_ANY, - "%s: warning, destination objectClass '%s' is not defined in schema\n", - c->log, dst ); - } - } else { - int rc; - const char *text = NULL; - AttributeDescription *ad = NULL; - - if ( src[ 0 ] != '\0' ) { - rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "%s: warning, source attributeType '%s' should be defined in schema\n", - c->log, src ); - - /* - * FIXME: this should become an err - */ - /* - * we create a fake "proxied" ad - * and add it here. - */ - - rc = slap_bv2undef_ad( &mapping[ 0 ].src, - &ad, &text, SLAP_AD_PROXIED ); - if ( rc != LDAP_SUCCESS ) { - snprintf( c->cr_msg, sizeof( c->cr_msg ), - "source attributeType \"%s\": %d (%s)", - src, rc, text ? text : "" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - goto error_return; - } - } - - ad = NULL; - } - - rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "%s: warning, destination attributeType '%s' is not defined in schema\n", - c->log, dst ); - - /* - * we create a fake "proxied" ad - * and add it here. - */ - - rc = slap_bv2undef_ad( &mapping[ 0 ].dst, - &ad, &text, SLAP_AD_PROXIED ); - if ( rc != LDAP_SUCCESS ) { - snprintf( c->cr_msg, sizeof( c->cr_msg ), - "destination attributeType \"%s\": %d (%s)\n", - dst, rc, text ? text : "" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - return 1; - } - } - } - - if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], asyncmeta_mapping_cmp ) != NULL) - || avl_find( map->remap, (caddr_t)&mapping[ 1 ], asyncmeta_mapping_cmp ) != NULL) - { - snprintf( c->cr_msg, sizeof( c->cr_msg ), - "duplicate mapping found." ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); - goto error_return; - } - - if ( src[ 0 ] != '\0' ) { - avl_insert( &map->map, (caddr_t)&mapping[ 0 ], - asyncmeta_mapping_cmp, asyncmeta_mapping_dup ); - } - avl_insert( &map->remap, (caddr_t)&mapping[ 1 ], - asyncmeta_mapping_cmp, asyncmeta_mapping_dup ); - -success_return:; - return 0; - -error_return:; - if ( mapping ) { - ch_free( mapping[ 0 ].src.bv_val ); - ch_free( mapping[ 0 ].dst.bv_val ); - ch_free( mapping ); - } - - return 1; -} - - -static char * -suffix_massage_regexize( const char *s ) -{ - char *res, *ptr; - const char *p, *r; - int i; - - if ( s[ 0 ] == '\0' ) { - return ch_strdup( "^(.+)$" ); - } - - for ( i = 0, p = s; - ( r = strchr( p, ',' ) ) != NULL; - p = r + 1, i++ ) - ; - - res = ch_calloc( sizeof( char ), - strlen( s ) - + STRLENOF( "((.+),)?" ) - + STRLENOF( "[ ]?" ) * i - + STRLENOF( "$" ) + 1 ); - - ptr = lutil_strcopy( res, "((.+),)?" ); - for ( i = 0, p = s; - ( r = strchr( p, ',' ) ) != NULL; - p = r + 1 , i++ ) { - ptr = lutil_strncopy( ptr, p, r - p + 1 ); - ptr = lutil_strcopy( ptr, "[ ]?" ); - - if ( r[ 1 ] == ' ' ) { - r++; - } - } - ptr = lutil_strcopy( ptr, p ); - ptr[ 0 ] = '$'; - ptr++; - ptr[ 0 ] = '\0'; - - return res; -} - -static char * -suffix_massage_patternize( const char *s, const char *p ) -{ - ber_len_t len; - char *res, *ptr; - - len = strlen( p ); - - if ( s[ 0 ] == '\0' ) { - len++; - } - - res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 ); - if ( res == NULL ) { - return NULL; - } - - ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) ); - if ( s[ 0 ] == '\0' ) { - ptr[ 0 ] = ','; - ptr++; - } - lutil_strcopy( ptr, p ); - - return res; -} - -int -asyncmeta_suffix_massage_config( - struct rewrite_info *info, - struct berval *pvnc, - struct berval *nvnc, - struct berval *prnc, - struct berval *nrnc -) -{ - char *rargv[ 5 ]; - int line = 0; - - rargv[ 0 ] = "rewriteEngine"; - rargv[ 1 ] = "on"; - rargv[ 2 ] = NULL; - rewrite_parse( info, "", ++line, 2, rargv ); - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "default"; - rargv[ 2 ] = NULL; - rewrite_parse( info, "", ++line, 2, rargv ); - - rargv[ 0 ] = "rewriteRule"; - rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val ); - rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val ); - rargv[ 3 ] = ":"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - ch_free( rargv[ 1 ] ); - ch_free( rargv[ 2 ] ); - - if ( BER_BVISEMPTY( pvnc ) ) { - rargv[ 0 ] = "rewriteRule"; - rargv[ 1 ] = "^$"; - rargv[ 2 ] = prnc->bv_val; - rargv[ 3 ] = ":"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - } - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "searchEntryDN"; - rargv[ 2 ] = NULL; - rewrite_parse( info, "", ++line, 2, rargv ); - - rargv[ 0 ] = "rewriteRule"; - rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val ); - rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val ); - rargv[ 3 ] = ":"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - ch_free( rargv[ 1 ] ); - ch_free( rargv[ 2 ] ); - - if ( BER_BVISEMPTY( prnc ) ) { - rargv[ 0 ] = "rewriteRule"; - rargv[ 1 ] = "^$"; - rargv[ 2 ] = pvnc->bv_val; - rargv[ 3 ] = ":"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - } - - /* backward compatibility */ - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "searchResult"; - rargv[ 2 ] = "alias"; - rargv[ 3 ] = "searchEntryDN"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "matchedDN"; - rargv[ 2 ] = "alias"; - rargv[ 3 ] = "searchEntryDN"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "searchAttrDN"; - rargv[ 2 ] = "alias"; - rargv[ 3 ] = "searchEntryDN"; - rargv[ 4 ] = NULL; - rewrite_parse( info, "", ++line, 4, rargv ); - - /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE; - * see servers/slapd/overlays/rwm.h for details */ - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "referralAttrDN"; - rargv[ 2 ] = NULL; - rewrite_parse( info, "", ++line, 2, rargv ); - - rargv[ 0 ] = "rewriteContext"; - rargv[ 1 ] = "referralDN"; - rargv[ 2 ] = NULL; - rewrite_parse( info, "", ++line, 2, rargv ); - - return 0; -} diff --git a/servers/slapd/back-asyncmeta/conn.c b/servers/slapd/back-asyncmeta/conn.c index eb90afa568..8d9690a49e 100644 --- a/servers/slapd/back-asyncmeta/conn.c +++ b/servers/slapd/back-asyncmeta/conn.c @@ -27,57 +27,11 @@ #include #include #include - - -#define AVL_INTERNAL #include "slap.h" +#include "../../../libraries/libldap/ldap-int.h" #include "../back-ldap/back-ldap.h" #include "back-asyncmeta.h" - -/* - * Debug stuff (got it from libavl) - */ -#if META_BACK_PRINT_CONNTREE > 0 - -static void -asyncmeta_back_ravl_print( Avlnode *root, int depth ) -{ - int i; - - if ( root == 0 ) { - return; - } - - asyncmeta_back_ravl_print( root->avl_right, depth + 1 ); - - for ( i = 0; i < depth; i++ ) { - fprintf( stderr, "-" ); - } - fputc( ' ', stderr ); - - asyncmeta_back_print( (a_metaconn_t *)root->avl_data, - avl_bf2str( root->avl_bf ) ); - - asyncmeta_back_ravl_print( root->avl_left, depth + 1 ); -} - -/* NOTE: duplicate from back-ldap/bind.c */ -static char* priv2str[] = { - "privileged", - "privileged/TLS", - "anonymous", - "anonymous/TLS", - "bind", - "bind/TLS", - NULL -}; - -#endif /* META_BACK_PRINT_CONNTREE */ -/* - * End of debug stuff - */ - /* * asyncmeta_conn_alloc * @@ -127,8 +81,6 @@ asyncmeta_init_one_conn( a_dncookie dc; int isauthz = ( candidate == mc->mc_authz_target ); int do_return = 0; - int nretries = 2; - #ifdef HAVE_TLS int is_ldaps = 0; int do_start_tls = 0; @@ -164,15 +116,16 @@ asyncmeta_init_one_conn( if ( dont_retry ) { rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Target is quarantined"; + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: Target is quarantined\n", + op->o_log_prefix ); if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { - rs->sr_text = "Target is quarantined"; send_ldap_result( op, rs ); } return rs->sr_err; } } msc = &mc->mc_conns[candidate]; -retry_lock:; /* * Already init'ed */ @@ -186,13 +139,7 @@ retry_lock:; } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) { - /* sounds more appropriate */ - if (nretries >= 0) { - nretries--; - ldap_pvt_thread_yield(); - goto retry_lock; - } - rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_err = LDAP_SUCCESS; do_return = 1; } else if ( META_BACK_CONN_INITED( msc ) ) { @@ -231,6 +178,8 @@ retry_lock:; #endif /* HAVE_TLS */ ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: ldap_initialize failed err=%d\n", + op->o_log_prefix, rs->sr_err ); goto error_return; } msc->msc_ldr = ldap_dup(msc->msc_ld); @@ -327,8 +276,8 @@ retry:; default: /* only touch when activity actually took place... */ - if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { - msc->msc_time = op->o_time; + if ( mi->mi_idle_timeout != 0 ) { + asyncmeta_set_msc_time(msc); } break; } @@ -348,6 +297,7 @@ retry:; res = NULL; if ( rs->sr_err == LDAP_SUCCESS ) { + rs->sr_err = err; } rs->sr_err = slap_map_api2result( rs ); @@ -385,7 +335,10 @@ retry:; */ rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL ); #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ - + if (rs->sr_err != LDAP_SUCCESS) { + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_init_one_conn: ldap_start_tls_s failed err=%d\n", + op->o_log_prefix, rs->sr_err ); + } /* if StartTLS is requested, only attempt it if the URL * is not "ldaps://"; this may occur not only in case * of misconfiguration, but also when used in the chain @@ -407,18 +360,16 @@ retry:; } } #endif /* HAVE_TLS */ - /* * Set the network timeout if set */ if ( mt->mt_network_timeout != 0 ) { - struct timeval network_timeout; - - network_timeout.tv_usec = 0; - network_timeout.tv_sec = mt->mt_network_timeout; + struct timeval network_timeout; + network_timeout.tv_sec = 0; + network_timeout.tv_usec = mt->mt_network_timeout*1000; ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, - (void *)&network_timeout ); + (void *)&network_timeout ); } /* @@ -452,38 +403,22 @@ retry:; BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISEMPTY( &op->o_ndn ) - && SLAP_IS_AUTHZ_BACKEND( op ) && isauthz ) { + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "bindDN"; + dc.memctx = NULL; + dc.to_from = MASSAGE_REQ; /* * Rewrite the bind dn if needed */ - if ( asyncmeta_dn_massage( &dc, &op->o_conn->c_dn, - &msc->msc_bound_ndn ) ) - { - -#ifdef DEBUG_205 - Debug( LDAP_DEBUG_ANY, - "### %s asyncmeta_init_one_conn(rewrite) " - "ldap_unbind_ext[%d] ld=%p\n", - op->o_log_prefix, candidate, - (void *)msc->msc_ld ); -#endif /* DEBUG_205 */ - goto error_return; - } + asyncmeta_dn_massage( &dc, &op->o_conn->c_dn, &msc->msc_bound_ndn ); /* copy the DN if needed */ if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); } - - assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); - } else { ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv ); } @@ -496,10 +431,6 @@ error_return:; META_BACK_CONN_CREATING_CLEAR( msc ); } if ( rs->sr_err == LDAP_SUCCESS && msc != NULL) { - /* - * Sets a cookie for the rewrite session - */ - ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn ); META_BACK_CONN_INITED_SET( msc ); } @@ -512,125 +443,6 @@ error_return:; return rs->sr_err; } -/* - * asyncmeta_retry - * - * Retries one connection - */ -int -asyncmeta_retry( - Operation *op, - SlapReply *rs, - a_metaconn_t **mcp, - int candidate, - ldap_back_send_t sendok ) -{ - a_metaconn_t *mc = *mcp; - a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - int rc = LDAP_UNAVAILABLE, - binding, - quarantine = 1; - - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - struct berval save_cred; - - if ( LogTest( LDAP_DEBUG_ANY ) ) { - /* this lock is required; however, - * it's invoked only when logging is on */ - ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); - Debug(LDAP_DEBUG_ANY, - "%s asyncmeta_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n", - op->o_log_prefix, candidate, mt->mt_uri, - BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val ); - ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); - } - - ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); - /* mc here must be the regular mc, reset and ready for init */ - rc = asyncmeta_init_one_conn( op, rs, mc, candidate, - LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 ); - - if ( rc != LDAP_SUCCESS ) { - if ( sendok & LDAP_BACK_SENDERR ) { - /* init_one_conn has set the result */ - send_ldap_result( op, rs ); - } - } - - if ( rc == LDAP_SUCCESS ) { - quarantine = 0; - LDAP_BACK_CONN_BINDING_SET( msc ); binding = 1; - /* todo this must be dobind_init */ - rc = asyncmeta_back_single_dobind( op, rs, mcp, candidate, - sendok, mt->mt_nretries, 0 ); - - Debug( LDAP_DEBUG_ANY, - "%s asyncmeta_retry[%d]: " - "asyncmeta_single_dobind=%d\n", - op->o_log_prefix, candidate, rc ); - if ( rc == LDAP_SUCCESS ) { - if ( !BER_BVISNULL( &msc->msc_bound_ndn ) && - !BER_BVISEMPTY( &msc->msc_bound_ndn ) ) - { - LDAP_BACK_CONN_ISBOUND_SET( msc ); - - } else { - LDAP_BACK_CONN_ISANON_SET( msc ); - } - - /* when bound, dispose of the "binding" flag */ - if ( binding ) { - LDAP_BACK_CONN_BINDING_CLEAR( msc ); - } - } - } - - - if ( rc != LDAP_SUCCESS ) { - if (mc->mc_active < 1) { - asyncmeta_clear_one_msc(NULL, mc, candidate); - } - if ( sendok & LDAP_BACK_SENDERR ) { - rs->sr_err = rc; - rs->sr_text = "Unable to retry"; - send_ldap_result( op, rs ); - } - } - - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); - if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) { - asyncmeta_quarantine( op, mi, rs, candidate ); - } - - return rc == LDAP_SUCCESS ? 1 : 0; -} - -/* - * callback for unique candidate selection - */ -static int -asyncmeta_conn_cb( Operation *op, SlapReply *rs ) -{ - assert( op->o_tag == LDAP_REQ_SEARCH ); - - switch ( rs->sr_type ) { - case REP_SEARCH: - ((long *)op->o_callback->sc_private)[0] = (long)op->o_private; - break; - - case REP_SEARCHREF: - case REP_RESULT: - break; - - default: - return rs->sr_err; - } - - return 0; -} - static int asyncmeta_get_candidate( @@ -654,59 +466,6 @@ asyncmeta_get_candidate( rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "No suitable candidate target found"; - } else if ( candidate == META_TARGET_MULTIPLE ) { - Operation op2 = *op; - SlapReply rs2 = { REP_RESULT }; - slap_callback cb2 = { 0 }; - int rc; - - /* try to get a unique match for the request ndn - * among the multiple candidates available */ - op2.o_tag = LDAP_REQ_SEARCH; - op2.o_req_dn = *ndn; - op2.o_req_ndn = *ndn; - op2.ors_scope = LDAP_SCOPE_BASE; - op2.ors_deref = LDAP_DEREF_NEVER; - op2.ors_attrs = slap_anlist_no_attrs; - op2.ors_attrsonly = 0; - op2.ors_limit = NULL; - op2.ors_slimit = 1; - op2.ors_tlimit = SLAP_NO_LIMIT; - - op2.ors_filter = (Filter *)slap_filter_objectClass_pres; - op2.ors_filterstr = *slap_filterstr_objectClass_pres; - - op2.o_callback = &cb2; - cb2.sc_response = asyncmeta_conn_cb; - cb2.sc_private = (void *)&candidate; - - rc = op->o_bd->be_search( &op2, &rs2 ); - - switch ( rs2.sr_err ) { - case LDAP_SUCCESS: - default: - rs->sr_err = rs2.sr_err; - break; - - case LDAP_SIZELIMIT_EXCEEDED: - /* if multiple candidates can serve the operation, - * and a default target is defined, and it is - * a candidate, try using it (FIXME: YMMV) */ - if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE - && asyncmeta_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ], - ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) ) - { - candidate = mi->mi_defaulttarget; - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; - - } else { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "Unable to select unique candidate target"; - } - break; - } - } else { rs->sr_err = LDAP_SUCCESS; } @@ -714,19 +473,6 @@ asyncmeta_get_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 @@ -910,7 +656,7 @@ asyncmeta_getconn( if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { - rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; + rs->sr_matched = mi->mi_suffix.bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; @@ -933,9 +679,6 @@ asyncmeta_getconn( } if ( op_type == META_OP_REQUIRE_SINGLE ) { - a_metatarget_t *mt = NULL; - a_metasingleconn_t *msc = NULL; - int j; for ( j = 0; j < mi->mi_ntargets; j++ ) { @@ -956,7 +699,7 @@ asyncmeta_getconn( if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) { if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { - rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; + rs->sr_matched = mi->mi_suffix.bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; @@ -998,9 +741,6 @@ asyncmeta_getconn( */ ( void )asyncmeta_clear_unused_candidates( op, i , mc, candidates); - mt = mi->mi_targets[ i ]; - msc = &mc->mc_conns[ i ]; - /* * The target is activated; if needed, it is * also init'd. In case of error, asyncmeta_init_one_conn @@ -1118,7 +858,7 @@ asyncmeta_getconn( if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { - rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; + rs->sr_matched = mi->mi_suffix.bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; @@ -1133,7 +873,6 @@ asyncmeta_getconn( } done:; - /* clear out meta_back_init_one_conn non-fatal errors */ rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; @@ -1266,6 +1005,7 @@ a_metaconn_t * asyncmeta_get_next_mc( a_metainfo_t *mi ) { a_metaconn_t *mc = NULL; + ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); if (mi->mi_next_conn >= mi->mi_num_conns-1) { mi->mi_next_conn = 0; @@ -1294,14 +1034,13 @@ int asyncmeta_start_one_listener(a_metaconn_t *mc, { a_metasingleconn_t *msc; ber_socket_t s; - int i; msc = &mc->mc_conns[candidate]; - if (msc->msc_ld == NULL || !META_IS_CANDIDATE( &candidates[ candidate ] )) { + if ( slapd_shutdown || !META_BACK_CONN_INITED( msc ) || msc->msc_ld == NULL + || !META_IS_CANDIDATE( &candidates[ candidate ] )) { return LDAP_SUCCESS; } bc->msgids[candidate] = candidates[candidate].sr_msgid; - msc->msc_pending_ops++; if ( msc->conn == NULL) { ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); if (s < 0) { @@ -1313,3 +1052,130 @@ int asyncmeta_start_one_listener(a_metaconn_t *mc, connection_client_enable( msc->conn ); return LDAP_SUCCESS; } + +int +asyncmeta_clear_one_msc( + Operation *op, + a_metaconn_t *mc, + int candidate, + int unbind, + const char *caller) +{ + a_metasingleconn_t *msc; + if (mc == NULL) { + return 0; + } + msc = &mc->mc_conns[candidate]; + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] Resetting msc: %p, msc_ld: %p, " + "msc_bound_ndn: %s, msc->conn: %p, %s \n", + time_buf, msc, msc->msc_ld, msc->msc_bound_ndn.bv_val, + msc->conn, caller ? caller : "" ); + } + msc->msc_mscflags = 0; + if (msc->conn) { + connection_client_stop( msc->conn ); + msc->conn = NULL; + } + + if ( msc->msc_ld != NULL ) { + +#ifdef DEBUG_205 + Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_clear_one_msc ldap_unbind_ext[%d] ld=%p\n", + op ? op->o_log_prefix : "", candidate, (void *)msc->msc_ld ); +#endif /* DEBUG_205 */ + + ldap_unbind_ext( msc->msc_ld, NULL, NULL ); + msc->msc_ld = NULL; + ldap_ld_free( msc->msc_ldr, 0, NULL, NULL ); + msc->msc_ldr = NULL; + } + + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { + ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL ); + BER_BVZERO( &msc->msc_bound_ndn ); + } + + if ( !BER_BVISNULL( &msc->msc_cred ) ) { + memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); + ber_memfree_x( msc->msc_cred.bv_val, NULL ); + BER_BVZERO( &msc->msc_cred ); + } + msc->msc_time = 0; + msc->msc_binding_time = 0; + msc->msc_result_time = 0; + return 0; +} + +void asyncmeta_get_timestamp(char *buf) +{ + struct timespec tp; + struct tm *ttm; + clock_gettime(CLOCK_REALTIME, &tp); + ttm = gmtime(&tp.tv_sec); + sprintf(buf, "%d:%d:%d.%ld", ttm->tm_hour, ttm->tm_min, ttm->tm_sec, tp.tv_nsec/1000); +} + +int +asyncmeta_reset_msc( + Operation *op, + a_metaconn_t *mc, + int candidate, + int unbind, + const char *caller) +{ + a_metasingleconn_t *msc = &mc->mc_conns[candidate]; + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug(asyncmeta_debug, "[%x] Will attempt to reset [%s] msc: %p, " + "msc->msc_binding_time: %x, msc->msc_flags:%x %s\n", + (unsigned int)slap_get_time(), time_buf, msc, + (unsigned int)msc->msc_binding_time, msc->msc_mscflags, caller ); + } + if (msc->msc_active <= 1 && mc->mc_active < 1) { + bm_context_t *om; + asyncmeta_clear_one_msc(NULL, mc, candidate, 0, caller); + /* set whatever's in the queue to invalid, so the timeout loop cleans it up, + * but do not invalidate the current op*/ + LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) { + if (om->candidates[candidate].sr_msgid >= 0 && (om->op != op)) { + om->bc_invalid = 1; + } + } + return LDAP_SUCCESS; + } else { + META_BACK_CONN_INVALID_SET(msc); + Debug( asyncmeta_debug, "[%x] Failed to reset msc %p, msc_active=%d, mc_active=%d, %s\n", + (unsigned int)slap_get_time(), msc, msc->msc_active, mc->mc_active, caller ); + } + return LDAP_OTHER; +} + + +void asyncmeta_log_msc(a_metasingleconn_t *msc) +{ + ber_socket_t s = 0; + if (msc->msc_ld) { + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + } + Debug( asyncmeta_debug, "msc: %p, msc_ld: %p, msc_ld socket: %d, " + "msc_bound_ndn: %s, msc->conn: %p\n", msc, msc->msc_ld, + (int)s, msc->msc_bound_ndn.bv_val, msc->conn ); +} + +void asyncmeta_log_conns(a_metainfo_t *mi) +{ + a_metaconn_t *mc; + int i, j; + for (i = 0; i < mi->mi_num_conns; i++) { + mc = &mi->mi_conns[i]; + Debug(asyncmeta_debug, "mc: %p, mc->pending_ops: %d\n", mc, mc->pending_ops); + for (j = 0; j < mi->mi_ntargets; j++ ) { + asyncmeta_log_msc(&mc->mc_conns[j]); + } + + } +} diff --git a/servers/slapd/back-asyncmeta/delete.c b/servers/slapd/back-asyncmeta/delete.c index 911a0ab27f..e4d46da7b1 100644 --- a/servers/slapd/back-asyncmeta/delete.c +++ b/servers/slapd/back-asyncmeta/delete.c @@ -23,28 +23,27 @@ #include "portable.h" #include - #include #include - #include "slap.h" -#include "../back-ldap/back-ldap.h" -#include "back-asyncmeta.h" #include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/libldap/ldap-int.h" +#include "../back-ldap/back-ldap.h" +#include "back-asyncmeta.h" meta_search_candidate_t asyncmeta_back_delete_start(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate) + int candidate, + int do_lock) { a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; struct berval mdn = BER_BVNULL; a_dncookie dc; - int rc = 0, nretries = 1; + int rc = 0; LDAPControl **ctrls = NULL; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; BerElement *ber = NULL; @@ -52,67 +51,119 @@ asyncmeta_back_delete_start(Operation *op, SlapReply *candidates = bc->candidates; ber_int_t msgid; + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "deleteDN"; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; - if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - retcode = META_SEARCH_ERR; - goto doreturn; - } + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); -retry:; + asyncmeta_set_msc_time(msc); ctrls = op->o_ctrls; - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_ERR; goto done; } - + /* someone might have reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } ber = ldap_build_delete_req( msc->msc_ld, mdn.bv_val, ctrls, NULL, &msgid); + + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_delete_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE, - mdn.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_DELETE, + mdn.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_clear_one_msc(NULL, mc, candidate); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - + /* fall though*/ default: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - retcode = META_SEARCH_ERR; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; } } + +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + retcode = META_SEARCH_NEED_BIND; + ldap_pvt_thread_yield(); + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send delete request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + ldap_pvt_thread_yield(); + break; + } done: (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); - BER_BVZERO( &mdn ); + op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); } -doreturn:; Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_delete_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); return retcode; } @@ -124,26 +175,32 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs ) a_metatarget_t *mt; a_metaconn_t *mc; int rc, candidate = -1; - OperationBuffer opbuf; + void *thrctx = op->o_threadctx; bm_context_t *bc; SlapReply *candidates; - slap_callback *cb = op->o_callback; + time_t current_time = slap_get_time(); - 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 ); - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + if (current_time > op->o_time) { + Debug(asyncmeta_debug, "==> asyncmeta_back_delete[%s]: o_time:[%ld], current time: [%ld]\n", + op->o_log_prefix, op->o_time, current_time ); + } + + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); return rs->sr_err; } candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + send_ldap_result(op, rs); return rs->sr_err; } @@ -152,16 +209,38 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs ) bc->retrying = LDAP_BACK_RETRYING; bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + mc->mc_conns[candidate].msc_active++; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + goto finish; + } + +retry: + if (bc->timeout && bc->stoptime < slap_get_time()) { + int timeout_err; + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + rs->sr_err = timeout_err; + rs->sr_text = "Operation timed out before it was sent to target"; + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; } @@ -171,47 +250,27 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs ) case META_SEARCH_CANDIDATE: /* target is already bound, just send the request */ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); - rc = asyncmeta_back_delete_start( op, rs, mc, bc, candidate); + rc = asyncmeta_back_delete_start( op, rs, mc, bc, candidate, 1); if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } - break; + break; case META_SEARCH_NOT_CANDIDATE: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NOT_CANDIDATE " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - } - break; case META_SEARCH_BINDING: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: BINDING " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); + "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); /* Todo add the context to the message queue but do not send the request the receiver must send this when we are done binding */ /* question - how would do receiver know to which targets??? */ @@ -219,22 +278,21 @@ asyncmeta_back_delete( Operation *op, SlapReply *rs ) case META_SEARCH_ERR: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_delete: ERR " - "cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; default: assert( 0 ); break; } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; asyncmeta_start_one_listener(mc, candidates, bc, candidate); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; finish: return rs->sr_err; } diff --git a/servers/slapd/back-asyncmeta/init.c b/servers/slapd/back-asyncmeta/init.c index f4e4658d9c..1b03aad52f 100644 --- a/servers/slapd/back-asyncmeta/init.c +++ b/servers/slapd/back-asyncmeta/init.c @@ -32,6 +32,8 @@ #include "../back-ldap/back-ldap.h" #include "back-asyncmeta.h" +int asyncmeta_debug; + int asyncmeta_back_open( BackendInfo *bi ) @@ -46,6 +48,14 @@ int asyncmeta_back_initialize( BackendInfo *bi ) { + int rc; + struct berval debugbv = BER_BVC("asyncmeta"); + + rc = slap_loglevel_get( &debugbv, &asyncmeta_debug ); + if ( rc ) { + return rc; + } + bi->bi_flags = #if 0 /* this is not (yet) set essentially because back-meta does not @@ -89,7 +99,7 @@ asyncmeta_back_initialize( bi->bi_chk_referrals = 0; bi->bi_connection_init = 0; - bi->bi_connection_destroy = asyncmeta_back_conn_destroy; + bi->bi_connection_destroy = 0 /* asyncmeta_back_conn_destroy */; return asyncmeta_back_init_cf( bi ); } @@ -164,9 +174,7 @@ asyncmeta_target_finish( ) { slap_bindconf sb = { BER_BVNULL }; - struct berval mapped; int rc; - int msc_num, i; ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri ); sb.sb_version = mt->mt_version; @@ -216,21 +224,6 @@ asyncmeta_target_finish( 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; } @@ -240,10 +233,8 @@ asyncmeta_back_db_open( ConfigReply *cr ) { a_metainfo_t *mi = (a_metainfo_t *)be->be_private; - char msg[SLAP_TEXT_BUFLEN]; - - int i, rc; + int i; if ( mi->mi_ntargets == 0 ) { /* Dynamically added, nothing to check here until @@ -272,11 +263,12 @@ asyncmeta_back_db_open( mc->mc_authz_target = META_BOUND_NONE; mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t )); mc->mc_info = mi; + LDAP_STAILQ_INIT( &mc->mc_om_list ); } - + mi->mi_suffix = be->be_suffix[0]; ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 0, - asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", be->be_suffix[0].bv_val ); + asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val ); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); return 0; } @@ -298,36 +290,6 @@ asyncmeta_back_conn_free( free( mc ); } -static void -mapping_free( - void *v_mapping ) -{ - struct ldapmapping *mapping = v_mapping; - ch_free( mapping->src.bv_val ); - ch_free( mapping->dst.bv_val ); - ch_free( mapping ); -} - -static void -mapping_dst_free( - void *v_mapping ) -{ - struct ldapmapping *mapping = v_mapping; - - if ( BER_BVISEMPTY( &mapping->dst ) ) { - mapping_free( &mapping[ -1 ] ); - } -} - -void -asyncmeta_back_map_free( struct ldapmap *lm ) -{ - avl_free( lm->remap, mapping_dst_free ); - avl_free( lm->map, mapping_free ); - lm->remap = NULL; - lm->map = NULL; -} - static void asyncmeta_back_stop_miconns( a_metainfo_t *mi ) { @@ -344,7 +306,7 @@ asyncmeta_back_clear_miconns( a_metainfo_t *mi ) mc = &mi->mi_conns[i]; /* todo clear the message queue */ for (j = 0; j < mi->mi_ntargets; j ++) { - asyncmeta_clear_one_msc(NULL, mc, j); + asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); } free(mc->mc_conns); ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex ); @@ -401,14 +363,12 @@ asyncmeta_target_free( if ( mt->mt_idassert_authz != NULL ) { ber_bvarray_free( mt->mt_idassert_authz ); } - if ( mt->mt_rwmap.rwm_rw ) { - rewrite_info_delete( &mt->mt_rwmap.rwm_rw ); - if ( mt->mt_rwmap.rwm_bva_rewrite ) - ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite ); + if ( !BER_BVISNULL( &mt->mt_lsuffixm )) { + ch_free( mt->mt_lsuffixm.bv_val ); + } + if ( !BER_BVISNULL( &mt->mt_rsuffixm )) { + ch_free( mt->mt_rsuffixm.bv_val ); } - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc ); - asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at ); - ber_bvarray_free( mt->mt_rwmap.rwm_bva_map ); free( mt ); } @@ -420,8 +380,6 @@ asyncmeta_back_db_close( a_metainfo_t *mi; if ( be->be_private ) { - int i; - mi = ( a_metainfo_t * )be->be_private; if ( mi->mi_task != NULL ) { ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); @@ -435,6 +393,7 @@ asyncmeta_back_db_close( asyncmeta_back_stop_miconns( mi ); ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); } + return 0; } int @@ -486,13 +445,14 @@ asyncmeta_back_db_destroy( if ( META_BACK_QUARANTINE( mi ) ) { mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine ); } - } - ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); - asyncmeta_back_clear_miconns(mi); - ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); - ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex ); - free( be->be_private ); + ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); + asyncmeta_back_clear_miconns(mi); + ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); + ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex ); + + free( be->be_private ); + } return 0; } diff --git a/servers/slapd/back-asyncmeta/map.c b/servers/slapd/back-asyncmeta/map.c index 83a332f097..833c50d5ac 100644 --- a/servers/slapd/back-asyncmeta/map.c +++ b/servers/slapd/back-asyncmeta/map.c @@ -63,641 +63,10 @@ #include "../back-ldap/back-ldap.h" #include "back-asyncmeta.h" -int -asyncmeta_mapping_cmp ( const void *c1, const void *c2 ) -{ - struct ldapmapping *map1 = (struct ldapmapping *)c1; - struct ldapmapping *map2 = (struct ldapmapping *)c2; - int rc = map1->src.bv_len - map2->src.bv_len; - if (rc) return rc; - return ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) ); -} - -int -asyncmeta_mapping_dup ( void *c1, void *c2 ) -{ - struct ldapmapping *map1 = (struct ldapmapping *)c1; - struct ldapmapping *map2 = (struct ldapmapping *)c2; - - return ( ( strcasecmp( map1->src.bv_val, map2->src.bv_val ) == 0 ) ? -1 : 0 ); -} - void -asyncmeta_map_init ( struct ldapmap *lm, struct ldapmapping **m ) -{ - struct ldapmapping *mapping; - - assert( m != NULL ); - - *m = NULL; - - mapping = (struct ldapmapping *)ch_calloc( 2, - sizeof( struct ldapmapping ) ); - if ( mapping == NULL ) { - return; - } - - ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src); - ber_dupbv( &mapping[0].dst, &mapping[0].src ); - mapping[1].src = mapping[0].src; - mapping[1].dst = mapping[0].dst; - - avl_insert( &lm->map, (caddr_t)&mapping[0], - asyncmeta_mapping_cmp, asyncmeta_mapping_dup ); - avl_insert( &lm->remap, (caddr_t)&mapping[1], - asyncmeta_mapping_cmp, asyncmeta_mapping_dup ); - *m = mapping; -} - -int -asyncmeta_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **m, - int remap ) -{ - Avlnode *tree; - struct ldapmapping fmapping; - - assert( m != NULL ); - - /* let special attrnames slip through (ITS#5760) */ - if ( bvmatch( s, slap_bv_no_attrs ) - || bvmatch( s, slap_bv_all_user_attrs ) - || bvmatch( s, slap_bv_all_operational_attrs ) ) - { - *m = NULL; - return 0; - } - - if ( remap == BACKLDAP_REMAP ) { - tree = map->remap; - - } else { - tree = map->map; - } - - fmapping.src = *s; - *m = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, asyncmeta_mapping_cmp ); - if ( *m == NULL ) { - return map->drop_missing; - } - - return 0; -} - -void -asyncmeta_map ( struct ldapmap *map, struct berval *s, struct berval *bv, - int remap ) -{ - struct ldapmapping *mapping; - int drop_missing; - - /* map->map may be NULL when mapping is configured, - * but map->remap can't */ - if ( map->remap == NULL ) { - *bv = *s; - return; - } - - BER_BVZERO( bv ); - drop_missing = asyncmeta_mapping( map, s, &mapping, remap ); - if ( mapping != NULL ) { - if ( !BER_BVISNULL( &mapping->dst ) ) { - *bv = mapping->dst; - } - return; - } - - if ( !drop_missing ) { - *bv = *s; - } -} - -int -asyncmeta_map_attrs( - Operation *op, - struct ldapmap *at_map, - AttributeName *an, - int remap, - char ***mapped_attrs ) -{ - int i, x, j; - char **na; - struct berval mapped; - - if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) { - *mapped_attrs = NULL; - return LDAP_SUCCESS; - } - - i = 0; - if ( an != NULL ) { - for ( ; !BER_BVISNULL( &an[i].an_name ); i++ ) - /* */ ; - } - - x = 0; - if ( op->o_bd->be_extra_anlist != NULL ) { - for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) - /* */ ; - } - - assert( i > 0 || x > 0 ); - - na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx ); - if ( na == NULL ) { - *mapped_attrs = NULL; - return LDAP_NO_MEMORY; - } - - j = 0; - if ( i > 0 ) { - for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) { - asyncmeta_map( at_map, &an[i].an_name, &mapped, remap ); - if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) { - na[j++] = mapped.bv_val; - } - } - } - - if ( x > 0 ) { - for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) { - if ( op->o_bd->be_extra_anlist[x].an_desc && - ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) ) - { - continue; - } - - asyncmeta_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap ); - if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) { - na[j++] = mapped.bv_val; - } - } - } - - if ( j == 0 && ( i > 0 || x > 0 ) ) { - na[j++] = LDAP_NO_ATTRS; - } - na[j] = NULL; - - *mapped_attrs = na; - - return LDAP_SUCCESS; -} - -static int -map_attr_value( - a_dncookie *dc, - AttributeDescription *ad, - struct berval *mapped_attr, - struct berval *value, - struct berval *mapped_value, - int remap, - void *memctx ) -{ - struct berval vtmp; - int freeval = 0; - - asyncmeta_map( &dc->target->mt_rwmap.rwm_at, &ad->ad_cname, mapped_attr, remap ); - if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) { -#if 0 - /* - * FIXME: are we sure we need to search oc_map if at_map fails? - */ - asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, &ad->ad_cname, mapped_attr, remap ); - if ( BER_BVISNULL( mapped_attr ) || BER_BVISEMPTY( mapped_attr ) ) { - *mapped_attr = ad->ad_cname; - } -#endif - if ( dc->target->mt_rwmap.rwm_at.drop_missing ) { - return -1; - } - - *mapped_attr = ad->ad_cname; - } - - if ( value == NULL ) { - return 0; - } - - if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) - { - a_dncookie fdc = *dc; - - fdc.ctx = "searchFilterAttrDN"; - - switch ( asyncmeta_dn_massage( &fdc, value, &vtmp ) ) { - case LDAP_SUCCESS: - if ( vtmp.bv_val != value->bv_val ) { - freeval = 1; - } - break; - - case LDAP_UNWILLING_TO_PERFORM: - return -1; - - case LDAP_OTHER: - return -1; - } - - } else if ( ad->ad_type->sat_equality && - ad->ad_type->sat_equality->smr_usage & SLAP_MR_MUTATION_NORMALIZER ) - { - if ( ad->ad_type->sat_equality->smr_normalize( - (SLAP_MR_DENORMALIZE|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX), - NULL, NULL, value, &vtmp, memctx ) ) - { - return -1; - } - freeval = 2; - - } else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) { - asyncmeta_map( &dc->target->mt_rwmap.rwm_oc, value, &vtmp, remap ); - if ( BER_BVISNULL( &vtmp ) || BER_BVISEMPTY( &vtmp ) ) { - vtmp = *value; - } - - } else { - vtmp = *value; - } - - filter_escape_value_x( &vtmp, mapped_value, memctx ); - - switch ( freeval ) { - case 1: - ber_memfree( vtmp.bv_val ); - break; - case 2: - ber_memfree_x( vtmp.bv_val, memctx ); - break; - } - - return 0; -} - -static int -asyncmeta_int_filter_map_rewrite( - a_dncookie *dc, - Filter *f, - struct berval *fstr, - int remap, - void *memctx ) -{ - int i; - Filter *p; - struct berval atmp, - vtmp, - *tmp; - static struct berval - /* better than nothing... */ - ber_bvfalse = BER_BVC( "(!(objectClass=*))" ), - ber_bvtf_false = BER_BVC( "(|)" ), - /* better than nothing... */ - ber_bvtrue = BER_BVC( "(objectClass=*)" ), - ber_bvtf_true = BER_BVC( "(&)" ), -#if 0 - /* no longer needed; preserved for completeness */ - ber_bvundefined = BER_BVC( "(?=undefined)" ), -#endif - ber_bverror = BER_BVC( "(?=error)" ), - ber_bvunknown = BER_BVC( "(?=unknown)" ), - ber_bvnone = BER_BVC( "(?=none)" ); - ber_len_t len; - - assert( fstr != NULL ); - BER_BVZERO( fstr ); - - if ( f == NULL ) { - ber_dupbv_x( fstr, &ber_bvnone, memctx ); - return LDAP_OTHER; - } - - switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) { - case LDAP_FILTER_EQUALITY: - if ( map_attr_value( dc, f->f_av_desc, &atmp, - &f->f_av_value, &vtmp, remap, memctx ) ) - { - goto computed; - } - - fstr->bv_len = atmp.bv_len + vtmp.bv_len - + ( sizeof("(=)") - 1 ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", - atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - break; - - case LDAP_FILTER_GE: - if ( map_attr_value( dc, f->f_av_desc, &atmp, - &f->f_av_value, &vtmp, remap, memctx ) ) - { - goto computed; - } - - fstr->bv_len = atmp.bv_len + vtmp.bv_len - + ( sizeof("(>=)") - 1 ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", - atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - break; - - case LDAP_FILTER_LE: - if ( map_attr_value( dc, f->f_av_desc, &atmp, - &f->f_av_value, &vtmp, remap, memctx ) ) - { - goto computed; - } - - fstr->bv_len = atmp.bv_len + vtmp.bv_len - + ( sizeof("(<=)") - 1 ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", - atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - break; - - case LDAP_FILTER_APPROX: - if ( map_attr_value( dc, f->f_av_desc, &atmp, - &f->f_av_value, &vtmp, remap, memctx ) ) - { - goto computed; - } - - fstr->bv_len = atmp.bv_len + vtmp.bv_len - + ( sizeof("(~=)") - 1 ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", - atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - break; - - case LDAP_FILTER_SUBSTRINGS: - if ( map_attr_value( dc, f->f_sub_desc, &atmp, - NULL, NULL, remap, memctx ) ) - { - goto computed; - } - - /* cannot be a DN ... */ - - fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */ - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", - atmp.bv_val ); - - if ( !BER_BVISNULL( &f->f_sub_initial ) ) { - len = fstr->bv_len; - - filter_escape_value_x( &f->f_sub_initial, &vtmp, memctx ); - - fstr->bv_len += vtmp.bv_len; - fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); - - snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3, - /* "(attr=" */ "%s*)", - vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - } - - if ( f->f_sub_any != NULL ) { - for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) { - len = fstr->bv_len; - filter_escape_value_x( &f->f_sub_any[i], &vtmp, memctx ); - - fstr->bv_len += vtmp.bv_len + 1; - fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); - - snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, - /* "(attr=[init]*[any*]" */ "%s*)", - vtmp.bv_len ? vtmp.bv_val : "" ); - ber_memfree_x( vtmp.bv_val, memctx ); - } - } - - if ( !BER_BVISNULL( &f->f_sub_final ) ) { - len = fstr->bv_len; - - filter_escape_value_x( &f->f_sub_final, &vtmp, memctx ); - - fstr->bv_len += vtmp.bv_len; - fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); - - snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, - /* "(attr=[init*][any*]" */ "%s)", - vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - } - - break; - - case LDAP_FILTER_PRESENT: - if ( map_attr_value( dc, f->f_desc, &atmp, - NULL, NULL, remap, memctx ) ) - { - goto computed; - } - - fstr->bv_len = atmp.bv_len + ( STRLENOF( "(=*)" ) ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", - atmp.bv_val ); - break; - - case LDAP_FILTER_AND: - case LDAP_FILTER_OR: - case LDAP_FILTER_NOT: - fstr->bv_len = STRLENOF( "(%)" ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */ - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", - f->f_choice == LDAP_FILTER_AND ? '&' : - f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); - - for ( p = f->f_list; p != NULL; p = p->f_next ) { - int rc; - - len = fstr->bv_len; - - rc = asyncmeta_int_filter_map_rewrite( dc, p, &vtmp, remap, memctx ); - if ( rc != LDAP_SUCCESS ) { - return rc; - } - - fstr->bv_len += vtmp.bv_len; - fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); - - snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, - /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" ); - - ber_memfree_x( vtmp.bv_val, memctx ); - } - - break; - - case LDAP_FILTER_EXT: - if ( f->f_mr_desc ) { - if ( map_attr_value( dc, f->f_mr_desc, &atmp, - &f->f_mr_value, &vtmp, remap, memctx ) ) - { - goto computed; - } - - } else { - BER_BVSTR( &atmp, "" ); - filter_escape_value_x( &f->f_mr_value, &vtmp, memctx ); - } - - /* FIXME: cleanup (less ?: operators...) */ - fstr->bv_len = atmp.bv_len + - ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) + - ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) + - vtmp.bv_len + ( STRLENOF( "(:=)" ) ); - fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); - - snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", - atmp.bv_val, - f->f_mr_dnattrs ? ":dn" : "", - !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "", - !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "", - vtmp.bv_len ? vtmp.bv_val : "" ); - ber_memfree_x( vtmp.bv_val, memctx ); - break; - - case SLAPD_FILTER_COMPUTED: - switch ( f->f_result ) { - /* FIXME: treat UNDEFINED as FALSE */ - case SLAPD_COMPARE_UNDEFINED: -computed:; - if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) { - return LDAP_COMPARE_FALSE; - } - /* fallthru */ - - case LDAP_COMPARE_FALSE: - if ( META_BACK_TGT_T_F( dc->target ) ) { - tmp = &ber_bvtf_false; - break; - } - tmp = &ber_bvfalse; - break; - - case LDAP_COMPARE_TRUE: - if ( META_BACK_TGT_T_F( dc->target ) ) { - tmp = &ber_bvtf_true; - break; - } - - tmp = &ber_bvtrue; - break; - - default: - tmp = &ber_bverror; - break; - } - - ber_dupbv_x( fstr, tmp, memctx ); - break; - - default: - ber_dupbv_x( fstr, &ber_bvunknown, memctx ); - break; - } - - return 0; -} - -int -asyncmeta_filter_map_rewrite( - a_dncookie *dc, - Filter *f, - struct berval *fstr, - int remap, - void *memctx ) -{ - int rc; - a_dncookie fdc; - struct berval ftmp; - static char *dmy = ""; - - rc = asyncmeta_int_filter_map_rewrite( dc, f, fstr, remap, memctx ); - - if ( rc != LDAP_SUCCESS ) { - return rc; - } - - fdc = *dc; - ftmp = *fstr; - - fdc.ctx = "searchFilter"; - - switch ( rewrite_session( fdc.target->mt_rwmap.rwm_rw, fdc.ctx, - ( !BER_BVISEMPTY( &ftmp ) ? ftmp.bv_val : dmy ), - fdc.conn, &fstr->bv_val ) ) - { - case REWRITE_REGEXEC_OK: - if ( !BER_BVISNULL( fstr ) ) { - fstr->bv_len = strlen( fstr->bv_val ); - - } else { - *fstr = ftmp; - } - Debug( LDAP_DEBUG_ARGS, - "[rw] %s: \"%s\" -> \"%s\"\n", - fdc.ctx, BER_BVISNULL( &ftmp ) ? "" : ftmp.bv_val, - BER_BVISNULL( fstr ) ? "" : fstr->bv_val ); - rc = LDAP_SUCCESS; - break; - - case REWRITE_REGEXEC_UNWILLING: - if ( fdc.rs ) { - fdc.rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - fdc.rs->sr_text = "Operation not allowed"; - } - rc = LDAP_UNWILLING_TO_PERFORM; - break; - - case REWRITE_REGEXEC_ERR: - if ( fdc.rs ) { - fdc.rs->sr_err = LDAP_OTHER; - fdc.rs->sr_text = "Rewrite error"; - } - rc = LDAP_OTHER; - break; - } - - if ( fstr->bv_val == dmy ) { - BER_BVZERO( fstr ); - - } else if ( fstr->bv_val != ftmp.bv_val ) { - /* NOTE: need to realloc mapped filter on slab - * and free the original one, until librewrite - * becomes slab-aware - */ - ber_dupbv_x( &ftmp, fstr, memctx ); - ch_free( fstr->bv_val ); - *fstr = ftmp; - } - - return rc; -} - -int asyncmeta_referral_result_rewrite( a_dncookie *dc, - BerVarray a_vals, - void *memctx + BerVarray a_vals ) { int i, last; @@ -731,144 +100,115 @@ asyncmeta_referral_result_rewrite( ber_str2bv( ludp->lud_dn, 0, 0, &olddn ); - rc = asyncmeta_dn_massage( dc, &olddn, &dn ); - switch ( rc ) { - case LDAP_UNWILLING_TO_PERFORM: - /* - * FIXME: need to check if it may be considered - * legal to trim values when adding/modifying; - * it should be when searching (e.g. ACLs). - */ - ber_memfree( a_vals[ i ].bv_val ); - if ( last > i ) { - a_vals[ i ] = a_vals[ last ]; - } - BER_BVZERO( &a_vals[ last ] ); - last--; - i--; - break; + asyncmeta_dn_massage( dc, &olddn, &dn ); + /* leave attr untouched if massage did nothing */ + if ( olddn.bv_val != dn.bv_val ) + { + char *newurl; - default: - /* leave attr untouched if massage failed */ - if ( !BER_BVISNULL( &dn ) && olddn.bv_val != dn.bv_val ) + ludp->lud_dn = dn.bv_val; + newurl = ldap_url_desc2str( ludp ); + dc->op->o_tmpfree( dn.bv_val, dc->memctx ); + if ( newurl ) { - char *newurl; + /* FIXME: leave attr untouched + * even if ldap_url_desc2str failed... + */ - ludp->lud_dn = dn.bv_val; - newurl = ldap_url_desc2str( ludp ); - free( dn.bv_val ); - if ( newurl == NULL ) { - /* FIXME: leave attr untouched - * even if ldap_url_desc2str failed... - */ - break; - } - - ber_memfree_x( a_vals[ i ].bv_val, memctx ); - ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], memctx ); + ber_memfree_x( a_vals[ i ].bv_val, dc->op->o_tmpmemctx ); + ber_str2bv_x( newurl, 0, 1, &a_vals[ i ], dc->memctx ); ber_memfree( newurl ); ludp->lud_dn = olddn.bv_val; } - break; } - ldap_free_urldesc( ludp ); } - - return 0; } -/* - * I don't like this much, but we need two different - * functions because different heap managers may be - * in use in back-ldap/meta to reduce the amount of - * calls to malloc routines, and some of the free() - * routines may be macros with args - */ -int -asyncmeta_dnattr_rewrite( - 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 +void asyncmeta_dnattr_result_rewrite( a_dncookie *dc, BerVarray a_vals ) { struct berval bv; - int i, last; + int i; assert( a_vals != NULL ); - for ( last = 0; !BER_BVISNULL( &a_vals[last] ); last++ ) - ; - last--; - for ( i = 0; !BER_BVISNULL( &a_vals[i] ); i++ ) { - switch ( asyncmeta_dn_massage( dc, &a_vals[i], &bv ) ) { - case LDAP_UNWILLING_TO_PERFORM: - /* - * FIXME: need to check if it may be considered - * legal to trim values when adding/modifying; - * it should be when searching (e.g. ACLs). - */ - 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; - } - break; + asyncmeta_dn_massage( dc, &a_vals[i], &bv ); + if ( bv.bv_val != a_vals[i].bv_val ) { + ber_memfree_x( a_vals[i].bv_val, dc->memctx ); + a_vals[i] = bv; } } - - return 0; +} + +/* + * 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 ); } diff --git a/servers/slapd/back-asyncmeta/message_queue.c b/servers/slapd/back-asyncmeta/message_queue.c index 382709e40a..f122233e3b 100644 --- a/servers/slapd/back-asyncmeta/message_queue.c +++ b/servers/slapd/back-asyncmeta/message_queue.c @@ -37,182 +37,6 @@ #include "lutil.h" -LDAPControl **asyncmeta_copy_controls(Operation *op) -{ - LDAPControl **new_controls = NULL; - LDAPControl **c; - LDAPControl *tmp_ctl = NULL; - int i, length = 1; - - - if (op->o_ctrls == NULL) { - return NULL; - } - for (c = op->o_ctrls; *c != NULL; c++) { - length++; - } - - new_controls = op->o_tmpalloc( sizeof(LDAPControl*)*length, op->o_tmpmemctx ); - for (i = 0; i < length-1; i ++) { - new_controls[i] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx ); - if (op->o_ctrls[i]->ldctl_value.bv_len > 0) { - ber_dupbv_x( &new_controls[i]->ldctl_value, &op->o_ctrls[i]->ldctl_value, op->o_tmpmemctx); - } - if (op->o_ctrls[i]->ldctl_oid) { - new_controls[i]->ldctl_oid = ber_strdup_x(op->o_ctrls[i]->ldctl_oid, op->o_tmpmemctx); - } - new_controls[i]->ldctl_iscritical = op->o_ctrls[i]->ldctl_iscritical; - } - new_controls[length-1] = NULL; - return new_controls; -} - -static -void asyncmeta_free_op_controls(Operation *op) -{ - LDAPControl **c; - for (c = op->o_ctrls; *c != NULL; c++) { - if ((*c)->ldctl_value.bv_len > 0) { - free((*c)->ldctl_value.bv_val); - } - if ((*c)->ldctl_oid) { - free((*c)->ldctl_oid); - } - free(*c); - } - free(op->o_ctrls); -} - - -static -Modifications* asyncmeta_copy_modlist(Operation *op, Modifications *modlist) -{ - Modifications *ml; - Modifications *new_mods = NULL; - for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { - Modifications *mod = op->o_tmpalloc( sizeof( Modifications ), op->o_tmpmemctx ); - *mod = *ml; - if ( ml->sml_values ) { - ber_bvarray_dup_x( &mod->sml_values, ml->sml_values, op->o_tmpmemctx ); - if ( ml->sml_nvalues ) { - ber_bvarray_dup_x( &mod->sml_nvalues, ml->sml_nvalues, op->o_tmpmemctx ); - } - } - mod->sml_next = NULL; - if (new_mods == NULL) { - new_mods = mod; - } else { - new_mods->sml_next = mod; - } - } - return new_mods; -} - -Operation *asyncmeta_copy_op(Operation *op) -{ - const char *text; - int rc; - char txtbuf[SLAP_TEXT_BUFLEN]; - size_t textlen = sizeof txtbuf; - Entry *e; - Operation *new_op = op->o_tmpcalloc( 1, sizeof(OperationBuffer), op->o_tmpmemctx ); - *new_op = *op; - new_op->o_hdr = &((OperationBuffer *) new_op)->ob_hdr; - *(new_op->o_hdr) = *(op->o_hdr); - new_op->o_controls = ((OperationBuffer *) new_op)->ob_controls; - new_op->o_callback = op->o_callback; - new_op->o_ber = NULL; - new_op->o_bd = op->o_bd->bd_self; - - ber_dupbv_x( &new_op->o_req_dn, &op->o_req_dn, op->o_tmpmemctx ); - ber_dupbv_x( &new_op->o_req_ndn, &op->o_req_ndn, op->o_tmpmemctx ); - op->o_callback = NULL; - - if (op->o_ndn.bv_len > 0) { - ber_dupbv_x( &new_op->o_ndn, &op->o_ndn, op->o_tmpmemctx ); - } - if (op->o_dn.bv_len > 0) { - ber_dupbv_x( &new_op->o_dn, &op->o_dn, op->o_tmpmemctx ); - } - - new_op->o_ctrls = asyncmeta_copy_controls(op); - switch (op->o_tag) { - case LDAP_REQ_SEARCH: - { - AttributeName *at_names; - int i; - for (i=0; op->ors_attrs && !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++); - if (i > 0) { - at_names = op->o_tmpcalloc( i+1, sizeof( AttributeName ), op->o_tmpmemctx ); - at_names[i].an_name.bv_len = 0; - i--; - for (i; i >= 0; i--) { - at_names[i] = op->ors_attrs[i]; - ber_dupbv_x( &at_names[i].an_name, &op->ors_attrs[i].an_name, op->o_tmpmemctx ); - } - } else { - at_names = NULL; - } - ber_dupbv_x( &new_op->ors_filterstr, &op->ors_filterstr, op->o_tmpmemctx ); - new_op->ors_filter = filter_dup( op->ors_filter, op->o_tmpmemctx ); - new_op->ors_attrs = at_names; - } - break; - case LDAP_REQ_ADD: - { - slap_entry2mods(op->ora_e, &new_op->ora_modlist, &text, txtbuf, textlen); - e = entry_alloc(); - new_op->ora_e = e; - ber_dupbv_x( &e->e_name, &op->o_req_dn, op->o_tmpmemctx ); - ber_dupbv_x( &e->e_nname, &op->o_req_ndn, op->o_tmpmemctx ); - rc = slap_mods2entry( new_op->ora_modlist, &new_op->ora_e, 1, 0, &text, txtbuf, textlen); - } - break; - case LDAP_REQ_MODIFY: - { - new_op->orm_modlist = asyncmeta_copy_modlist(op, op->orm_modlist); - } - break; - case LDAP_REQ_COMPARE: - new_op->orc_ava = (AttributeAssertion *)ch_calloc( 1, sizeof( AttributeAssertion )); - *new_op->orc_ava = *op->orc_ava; - if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) { - ber_dupbv_x( &new_op->orc_ava->aa_value, &op->orc_ava->aa_value, op->o_tmpmemctx); - } - break; - case LDAP_REQ_MODRDN: - - if (op->orr_newrdn.bv_len > 0) { - ber_dupbv_x( &new_op->orr_newrdn, &op->orr_newrdn, op->o_tmpmemctx ); - } - if (op->orr_nnewrdn.bv_len > 0) { - ber_dupbv_x( &new_op->orr_nnewrdn, &op->orr_nnewrdn, op->o_tmpmemctx ); - } - if (op->orr_newSup != NULL) { - new_op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx ); - new_op->orr_newSup->bv_len = 0; - if (op->orr_newSup->bv_len > 0) { - ber_dupbv_x( new_op->orr_newSup, op->orr_newSup, op->o_tmpmemctx ); - } - } - - if (op->orr_nnewSup != NULL) { - new_op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx ); - new_op->orr_nnewSup->bv_len = 0; - if (op->orr_nnewSup->bv_len > 0) { - ber_dupbv_x( new_op->orr_nnewSup, op->orr_nnewSup, op->o_tmpmemctx ); - } - } - new_op->orr_modlist = asyncmeta_copy_modlist(op, op->orr_modlist); - break; - case LDAP_REQ_DELETE: - default: - break; - } - return new_op; -} - - typedef struct listptr { void *reserved; struct listptr *next; @@ -223,80 +47,73 @@ typedef struct listhead { int cnt; } listhead; -static void *asyncmeta_memctx_destroy(void *key, void *data) -{ - listhead *lh = data; - listptr *lp; - while (lp = lh->list) { - lh->list = lp->next; - slap_sl_mem_destroy((void *)1, lp); - } - ch_free(lh); -} - #ifndef LH_MAX #define LH_MAX 16 #endif static void *asyncmeta_memctx_get(void *threadctx) { - listhead *lh = NULL; - listptr *lp = NULL; - ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL); - if (!lh) { - lh = ch_malloc(sizeof(listhead)); - lh->cnt = 0; - lh->list = NULL; - ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL); - } - if (lh->list) { - lp = lh->list; - lh->list = lp->next; - lh->cnt--; - slap_sl_mem_setctx(threadctx, lp); - } return slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, threadctx, 1); } static void asyncmeta_memctx_put(void *threadctx, void *memctx) { - listhead *lh = NULL; - ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL); - if (!lh) { - lh = ch_malloc(sizeof(listhead)); - lh->cnt = 0; - lh->list = NULL; - ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL); - } - if (lh->cnt < LH_MAX) { - listptr *lp = memctx; - lp->next = lh->list; - lh->list = lp; - lh->cnt++; - } else { - slap_sl_mem_destroy((void *)1, memctx); - } + slap_sl_mem_setctx(threadctx, NULL); + slap_sl_mem_destroy((void *)1, memctx); } -int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets) +void asyncmeta_memctx_toggle(void *thrctx) +{ + asyncmeta_memctx_get(thrctx); +} + +int asyncmeta_new_bm_context(Operation *op, + SlapReply *rs, + bm_context_t **new_bc, + int ntargets, + a_metainfo_t *mi) { - void *oldctx = op->o_tmpmemctx; int i; - /* prevent old memctx from being destroyed */ - slap_sl_mem_setctx(op->o_threadctx, NULL); - /* create new memctx */ - op->o_tmpmemctx = asyncmeta_memctx_get( op->o_threadctx ); *new_bc = op->o_tmpcalloc( 1, sizeof( bm_context_t ), op->o_tmpmemctx ); - (*new_bc)->op = asyncmeta_copy_op(op); + (*new_bc)->op = op; + (*new_bc)->copy_op = *op; (*new_bc)->candidates = op->o_tmpcalloc(ntargets, sizeof(SlapReply),op->o_tmpmemctx); (*new_bc)->msgids = op->o_tmpcalloc(ntargets, sizeof(int),op->o_tmpmemctx); + (*new_bc)->nretries = op->o_tmpcalloc(ntargets, sizeof(int),op->o_tmpmemctx); + (*new_bc)->c_peer_name = op->o_conn->c_peer_name; + (*new_bc)->is_root = be_isroot( op ); + + switch(op->o_tag) { + case LDAP_REQ_COMPARE: + { + AttributeAssertion *ava = op->o_tmpcalloc( 1, sizeof(AttributeAssertion), op->o_tmpmemctx ); + *ava = *op->orc_ava; + op->orc_ava = ava; + } + break; + case LDAP_REQ_MODRDN: + if (op->orr_newSup != NULL) { + struct berval *bv = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx ); + *bv = *op->orr_newSup; + op->orr_newSup = bv; + } + + if (op->orr_nnewSup != NULL) { + struct berval *bv = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx ); + *bv = *op->orr_nnewSup; + op->orr_nnewSup = bv; + } + break; + default: + break; + } for (i = 0; i < ntargets; i++) { (*new_bc)->msgids[i] = META_MSGID_UNDEFINED; } - /* restore original memctx */ - slap_sl_mem_setctx(op->o_threadctx, oldctx); - op->o_tmpmemctx = oldctx; + for (i = 0; i < ntargets; i++) { + (*new_bc)->nretries[i] = mi->mi_targets[i]->mt_nretries; + } return LDAP_SUCCESS; } @@ -305,15 +122,6 @@ void asyncmeta_free_op(Operation *op) assert (op != NULL); switch (op->o_tag) { case LDAP_REQ_SEARCH: - if (op->ors_filterstr.bv_len != 0) { - free(op->ors_filterstr.bv_val); - } - if (op->ors_filter) { - filter_free(op->ors_filter); - } - if (op->ors_attrs) { - free(op->ors_attrs); - } break; case LDAP_REQ_ADD: if ( op->ora_modlist != NULL ) { @@ -331,36 +139,11 @@ void asyncmeta_free_op(Operation *op) } break; case LDAP_REQ_MODRDN: - if (op->orr_newrdn.bv_len > 0) { - free(op->orr_newrdn.bv_val); - } - if (op->orr_nnewrdn.bv_len > 0) { - free(op->orr_nnewrdn.bv_val); - } - - if (op->orr_nnewSup != NULL ) { - if (op->orr_nnewSup->bv_len > 0) { - free(op->orr_nnewSup->bv_val); - } - free (op->orr_nnewSup); - } - - if (op->orr_newSup != NULL ) { - if (op->orr_newSup->bv_len > 0) { - free(op->orr_newSup->bv_val); - } - free (op->orr_newSup); - } - if ( op->orr_modlist != NULL ) { slap_mods_free(op->orr_modlist, 1 ); } break; case LDAP_REQ_COMPARE: - if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) { - free(op->orc_ava->aa_value.bv_val); - } - free(op->orc_ava); break; case LDAP_REQ_DELETE: break; @@ -368,22 +151,8 @@ void asyncmeta_free_op(Operation *op) Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type" ); } - if (op->o_ctrls != NULL) { - asyncmeta_free_op_controls(op); - } - if (op->o_ndn.bv_len > 0) { - free(op->o_ndn.bv_val); - } - if (op->o_dn.bv_len > 0) { - free( op->o_dn.bv_val ); - } - if (op->o_req_dn.bv_len > 0) { - free(op->o_req_dn.bv_val); - } - if (op->o_req_dn.bv_len > 0) { - free(op->o_req_ndn.bv_val); - } - free(op); + connection_op_finish( op ); + slap_op_free( op, op->o_threadctx ); } @@ -393,96 +162,26 @@ void asyncmeta_clear_bm_context(bm_context_t *bc) { Operation *op = bc->op; -#if 0 - bm_candidates_t *cl; - a_metainfo_t *mi; - int i = 0; - if (bmc == NULL) { + void *thrctx, *memctx; + int i; + + if ( bc->bc_mc && bc->bc_mc->mc_info ) { + for (i = 0; i < bc->bc_mc->mc_info->mi_ntargets; i++) { + if (bc->candidates[ i ].sr_text != NULL) { + ch_free( (char *)bc->candidates[ i ].sr_text ); + bc->candidates[ i ].sr_text = NULL; + } + } + } + + if (op->o_conn->c_conn_idx == -1) return; - } else if (bmc->cl == NULL) { - free(bmc); - return; - } - cl = bmc->cl; - op = cl->op; - switch (op->o_tag) { - case LDAP_REQ_SEARCH: - break; - case LDAP_REQ_ADD: - if ( (bmc->mdn.bv_len != 0) && - (bmc->mdn.bv_val != op->o_req_dn.bv_val) ) { - free( bmc->mdn.bv_val ); - } - - if (bmc->data.add_d.attrs != NULL ) { - while (bmc->data.add_d.attrs[i] != NULL) { - free( bmc->data.add_d.attrs[i]->mod_bvalues ); - free( bmc->data.add_d.attrs[i] ); - i++; - } - free( bmc->data.add_d.attrs ); - } - break; - case LDAP_REQ_MODIFY: - if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) { - free( bmc->mdn.bv_val ); - } - if ( bmc->data.mod_d.modv != NULL ) { - for ( i = 0; bmc->data.mod_d.modv[ i ]; i++ ) { - free( bmc->data.mod_d.modv[ i ]->mod_bvalues ); - } - } - free( bmc->data.mod_d.mods ); - free( bmc->data.mod_d.modv ); - - break; - case LDAP_REQ_MODRDN: - if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) { - free( bmc->mdn.bv_val ); - } - - if ( bmc->data.modrdn_d.newSuperior.bv_len != 0 && - bmc->data.modrdn_d.newSuperior.bv_val != op->orr_newSup->bv_val ) - { - free( bmc->data.modrdn_d.newSuperior.bv_val ); - - } - - if ( bmc->data.modrdn_d.newrdn.bv_len != 0 && - bmc->data.modrdn_d.newrdn.bv_val != op->orr_newrdn.bv_val ) - { - free( bmc->data.modrdn_d.newrdn.bv_val ); - - } - 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 + memctx = op->o_tmpmemctx; + thrctx = op->o_threadctx; + while (op->o_bd == bc->copy_op.o_bd) + ldap_pvt_thread_yield(); + asyncmeta_free_op(op); + asyncmeta_memctx_put(thrctx, memctx); } int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc) @@ -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", mc, mc->pending_ops, max_pending_ops ); + assert(bc->bc_mc == NULL); if (mc->pending_ops >= max_pending_ops) { return LDAP_BUSY; } + bc->bc_mc = mc; - LDAP_SLIST_INSERT_HEAD( &mc->mc_om_list, bc, bc_next); + slap_sl_mem_setctx(bc->op->o_threadctx, NULL); + LDAP_STAILQ_INSERT_TAIL( &mc->mc_om_list, bc, bc_next); mc->pending_ops++; return LDAP_SUCCESS; } + void asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc) { bm_context_t *om; - int i; - LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) { + LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) { if (om == bc) { - for (i = 0; i < mc->mc_info->mi_ntargets; i++) - { - if (bc->msgids[i] >= 0) { - mc->mc_conns[i].msc_pending_ops--; - } - } - LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next); + LDAP_STAILQ_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next); mc->pending_ops--; break; } } + assert(om == bc); + assert(bc->bc_mc == mc); } + bm_context_t * asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate) { bm_context_t *om; - LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) { - if (om->candidates[candidate].sr_msgid == msgid) { + LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) { + if (om->candidates[candidate].sr_msgid == msgid && !om->bc_invalid) { break; } } return om; } - - bm_context_t * -asyncmeta_find_message_by_opmsguid (ber_int_t msgid, a_metaconn_t *mc, int remove) +asyncmeta_bc_in_queue(a_metaconn_t *mc, bm_context_t *bc) { bm_context_t *om; - LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) { - if (om->op->o_msgid == msgid) { - break; + LDAP_STAILQ_FOREACH( om, &mc->mc_om_list, bc_next ) { + if (om == bc) { + return bc; } } - if (remove && om) { - LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next); - mc->pending_ops--; - } - return om; + return NULL; } diff --git a/servers/slapd/back-asyncmeta/meta_result.c b/servers/slapd/back-asyncmeta/meta_result.c index 47651344de..1fa733fa24 100644 --- a/servers/slapd/back-asyncmeta/meta_result.c +++ b/servers/slapd/back-asyncmeta/meta_result.c @@ -33,12 +33,22 @@ #include "ldap_rq.h" #include "../../../libraries/liblber/lber-int.h" +static void +asyncmeta_send_ldap_result(bm_context_t *bc, Operation *op, SlapReply *rs) +{ + if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !bc->op->o_abandon ) { + send_ldap_result(&bc->copy_op, rs); + bc->op->o_callback = bc->copy_op.o_callback; + bc->op->o_extra = bc->copy_op.o_extra; + bc->op->o_ctrls = bc->copy_op.o_ctrls; + } +} + static int asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate) { a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - int i,found = 0; + int i; SlapReply *candidates = bc->candidates; for ( i = 0; i < mi->mi_ntargets; i++ ) { if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { @@ -54,11 +64,9 @@ asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate) meta_search_candidate_t asyncmeta_dobind_result( - Operation *op, - SlapReply *rs, a_metaconn_t *mc, int candidate, - SlapReply *candidates, + SlapReply *bind_result, LDAPMessage *res ) { a_metainfo_t *mi = mc->mc_info; @@ -70,30 +78,53 @@ asyncmeta_dobind_result( assert( msc->msc_ldr != NULL ); + if ( mi->mi_idle_timeout != 0 ) { + asyncmeta_set_msc_time(msc); + } + + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%x] [%s] asyncmeta_dobind_result msc: %p, " + "msc->msc_binding_time: %x, msc->msc_flags:%x\n ", + (unsigned int)slap_get_time(), time_buf, msc, + (unsigned int)msc->msc_binding_time, msc->msc_mscflags ); + } /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( msc->msc_ldr, res, - &candidates[ candidate ].sr_err, - NULL, NULL, NULL, NULL, 0 ); - if ( rc != LDAP_SUCCESS ) { - candidates[ candidate ].sr_err = rc; + &(bind_result->sr_err), + (char **)&(bind_result->sr_matched), + (char **)&(bind_result->sr_text), + NULL, NULL, 0 ); + + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, + "[%s] asyncmeta_dobind_result error=%d msc: %p\n", + time_buf,bind_result->sr_err, msc ); } - rc = slap_map_api2result( &candidates[ candidate ] ); + + if ( rc != LDAP_SUCCESS ) { + bind_result->sr_err = rc; + } + rc = slap_map_api2result( bind_result ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( rc != LDAP_SUCCESS ) { - candidates[ candidate ].sr_err = rc; - if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) { - asyncmeta_clear_one_msc(op, mc, candidate); - retcode = META_SEARCH_ERR; - rs->sr_err = rc; - } - + bind_result->sr_err = rc; } else { /* FIXME: check if bound as idassert authcDN! */ if ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) ) { LDAP_BACK_CONN_ISANON_SET( msc ); + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result anonymous msc: %p\n", + time_buf, msc ); + } } else { if ( META_BACK_TGT_SAVECRED( mt ) && @@ -102,17 +133,16 @@ asyncmeta_dobind_result( { ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc ); } + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result success msc: %p\n", + time_buf, msc ); + } LDAP_BACK_CONN_ISBOUND_SET( msc ); } retcode = META_SEARCH_CANDIDATE; - - /* connect must be async */ - //ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF ); } - - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - META_BINDING_CLEAR( &candidates[ candidate ] ); - return retcode; } @@ -125,8 +155,7 @@ asyncmeta_send_entry( LDAPMessage *e ) { a_metainfo_t *mi = mc->mc_info; - struct berval a, mapped; - int check_duplicate_attrs = 0; + struct berval a, mapped = BER_BVNULL; int check_sorted_attrs = 0; Entry ent = {0}; BerElement ber = *ldap_get_message_ber( e ); @@ -137,6 +166,10 @@ asyncmeta_send_entry( a_dncookie dc; ber_len_t len; int rc; + void *mem_mark; + + mem_mark = slap_sl_mark( op->o_tmpmemctx ); + ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; @@ -153,15 +186,11 @@ asyncmeta_send_entry( /* * Rewrite the dn of the result, if needed */ + dc.op = op; dc.target = mi->mi_targets[ target ]; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "searchResult"; - - rs->sr_err = asyncmeta_dn_massage( &dc, &bdn, &dn ); - if ( rs->sr_err != LDAP_SUCCESS) { - return rs->sr_err; - } + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REP; + asyncmeta_dn_massage( &dc, &bdn, &dn ); /* * Note: this may fail if the target host(s) schema differs @@ -173,7 +202,7 @@ asyncmeta_send_entry( rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname, op->o_tmpmemctx ); if ( dn.bv_val != bdn.bv_val ) { - free( dn.bv_val ); + op->o_tmpfree( dn.bv_val, op->o_tmpmemctx ); } BER_BVZERO( &dn ); @@ -196,7 +225,6 @@ asyncmeta_send_entry( attrp = &ent.e_attrs; - dc.ctx = "searchAttrDN"; while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { int last = 0; slap_syntax_validate_func *validate; @@ -216,24 +244,12 @@ asyncmeta_send_entry( break; } - asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, - &a, &mapped, BACKLDAP_REMAP ); - if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) { - ( void )ber_scanf( &ber, "x" /* [W] */ ); - continue; - } - if ( mapped.bv_val != a.bv_val ) { - /* will need to check for duplicate attrs */ - check_duplicate_attrs++; - } attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx ); - if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) + if ( slap_bv2ad( &a, &attr->a_desc, &text ) != LDAP_SUCCESS) { - if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text, + if ( slap_bv2undef_ad( &a, &attr->a_desc, &text, SLAP_AD_PROXIED ) != LDAP_SUCCESS ) { - char buf[ SLAP_TEXT_BUFLEN ]; - Debug(LDAP_DEBUG_ANY, "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n", op->o_log_prefix, ent.e_name.bv_val, @@ -283,58 +299,11 @@ asyncmeta_send_entry( pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; if ( !validate && !pretty ) { - attr_clean( attr ); + ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); goto next_attr; } - if ( attr->a_desc == slap_schema.si_ad_objectClass - || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) - { - struct berval *bv; - - for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) { - ObjectClass *oc; - - asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc, - bv, &mapped, BACKLDAP_REMAP ); - if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') { -remove_oc:; - free( bv->bv_val ); - BER_BVZERO( bv ); - if ( --last < 0 ) { - break; - } - *bv = attr->a_vals[ last ]; - BER_BVZERO( &attr->a_vals[ last ] ); - bv--; - - } else if ( mapped.bv_val != bv->bv_val ) { - int i; - - for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) { - if ( &attr->a_vals[ i ] == bv ) { - continue; - } - - if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) { - break; - } - } - - if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) { - goto remove_oc; - } - - ber_bvreplace( bv, &mapped ); - - } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) { - goto remove_oc; - - } else { - ber_bvreplace( bv, &oc->soc_cname ); - } - } /* * It is necessary to try to rewrite attributes with * dn syntax because they might be used in ACLs as @@ -346,7 +315,7 @@ remove_oc:; * ACLs to the target directory server, and letting * everything pass thru the ldap backend. */ - } else { + { int i; if ( attr->a_desc->ad_type->sat_syntax == @@ -355,7 +324,7 @@ remove_oc:; asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals ); } else if ( attr->a_desc == slap_schema.si_ad_ref ) { - asyncmeta_referral_result_rewrite( &dc, attr->a_vals, NULL ); + asyncmeta_referral_result_rewrite( &dc, attr->a_vals ); } @@ -365,7 +334,7 @@ remove_oc:; if ( pretty ) { rc = ordered_value_pretty( attr->a_desc, - &attr->a_vals[i], &pval, NULL ); + &attr->a_vals[i], &pval, op->o_tmpmemctx ); } else { rc = ordered_value_validate( attr->a_desc, @@ -373,7 +342,7 @@ remove_oc:; } if ( rc ) { - ber_memfree( attr->a_vals[i].bv_val ); + ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[ i ] ); break; @@ -385,13 +354,13 @@ remove_oc:; } if ( pretty ) { - ber_memfree( attr->a_vals[i].bv_val ); + ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); attr->a_vals[i] = pval; } } if ( last == 0 && attr->a_vals != &slap_dummy_bv ) { - attr_clean( attr ); + ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); goto next_attr; } @@ -402,7 +371,7 @@ remove_oc:; { int i; - attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) ); + attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); for ( i = 0; ia_desc, attr->a_desc->ad_type->sat_equality, &attr->a_vals[i], &attr->a_nvals[i], - NULL )) { - ber_memfree( attr->a_vals[i].bv_val ); + op->o_tmpmemctx )) { + ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[ i ] ); break; @@ -423,7 +392,8 @@ remove_oc:; } BER_BVZERO( &attr->a_nvals[i] ); if ( last == 0 ) { - attr_clean( attr ); + ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); + ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); goto next_attr; } @@ -438,51 +408,6 @@ remove_oc:; next_attr:; } - /* only check if some mapping occurred */ - if ( check_duplicate_attrs ) { - Attribute **ap; - - for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) { - Attribute **tap; - - for ( tap = &(*ap)->a_next; *tap != NULL; ) { - if ( (*tap)->a_desc == (*ap)->a_desc ) { - Entry e = { 0 }; - Modification mod = { 0 }; - const char *text = NULL; - char textbuf[ SLAP_TEXT_BUFLEN ]; - Attribute *next = (*tap)->a_next; - - BER_BVSTR( &e.e_name, "" ); - BER_BVSTR( &e.e_nname, "" ); - e.e_attrs = *ap; - mod.sm_op = LDAP_MOD_ADD; - mod.sm_desc = (*ap)->a_desc; - mod.sm_type = mod.sm_desc->ad_cname; - mod.sm_numvals = (*ap)->a_numvals; - mod.sm_values = (*tap)->a_vals; - if ( (*tap)->a_nvals != (*tap)->a_vals ) { - mod.sm_nvalues = (*tap)->a_nvals; - } - - (void)modify_add_values( &e, &mod, - /* permissive */ 1, - &text, textbuf, sizeof( textbuf ) ); - - /* should not insert new attrs! */ - assert( e.e_attrs == *ap ); - - attr_clean( *tap ); - op->o_tmpfree( *tap, op->o_tmpmemctx ); - *tap = next; - - } else { - tap = &(*tap)->a_next; - } - } - } - } - /* Check for sorted attributes */ if ( check_sorted_attrs ) { for ( attr = ent.e_attrs; attr; attr = attr->a_next ) { @@ -495,8 +420,8 @@ next_attr:; /* Strip duplicate values */ if ( attr->a_nvals != attr->a_vals ) - ber_memfree( attr->a_nvals[i].bv_val ); - ber_memfree( attr->a_vals[i].bv_val ); + ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx ); + ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); attr->a_numvals--; if ( (unsigned)i < attr->a_numvals ) { attr->a_vals[i] = attr->a_vals[attr->a_numvals]; @@ -534,28 +459,39 @@ done:; ldap_controls_free( rs->sr_ctrls ); rs->sr_ctrls = NULL; } +#if 0 while ( ent.e_attrs ) { attr = ent.e_attrs; ent.e_attrs = attr->a_next; - attr_clean( attr ); + if ( attr->a_nvals != attr->a_vals ) + ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); + ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); } + if (ent.e_name.bv_val != NULL) { + op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx ); + } + + if (ent.e_nname.bv_val != NULL) { + op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx ); + } if (rs->sr_entry && rs->sr_entry != &ent) { entry_free( rs->sr_entry ); } +#endif + slap_sl_release( mem_mark, op->o_tmpmemctx ); rs->sr_entry = NULL; rs->sr_attrs = NULL; return rc; } -int +static void asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, int sres) { a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; Operation *op = bc->op; SlapReply *rs = &bc->rs; - int rc, i; + int i; SlapReply *candidates = bc->candidates; char *matched = NULL; @@ -614,7 +550,7 @@ asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, } } else if ( sres == LDAP_NO_SUCH_OBJECT ) { - matched = op->o_bd->be_suffix[ 0 ].bv_val; + matched = mi->mi_suffix.bv_val; } /* @@ -649,181 +585,147 @@ asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, } } Debug( LDAP_DEBUG_TRACE, - "%s asyncmeta_search_last_result(\"%s\"): " + "%s asyncmeta_search_last_result(\"%d\"): " ".\n", - op->o_log_prefix, 0 ); + op->o_log_prefix, candidate ); rs->sr_err = sres; rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched ); + rs->sr_text = ( sres == LDAP_SUCCESS ? NULL : candidates[candidate].sr_text ); rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL ); - send_ldap_result(op, rs); + asyncmeta_send_ldap_result(bc, op, rs); + rs->sr_text = NULL; rs->sr_matched = NULL; rs->sr_ref = NULL; } - -int -asyncmeta_search_finish(a_metaconn_t *mc, bm_context_t *bc, int candidate, char *matched) -{ - a_metainfo_t *mi = mc->mc_info; - a_metatarget_t *mt = mi->mi_targets[ candidate ]; - Operation *op = bc->op; - SlapReply *rs = &bc->rs; - SlapReply *candidates = bc->candidates; - int i; - int do_taint = 0; - if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) { - op->o_tmpfree( matched, op->o_tmpmemctx ); - } - - if ( rs->sr_v2ref ) { - ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx ); - } - - for ( i = 0; i < mi->mi_ntargets; i++ ) { - if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { - continue; - } - - if ( META_IS_BINDING( &candidates[ i ] ) - || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) - { - if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) - || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) - { - assert( candidates[ i ].sr_msgid >= 0 - || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ); - assert( mc->mc_conns[ i ].msc_ldr != NULL ); - -#ifdef DEBUG_205 - Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_finish " - "ldap_unbind_ext[%ld] ld=%p\n", - op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ldr ); -#endif /* DEBUG_205 */ - - } - META_BINDING_CLEAR( &candidates[ i ] ); - - } else if ( candidates[ i ].sr_msgid >= 0 ) { - (void)asyncmeta_back_cancel( mc, op, - candidates[ i ].sr_msgid, i ); - } - - if ( candidates[ i ].sr_matched ) { - free( (char *)candidates[ i ].sr_matched ); - candidates[ i ].sr_matched = NULL; - } - - if ( candidates[ i ].sr_text ) { - ldap_memfree( (char *)candidates[ i ].sr_text ); - candidates[ i ].sr_text = NULL; - } - - if ( candidates[ i ].sr_ref ) { - ber_bvarray_free( candidates[ i ].sr_ref ); - candidates[ i ].sr_ref = NULL; - } - - if ( candidates[ i ].sr_ctrls ) { - ldap_controls_free( candidates[ i ].sr_ctrls ); - candidates[ i ].sr_ctrls = NULL; - } - - if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) { - asyncmeta_quarantine( op, mi, &candidates[ i ], i ); - } - /* this remains as it is only for explicitly bound connections, for the time being */ - /* only in case of timelimit exceeded, if the timelimit exceeded because - * one contacted target never responded, invalidate the connection - * NOTE: should we quarantine the target as well? right now, the connection - * is invalidated; the next time it will be recreated and the target - * will be quarantined if it cannot be contacted */ - if ( mi->mi_idle_timeout != 0 - && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED - && op->o_time > mc->mc_conns[ i ].msc_time ) - { - /* don't let anyone else use this expired connection */ - do_taint++; - } - } - - if ( mc && do_taint) { - LDAP_BACK_CONN_TAINTED_SET( mc ); - } - - return rs->sr_err; -} - - -int -asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate) +static meta_search_candidate_t +asyncmeta_send_pending_op(bm_context_t *bc, int candidate) { meta_search_candidate_t retcode; - a_metainfo_t *mi; - a_metatarget_t *mt; - Operation *op; - SlapReply *rs; - int rc; - SlapReply *candidates; - - mi = mc->mc_info; - mt = mi->mi_targets[ candidate ]; - op = bc->op; - rs = &bc->rs; - candidates = bc->candidates; - Debug( LDAP_DEBUG_TRACE, - "%s asyncmeta_handle_bind_result[%d]\n", - op->o_log_prefix, candidate ); - retcode = asyncmeta_dobind_result( op, rs, mc, candidate, candidates, msg ); - if ( retcode == META_SEARCH_CANDIDATE ) { - switch (op->o_tag) { + switch (bc->op->o_tag) { case LDAP_REQ_SEARCH: - retcode = asyncmeta_back_search_start( op, rs, mc, bc, candidate, NULL, 0 ); + retcode = asyncmeta_back_search_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, NULL, 0 , 0); break; case LDAP_REQ_ADD: - retcode = asyncmeta_back_add_start( op, rs, mc, bc, candidate); + retcode = asyncmeta_back_add_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); break; case LDAP_REQ_MODIFY: - retcode = asyncmeta_back_modify_start( op, rs, mc, bc, candidate); + retcode = asyncmeta_back_modify_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); break; case LDAP_REQ_MODRDN: - retcode = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate); + retcode = asyncmeta_back_modrdn_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); break; case LDAP_REQ_COMPARE: - retcode = asyncmeta_back_compare_start( op, rs, mc, bc, candidate); + retcode = asyncmeta_back_compare_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); break; case LDAP_REQ_DELETE: - retcode = asyncmeta_back_delete_start( op, rs, mc, bc, candidate); + retcode = asyncmeta_back_delete_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); break; default: retcode = META_SEARCH_NOT_CANDIDATE; } + return retcode; +} + + +meta_search_candidate_t +asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock) +{ + a_metainfo_t *mi = mc->mc_info; + bm_context_t *bc, *onext; + a_metasingleconn_t *msc = &mc->mc_conns[candidate]; + + if ( dolock ) + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + + msc->msc_active++; + for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { + meta_search_candidate_t ret; + onext = LDAP_STAILQ_NEXT(bc, bc_next); + if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) { + continue; + } + bc->op->o_threadctx = ctx; + bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); + bc->bc_active++; + ret = asyncmeta_send_pending_op(bc, candidate); + if (ret != META_SEARCH_CANDIDATE) { + bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + bc->candidates[ candidate ].sr_type = REP_RESULT; + bc->candidates[ candidate ].sr_err = bc->rs.sr_err; + if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) || + (asyncmeta_is_last_result(mc, bc, candidate) == 0)) { + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + mc->pending_ops--; + asyncmeta_send_ldap_result(bc, bc->op, &bc->rs); + asyncmeta_clear_bm_context(bc); + } + } else { + bc->bc_active--; + } + } + msc->msc_active--; + + if ( dolock ) + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + + return META_SEARCH_CANDIDATE; +} + +meta_search_candidate_t +asyncmeta_return_bind_errors(a_metaconn_t *mc, int candidate, SlapReply *bind_result, void *ctx, int dolock) +{ + a_metainfo_t *mi = mc->mc_info; + bm_context_t *bc, *onext; + + if ( dolock ) + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + + for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { + onext = LDAP_STAILQ_NEXT(bc, bc_next); + if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND + || bc->bc_active > 0 || bc->op->o_abandon > 0) { + continue; + } + bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + bc->candidates[ candidate ].sr_type = REP_RESULT; + bc->candidates[ candidate ].sr_err = bind_result->sr_err; + if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) || + (asyncmeta_is_last_result(mc, bc, candidate) == 0)) { + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + bc->op->o_threadctx = ctx; + bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); + bc->rs.sr_err = bind_result->sr_err; + bc->rs.sr_text = bind_result->sr_text; + mc->pending_ops--; + asyncmeta_send_ldap_result(bc, bc->op, &bc->rs); + asyncmeta_clear_bm_context(bc); + } } - switch ( retcode ) { - case META_SEARCH_CANDIDATE: - break; - /* means that failed but onerr == continue */ - case META_SEARCH_NOT_CANDIDATE: - case META_SEARCH_ERR: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - candidates[ candidate ].sr_err = rs->sr_err; - if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) { - send_ldap_result(op, rs); - } - if (op->o_tag != LDAP_REQ_SEARCH) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - asyncmeta_drop_bc( mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); - asyncmeta_clear_bm_context(bc); - return retcode; - } - break; - default: - assert( 0 ); - break; + if ( dolock ) + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + + return META_SEARCH_CANDIDATE; +} + +static meta_search_candidate_t +asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, int candidate, void *ctx) +{ + meta_search_candidate_t retcode; + SlapReply bind_result = {0}; + /* could modify the msc, safer to lock it */ + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + retcode = asyncmeta_dobind_result( mc, candidate, &bind_result, msg ); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + if ( retcode == META_SEARCH_CANDIDATE ) { + /* send the remaining pending ops */ + asyncmeta_send_all_pending_ops(mc, candidate, ctx, 1); + } else { + asyncmeta_return_bind_errors(mc, candidate, &bind_result, ctx, 1); } - bc->bc_active = 0; return retcode; } @@ -833,9 +735,9 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc a_metainfo_t *mi; a_metatarget_t *mt; a_metasingleconn_t *msc; - Operation op; + Operation *op = bc->op; SlapReply *rs; - int i, j, rc, sres; + int i, rc = LDAP_SUCCESS, sres; SlapReply *candidates; char **references = NULL; LDAPControl **ctrls = NULL; @@ -843,48 +745,55 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc LDAPMessage *msg; ber_int_t id; - op = *bc->op; rs = &bc->rs; mi = mc->mc_info; mt = mi->mi_targets[ candidate ]; msc = &mc->mc_conns[ candidate ]; + dc.op = op; dc.target = mt; - dc.conn = op.o_conn; - dc.rs = rs; + dc.to_from = MASSAGE_REP; id = ldap_msgid(res); + candidates = bc->candidates; i = candidate; - while (res) { + while (res && !META_BACK_CONN_INVALID(msc)) { for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) { switch(ldap_msgtype(msg)) { case LDAP_RES_SEARCH_ENTRY: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_handle_search_msg: msc %p entry\n", - op.o_log_prefix, msc ); + op->o_log_prefix, msc ); if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { /* don't retry any more... */ candidates[ i ].sr_type = REP_RESULT; } /* count entries returned by target */ candidates[ i ].sr_nentries++; - rs->sr_err = asyncmeta_send_entry( &op, rs, mc, i, msg ); + if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) { + rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg ); + } else { + goto err_cleanup; + } switch ( rs->sr_err ) { case LDAP_SIZELIMIT_EXCEEDED: - send_ldap_result(&op, rs); + asyncmeta_send_ldap_result(bc, op, rs); rs->sr_err = LDAP_SUCCESS; goto err_cleanup; case LDAP_UNAVAILABLE: rs->sr_err = LDAP_OTHER; + break; + default: + break; } bc->is_ok++; break; case LDAP_RES_SEARCH_REFERENCE: - if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) { + if ( META_BACK_TGT_NOREFS( mt ) ) { rs->sr_err = LDAP_OTHER; - send_ldap_result(&op, rs); + asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { @@ -897,7 +806,7 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc if ( rc != LDAP_SUCCESS || references == NULL ) { rs->sr_err = LDAP_OTHER; - send_ldap_result(&op, rs); + asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } @@ -909,28 +818,27 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc ; rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ), - op.o_tmpmemctx ); + op->o_tmpmemctx ); for ( cnt = 0; references[ cnt ]; cnt++ ) { ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ], - op.o_tmpmemctx ); + op->o_tmpmemctx ); } BER_BVZERO( &rs->sr_ref[ cnt ] ); } { - dc.ctx = "referralDN"; - ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref, - op.o_tmpmemctx ); + dc.memctx = op->o_tmpmemctx; + ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref ); } if ( rs->sr_ref != NULL ) { if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) { /* ignore return value by now */ - ( void )send_search_reference( &op, rs ); + ( void )send_search_reference( op, rs ); } - ber_bvarray_free_x( rs->sr_ref, op.o_tmpmemctx ); + ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } @@ -963,11 +871,11 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc if ( rs->sr_err != LDAP_SUCCESS ) { candidates[ i ].sr_type = REP_RESULT; rs->sr_err = LDAP_OTHER; - send_ldap_result(&op, rs); + asyncmeta_send_ldap_result(bc, op, rs); goto err_cleanup; } - slap_send_ldap_intermediate( &op, rs ); + slap_send_ldap_intermediate( op, rs ); if ( rs->sr_rspoid != NULL ) { ber_memfree( (char *)rs->sr_rspoid ); @@ -986,9 +894,12 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc break; case LDAP_RES_SEARCH_RESULT: + if ( mi->mi_idle_timeout != 0 ) { + asyncmeta_set_msc_time(msc); + } Debug( LDAP_DEBUG_TRACE, - "%s asyncmeta_handle_search_msg: msc %p result\n", - op.o_log_prefix, msc ); + "%s asyncmeta_handle_search_msg: msc %p result\n", + op->o_log_prefix, msc ); candidates[ i ].sr_type = REP_RESULT; candidates[ i ].sr_msgid = META_MSGID_IGNORE; /* NOTE: ignores response controls @@ -1025,19 +936,17 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc 0, 0, &match ); candidates[ i ].sr_matched = NULL; - dc.ctx = "matchedDN"; - dc.target = mi->mi_targets[ i ]; - if ( !asyncmeta_dn_massage( &dc, &match, &mmatch ) ) { - if ( mmatch.bv_val == match.bv_val ) { - candidates[ i ].sr_matched - = ch_strdup( mmatch.bv_val ); + dc.memctx = NULL; + asyncmeta_dn_massage( &dc, &match, &mmatch ); + if ( mmatch.bv_val == match.bv_val ) { + candidates[ i ].sr_matched + = ch_strdup( mmatch.bv_val ); - } else { - candidates[ i ].sr_matched = mmatch.bv_val; - } - - bc->candidate_match++; + } else { + candidates[ i ].sr_matched = mmatch.bv_val; } + + bc->candidate_match++; ldap_memfree( match.bv_val ); } @@ -1052,7 +961,7 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc Debug( LDAP_DEBUG_ANY, "%s asncmeta_search_result[%d]: " "got referrals with err=%d\n", - op.o_log_prefix, + op->o_log_prefix, i, rs->sr_err ); } else { @@ -1063,16 +972,16 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc ; sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ), - op.o_tmpmemctx ); + op->o_tmpmemctx ); for ( cnt = 0; references[ cnt ]; cnt++ ) { ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ], - op.o_tmpmemctx ); + op->o_tmpmemctx ); } BER_BVZERO( &sr_ref[ cnt ] ); - ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref, - op.o_tmpmemctx ); + dc.memctx = op->o_tmpmemctx; + ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref ); if ( rs->sr_v2ref == NULL ) { rs->sr_v2ref = sr_ref; @@ -1080,18 +989,18 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc } else { for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) { ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ], - op.o_tmpmemctx ); + op->o_tmpmemctx ); } - ber_memfree_x( sr_ref, op.o_tmpmemctx ); + ber_memfree_x( sr_ref, op->o_tmpmemctx ); } } } else if ( rs->sr_err == LDAP_REFERRAL ) { - Debug( LDAP_DEBUG_ANY, + Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d]: " "got err=%d with null " "or empty referrals\n", - op.o_log_prefix, + op->o_log_prefix, i, rs->sr_err ); rs->sr_err = LDAP_NO_SUCH_OBJECT; @@ -1102,21 +1011,18 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc sres = slap_map_api2result( rs ); - if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) { - char buf[ SLAP_TEXT_BUFLEN ]; - snprintf( buf, sizeof( buf ), - "%s asyncmeta_search_result[%ld] " - "match=\"%s\" err=%d", - op.o_log_prefix, i, - candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", - (long) candidates[ i ].sr_err ); - if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "%s.\n", buf ); - - } else { - Debug( LDAP_DEBUG_ANY, "%s (%s).\n", - buf, ldap_err2string( candidates[ i ].sr_err ) ); - } + if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] " + "match=\"%s\" err=%ld", + op->o_log_prefix, i, + candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", + (long) candidates[ i ].sr_err ); + } else { + Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_result[%d] " + "match=\"%s\" err=%ld (%s)", + op->o_log_prefix, i, + candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", + (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) ); } switch ( sres ) { @@ -1146,7 +1052,7 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc struct berval prcookie; /* unsolicited, do not accept */ - if ( mi->mi_targets[i]->mt_ps == 0 ) { + if ( mt->mt_ps == 0 ) { rs->sr_err = LDAP_OTHER; goto err_pr; } @@ -1161,7 +1067,7 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc /* more pages? new search request */ if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) { - if ( mi->mi_targets[i]->mt_ps > 0 ) { + if ( mt->mt_ps > 0 ) { /* ignore size if specified */ prsize = 0; @@ -1178,7 +1084,7 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc assert( candidates[ i ].sr_text == NULL ); assert( candidates[ i ].sr_ref == NULL ); - switch ( asyncmeta_back_search_start( &op, rs, mc, bc, i, &prcookie, prsize ) ) + switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) ) { case META_SEARCH_CANDIDATE: assert( candidates[ i ].sr_msgid >= 0 ); @@ -1186,11 +1092,12 @@ asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc // goto free_message; case META_SEARCH_ERR: + case META_SEARCH_NEED_BIND: err_pr:; candidates[ i ].sr_err = rs->sr_err; candidates[ i ].sr_type = REP_RESULT; if ( META_BACK_ONERR_STOP( mi ) ) { - send_ldap_result(&op, rs); + asyncmeta_send_ldap_result(bc, op, rs); ldap_controls_free( ctrls ); goto err_cleanup; } @@ -1231,16 +1138,18 @@ err_pr:; * than what requested by the proxy; * ignore it */ candidates[ i ].sr_err = rs->sr_err; - if ( rs->sr_nentries == op.ors_slimit + if ( rs->sr_nentries == op->ors_slimit || META_BACK_ONERR_STOP( mi ) ) { const char *save_text; got_err: save_text = rs->sr_text; rs->sr_text = candidates[ i ].sr_text; - send_ldap_result(&op, rs); - ch_free( candidates[ i ].sr_text ); - candidates[ i ].sr_text = NULL; + asyncmeta_send_ldap_result(bc, op, rs); + if (candidates[ i ].sr_text != NULL) { + ch_free( (char *)candidates[ i ].sr_text ); + candidates[ i ].sr_text = NULL; + } rs->sr_text = save_text; ldap_controls_free( ctrls ); goto err_cleanup; @@ -1259,14 +1168,14 @@ got_err: if (asyncmeta_is_last_result(mc, bc, i) == 0) { Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_handle_search_msg: msc %p last result\n", - op.o_log_prefix, msc ); + op->o_log_prefix, msc ); asyncmeta_search_last_result(mc, bc, i, sres); err_cleanup: rc = rs->sr_err; ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); asyncmeta_drop_bc( mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); asyncmeta_clear_bm_context(bc); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); ldap_msgfree(res); return rc; } @@ -1282,9 +1191,14 @@ finish: if (candidates[ i ].sr_type != REP_RESULT) { struct timeval tv = {0}; rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res ); + if (res != NULL) { + msc->msc_result_time = slap_get_time(); + } } } - bc->bc_active = 0; + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + bc->bc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; } @@ -1326,8 +1240,8 @@ int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_contex rs->sr_ctrls = NULL; /* only touch when activity actually took place... */ - if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { - msc->msc_time = op->o_time; + if ( mi->mi_idle_timeout != 0 ) { + asyncmeta_set_msc_time(msc); } rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err, @@ -1413,20 +1327,20 @@ int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_contex rs->sr_matched = matched; } - if ( rs->sr_err == LDAP_UNAVAILABLE ) { - if ( !( bc->sendok & LDAP_BACK_RETRYING ) ) { - if ( op->o_conn && ( bc->sendok & LDAP_BACK_SENDERR ) ) { - if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; - send_ldap_result( op, rs ); + if ( rs->sr_err == LDAP_UNAVAILABLE || rs->sr_err == LDAP_SERVER_DOWN ) { + if ( rs->sr_text == NULL ) { + rs->sr_text = "Target is unavailable"; } - } - - } else if ( op->o_conn && - ( ( ( bc->sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) - || ( ( bc->sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) - { - send_ldap_result( op, rs ); } + + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + asyncmeta_drop_bc( mc, bc); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + + if ( op->o_conn ) { + asyncmeta_send_ldap_result(bc, op, rs); + } + if ( matched ) { op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); } @@ -1451,52 +1365,60 @@ int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_contex rs->sr_ctrls = save_ctrls; rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - asyncmeta_drop_bc( mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); asyncmeta_clear_bm_context(bc); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; } /* This takes care to clean out the outbound queue in case we have a read error * sending back responses to the client */ int -asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error) +asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx) { bm_context_t *bc, *onext; - int rc, cleanup; + int cleanup; Operation *op; SlapReply *rs; SlapReply *candidates; /* no outstanding ops, nothing to do but log */ - Debug( LDAP_DEBUG_ANY, - "asyncmeta_op_read_error: %x\n", - error ); -#if 0 - if (mc->mc_conns[candidate].conn) { - Connection *conn = mc->mc_conns[candidate].conn; - mc->mc_conns[candidate].conn = NULL; - connection_client_stop(conn); - } -#endif + Debug( LDAP_DEBUG_TRACE, + "asyncmeta_op_read_error: ldr=%p\n", + mc->mc_conns[candidate].msc_ldr ); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - asyncmeta_clear_one_msc(NULL, mc, candidate); + /*someone may be trying to write */ + if (mc->mc_conns[candidate].msc_active <= 1) { + asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__); + } else { + META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]); + } + if (mc->pending_ops <= 0) { ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return LDAP_SUCCESS; } - for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) { - onext = LDAP_SLIST_NEXT(bc, bc_next); + for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { + onext = LDAP_STAILQ_NEXT(bc, bc_next); cleanup = 0; candidates = bc->candidates; /* was this op affected? */ if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) ) continue; - if (bc->op->o_abandon == 1) { + if (bc->op->o_abandon) { + bc->bc_invalid = 1; continue; } + if (bc->bc_active > 0) { + continue; + } + + bc->op->o_threadctx = ctx; + bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); + op = bc->op; rs = &bc->rs; switch (op->o_tag) { @@ -1506,18 +1428,20 @@ asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error) case LDAP_REQ_COMPARE: case LDAP_REQ_DELETE: rs->sr_err = LDAP_UNAVAILABLE; - send_ldap_error( op, rs, rs->sr_err , "Read error on connection to target" ); + rs->sr_text = "Read error on connection to target"; + asyncmeta_send_ldap_result( bc, op, rs ); cleanup = 1; break; case LDAP_REQ_SEARCH: { a_metainfo_t *mi = mc->mc_info; rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Read error on connection to target"; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; candidates[ candidate ].sr_type = REP_RESULT; - if ( META_BACK_ONERR_STOP( mi ) || - asyncmeta_is_last_result(mc, bc, candidate) && op->o_conn) { - send_ldap_error(op, rs, rs->sr_err, "Read error on connection to target"); + if ( (META_BACK_ONERR_STOP( mi ) || + asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) { + asyncmeta_send_ldap_result( bc, op, rs ); cleanup = 1; } } @@ -1532,12 +1456,12 @@ asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error) for (j=0; jmi_ntargets; j++) { if (j != candidate && bc->candidates[j].sr_msgid >= 0 && mc->mc_conns[j].msc_ld != NULL) { - asyncmeta_back_abandon_candidate( mc, op, - bc->candidates[ j ].sr_msgid, j ); + asyncmeta_back_cancel( mc, op, + bc->candidates[ j ].sr_msgid, j ); } } - asyncmeta_drop_bc( mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + mc->pending_ops--; asyncmeta_clear_bm_context(bc); } } @@ -1549,7 +1473,7 @@ void * asyncmeta_op_handle_result(void *ctx, void *arg) { a_metaconn_t *mc = arg; - int i, j, rc, ntargets, processed; + int i, j, rc, ntargets; struct timeval tv = {0}; LDAPMessage *msg; a_metasingleconn_t *msc; @@ -1567,30 +1491,71 @@ asyncmeta_op_handle_result(void *ctx, void *arg) oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); /* get existing memctx */ again: - processed = 0; for (j=0; j= ntargets) i = 0; - if (!mc->mc_conns[i].msc_ldr || mc->mc_conns[i].msc_pending_ops <= 0) continue; - rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg ); msc = &mc->mc_conns[i]; - if (rc < 1) { - if (rc < 0) { - asyncmeta_op_read_error(mc, i, rc); - } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + if (!mc->mc_conns[i].msc_ldr || + META_BACK_CONN_CREATING( &mc->mc_conns[i] ) || + META_BACK_CONN_INVALID(&mc->mc_conns[i])) { + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); continue; } - Debug(LDAP_DEBUG_TRACE, "asyncmeta_op_handle_result: got msgid %d on msc %p\n", - ldap_msgid(msg), msc ); + + msc->msc_active++; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + + rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg ); + if (rc < 1) { + if (rc < 0) { + ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc); + asyncmeta_op_read_error(mc, i, rc, ctx); + } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + msc->msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + continue; + } + rc = ldap_msgtype( msg ); + if (rc == LDAP_RES_BIND) { + if ( LogTest( asyncmeta_debug ) ) { + char time_buf[ SLAP_TEXT_BUFLEN ]; + asyncmeta_get_timestamp(time_buf); + Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n", + time_buf, ldap_msgid(msg), msc ); + } + asyncmeta_handle_bind_result(msg, mc, i, ctx); + mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); + msc->msc_result_time = slap_get_time(); + msc->msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + if (msg) + ldap_msgfree(msg); + + continue; + } +retry_bc: ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); bc = asyncmeta_find_message(ldap_msgid(msg), mc, i); +/* The sender might not be yet done with the context. On error it might also remove it + * so it's best to try and find it again after a wait */ + if (bc && bc->bc_active > 0) { + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + ldap_pvt_thread_yield(); + goto retry_bc; + } + if (bc) { + bc->bc_active++; + } - if (bc) - bc->bc_active = 1; + msc->msc_result_time = slap_get_time(); + msc->msc_active--; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); if (!bc) { - Debug( LDAP_DEBUG_ANY, - "asyncmeta_op_handle_result: Unable to find bc for msguid %d\n", ldap_msgid(msg) ); + Debug( asyncmeta_debug, + "asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc ); ldap_msgfree(msg); continue; } @@ -1599,38 +1564,34 @@ again: bc->op->o_threadctx = ctx; bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); - if (bc->op->o_abandon == 1) { + if (bc->op->o_abandon) { ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); asyncmeta_drop_bc( mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + if ( bc->op->o_tag == LDAP_REQ_SEARCH ) { + int j; + for (j=0; jcandidates[j].sr_msgid >= 0) { + a_metasingleconn_t *tmp_msc = &mc->mc_conns[j]; + tmp_msc->msc_active++; + asyncmeta_back_cancel( mc, bc->op, + bc->candidates[ j ].sr_msgid, j ); + tmp_msc->msc_active--; + } + } + } asyncmeta_clear_bm_context(bc); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); if (msg) ldap_msgfree(msg); continue; } - rc = ldap_msgtype( msg ); switch (rc) { - case LDAP_RES_BIND: - asyncmeta_handle_bind_result(msg, mc, bc, i); - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - LDAP_SLIST_FOREACH( bc, &mc->mc_om_list, bc_next ) { - if (bc->candidates[i].sr_msgid == META_MSGID_NEED_BIND) { - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); - asyncmeta_handle_bind_result(msg, mc, bc, i); - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - } - } - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); - msc->msc_timeout_ops = 0; - mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; - break; case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_SEARCH_RESULT: case LDAP_RES_INTERMEDIATE: asyncmeta_handle_search_msg(msg, mc, bc, i); - msc->msc_timeout_ops = 0; mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; msg = NULL; break; @@ -1640,14 +1601,16 @@ again: case LDAP_RES_COMPARE: case LDAP_RES_MODIFY: rc = asyncmeta_handle_common_result(msg, mc, bc, i); - msc->msc_timeout_ops = 0; mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; break; default: - Debug( LDAP_DEBUG_ANY, - "asyncmeta_op_handle_result: " - "unrecognized response message tag=%d\n", - rc ); + { + Debug( asyncmeta_debug, + "asyncmeta_op_handle_result: " + "unrecognized response message tag=%d\n", + rc ); + + } } if (msg) ldap_msgfree(msg); @@ -1662,9 +1625,11 @@ again: } slap_sl_mem_setctx(ctx, oldctx); if (mc->mc_conns) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); for (i=0; imc_conns[i].msc_ldr && mc->mc_conns[i].conn) connection_client_enable(mc->mc_conns[i].conn); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); } return NULL; } @@ -1678,42 +1643,114 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg) { struct re_s* rtask = arg; a_metainfo_t *mi = rtask->arg; - a_metaconn_t *mc; bm_context_t *bc, *onext; time_t current_time = slap_get_time(); int i, j; + LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list; + LDAP_STAILQ_INIT( &timeout_list ); + Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time ); + void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); for (i=0; imi_num_conns; i++) { - mc = &mi->mi_conns[i]; + a_metaconn_t * mc= &mi->mi_conns[i]; ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); - for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) { - onext = LDAP_SLIST_NEXT(bc, bc_next); - if (!bc->bc_active && bc->timeout && bc->stoptime <= current_time) { - Operation *op = bc->op; - SlapReply *rs = &bc->rs; - int timeout_err; - const char *timeout_text; - LDAP_SLIST_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); - mc->pending_ops--; + for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { + onext = LDAP_STAILQ_NEXT(bc, bc_next); + if (bc->bc_active > 0) { + continue; + } - if (bc->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"; - } + if (bc->op->o_abandon ) { + /* set our memctx */ + bc->op->o_threadctx = ctx; + bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); + Operation *op = bc->op; + + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + mc->pending_ops--; for (j=0; jmi_ntargets; j++) { if (bc->candidates[j].sr_msgid >= 0) { a_metasingleconn_t *msc = &mc->mc_conns[j]; - a_metatarget_t *mt = mi->mi_targets[j]; - msc->msc_timeout_ops++; - if (bc->msgids[j] >= 0) { - msc->msc_pending_ops--; + if ( op->o_tag == LDAP_REQ_SEARCH ) { + msc->msc_active++; + asyncmeta_back_cancel( mc, op, + bc->candidates[ j ].sr_msgid, j ); + msc->msc_active--; } - asyncmeta_back_cancel( mc, op, - bc->candidates[ j ].sr_msgid, j ); + } + } + asyncmeta_clear_bm_context(bc); + continue; + } + if (bc->bc_invalid) { + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + mc->pending_ops--; + LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); + continue; + } + + if (bc->timeout && bc->stoptime < current_time) { + Operation *op = bc->op; + LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); + mc->pending_ops--; + LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); + for (j=0; jmi_ntargets; j++) { + if (bc->candidates[j].sr_msgid >= 0) { + a_metasingleconn_t *msc = &mc->mc_conns[j]; + asyncmeta_set_msc_time(msc); + if ( op->o_tag == LDAP_REQ_SEARCH ) { + msc->msc_active++; + asyncmeta_back_cancel( mc, op, + bc->candidates[ j ].sr_msgid, j ); + msc->msc_active--; + } + } + } + } + } + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); + + for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) { + Operation *op = bc->op; + SlapReply *rs = &bc->rs; + int timeout_err; + const char *timeout_text; + + onext = LDAP_STAILQ_NEXT(bc, bc_next); + LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next); + /* set our memctx */ + bc->op->o_threadctx = ctx; + bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); + slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); + + if (bc->searchtime) { + timeout_err = LDAP_TIMELIMIT_EXCEEDED; + } else { + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + } + + if ( bc->bc_invalid ) { + timeout_text = "Operation is invalid - target connection has been reset"; + } else { + a_metasingleconn_t *log_msc = &mc->mc_conns[0]; + Debug( asyncmeta_debug, + "asyncmeta_timeout_loop:Timeout op %s loop[%p], " + "current_time:%ld, op->o_time:%ld msc: %p, " + "msc->msc_binding_time: %x, msc->msc_flags:%x \n", + bc->op->o_log_prefix, rtask, current_time, bc->op->o_time, + log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags ); + + if (bc->searchtime) { + timeout_text = NULL; + } else { + timeout_text = "Operation timed out"; + } + + for (j=0; jmi_ntargets; j++) { + if (bc->candidates[j].sr_msgid >= 0) { + a_metatarget_t *mt = mi->mi_targets[j]; if (!META_BACK_TGT_QUARANTINE( mt ) || bc->candidates[j].sr_type == REP_RESULT) { continue; @@ -1733,25 +1770,37 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg) } } } - send_ldap_error( op, rs, timeout_err, timeout_text ); - asyncmeta_clear_bm_context(bc); } + rs->sr_err = timeout_err; + rs->sr_text = timeout_text; + if (!bc->op->o_abandon ) { + asyncmeta_send_ldap_result( bc, bc->op, &bc->rs ); + } + asyncmeta_clear_bm_context(bc); } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); if (mi->mi_idle_timeout) { for (j=0; jmi_ntargets; j++) { a_metasingleconn_t *msc = &mc->mc_conns[j]; - if (msc->msc_pending_ops > 0) { + if ( msc->msc_active > 0 ) { continue; } - if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout <= current_time) { - asyncmeta_clear_one_msc(NULL, mc, j); + if (mc->pending_ops > 0) { + continue; + } + current_time = slap_get_time(); + if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) { + asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); } } } ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); } + slap_sl_mem_setctx(ctx, oldctx); + current_time = slap_get_time(); + Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time ); ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); @@ -1763,15 +1812,3 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg) return NULL; } -#if 0 -int -asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bc ) -{ - if (bc->ctrls != NULL && bc->cl != NULL && bc->cl->mc != NULL) { - a_metainfo_t *mi = bc->cl->mc->mc_info; - (void)mi->mi_ldap_extra->controls_free(op, rs, &bc->ctrls ); - } - asyncmeta_clear_bm_context(bc, 1, 1); - return rs->sr_err; -} -#endif diff --git a/servers/slapd/back-asyncmeta/modify.c b/servers/slapd/back-asyncmeta/modify.c index 362b1544ea..ae7559ee3a 100644 --- a/servers/slapd/back-asyncmeta/modify.c +++ b/servers/slapd/back-asyncmeta/modify.c @@ -26,21 +26,21 @@ #include #include - #include "slap.h" -#include "../back-ldap/back-ldap.h" -#include "back-asyncmeta.h" #include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/libldap/ldap-int.h" +#include "../back-ldap/back-ldap.h" +#include "back-asyncmeta.h" meta_search_candidate_t asyncmeta_back_modify_start(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate) + int candidate, + int do_lock) { - int i, isupdate, rc = 0, nretries = 1; + int i, isupdate, rc = 0; a_dncookie dc; a_metainfo_t *mi = mc->mc_info; a_metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -48,7 +48,6 @@ asyncmeta_back_modify_start(Operation *op, LDAPMod *mods = NULL; struct berval mdn; Modifications *ml; - struct berval mapped; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; BerElement *ber = NULL; a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; @@ -59,122 +58,55 @@ asyncmeta_back_modify_start(Operation *op, /* * Rewrite the modify dn, if needed */ + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "modifyDN"; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; - switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) - { - case LDAP_SUCCESS: - break; - case LDAP_UNWILLING_TO_PERFORM: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "Operation not allowed"; - retcode = META_SEARCH_ERR; - goto doreturn; - default: - rs->sr_err = LDAP_NO_SUCH_OBJECT; - retcode = META_SEARCH_NOT_CANDIDATE; - goto doreturn; - } + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next ) ; + if (i > 0) { + mods = op->o_tmpalloc( sizeof( LDAPMod )*i, op->o_tmpmemctx ); + } - mods = ch_malloc( sizeof( LDAPMod )*i ); if ( mods == NULL ) { rs->sr_err = LDAP_OTHER; retcode = META_SEARCH_ERR; goto doreturn; } - modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) ); + modv = ( LDAPMod ** )op->o_tmpalloc( ( i + 1 )*sizeof( LDAPMod * ), op->o_tmpmemctx ); if ( modv == NULL ) { rs->sr_err = LDAP_OTHER; retcode = META_SEARCH_ERR; goto doreturn; } - dc.ctx = "modifyAttrDN"; isupdate = be_shadow_update( op ); for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) { - int j, is_oc = 0; + int j; if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod ) { continue; } - if ( ml->sml_desc == slap_schema.si_ad_objectClass - || ml->sml_desc == slap_schema.si_ad_structuralObjectClass ) - { - is_oc = 1; - mapped = ml->sml_desc->ad_cname; - - } else { - asyncmeta_map( &mt->mt_rwmap.rwm_at, - &ml->sml_desc->ad_cname, &mapped, - BACKLDAP_MAP ); - if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) { - continue; - } - } - modv[ i ] = &mods[ i ]; mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES; - mods[ i ].mod_type = mapped.bv_val; + mods[ i ].mod_type = ml->sml_desc->ad_cname.bv_val; - /* - * FIXME: dn-valued attrs should be rewritten - * to allow their use in ACLs at the back-ldap - * level. - */ if ( ml->sml_values != NULL ) { - if ( is_oc ) { - for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) - ; - mods[ i ].mod_bvalues = - (struct berval **)ch_malloc( ( j + 1 ) * - sizeof( struct berval * ) ); - for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) { - struct ldapmapping *mapping; - - asyncmeta_mapping( &mt->mt_rwmap.rwm_oc, - &ml->sml_values[ j ], &mapping, BACKLDAP_MAP ); - - if ( mapping == NULL ) { - if ( mt->mt_rwmap.rwm_oc.drop_missing ) { - continue; - } - mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ]; - - } else { - mods[ i ].mod_bvalues[ j ] = &mapping->dst; - } - j++; - } - mods[ i ].mod_bvalues[ j ] = NULL; - - } else { - if ( ml->sml_desc->ad_type->sat_syntax == - slap_schema.si_syn_distinguishedName ) - { - ( void )asyncmeta_dnattr_rewrite( &dc, ml->sml_values ); - if ( ml->sml_values == NULL ) { - continue; - } - } - - for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) - ; - mods[ i ].mod_bvalues = - (struct berval **)ch_malloc( ( j + 1 ) * - sizeof( struct berval * ) ); - for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) { - mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ]; - } - mods[ i ].mod_bvalues[ j ] = NULL; + j = ml->sml_numvals; + mods[ i ].mod_bvalues =(struct berval **)op->o_tmpalloc( ( j + 1 ) *sizeof( struct berval * ), op->o_tmpmemctx ); + for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) { + mods[ i ].mod_bvalues[ j ] = op->o_tmpalloc(sizeof( struct berval ), op->o_tmpmemctx ); + if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) + asyncmeta_dn_massage( &dc, &ml->sml_values[ j ], mods[ i ].mod_bvalues[ j ] ); + else + *mods[ i ].mod_bvalues[ j ] = ml->sml_values[ j ]; } + mods[ i ].mod_bvalues[ j ] = NULL; } else { mods[ i ].mod_bvalues = NULL; @@ -184,62 +116,113 @@ asyncmeta_back_modify_start(Operation *op, } modv[ i ] = 0; -retry:; + asyncmeta_set_msc_time(msc); ctrls = op->o_ctrls; - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_ERR; goto done; } + /* someone reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug , "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + ber = ldap_build_modify_req( msc->msc_ld, mdn.bv_val, modv, ctrls, NULL, &msgid); + + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_modify_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY, - mdn.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY, + mdn.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_clear_one_msc(NULL, mc, candidate); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - + /* fall though*/ default: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - retcode = META_SEARCH_ERR; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; } } +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + ldap_pvt_thread_yield(); + retcode = META_SEARCH_NEED_BIND; + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send modify request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + ldap_pvt_thread_yield(); + break; + } done: (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); - BER_BVZERO( &mdn ); + op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); } - if ( modv != NULL ) { - for ( i = 0; modv[ i ]; i++ ) { - free( modv[ i ]->mod_bvalues ); - } - } - free( mods ); - free( modv ); doreturn:; Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); @@ -253,26 +236,31 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs ) a_metatarget_t *mt; a_metaconn_t *mc; int rc, candidate = -1; - OperationBuffer opbuf; + void *thrctx = op->o_threadctx; bm_context_t *bc; SlapReply *candidates; - slap_callback *cb = op->o_callback; + time_t current_time = slap_get_time(); + int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modify: %s\n", op->o_req_dn.bv_val ); - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + if (current_time > op->o_time) { + Debug(asyncmeta_debug, "==> asyncmeta_back_modify[%s]: o_time:[%ld], current time: [%ld]\n", + op->o_log_prefix, op->o_time, current_time ); + } + + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); return rs->sr_err; } candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + send_ldap_result(op, rs); return rs->sr_err; } @@ -281,16 +269,38 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs ) bc->retrying = LDAP_BACK_RETRYING; bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + mc->mc_conns[candidate].msc_active++; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); + ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex); + goto finish; + } + +retry: + if (bc->timeout && bc->stoptime < slap_get_time()) { + int timeout_err; + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + rs->sr_err = timeout_err; + rs->sr_text = "Operation timed out before it was sent to target"; + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; } @@ -300,70 +310,49 @@ asyncmeta_back_modify( Operation *op, SlapReply *rs ) case META_SEARCH_CANDIDATE: /* target is already bound, just send the request */ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); - rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate); + rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate, 1); if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } - break; + break; case META_SEARCH_NOT_CANDIDATE: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - } - break; case META_SEARCH_BINDING: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: BINDING " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); + "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); /* Todo add the context to the message queue but do not send the request the receiver must send this when we are done binding */ - /* question - how would do receiver know to which targets??? */ break; case META_SEARCH_ERR: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR " - "cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; default: assert( 0 ); break; } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; asyncmeta_start_one_listener(mc, candidates, bc, candidate); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; + finish: return rs->sr_err; } diff --git a/servers/slapd/back-asyncmeta/modrdn.c b/servers/slapd/back-asyncmeta/modrdn.c index 2fe2de2688..deaf63c42f 100644 --- a/servers/slapd/back-asyncmeta/modrdn.c +++ b/servers/slapd/back-asyncmeta/modrdn.c @@ -26,19 +26,19 @@ #include #include - #include "slap.h" -#include "../back-ldap/back-ldap.h" -#include "back-asyncmeta.h" #include "../../../libraries/liblber/lber-int.h" #include "../../../libraries/libldap/ldap-int.h" +#include "../back-ldap/back-ldap.h" +#include "back-asyncmeta.h" meta_search_candidate_t asyncmeta_back_modrdn_start(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate) + int candidate, + int do_lock) { a_dncookie dc; a_metainfo_t *mi = mc->mc_info; @@ -46,7 +46,7 @@ asyncmeta_back_modrdn_start(Operation *op, struct berval mdn = BER_BVNULL, mnewSuperior = BER_BVNULL, newrdn = BER_BVNULL; - int rc = 0, nretries = 1; + int rc = 0; LDAPControl **ctrls = NULL; meta_search_candidate_t retcode = META_SEARCH_CANDIDATE; BerElement *ber = NULL; @@ -54,9 +54,10 @@ asyncmeta_back_modrdn_start(Operation *op, SlapReply *candidates = bc->candidates; ber_int_t msgid; + dc.op = op; dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; if ( op->orr_newSup ) { @@ -101,23 +102,13 @@ asyncmeta_back_modrdn_start(Operation *op, /* * Rewrite the new superior, if defined and required */ - dc.ctx = "newSuperiorDN"; - if ( asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) { - rs->sr_err = LDAP_OTHER; - retcode = META_SEARCH_ERR; - goto done; - } + asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ); } /* * Rewrite the modrdn dn, if required */ - dc.ctx = "modrDN"; - if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - rs->sr_err = LDAP_OTHER; - retcode = META_SEARCH_ERR; - goto done; - } + asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ); /* NOTE: we need to copy the newRDN in case it was formed * from a DN by simply changing the length (ITS#5397) */ @@ -125,69 +116,125 @@ asyncmeta_back_modrdn_start(Operation *op, if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) { ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx ); } -retry:; + + asyncmeta_set_msc_time(msc); ctrls = op->o_ctrls; - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_ERR; goto done; } - + /* someone might have reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } ber = ldap_build_moddn_req( msc->msc_ld, mdn.bv_val, newrdn.bv_val, mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid); + + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_modrdn_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN, - mdn.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN, + mdn.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_clear_one_msc(NULL, mc, candidate); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__ ); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - + /* fall though*/ default: - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - retcode = META_SEARCH_ERR; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; } } +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + retcode = META_SEARCH_NEED_BIND; + ldap_pvt_thread_yield(); + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send modrdn request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + ldap_pvt_thread_yield(); + break; + } done: (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); - BER_BVZERO( &mdn ); + op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &mnewSuperior ) && mnewSuperior.bv_val != op->orr_newSup->bv_val ) { - free( mnewSuperior.bv_val ); - BER_BVZERO( &mnewSuperior ); + op->o_tmpfree( mnewSuperior.bv_val, op->o_tmpmemctx ); } if ( newrdn.bv_val != op->orr_newrdn.bv_val ) { op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx ); } -doreturn:; Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modrdn_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid ); return retcode; } @@ -199,26 +246,30 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs ) a_metatarget_t *mt; a_metaconn_t *mc; int rc, candidate = -1; - OperationBuffer opbuf; + void *thrctx = op->o_threadctx; bm_context_t *bc; SlapReply *candidates; - slap_callback *cb = op->o_callback; + time_t current_time = slap_get_time(); + int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modrdn: %s\n", op->o_req_dn.bv_val ); - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + if (current_time > op->o_time) { + Debug(asyncmeta_debug, "==> asyncmeta_back_modrdn[%s]: o_time:[%ld], current time: [%ld]\n", + op->o_log_prefix, op->o_time, current_time ); + } + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); return rs->sr_err; } candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + send_ldap_result(op, rs); return rs->sr_err; } @@ -227,66 +278,69 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs ) bc->retrying = LDAP_BACK_RETRYING; bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying ); bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; + } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + mc->mc_conns[candidate].msc_active++; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - asyncmeta_sender_error(op, rs, cb); + send_ldap_result(op, rs); + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); goto finish; } +retry: + if (bc->timeout && bc->stoptime < slap_get_time()) { + int timeout_err; + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + rs->sr_err = timeout_err; + rs->sr_text = "Operation timed out before it was sent to target"; + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); + goto finish; + + } + rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate); switch (rc) { case META_SEARCH_CANDIDATE: /* target is already bound, just send the request */ Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); - rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate); + rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate, 1); if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } - break; + break; case META_SEARCH_NOT_CANDIDATE: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE " - "cnd=\"%ld\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); - rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate); - if (rc == META_SEARCH_ERR) { - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); - goto finish; - } - break; case META_SEARCH_BINDING: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: BINDING " - "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); + "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]); /* Todo add the context to the message queue but do not send the request the receiver must send this when we are done binding */ /* question - how would do receiver know to which targets??? */ @@ -294,22 +348,21 @@ asyncmeta_back_modrdn( Operation *op, SlapReply *rs ) case META_SEARCH_ERR: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR " - "cnd=\"%ldd\"\n", op->o_log_prefix, candidate ); - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - candidates[ candidate ].sr_type = REP_RESULT; - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - asyncmeta_sender_error(op, rs, cb); - asyncmeta_clear_bm_context(bc); + "cnd=\"%d\"\n", op->o_log_prefix, candidate ); + asyncmeta_error_cleanup(op, rs, bc, mc, candidate); goto finish; default: assert( 0 ); break; } + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + mc->mc_conns[candidate].msc_active--; asyncmeta_start_one_listener(mc, candidates, bc, candidate); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; finish: return rs->sr_err; } diff --git a/servers/slapd/back-asyncmeta/proto-asyncmeta.h b/servers/slapd/back-asyncmeta/proto-asyncmeta.h index 3013b6a843..0dbe3f0c74 100644 --- a/servers/slapd/back-asyncmeta/proto-asyncmeta.h +++ b/servers/slapd/back-asyncmeta/proto-asyncmeta.h @@ -43,7 +43,6 @@ extern BI_op_modify asyncmeta_back_modify; extern BI_op_modrdn asyncmeta_back_modrdn; extern BI_op_add asyncmeta_back_add; extern BI_op_delete asyncmeta_back_delete; -extern BI_op_abandon asyncmeta_back_abandon; extern BI_connection_destroy asyncmeta_back_conn_destroy; diff --git a/servers/slapd/back-asyncmeta/search.c b/servers/slapd/back-asyncmeta/search.c index 97ba375344..9423f36ae0 100644 --- a/servers/slapd/back-asyncmeta/search.c +++ b/servers/slapd/back-asyncmeta/search.c @@ -27,59 +27,297 @@ #include #include #include - -#include "lutil.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-asyncmeta.h" -#include "../../../libraries/liblber/lber-int.h" - -#include "../../../libraries/libldap/ldap-int.h" -#undef ldap_debug -#define ldap_debug slap_debug static void asyncmeta_handle_onerr_stop(Operation *op, SlapReply *rs, a_metaconn_t *mc, bm_context_t *bc, - int candidate, - slap_callback *cb) + int candidate) { a_metainfo_t *mi = mc->mc_info; int j; ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - if (bc->bc_active > 0) { + if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) { + bc->bc_active--; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); return; } - bc->bc_active = 1; asyncmeta_drop_bc(mc, bc); - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - for (j=0; jmi_ntargets; j++) { if (j != candidate && bc->candidates[j].sr_msgid >= 0 - && mc->mc_conns[j].msc_ld != NULL) { - asyncmeta_back_abandon_candidate( mc, op, + && mc->mc_conns[j].msc_ld != NULL && !META_BACK_CONN_CREATING( &mc->mc_conns[j] )) { + asyncmeta_back_cancel( mc, op, bc->candidates[ j ].sr_msgid, j ); } } - if (cb != NULL) { - op->o_callback = cb; - } + slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); send_ldap_result(op, rs); - asyncmeta_clear_bm_context(bc); } +static int +asyncmeta_int_filter2bv( a_dncookie *dc, + Filter *f, + struct berval *fstr ) +{ + int i; + Filter *p; + struct berval atmp, + vtmp, + ntmp, + *tmp; + static struct berval + /* better than nothing... */ + ber_bvfalse = BER_BVC( "(!(objectClass=*))" ), + ber_bvtf_false = BER_BVC( "(|)" ), + /* better than nothing... */ + ber_bvtrue = BER_BVC( "(objectClass=*)" ), + ber_bvtf_true = BER_BVC( "(&)" ), + ber_bverror = BER_BVC( "(?=error)" ), + ber_bvunknown = BER_BVC( "(?=unknown)" ), + ber_bvnone = BER_BVC( "(?=none)" ); + ber_len_t len; + void *memctx = dc->memctx; + + assert( fstr != NULL ); + BER_BVZERO( fstr ); + + if ( f == NULL ) { + ber_dupbv_x( fstr, &ber_bvnone, memctx ); + return LDAP_OTHER; + } + + switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) { + case LDAP_FILTER_EQUALITY: + if ( f->f_av_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { + asyncmeta_dn_massage( dc, &f->f_av_value, &vtmp ); + } else { + vtmp = f->f_av_value; + } + + filter_escape_value_x( &vtmp, &ntmp, memctx ); + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len + + ( sizeof("(=)") - 1 ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", + f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + break; + + case LDAP_FILTER_GE: + filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len + + ( sizeof("(>=)") - 1 ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", + f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + break; + + case LDAP_FILTER_LE: + filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len + + ( sizeof("(<=)") - 1 ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", + f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + break; + + case LDAP_FILTER_APPROX: + filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); + fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len + + ( sizeof("(~=)") - 1 ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", + f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + break; + + case LDAP_FILTER_SUBSTRINGS: + fstr->bv_len = f->f_sub_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */ + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + f->f_sub_desc->ad_cname.bv_val ); + + if ( !BER_BVISNULL( &f->f_sub_initial ) ) { + len = fstr->bv_len; + + filter_escape_value_x( &f->f_sub_initial, &ntmp, memctx ); + + fstr->bv_len += ntmp.bv_len; + fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); + + snprintf( &fstr->bv_val[len - 2], ntmp.bv_len + 3, + /* "(attr=" */ "%s*)", + ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + } + + if ( f->f_sub_any != NULL ) { + for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) { + len = fstr->bv_len; + filter_escape_value_x( &f->f_sub_any[i], &ntmp, memctx ); + + fstr->bv_len += ntmp.bv_len + 1; + fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); + + snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3, + /* "(attr=[init]*[any*]" */ "%s*)", + ntmp.bv_len ? ntmp.bv_val : "" ); + ber_memfree_x( ntmp.bv_val, memctx ); + } + } + + if ( !BER_BVISNULL( &f->f_sub_final ) ) { + len = fstr->bv_len; + + filter_escape_value_x( &f->f_sub_final, &ntmp, memctx ); + + fstr->bv_len += ntmp.bv_len; + fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); + + snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3, + /* "(attr=[init*][any*]" */ "%s)", + ntmp.bv_len ? ntmp.bv_val : "" ); + + ber_memfree_x( ntmp.bv_val, memctx ); + } + + break; + + case LDAP_FILTER_PRESENT: + fstr->bv_len = f->f_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + f->f_desc->ad_cname.bv_val ); + break; + + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: + case LDAP_FILTER_NOT: + fstr->bv_len = STRLENOF( "(%)" ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */ + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", + f->f_choice == LDAP_FILTER_AND ? '&' : + f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); + + for ( p = f->f_list; p != NULL; p = p->f_next ) { + int rc; + + len = fstr->bv_len; + + rc = asyncmeta_int_filter2bv( dc, p, &vtmp ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + fstr->bv_len += vtmp.bv_len; + fstr->bv_val = ber_memrealloc_x( fstr->bv_val, fstr->bv_len + 1, memctx ); + + snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, + /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" ); + + ber_memfree_x( vtmp.bv_val, memctx ); + } + + break; + + case LDAP_FILTER_EXT: + if ( f->f_mr_desc ) { + atmp = f->f_mr_desc->ad_cname; + + } else { + BER_BVSTR( &atmp, "" ); + } + filter_escape_value_x( &f->f_mr_value, &ntmp, memctx ); + + /* FIXME: cleanup (less ?: operators...) */ + fstr->bv_len = atmp.bv_len + + ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) + + ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) + + ntmp.bv_len + ( STRLENOF( "(:=)" ) ); + fstr->bv_val = ber_memalloc_x( fstr->bv_len + 1, memctx ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", + atmp.bv_val, + f->f_mr_dnattrs ? ":dn" : "", + !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "", + !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "", + ntmp.bv_len ? ntmp.bv_val : "" ); + ber_memfree_x( ntmp.bv_val, memctx ); + break; + + case SLAPD_FILTER_COMPUTED: + switch ( f->f_result ) { + /* FIXME: treat UNDEFINED as FALSE */ + case SLAPD_COMPARE_UNDEFINED: + if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) { + return LDAP_COMPARE_FALSE; + } + /* fallthru */ + + case LDAP_COMPARE_FALSE: + if ( META_BACK_TGT_T_F( dc->target ) ) { + tmp = &ber_bvtf_false; + break; + } + tmp = &ber_bvfalse; + break; + + case LDAP_COMPARE_TRUE: + if ( META_BACK_TGT_T_F( dc->target ) ) { + tmp = &ber_bvtf_true; + break; + } + + tmp = &ber_bvtrue; + break; + + default: + tmp = &ber_bverror; + break; + } + + ber_dupbv_x( fstr, tmp, memctx ); + break; + + default: + ber_dupbv_x( fstr, &ber_bvunknown, memctx ); + break; + } + + return 0; +} meta_search_candidate_t asyncmeta_back_search_start( Operation *op, SlapReply *rs, - a_metaconn_t *mc, - bm_context_t *bc, - int candidate, - struct berval *prcookie, - ber_int_t prsize ) + a_metaconn_t *mc, + bm_context_t *bc, + int candidate, + struct berval *prcookie, + ber_int_t prsize, + int do_lock) { SlapReply *candidates = bc->candidates; a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info; @@ -87,16 +325,15 @@ asyncmeta_back_search_start( a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; a_dncookie dc; struct berval realbase = op->o_req_dn; + char **attrs; int realscope = op->ors_scope; struct berval mbase = BER_BVNULL; - struct berval mfilter = BER_BVNULL; - char **mapped_attrs = NULL; int rc; + struct berval filterbv = BER_BVNULL; meta_search_candidate_t retcode; int timelimit; - int nretries = 1; LDAPControl **ctrls = NULL; - BerElement *ber; + BerElement *ber = NULL; ber_int_t msgid; #ifdef SLAPD_META_CLIENT_PR LDAPControl **save_ctrls = NULL; @@ -116,7 +353,8 @@ asyncmeta_back_search_start( 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 */ @@ -199,59 +437,13 @@ asyncmeta_back_search_start( /* * Rewrite the search base, if required */ + dc.op = op; dc.target = mt; - dc.ctx = "searchBase"; - dc.conn = op->o_conn; - dc.rs = rs; - switch ( asyncmeta_dn_massage( &dc, &realbase, &mbase ) ) { - case LDAP_SUCCESS: - break; + dc.memctx = op->o_tmpmemctx; + dc.to_from = MASSAGE_REQ; + asyncmeta_dn_massage( &dc, &realbase, &mbase ); - 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: - - /* - * this target is no longer candidate - */ - retcode = META_SEARCH_NOT_CANDIDATE; - goto doreturn; - } - - /* - * Maps filter - */ - rc = asyncmeta_filter_map_rewrite( &dc, op->ors_filter, - &mfilter, BACKLDAP_MAP, NULL ); - switch ( rc ) { - case LDAP_SUCCESS: - break; - - case LDAP_COMPARE_FALSE: - default: - /* - * this target is no longer candidate - */ - retcode = META_SEARCH_NOT_CANDIDATE; - goto done; - } - - /* - * Maps required attributes - */ - rc = asyncmeta_map_attrs( op, &mt->mt_rwmap.rwm_at, - op->ors_attrs, BACKLDAP_MAP, &mapped_attrs ); - if ( rc != LDAP_SUCCESS ) { - /* - * this target is no longer candidate - */ - retcode = META_SEARCH_NOT_CANDIDATE; - goto done; - } + attrs = anlist2charray_x( op->ors_attrs, 0, op->o_tmpmemctx ); if ( op->ors_tlimit != SLAP_NO_LIMIT ) { timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1; @@ -338,21 +530,10 @@ done_pr:; } #endif /* SLAPD_META_CLIENT_PR */ -retry:; asyncmeta_set_msc_time(msc); ctrls = op->o_ctrls; - if (nretries == 0) - { - if (rc != LDAP_SUCCESS) - { - rs->sr_err = LDAP_BUSY; - retcode = META_SEARCH_ERR; - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; - goto done; - } - } - if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) + if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; @@ -363,48 +544,114 @@ retry:; /* * Starts the search */ + /* someone reset the connection */ + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + rc = asyncmeta_int_filter2bv( &dc, op->ors_filter, &filterbv ); + if ( rc ) { + retcode = META_SEARCH_ERR; + goto done; + } + ber = ldap_build_search_req( msc->msc_ld, - mbase.bv_val, realscope, mfilter.bv_val, - mapped_attrs, op->ors_attrsonly, + mbase.bv_val, realscope, filterbv.bv_val, + attrs, op->ors_attrsonly, ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref, &msgid ); + if (!ber) { + Debug( asyncmeta_debug, "%s asyncmeta_back_search_start: Operation encoding failed with errno %d\n", + op->o_log_prefix, msc->msc_ld->ld_errno ); + rs->sr_err = LDAP_OPERATIONS_ERROR; + rs->sr_text = "Failed to encode proxied request"; + retcode = META_SEARCH_ERR; + goto done; + } + if (ber) { - candidates[ candidate ].sr_msgid = msgid; - rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH, - mbase.bv_val, ber, msgid ); - if (rc == msgid) - rc = LDAP_SUCCESS; - else - rc = LDAP_SERVER_DOWN; + struct timeval tv = {0, mt->mt_network_timeout*1000}; + ber_socket_t s; + + if (!( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); + if (s < 0) { + Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + } + + rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); + if (rc < 0) { + Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); + if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { + rc = LDAP_SERVER_DOWN; + } else { + goto error_unavailable; + } + } else { + candidates[ candidate ].sr_msgid = msgid; + rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH, + mbase.bv_val, ber, msgid ); + if (rc == msgid) + rc = LDAP_SUCCESS; + else + rc = LDAP_SERVER_DOWN; + ber = NULL; + } + switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; asyncmeta_set_msc_time(msc); - break; + goto done; case LDAP_SERVER_DOWN: - ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); - if (mc->mc_active < 1) { - asyncmeta_clear_one_msc(NULL, mc, candidate); + /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ + if (do_lock > 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); } - ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) { - nretries = 0; - /* if the identity changed, there might be need to re-authz */ - (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); - goto retry; - } - rs->sr_err = LDAP_UNAVAILABLE; - retcode = META_SEARCH_ERR; - break; + Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); + goto error_unavailable; + default: candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_NOT_CANDIDATE; + goto done; } } +error_unavailable: + if (ber) + ber_free(ber, 1); + switch (bc->nretries[candidate]) { + case -1: /* nretries = forever */ + retcode = META_SEARCH_NEED_BIND; + ldap_pvt_thread_yield(); + break; + case 0: /* no retries left */ + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "Unable to send search request to target"; + retcode = META_SEARCH_ERR; + break; + default: /* more retries left - try to rebind and go again */ + retcode = META_SEARCH_NEED_BIND; + bc->nretries[candidate]--; + ldap_pvt_thread_yield(); + break; + } done:; +#if 0 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); +#endif #ifdef SLAPD_META_CLIENT_PR if ( save_ctrls != op->o_ctrls ) { op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); @@ -412,14 +659,8 @@ done:; } #endif /* SLAPD_META_CLIENT_PR */ - if ( mapped_attrs ) { - ber_memfree_x( mapped_attrs, op->o_tmpmemctx ); - } - if ( mfilter.bv_val != op->ors_filterstr.bv_val ) { - ber_memfree_x( mfilter.bv_val, NULL ); - } if ( mbase.bv_val != realbase.bv_val ) { - free( mbase.bv_val ); + op->o_tmpfree( mbase.bv_val, op->o_tmpmemctx ); } doreturn:; @@ -431,25 +672,16 @@ int asyncmeta_back_search( Operation *op, SlapReply *rs ) { a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private; - struct timeval save_tv = { 0, 0 }, - tv; - time_t stoptime = (time_t)(-1), - lastres_time = slap_get_time(), - timeout = 0; - int rc = 0, sres = LDAP_SUCCESS; - char *matched = NULL; - int last = 0, ncandidates = 0, - initial_candidates = 0, candidate_match = 0, - needbind = 0; - ldap_back_send_t sendok = LDAP_BACK_SENDERR; - long i,j; - int is_ok = 0; - void *savepriv; + time_t timeout = 0; + int rc = 0; + int ncandidates = 0, initial_candidates = 0; + long i; SlapReply *candidates = NULL; - int do_taint = 0; + void *thrctx = op->o_threadctx; bm_context_t *bc; a_metaconn_t *mc; - slap_callback *cb = op->o_callback; + int msc_decr = 0; + int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; rs_assert_ready( rs ); rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */ @@ -461,7 +693,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) * to map attrs and maybe rewrite value */ - asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets ); + asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); if (bc == NULL) { rs->sr_err = LDAP_OTHER; send_ldap_result(op, rs); @@ -471,9 +703,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) candidates = bc->candidates; mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0); if ( !mc || rs->sr_err != LDAP_SUCCESS) { - op->o_callback = cb; send_ldap_result(op, rs); - asyncmeta_clear_bm_context(bc); return rs->sr_err; } @@ -511,27 +741,33 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) } } - bc->timeout = timeout; - bc->stoptime = op->o_time + bc->timeout; + if ( op->ors_tlimit != SLAP_NO_LIMIT && (timeout == 0 || op->ors_tlimit < timeout)) { + bc->searchtime = 1; + bc->timeout = op->ors_tlimit; + } else { + bc->timeout = timeout; + } - if ( op->ors_tlimit != SLAP_NO_LIMIT ) { - stoptime = op->o_time + op->ors_tlimit; - if (stoptime < bc->stoptime) { - bc->stoptime = stoptime; - bc->searchtime = 1; - bc->timeout = op->ors_tlimit; - } + bc->stoptime = op->o_time + bc->timeout; + bc->bc_active = 1; + + if (mc->pending_ops >= max_pending_ops) { + rs->sr_err = LDAP_BUSY; + rs->sr_text = "Maximum pending ops limit exceeded"; + send_ldap_result(op, rs); + return rs->sr_err; } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); rc = asyncmeta_add_message_queue(mc, bc); + for ( i = 0; i < mi->mi_ntargets; i++ ) { + mc->mc_conns[i].msc_active++; + } ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); if (rc != LDAP_SUCCESS) { rs->sr_err = LDAP_BUSY; rs->sr_text = "Maximum pending ops limit exceeded"; - asyncmeta_clear_bm_context(bc); - op->o_callback = cb; send_ldap_result(op, rs); goto finish; } @@ -542,6 +778,30 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) { continue; } +retry: + if (bc->timeout && bc->stoptime < slap_get_time() && META_BACK_ONERR_STOP( mi )) { + int timeout_err; + const char *timeout_text; + if (bc->searchtime) { + timeout_err = LDAP_TIMELIMIT_EXCEEDED; + timeout_text = NULL; + } else { + timeout_err = op->o_protocol >= LDAP_VERSION3 ? + LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; + timeout_text = "Operation timed out before it was sent to target"; + } + rs->sr_err = timeout_err; + rs->sr_text = timeout_text; + asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); + goto finish; + + } + + if (op->o_abandon) { + rs->sr_err = SLAPD_ABANDON; + asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); + goto finish; + } rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, i); switch (rc) @@ -552,17 +812,19 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE " "cnd=\"%ld\"\n", op->o_log_prefix, i ); - rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 ); + rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 , 1); if (rc == META_SEARCH_ERR) { META_CANDIDATE_CLEAR(&candidates[i]); candidates[ i ].sr_msgid = META_MSGID_IGNORE; if ( META_BACK_ONERR_STOP( mi ) ) { - asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb); + asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); goto finish; } else { continue; } + } else if (rc == META_SEARCH_NEED_BIND) { + goto retry; } break; case META_SEARCH_NOT_CANDIDATE: @@ -572,22 +834,6 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) break; case META_SEARCH_NEED_BIND: - case META_SEARCH_CONNECTING: - Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: NEED_BIND " - "cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]); - ncandidates++; - rc = asyncmeta_dobind_init(op, rs, bc, mc, i); - if (rc == META_SEARCH_ERR) { - candidates[ i ].sr_msgid = META_MSGID_IGNORE; - if ( META_BACK_ONERR_STOP( mi ) ) { - asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb); - goto finish; - } - else { - continue; - } - } - break; case META_SEARCH_BINDING: Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING " "cnd=\"%ld\" %p\n", op->o_log_prefix, i , &mc->mc_conns[i]); @@ -604,7 +850,7 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) candidates[ i ].sr_type = REP_RESULT; if ( META_BACK_ONERR_STOP( mi ) ) { - asyncmeta_handle_onerr_stop(op,rs,mc,bc,i,cb); + asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); goto finish; } else { @@ -666,14 +912,29 @@ asyncmeta_back_search( Operation *op, SlapReply *rs ) ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); asyncmeta_drop_bc(mc, bc); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); - op->o_callback = cb; send_ldap_result(op, rs); - asyncmeta_clear_bm_context(bc); goto finish; } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + for ( i = 0; i < mi->mi_ntargets; i++ ) { + mc->mc_conns[i].msc_active--; + } + msc_decr = 1; + asyncmeta_start_listeners(mc, candidates, bc); + bc->bc_active--; + asyncmeta_memctx_toggle(thrctx); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + rs->sr_err = SLAPD_ASYNCOP; + finish: + /* we ended up straight here due to error and need to reset the msc_active*/ + if (msc_decr == 0) { + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); + for ( i = 0; i < mi->mi_ntargets; i++ ) { + mc->mc_conns[i].msc_active--; + } + ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); + } return rs->sr_err; } diff --git a/servers/slapd/back-asyncmeta/suffixmassage.c b/servers/slapd/back-asyncmeta/suffixmassage.c deleted file mode 100644 index 36889c0da4..0000000000 --- a/servers/slapd/back-asyncmeta/suffixmassage.c +++ /dev/null @@ -1,112 +0,0 @@ -/* suffixmassage.c - massages ldap backend dns */ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * 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 - * . - */ - -/* 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. - * Copyright 2000, Pierangelo Masarati, All rights reserved. - * - * 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 - -#include -#include - -#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; -} diff --git a/servers/slapd/back-asyncmeta/unbind.c b/servers/slapd/back-asyncmeta/unbind.c deleted file mode 100644 index 6ad3b1a8ac..0000000000 --- a/servers/slapd/back-asyncmeta/unbind.c +++ /dev/null @@ -1,55 +0,0 @@ -/* unbind.c - unbind handler for back-asyncmeta */ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * 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 - * . - */ - -/* 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 - -#include -#include -#include - -#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; -} diff --git a/tests/data/slapd-asyncmeta.conf b/tests/data/slapd-asyncmeta.conf new file mode 100644 index 0000000000..8af4932f55 --- /dev/null +++ b/tests/data/slapd-asyncmeta.conf @@ -0,0 +1,88 @@ +# master slapd config -- for testing +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## 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 +## . + +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 diff --git a/tests/run.in b/tests/run.in index 0c2667af3e..9d81b1d846 100644 --- a/tests/run.in +++ b/tests/run.in @@ -33,6 +33,7 @@ AC_null=@BUILD_NULL@ # other backends AC_ldap=ldap@BUILD_LDAP@ AC_meta=meta@BUILD_META@ +AC_asyncmeta=asyncmeta@BUILD_ASYNCMETA@ AC_monitor=@BUILD_MONITOR@ AC_relay=relay@BUILD_RELAY@ AC_sql=sql@BUILD_SQL@ @@ -70,8 +71,10 @@ fi if test "${AC_meta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then AC_meta="metano" fi - -export AC_bdb AC_hdb AC_ldap AC_mdb AC_meta AC_monitor AC_null AC_relay AC_sql \ +if test "${AC_asyncmeta}" = "metamod" && test "${AC_LIBS_DYNAMIC}" = "static" ; then + AC_meta="asyncmetano" +fi +export AC_bdb AC_hdb AC_ldap AC_mdb AC_meta AC_asyncmeta AC_monitor AC_null AC_relay AC_sql \ AC_accesslog AC_autoca AC_constraint AC_dds AC_dynlist AC_memberof AC_pcache AC_ppolicy \ AC_refint AC_retcode AC_rwm AC_unique AC_syncprov AC_translucent \ AC_valsort \ diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 6a8b103dbf..a52dc285df 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -21,6 +21,7 @@ TESTWD=`pwd` MONITORDB=${AC_monitor-no} BACKLDAP=${AC_ldap-ldapno} BACKMETA=${AC_meta-metano} +BACKASYNCMETA=${AC_asyncmeta-asyncmetano} BACKRELAY=${AC_relay-relayno} BACKSQL=${AC_sql-sqlno} RDBMS=${SLAPD_USE_SQL-rdbmsno} @@ -134,6 +135,7 @@ TRANSLUCENTREMOTECONF=$DATADIR/slapd-translucent-remote.conf METACONF=$DATADIR/slapd-meta.conf METACONF1=$DATADIR/slapd-meta-target1.conf METACONF2=$DATADIR/slapd-meta-target2.conf +ASYNCMETACONF=$DATADIR/slapd-asyncmeta.conf GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf ACICONF=$DATADIR/slapd-aci.conf VALSORTCONF=$DATADIR/slapd-valsort.conf diff --git a/tests/scripts/test073-asyncmeta b/tests/scripts/test073-asyncmeta new file mode 100755 index 0000000000..e24a7d250b --- /dev/null +++ b/tests/scripts/test073-asyncmeta @@ -0,0 +1,620 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## 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 +## . + +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 diff --git a/tests/scripts/test074-asyncmeta-concurrency b/tests/scripts/test074-asyncmeta-concurrency new file mode 100755 index 0000000000..a9274afbf3 --- /dev/null +++ b/tests/scripts/test074-asyncmeta-concurrency @@ -0,0 +1,242 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## 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 +## . + +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