From 277d921945f4532246f31e0af4045fe071d8ae9a Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sun, 4 Jul 2004 23:35:18 +0000 Subject: [PATCH] clear shared connections when ldap_result fails with -1 (typically, remote server is down); fixes ITS#3217 --- servers/slapd/back-ldap/back-ldap.h | 1 + servers/slapd/back-ldap/bind.c | 22 ++++++++-- servers/slapd/back-ldap/config.c | 3 ++ servers/slapd/back-ldap/extended.c | 3 ++ servers/slapd/back-ldap/search.c | 63 ++++++++++++++++++----------- 5 files changed, 65 insertions(+), 27 deletions(-) diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 55358621b0..4420322286 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -164,6 +164,7 @@ typedef struct dncookie { #endif } dncookie; +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_map_result(SlapReply *rs); diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index c11d87f5a8..5d21a3c581 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -209,6 +209,20 @@ static void myprint( Avlnode *root ) } #endif /* PRINT_CONNTREE */ +int +ldap_back_freeconn( Operation *op, struct ldapconn *lc ) +{ + struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; + + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + lc = avl_delete( &li->conntree, (caddr_t)lc, + ldap_back_conn_cmp ); + ldap_back_conn_free( (void *)lc ); + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + + return 0; +} + struct ldapconn * ldap_back_getconn(Operation *op, SlapReply *rs) { @@ -645,16 +659,16 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, if ( ERR_OK( rs->sr_err ) ) { /* if result parsing fails, note the failure reason */ if ( ldap_result( lc->ld, msgid, 1, NULL, &res ) == -1 ) { - ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, - &rs->sr_err); + ldap_get_option( lc->ld, LDAP_OPT_ERROR_NUMBER, + &rs->sr_err ); /* otherwise get the result; if it is not * LDAP_SUCCESS, record it in the reply * structure (this includes * LDAP_COMPARE_{TRUE|FALSE}) */ } else { - int rc = ldap_parse_result(lc->ld, res, &rs->sr_err, - &match, &text, NULL, NULL, 1); + int rc = ldap_parse_result( lc->ld, res, &rs->sr_err, + &match, &text, NULL, NULL, 1 ); rs->sr_text = text; if ( rc != LDAP_SUCCESS ) rs->sr_err = rc; } diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 44167c6a76..88467b3f35 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -501,6 +501,9 @@ ldap_back_exop_whoami( if (ldap_result(lc->ld, msgid, 1, NULL, &res) == -1) { ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err); + ldap_back_freeconn( op, lc ); + lc = NULL; + } else { rs->sr_err = ldap_parse_whoami(lc->ld, res, &bv); ldap_msgfree(res); diff --git a/servers/slapd/back-ldap/extended.c b/servers/slapd/back-ldap/extended.c index 6f35c898a2..ecd6f4dcaf 100644 --- a/servers/slapd/back-ldap/extended.c +++ b/servers/slapd/back-ldap/extended.c @@ -145,6 +145,9 @@ ldap_back_exop_passwd( if (rc == LDAP_SUCCESS) { if (ldap_result(lc->ld, msgid, 1, NULL, &res) == -1) { ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &rc); + ldap_back_freeconn( op, lc ); + lc = NULL; + } else { /* sigh. parse twice, because parse_passwd doesn't give * us the err / match / msg info. diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 7fc6cefc81..f2c552bc16 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -58,6 +58,7 @@ ldap_back_search( struct berval mbase; struct berval mfilter = BER_BVNULL; int dontfreetext = 0; + int freeconn = 0; dncookie dc; LDAPControl **ctrls = NULL; @@ -75,11 +76,14 @@ ldap_back_search( } /* should we check return values? */ - if (op->ors_deref != -1) - ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->ors_deref); - if (op->ors_tlimit != SLAP_NO_LIMIT) { + if ( op->ors_deref != -1 ) { + ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->ors_deref ); + } + + if ( op->ors_tlimit != SLAP_NO_LIMIT ) { tv.tv_sec = op->ors_tlimit; tv.tv_usec = 0; + } else { tv.tv_sec = 0; } @@ -125,7 +129,7 @@ ldap_back_search( rs->sr_err = ldap_back_map_attrs( &li->rwmap.rwm_at, op->ors_attrs, BACKLDAP_MAP, &mapped_attrs ); - if ( rs->sr_err ) { + if ( rs->sr_err != LDAP_SUCCESS ) { rc = -1; goto finish; } @@ -139,7 +143,7 @@ ldap_back_search( } #endif /* LDAP_BACK_PROXY_AUTHZ */ - rs->sr_err = ldap_search_ext(lc->ld, mbase.bv_val, + rs->sr_err = ldap_search_ext( lc->ld, mbase.bv_val, op->ors_scope, mfilter.bv_val, mapped_attrs, op->ors_attrsonly, ctrls, NULL, @@ -148,7 +152,11 @@ ldap_back_search( 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, 0 ); + if ( freeconn ) { + ldap_back_freeconn( op, lc ); + lc = NULL; + } goto finish; } @@ -157,27 +165,28 @@ fail:; * but this is necessary for version matching, and for ACL processing. */ - for ( rc=0; rc != -1; rc = ldap_result(lc->ld, msgid, 0, &tv, &res)) + for ( rc = 0; rc != -1; rc = ldap_result( lc->ld, msgid, 0, &tv, &res ) ) { /* check for abandon */ - if (op->o_abandon) { - ldap_abandon(lc->ld, msgid); + if ( op->o_abandon ) { + ldap_abandon( lc->ld, msgid ); rc = 0; goto finish; } - if (rc == 0) { + if ( rc == 0 ) { tv.tv_sec = 0; tv.tv_usec = 100000; ldap_pvt_thread_yield(); - } else if (rc == LDAP_RES_SEARCH_ENTRY) { + } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { Entry ent = {0}; struct berval bdn; int abort = 0; - e = ldap_first_entry(lc->ld,res); - if ( ( rc = ldap_build_entry(op, e, &ent, &bdn, - LDAP_BUILD_ENTRY_PRIVATE)) == LDAP_SUCCESS ) { + e = ldap_first_entry( lc->ld, res ); + rc = ldap_build_entry( op, e, &ent, &bdn, + LDAP_BUILD_ENTRY_PRIVATE ); + if ( rc == LDAP_SUCCESS ) { rs->sr_entry = &ent; rs->sr_attrs = op->ors_attrs; rs->sr_flags = 0; @@ -190,10 +199,12 @@ fail:; ent.e_attrs = a->a_next; v = a->a_vals; - if (a->a_vals != &dummy) + if ( a->a_vals != &dummy ) { ber_bvarray_free(a->a_vals); - if (a->a_nvals != v) + } + if ( a->a_nvals != v ) { ber_bvarray_free(a->a_nvals); + } ch_free(a); } @@ -202,9 +213,9 @@ fail:; if ( ent.e_ndn ) free( ent.e_ndn ); } - ldap_msgfree(res); + ldap_msgfree( res ); if ( abort ) { - ldap_abandon(lc->ld, msgid); + ldap_abandon( lc->ld, msgid ); goto finish; } @@ -249,18 +260,24 @@ fail:; } } else { - rc = ldap_parse_result(lc->ld, res, &rs->sr_err, + rc = ldap_parse_result( lc->ld, res, &rs->sr_err, &match.bv_val, (char **)&rs->sr_text, - NULL, NULL, 1); - if (rc != LDAP_SUCCESS ) rs->sr_err = rc; + NULL, NULL, 1 ); + if (rc != LDAP_SUCCESS ) { + rs->sr_err = rc; + } rs->sr_err = slap_map_api2result( rs ); rc = 0; break; } } - if (rc == -1) + if ( rc == -1 ) { + /* FIXME: invalidate the connection? */ + rs->sr_err = LDAP_SERVER_DOWN; + freeconn = 1; goto fail; + } /* * Rewrite the matched portion of the search base, if required @@ -275,7 +292,7 @@ fail:; dc.normalized = 0; #endif match.bv_len = strlen( match.bv_val ); - ldap_back_dn_massage(&dc, &match, &mdn); + ldap_back_dn_massage( &dc, &match, &mdn ); rs->sr_matched = mdn.bv_val; } if ( rs->sr_v2ref ) { -- 2.39.5