int isupdate;
int do_retry = 1;
LDAPControl **ctrls = NULL;
- int rc = LDAP_SUCCESS;
+ rs->sr_err = LDAP_SUCCESS;
+
Debug( LDAP_DEBUG_ARGS, "==> ldap_back_add(\"%s\")\n",
op->o_req_dn.bv_val, 0, 0 );
- lc = ldap_back_getconn( op, rs );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
- rc = -1;
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto cleanup;
}
attrs[ i ] = NULL;
ctrls = op->o_ctrls;
- rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
- if ( rc != LDAP_SUCCESS ) {
+ rs->sr_err = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
- rc = -1;
goto cleanup;
}
retry:
rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
+ rs->sr_err = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry( lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
}
Debug( LDAP_DEBUG_ARGS, "<== ldap_back_add(\"%s\"): %d\n",
- op->o_req_dn.bv_val, rc, 0 );
+ op->o_req_dn.bv_val, rs->sr_err, 0 );
- return rc;
+ return rs->sr_err;
}
/* end of ID assert stuff */
ldap_pvt_thread_mutex_t conn_mutex;
- int savecred;
+ unsigned flags;
+#define LDAP_BACK_F_NONE 0x00U
+#define LDAP_BACK_F_SAVECRED 0x01U
+#define LDAP_BACK_F_USE_TLS 0x02U
+#define LDAP_BACK_F_TLS_CRITICAL ( 0x04U | LDAP_BACK_F_USE_TLS )
Avlnode *conntree;
int rwm_started;
};
+typedef enum ldap_back_send_t {
+ LDAP_BACK_DONTSEND = 0x00,
+ LDAP_BACK_SENDOK = 0x01,
+ LDAP_BACK_SENDERR = 0x02,
+ LDAP_BACK_SENDRESULT = (LDAP_BACK_SENDOK|LDAP_BACK_SENDERR)
+} ldap_back_send_t;
+
LDAP_END_DECL
#include "proto-ldap.h"
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
- * This work was initially developed by the Howard Chu for inclusion
+ * This work was initially developed by Howard Chu for inclusion
* in OpenLDAP Software and subsequently enhanced by Pierangelo
* Masarati.
*/
static int
ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs );
+static int
+ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
+
int
ldap_back_bind( Operation *op, SlapReply *rs )
{
int rc = 0;
ber_int_t msgid;
- lc = ldap_back_getconn( op, rs );
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
if ( !lc ) {
- return( -1 );
+ return rs->sr_err;
}
if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
LDAP_SASL_SIMPLE,
&op->orb_cred, op->o_ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
if ( rc == LDAP_SUCCESS ) {
/* If defined, proxyAuthz will be used also when
lc->lc_bound = 1;
ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
- if ( li->savecred ) {
+ if ( li->flags & LDAP_BACK_F_SAVECRED ) {
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
return 0;
}
+static int
+ldap_back_prepare_conn( struct ldapconn **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+{
+ struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
+ int vers = op->o_protocol;
+ LDAP *ld = NULL;
+
+ assert( lcp != NULL );
+
+ rs->sr_err = ldap_initialize( &ld, li->url );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ goto error_return;
+ }
+
+ /* Set LDAP version. This will always succeed: If the client
+ * bound with a particular version, then so can we.
+ */
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
+
+ /* Set LDAP version. This will always succeed: If the client
+ * bound with a particular version, then so can we.
+ */
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+ (const void *)&vers );
+
+ /* FIXME: configurable? */
+ ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
+
+ if ( ( li->flags & LDAP_BACK_F_USE_TLS )
+ && !ldap_is_ldaps_url( li->url )
+ && ( rs->sr_err = ldap_start_tls_s( ld, NULL, NULL ) ) != LDAP_SUCCESS )
+ {
+ /* 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
+ * overlay, where the "uri" can be parsed out of a referral */
+ if ( rs->sr_err == LDAP_SERVER_DOWN
+ || ( li->flags & LDAP_BACK_F_TLS_CRITICAL ) )
+ {
+ ldap_unbind_ext_s( ld, NULL, NULL );
+ goto error_return;
+ }
+ }
+
+ if ( *lcp == NULL ) {
+ *lcp = (struct ldapconn *)ch_malloc( sizeof( struct ldapconn ) );
+ memset( *lcp, 0, sizeof( struct ldapconn ) );
+ }
+ (*lcp)->lc_ld = ld;
+
+error_return:;
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ rs->sr_err = slap_map_api2result( rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ if ( rs->sr_text == NULL ) {
+ rs->sr_text = "ldap_initialize() failed";
+ }
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ }
+
+ return rs->sr_err;
+}
+
struct ldapconn *
-ldap_back_getconn( Operation *op, SlapReply *rs )
+ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc, lc_curr;
- LDAP *ld;
int is_priv = 0;
/* Searches for a ldapconn in the avl tree */
/* Looks like we didn't get a bind. Open a new session... */
if ( !lc ) {
- int vers = op->o_protocol;
- rs->sr_err = ldap_initialize( &ld, li->url );
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- rs->sr_err = slap_map_api2result( rs );
- if ( rs->sr_text == NULL ) {
- rs->sr_text = "ldap_initialize() failed";
- }
- if ( op->o_conn ) {
- send_ldap_result( op, rs );
- }
- rs->sr_text = NULL;
- return( NULL );
+ /* lc here must be NULL */
+ if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
+ return NULL;
}
- /* Set LDAP version. This will always succeed: If the client
- * bound with a particular version, then so can we.
- */
- ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
- (const void *)&vers );
- /* FIXME: configurable? */
- ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
- lc = (struct ldapconn *)ch_malloc( sizeof( struct ldapconn ) );
lc->lc_conn = lc_curr.lc_conn;
- lc->lc_ld = ld;
ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
ldap_pvt_thread_mutex_init( &lc->lc_mutex );
/* Err could be -1 in case a duplicate ldapconn is inserted */
if ( rs->sr_err != 0 ) {
ldap_back_conn_free( lc );
- if ( op->o_conn ) {
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
send_ldap_error( op, rs, LDAP_OTHER,
"internal server error" );
}
- return( NULL );
+ return NULL;
}
} else {
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_getconn: conn %p fetched\n", (void *) lc, 0, 0 );
}
- return( lc );
+ return lc;
}
/*
* it from all the callers, and I made the function return the flag, so
* it can be used to simplify the check.
*/
-int
-ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs )
+static int
+ldap_back_dobind_int(
+ struct ldapconn *lc,
+ Operation *op,
+ SlapReply *rs,
+ ldap_back_send_t sendok,
+ int retries )
{
int rc;
ber_int_t msgid;
+ assert( retries >= 0 );
+
ldap_pvt_thread_mutex_lock( &lc->lc_mutex );
if ( !lc->lc_bound ) {
/*
goto done;
}
+retry:;
rs->sr_err = ldap_sasl_bind( lc->lc_ld,
lc->lc_bound_ndn.bv_val,
LDAP_SASL_SIMPLE, &lc->lc_cred,
NULL, NULL, &msgid );
-
- rc = ldap_back_op_result( lc, op, rs, msgid, 0 );
+
+ if ( rs->sr_err == LDAP_SERVER_DOWN ) {
+ if ( retries > 0 ) {
+ ldap_unbind_ext_s( lc->lc_ld, NULL, NULL );
+ lc->lc_ld = NULL;
+
+ /* lc here must be the regular lc, reset and ready for init */
+ if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ retries--;
+ goto retry;
+ }
+
+ ldap_back_freeconn( op, lc );
+ rs->sr_err = slap_map_api2result( rs );
+
+ return 0;
+ }
+
+ rc = ldap_back_op_result( lc, op, rs, msgid, sendok );
if ( rc == LDAP_SUCCESS ) {
lc->lc_bound = 1;
}
return rc;
}
+int
+ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
+{
+ return ldap_back_dobind_int( lc, op, rs, sendok, 1 );
+}
+
/*
* ldap_back_rebind
*
ldap_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
ber_int_t msgid, void *params )
{
- struct ldapconn *lc = params;
+ struct ldapconn *lc = (struct ldapconn *)params;
+
+ /* FIXME: add checks on the URL/identity? */
return ldap_sasl_bind_s( ld, lc->lc_bound_ndn.bv_val,
LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
int
ldap_back_op_result(
- struct ldapconn *lc,
- Operation *op,
- SlapReply *rs,
- ber_int_t msgid,
- int sendok )
+ struct ldapconn *lc,
+ Operation *op,
+ SlapReply *rs,
+ ber_int_t msgid,
+ ldap_back_send_t sendok )
{
char *match = NULL;
LDAPMessage *res = NULL;
rs->sr_matched = match;
}
}
- if ( op->o_conn && ( sendok || rs->sr_err != LDAP_SUCCESS ) ) {
+ if ( op->o_conn &&
+ ( ( sendok & LDAP_BACK_SENDOK )
+ || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
+ {
send_ldap_result( op, rs );
}
if ( match ) {
/* return true if bound, false if failed */
int
-ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs )
+ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
- struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
- int vers = op->o_protocol;
- LDAP *ld;
-
ldap_pvt_thread_mutex_lock( &lc->lc_mutex );
ldap_unbind_ext_s( lc->lc_ld, NULL, NULL );
+ lc->lc_ld = NULL;
lc->lc_bound = 0;
- rs->sr_err = ldap_initialize( &ld, li->url );
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- rs->sr_err = slap_map_api2result( rs );
- if ( rs->sr_text == NULL ) {
- rs->sr_text = "ldap_initialize() failed";
- }
- if ( op->o_conn ) {
- send_ldap_result( op, rs );
- }
- rs->sr_text = NULL;
+
+ /* lc here must be the regular lc, reset and ready for init */
+ if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
return 0;
}
- /* Set LDAP version. This will always succeed: If the client
- * bound with a particular version, then so can we.
- */
- ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
- /* FIXME: configurable? */
- ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
- lc->lc_ld = ld;
+
ldap_pvt_thread_mutex_unlock( &lc->lc_mutex );
- return ldap_back_dobind( lc, op, rs );
+ return ldap_back_dobind_int( lc, op, rs, sendok, 0 );
}
static int
goto done;
}
- rc = ldap_back_op_result( lc, op, rs, msgid, 0 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
if ( rc == LDAP_SUCCESS ) {
lc->lc_bound = 1;
}
static BackendInfo *lback;
-#if 0
-static int
-ldap_chain_chk_referrals( Operation *op, SlapReply *rs )
-{
- return LDAP_SUCCESS;
-}
-#endif
-
static int
ldap_chain_operational( Operation *op, SlapReply *rs )
{
- /* trap entries generated by back-ldap.
+ /* Trap entries generated by back-ldap.
+ *
* FIXME: we need a better way to recognize them; a cleaner
* solution would be to be able to intercept the response
* of be_operational(), so that we can divert only those
return SLAP_CB_CONTINUE;
}
+/*
+ * Search specific response that strips entryDN from entries
+ */
static int
-ldap_chain_cb_response( Operation *op, SlapReply *rs )
+ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
{
assert( op->o_tag == LDAP_REQ_SEARCH );
}
return SLAP_CB_CONTINUE;
+
+ } else if ( rs->sr_type == REP_RESULT ) {
+ /* back-ldap tried to send result */
+ op->o_callback->sc_private = (void *)(1);
}
return 0;
}
+/*
+ * Dummy response that simply traces if back-ldap tried to send
+ * anything to the client
+ */
+static int
+ldap_chain_cb_response( Operation *op, SlapReply *rs )
+{
+ if ( rs->sr_type == REP_RESULT ) {
+ op->o_callback->sc_private = (void *)(1);
+
+ } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
+ {
+ /* strip the entryDN attribute, but keep returning results */
+ (void)ldap_chain_cb_search_response( op, rs );
+ }
+
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+ldap_chain_op(
+ Operation *op,
+ SlapReply *rs,
+ int ( *op_f )( Operation *op, SlapReply *rs ),
+ BerVarray ref )
+{
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
+ int rc;
+
+ if ( lip->url != NULL ) {
+ op->o_bd->be_private = on->on_bi.bi_private;
+ return ( *op_f )( op, rs );
+ }
+
+ li = *lip;
+ op->o_bd->be_private = &li;
+
+ /* if we parse the URI then by no means
+ * we can cache stuff or reuse connections,
+ * because in back-ldap there's no caching
+ * based on the URI value, which is supposed
+ * to be set once for all (correct?) */
+ op->o_do_not_cache = 1;
+
+ for ( ; !BER_BVISNULL( ref ); ref++ ) {
+ LDAPURLDesc *srv;
+ char *save_dn;
+
+ /* We're setting the URI of the first referral;
+ * what if there are more?
+
+Document: draft-ietf-ldapbis-protocol-27.txt
+
+4.1.10. Referral
+ ...
+ If the client wishes to progress the operation, it MUST follow the
+ referral by contacting one of the supported services. If multiple
+ URIs are present, the client assumes that any supported URI may be
+ used to progress the operation.
+
+ * so we actually need to follow exactly one,
+ * and we can assume any is fine.
+ */
+
+ /* parse reference and use
+ * proto://[host][:port]/ only */
+ rc = ldap_url_parse_ext( ref->bv_val, &srv );
+ if ( rc != LDAP_URL_SUCCESS ) {
+ /* try next */
+ rc = LDAP_OTHER;
+ continue;
+ }
+
+ /* remove DN essentially because later on
+ * ldap_initialize() will parse the URL
+ * as a comma-separated URL list */
+ save_dn = srv->lud_dn;
+ srv->lud_dn = "";
+ srv->lud_scope = LDAP_SCOPE_DEFAULT;
+ li.url = ldap_url_desc2str( srv );
+ srv->lud_dn = save_dn;
+ ldap_free_urldesc( srv );
+
+ if ( li.url == NULL ) {
+ /* try next */
+ rc = LDAP_OTHER;
+ continue;
+ }
+
+ rc = ( *op_f )( op, rs );
+
+ ldap_memfree( li.url );
+ li.url = NULL;
+
+ if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
static int
ldap_chain_response( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
void *private = op->o_bd->be_private;
- slap_callback *sc = op->o_callback;
+ slap_callback *sc = op->o_callback,
+ sc2 = { 0 };
int rc = 0;
int cache = op->o_do_not_cache;
- char *authzid = NULL;
BerVarray ref;
struct berval ndn = op->o_ndn;
struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
- if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF )
+ if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
return SLAP_CB_CONTINUE;
+ }
+
+ /*
+ * TODO: add checks on who/when chain operations; e.g.:
+ * a) what identities are authorized
+ * b) what request DN (e.g. only chain requests rooted at <DN>)
+ * c) what referral URIs
+ * d) what protocol scheme (e.g. only ldaps://)
+ * e) what ssf
+ */
ref = rs->sr_ref;
rs->sr_ref = NULL;
- op->o_callback = NULL;
-
- if ( lip->url == NULL ) {
- /* if we parse the URI then by no means
- * we can cache stuff or reuse connections,
- * because in back-ldap there's no caching
- * based on the URI value, which is supposed
- * to be set once for all (correct?) */
- op->o_do_not_cache = 1;
-
- /* FIXME: we're setting the URI of the first referral;
- * what if there are more? Is this something we should
- * worry about? */
- li = *lip;
- op->o_bd->be_private = &li;
-
- if ( rs->sr_type != REP_SEARCHREF ) {
- LDAPURLDesc *srv;
- char *save_dn;
-
- /* parse reference and use
- * proto://[host][:port]/ only */
- rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
- if ( rc != LDAP_URL_SUCCESS ) {
- /* error */
- return 1;
- }
-
- /* remove DN essentially because later on
- * ldap_initialize() will parse the URL
- * as a comma-separated URL list */
- save_dn = srv->lud_dn;
- srv->lud_dn = "";
- srv->lud_scope = LDAP_SCOPE_DEFAULT;
- li.url = ldap_url_desc2str( srv );
- srv->lud_dn = save_dn;
- ldap_free_urldesc( srv );
-
- if ( li.url == NULL ) {
- /* error */
- return 1;
- }
- }
-
- } else {
- op->o_bd->be_private = on->on_bi.bi_private;
- }
+ /* we need this to know if back-ldap returned any result */
+ sc2.sc_response = ldap_chain_cb_response;
+ op->o_callback = &sc2;
/* Chaining can be performed by a privileged user on behalf
* of normal users, using the ProxyAuthz control, by exploiting
* the identity assertion feature of back-ldap; see idassert-*
* directives in slapd-ldap(5).
+ *
+ * FIXME: the idassert-authcDN is one, will it be fine regardless
+ * of the URI we obtain from the referral?
*/
switch ( op->o_tag ) {
struct berval rndn = op->o_req_ndn;
Connection *conn = op->o_conn;
+ /* FIXME: can we really get a referral for binds? */
op->o_req_ndn = slap_empty_bv;
-
op->o_conn = NULL;
- rc = lback->bi_op_bind( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
op->o_req_ndn = rndn;
op->o_conn = conn;
}
char textbuf[ SLAP_TEXT_BUFLEN ];
size_t textlen = sizeof( textbuf );
- /* global overlay; create entry */
+ /* global overlay: create entry */
/* NOTE: this is a hack to use the chain overlay
* as global. I expect to be able to remove this
* soon by using slap_mods2entry() earlier in
break;
}
}
- rc = lback->bi_op_add( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
if ( cleanup_attrs ) {
attrs_free( op->ora_e->e_attrs );
op->ora_e->e_attrs = NULL;
break;
}
case LDAP_REQ_DELETE:
- rc = lback->bi_op_delete( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
break;
case LDAP_REQ_MODRDN:
- rc = lback->bi_op_modrdn( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
break;
case LDAP_REQ_MODIFY:
- rc = lback->bi_op_modify( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
break;
case LDAP_REQ_COMPARE:
- rc = lback->bi_op_compare( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
break;
case LDAP_REQ_SEARCH:
if ( rs->sr_type == REP_SEARCHREF ) {
struct berval *curr = ref,
odn = op->o_req_dn,
ondn = op->o_req_ndn;
- slap_callback sc2 = { 0 };
- int tmprc = 0;
- ber_len_t refcnt = 0;
- BerVarray newref = NULL;
-
- sc2.sc_response = ldap_chain_cb_response;
- op->o_callback = &sc2;
rs->sr_type = REP_SEARCH;
+ sc2.sc_response = ldap_chain_cb_search_response;
+
+ li = *lip;
+ li.url = NULL;
+ op->o_bd->be_private = &li;
+
+ /* if we parse the URI then by no means
+ * we can cache stuff or reuse connections,
+ * because in back-ldap there's no caching
+ * based on the URI value, which is supposed
+ * to be set once for all (correct?) */
+ op->o_do_not_cache = 1;
+
/* copy the private info because we need to modify it */
for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
LDAPURLDesc *srv;
/* parse reference and use
* proto://[host][:port]/ only */
- tmprc = ldap_url_parse_ext( curr[0].bv_val, &srv );
- if ( tmprc != LDAP_URL_SUCCESS ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
+ rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
+ if ( rc != LDAP_URL_SUCCESS ) {
+ /* try next */
+ rs->sr_err = LDAP_OTHER;
+ continue;
}
/* remove DN essentially because later on
ldap_free_urldesc( srv );
if ( li.url == NULL ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
+ /* try next */
+ rs->sr_err = LDAP_OTHER;
+ continue;
}
/* FIXME: should we also copy filter and scope?
* according to RFC3296, no */
- tmprc = lback->bi_op_search( op, rs );
+ rc = lback->bi_op_search( op, rs );
ldap_memfree( li.url );
li.url = NULL;
op->o_tmpfree( op->o_req_ndn.bv_val,
op->o_tmpmemctx );
- if ( tmprc ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
- }
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- /* if search was not successful,
- * at least return the referral! */
- /* FIXME: assumes referrals
- * are always created via
- * referral_rewrite() and freed via
- * ber_bvarray_free( rs->sr_ref ) */
- newref = ch_realloc( newref, sizeof( struct berval ) * (refcnt + 2) );
- ber_dupbv( &newref[ refcnt ], &curr[ 0 ] );
- refcnt++;
- BER_BVZERO( &newref[ refcnt ] );
+ if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
+ break;
}
}
-end_of_searchref:;
op->o_req_dn = odn;
op->o_req_ndn = ondn;
rs->sr_type = REP_SEARCHREF;
rs->sr_entry = NULL;
- /* if the error was bad, it was already returned
- * by back-ldap; destroy the referrals left;
- * otherwise, let the frontend return them. */
- if ( newref ) {
- if ( rc == 0 ) {
- rc = SLAP_CB_CONTINUE;
- if ( ref != default_referral ) {
- ber_bvarray_free( ref );
- }
- ref = newref;
-
- } else {
- ber_bvarray_free( newref );
- }
+ if ( rc != LDAP_SUCCESS ) {
+ /* couldn't chase any of the referrals */
+ rc = SLAP_CB_CONTINUE;
}
} else {
- rc = lback->bi_op_search( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
}
break;
case LDAP_REQ_EXTENDED:
- rc = lback->bi_extended( op, rs );
+ rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
/* FIXME: ldap_back_extended() by design
* doesn't send result; frontend is expected
* to send it... */
if ( rc != SLAPD_ABANDON ) {
send_ldap_extended( op, rs );
+ rc = LDAP_SUCCESS;
}
break;
default:
rc = SLAP_CB_CONTINUE;
break;
}
+
+ if ( sc2.sc_private == NULL ) {
+ op->o_callback = NULL;
+ rc = rs->sr_err = slap_map_api2result( rs );
+ send_ldap_result( op, rs );
+ }
+
op->o_do_not_cache = cache;
op->o_bd->be_private = private;
op->o_callback = sc;
op->o_ndn = ndn;
- if ( authzid ) {
- op->o_tmpfree( authzid, op->o_tmpmemctx );
- }
rs->sr_ref = ref;
- if ( lip->url == NULL && li.url != NULL ) {
- ldap_memfree( li.url );
- }
return rc;
}
BackendDB *be
)
{
- slap_overinst *on = (slap_overinst *) be->bd_info;
- void *private = be->be_private;
- int rc;
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ int rc;
+ BackendDB bd = *be;
if ( lback == NULL ) {
lback = backend_info( "ldap" );
}
}
- be->be_private = NULL;
- rc = lback->bi_db_init( be );
- on->on_bi.bi_private = be->be_private;
- be->be_private = private;
+ bd.be_private = NULL;
+ rc = lback->bi_db_init( &bd );
+ on->on_bi.bi_private = bd.be_private;
return rc;
}
ldapchain.on_response = ldap_chain_response;
-#if 0
- ldapchain.on_bi.bi_chk_referrals = ldap_chain_chk_referrals;
-#endif
-
return overlay_register( &ldapchain );
}
LDAPControl **ctrls = NULL;
int rc = LDAP_SUCCESS;
- lc = ldap_back_getconn( op, rs );
- if (!lc || !ldap_back_dobind( lc, op, rs ) ) {
- rc = -1;
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto cleanup;
}
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
- rc = -1;
goto cleanup;
}
op->orc_ava->aa_desc->ad_cname.bv_val,
&op->orc_ava->aa_value,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
- if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
+ if ( rc == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry(lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
cleanup:
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
- return rc;
+ return rs->sr_err;
}
li->url = ch_strdup( argv[ 1 ] );
#endif
+ /* start tls */
+ } else if ( strcasecmp( argv[0], "start-tls" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: start-tls takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags |= LDAP_BACK_F_TLS_CRITICAL;
+
+ /* try start tls */
+ } else if ( strcasecmp( argv[0], "try-start-tls" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: try-start-tls takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
+ li->flags |= LDAP_BACK_F_USE_TLS;
+
/* name to use for ldap_back_group */
} else if ( strcasecmp( argv[0], "acl-authcdn" ) == 0
|| strcasecmp( argv[0], "binddn" ) == 0 )
fname, lineno );
return( 1 );
}
- li->savecred = 1;
+ li->flags |= LDAP_BACK_F_SAVECRED;
/* intercept exop_who_am_i? */
} else if ( strcasecmp( argv[0], "proxy-whoami" ) == 0 ) {
ctrls[0] = &c;
op2.o_ndn = op->o_conn->c_ndn;
- lc = ldap_back_getconn(&op2, rs);
- if (!lc || !ldap_back_dobind( lc, op, rs )) {
+ lc = ldap_back_getconn(&op2, rs, LDAP_BACK_SENDERR);
+ if (!lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR )) {
return -1;
}
c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
&rs->sr_err);
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry( lc, op, rs ) )
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) )
goto retry;
}
ldap_back_freeconn( op, lc );
int do_retry = 1;
int rc = LDAP_SUCCESS;
- lc = ldap_back_getconn( op, rs );
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
rc = -1;
goto cleanup;
}
retry:
rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_ndn.bv_val,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry (lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
* called twice; maybe we could avoid the
* ldap_back_dobind() call inside each extended()
* call ... */
- lc = ldap_back_getconn( op, rs );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
int rc, isproxy;
int do_retry = 1;
- lc = ldap_back_getconn( op, rs );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry(lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
/* FIXME: disabled because namingContexts doesn't have
* a matching rule, and using an MRA filter doesn't work
* because the normalized assertion is compared to the
- * non-normalized value, which in general differ.
- * See ITS#3406 */
+ * non-normalized value, which in general differs from
+ * the normalized one. See ITS#3406 */
struct berval filter,
- base = BER_BVC( "cn=Databases,cn=Monitor" );
+ base = BER_BVC( "cn=Databases," SLAPD_MONITOR );
struct berval vals[ 2 ];
Attribute a = { 0 };
int do_retry = 1;
LDAPControl **ctrls = NULL;
- lc = ldap_back_getconn( op, rs );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
return -1;
}
retry:
rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_ndn.bv_val, modv,
ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry(lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
int rc = LDAP_SUCCESS;
char *newSup = NULL;
- lc = ldap_back_getconn( op, rs );
- if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
return( -1 );
}
rs->sr_err = ldap_rename( lc->lc_ld, op->o_req_ndn.bv_val,
op->orr_newrdn.bv_val, newSup,
op->orr_deleteoldrdn, ctrls, NULL, &msgid );
- rc = ldap_back_op_result( lc, op, rs, msgid, 1 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry( lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
extern BI_entry_get_rw ldap_back_entry_get;
int ldap_back_freeconn( Operation *op, struct ldapconn *lc );
-struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs);
-int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs);
-int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs);
+struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs, ldap_back_send_t sendok);
+int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok);
+int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok);
int ldap_back_map_result(SlapReply *rs);
int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs,
- ber_int_t msgid, int sendok);
+ ber_int_t msgid, ldap_back_send_t sendok);
int back_ldap_LTX_init_module(int argc, char *argv[]);
extern int ldap_back_conn_cmp( const void *c1, const void *c2);
int do_retry = 1;
LDAPControl **ctrls = NULL;
- lc = ldap_back_getconn( op, rs );
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
if ( !lc ) {
- return -1;
+ return rs->sr_err;
}
/*
* FIXME: in case of values return filter, we might want
* to map attrs and maybe rewrite value
*/
- if ( !ldap_back_dobind( lc, op, rs ) ) {
- return -1;
+ if ( !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
/* should we check return values? */
if ( rs->sr_err != LDAP_SUCCESS ) {
fail:;
- rc = ldap_back_op_result( lc, op, rs, msgid, 0 );
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
if ( freeconn ) {
ldap_back_freeconn( op, lc );
lc = NULL;
if ( rc == -1 ) {
if ( do_retry ) {
do_retry = 0;
- if ( ldap_back_retry( lc, op, rs ) ) {
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
goto retry;
}
}
*e = NULL;
char *gattr[3];
char *filter = NULL;
- Connection *oconn;
SlapReply rs;
int do_retry = 1;
LDAPControl **ctrls = NULL;
/* Tell getconn this is a privileged op */
do_not_cache = op->o_do_not_cache;
op->o_do_not_cache = 1;
- lc = ldap_back_getconn( op, &rs );
- oconn = op->o_conn;
- op->o_conn = NULL;
- if ( !lc || !ldap_back_dobind( lc, op, &rs ) ) {
+ lc = ldap_back_getconn( op, &rs, LDAP_BACK_DONTSEND );
+ if ( !lc || !ldap_back_dobind( lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
op->o_do_not_cache = do_not_cache;
- op->o_conn = oconn;
- return 1;
+ return rs.sr_err;
}
op->o_do_not_cache = do_not_cache;
- op->o_conn = oconn;
if ( at ) {
if ( oc && at != slap_schema.si_ad_objectClass ) {
if ( rc != LDAP_SUCCESS ) {
if ( rc == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
- if ( ldap_back_retry( lc, op, &rs ) ) {
+ if ( ldap_back_retry( lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
goto retry;
}
}
#define META_BIND_NRETRIES 3
#define META_BIND_TIMEOUT 1000
-int ldap_back_freeconn( Operation *op, struct ldapconn *lc );
-struct ldapconn *ldap_back_getconn(struct slap_op *op, struct slap_rep *rs);
-int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs);
-int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs);
-int ldap_back_map_result(SlapReply *rs);
-int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs,
- ber_int_t msgid, int sendok);
-int back_ldap_LTX_init_module(int argc, char *argv[]);
-
int ldap_back_dn_massage(dncookie *dc, struct berval *dn,
struct berval *res);
facsimileTelephoneNumber: +1 313 555 7762
telephoneNumber: +1 313 555 4177
+dn: ou=Other,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Other
+
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
objectClass: extensibleObject
facsimileTelephoneNumber: +1 313 555 7762
telephoneNumber: +1 313 555 4177
+dn: ou=Other,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Other
+
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
objectClass: extensibleObject
--- /dev/null
+dn: ou=Other,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Other
+
ou: Groups
ref: @URI2@ou=Groups,dc=example,dc=com
+dn: ou=Other,dc=example,dc=com
+objectclass: referral
+objectclass: extensibleobject
+ou: Other
+# invalid URI first to test failover capabilities (search only)
+ref: @URI3@ou=Other,dc=example,dc=com
+ref: @URI2@ou=Other,dc=example,dc=com
+
dn: ou=Alumni Association,ou=People,dc=example,dc=com
objectclass: organizationalUnit
ou: Alumni Association
sn: Manager
description: Manager of the directory
userpassword:: c2VjcmV0
+
+dn: ou=Other,dc=example,dc=com
+objectclass: organizationalUnit
+ou: Other
+
LDAPGLUEANONYMOUSOUT=$DATADIR/ldapglueanonymous.out
RELAYOUT=$DATADIR/relay.out
CHAINOUT=$DATADIR/chain.out
+CHAINREFOUT=$DATADIR/chainref.out
CHAINMODOUT=$DATADIR/chainmod.out
SQLREAD=$DATADIR/sql-read.out
SQLWRITE=$DATADIR/sql-write.out
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
+
+ echo "Reading the referral entry "ou=Other,$BASEDN" as anonymous on port $P..."
+ $LDAPSEARCH -h $LOCALHOST -p $P -b "ou=Other,$BASEDN" -S "" \
+ > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ . $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ . $LDIFFILTER < $CHAINREFOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - chained search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
done
#