📄 bind.c
字号:
if ( lc == NULL ) { return 0; } *lcp = lc; } else { lc = *lcp; } assert( lc != NULL );retry_lock:; if ( dolock ) { ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); } if ( binding == 0 ) { /* check if already bound */ rc = isbound = LDAP_BACK_CONN_ISBOUND( lc ); if ( isbound ) { if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } return rc; } if ( LDAP_BACK_CONN_BINDING( lc ) ) { /* if someone else is about to bind it, give up and retry */ if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } ldap_pvt_thread_yield(); goto retry_lock; } else { /* otherwise this thread will bind it */ LDAP_BACK_CONN_BINDING_SET( lc ); binding = 1; } } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } /* * FIXME: we need to let clients use proxyAuthz * otherwise we cannot do symmetric pools of servers; * we have to live with the fact that a user can * authorize itself as any ID that is allowed * by the authzTo directive of the "proxyauthzdn". */ /* * NOTE: current Proxy Authorization specification * and implementation do not allow proxy authorization * control to be provided with Bind requests */ /* * if no bind took place yet, but the connection is bound * and the "idassert-authcDN" (or other ID) is set, * then bind as the asserting identity and explicitly * add the proxyAuthz control to every operation with the * dn bound to the connection as control value. * This is done also if this is the authrizing backend, * but the "override" flag is given to idassert. * It allows to use SASL bind and yet proxyAuthz users */ if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) { if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) { /* if we got here, it shouldn't return result */ rc = ldap_back_is_proxy_authz( op, rs, LDAP_BACK_DONTSEND, &binddn, &bindcred ); assert( rc == 1 ); } rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred ); goto done; }#ifdef HAVE_CYRUS_SASL if ( LDAP_BACK_CONN_ISPRIV( lc ) && li->li_acl_authmethod == LDAP_AUTH_SASL ) { void *defaults = NULL; if ( li->li_acl_secprops != NULL ) { rc = ldap_set_option( lc->lc_ld, LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops ); if ( rc != LDAP_OPT_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option " "(SECPROPS,\"%s\") failed!\n", li->li_acl_secprops, 0, 0 ); goto done; } } defaults = lutil_sasl_defaults( lc->lc_ld, li->li_acl_sasl_mech.bv_val, li->li_acl_sasl_realm.bv_val, li->li_acl_authcID.bv_val, li->li_acl_passwd.bv_val, NULL ); rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, li->li_acl_authcDN.bv_val, li->li_acl_sasl_mech.bv_val, NULL, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); lutil_sasl_freedefs( defaults ); rs->sr_err = slap_map_api2result( rs ); if ( rs->sr_err != LDAP_SUCCESS ) { LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } } else { LDAP_BACK_CONN_ISBOUND_SET( lc ); } if ( LDAP_BACK_QUARANTINE( li ) ) { ldap_back_quarantine( op, rs ); } goto done; }#endif /* HAVE_CYRUS_SASL */retry:; rs->sr_err = ldap_sasl_bind( lc->lc_ld, BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val, LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, &msgid ); if ( rs->sr_err == LDAP_SERVER_DOWN ) { if ( retries != LDAP_BACK_RETRY_NEVER ) { if ( dolock ) { ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); } assert( lc->lc_refcnt > 0 ); if ( lc->lc_refcnt == 1 ) { ldap_unbind_ext( lc->lc_ld, NULL, NULL ); lc->lc_ld = NULL; /* lc here must be the regular lc, reset and ready for init */ rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok ); if ( rs->sr_err != LDAP_SUCCESS ) { sendok &= ~LDAP_BACK_SENDERR; lc->lc_refcnt = 0; } } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } if ( rs->sr_err == LDAP_SUCCESS ) { if ( retries > 0 ) { retries--; } goto retry; } } assert( lc->lc_refcnt == 1 ); lc->lc_refcnt = 0; ldap_back_freeconn( li, lc, dolock ); *lcp = NULL; rs->sr_err = slap_map_api2result( rs ); if ( LDAP_BACK_QUARANTINE( li ) ) { ldap_back_quarantine( op, rs ); } if ( rs->sr_err != LDAP_SUCCESS && ( sendok & LDAP_BACK_SENDERR ) ) { rs->sr_text = "Internal proxy bind failure"; send_ldap_result( op, rs ); } return 0; } rc = ldap_back_op_result( lc, op, rs, msgid, -1, ( sendok | LDAP_BACK_BINDING ) ); if ( rc == LDAP_SUCCESS ) { LDAP_BACK_CONN_ISBOUND_SET( lc ); }done:; LDAP_BACK_CONN_BINDING_CLEAR( lc ); rc = LDAP_BACK_CONN_ISBOUND( lc ); if ( !rc ) { ldap_back_release_conn_lock( li, lcp, dolock ); } else if ( LDAP_BACK_SAVECRED( li ) ) { ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); } return rc;}/* * ldap_back_dobind * * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not */intldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; return ldap_back_dobind_int( lcp, op, rs, ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );}/* * ldap_back_default_rebind * * This is a callback used for chasing referrals using the same * credentials as the original user on this session. */int ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *params ){ ldapconn_t *lc = (ldapconn_t *)params;#ifdef HAVE_TLS /* ... otherwise we couldn't get here */ assert( lc != NULL ); if ( !ldap_tls_inplace( ld ) ) { int is_tls = LDAP_BACK_CONN_ISTLS( lc ), rc; const char *text = NULL; rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags, LDAP_BACK_RETRY_DEFAULT, &text ); if ( rc != LDAP_SUCCESS ) { return rc; } }#endif /* HAVE_TLS */ /* FIXME: add checks on the URL/identity? */ return ldap_sasl_bind_s( ld, BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val, LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );}intldap_back_cancel( ldapconn_t *lc, Operation *op, SlapReply *rs, ber_int_t msgid, ldap_back_send_t sendok ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; /* default behavior */ if ( LDAP_BACK_ABANDON( li ) ) { return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); } if ( LDAP_BACK_CANCEL( li ) ) { /* FIXME: asynchronous? */ return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL ); } assert( 0 ); return LDAP_OTHER;}intldap_back_op_result( ldapconn_t *lc, Operation *op, SlapReply *rs, ber_int_t msgid, time_t timeout, ldap_back_send_t sendok ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; char *match = NULL; char *text = NULL; char **refs = NULL; LDAPControl **ctrls = NULL;#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE) rs->sr_text = NULL; rs->sr_matched = NULL; rs->sr_ref = NULL; rs->sr_ctrls = NULL; /* if the error recorded in the reply corresponds * to a successful state, get the error from the * remote server response */ if ( 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 = li->li_timeout[ opidx ]; } } /* better than nothing :) */ if ( timeout == 0 ) { if ( li->li_idle_timeout ) { timeout = li->li_idle_timeout; } else if ( li->li_conn_ttl ) { timeout = li->li_conn_ttl; } } if ( timeout ) { stoptime = op->o_time + timeout; } LDAP_BACK_TV_SET( &tv );retry:; /* if result parsing fails, note the failure reason */ rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: if ( timeout && slap_get_time() > stoptime ) { if ( sendok & LDAP_BACK_BINDING ) { ldap_unbind_ext( lc->lc_ld, NULL, NULL ); lc->lc_ld = NULL; /* let it be used, but taint/delete it so that * no-one else can look it up any further */ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );#if LDAP_BACK_PRINT_CONNTREE > 0 ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );#endif /* LDAP_BACK_PRINT_CONNTREE */ (void)ldap_back_conn_delete( li, lc ); LDAP_BACK_CONN_TAINTED_SET( lc );#if LDAP_BACK_PRINT_CONNTREE > 0 ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );#endif /* LDAP_BACK_PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } else { (void)ldap_back_cancel( lc, op, rs, msgid, sendok ); } rs->sr_err = timeout_err; rs->sr_text = timeout_text; break; } /* timeout == 0 */ LDAP_BACK_TV_SET( &tv ); ldap_pvt_thread_yield(); goto retry; case -1: ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &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 ( li->li_idle_timeout && lc ) { lc->lc_time = op->o_time; } rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, &match, &text, &refs, &ctrls, 1 ); rs->sr_text = text; if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } if ( refs != NULL ) { 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 ] ); } if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } } } /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ if ( !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 && match ) { /* record the (massaged) matched * DN into the reply structure */ rs->sr_matched = match; } } if ( rs->sr_err == LDAP_UNAVAILABLE ) { if ( !( sendok & LDAP_BACK_RETRYING ) ) { if ( LDAP_BACK_QUARANTINE( li ) ) { ldap_back_quarantine( op, rs ); } 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 ) && ERR_OK( rs->sr_err ) ) || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) { send_ldap_result( op, rs ); } if ( match ) { if ( rs->sr_matched != match ) { free( (char *)rs->sr_matched ); } rs->sr_matched = NULL; ldap_memfree( match ); } if ( text ) { ldap_memfree( text ); } rs->sr_text = NULL; if ( rs->sr_ref ) { assert( refs != NULL ); ber_memvfree( (void **)refs ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); ldap_controls_free( ctrls ); rs->sr_ctrls = NULL; } return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );}/* return true if bound, false if failed */intldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; int rc = 0; assert( lcp != NULL ); assert( *lcp != NULL ); ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); if ( (*lcp)->lc_refcnt == 1 ) { int binding = LDAP_BACK_CONN_BINDING( *lcp ); ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); Debug( LDAP_DEBUG_ANY, "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n", op->o_log_prefix, li->li_uri, BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ? "" : (*lcp)->lc_bound_ndn.bv_val ); ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL ); (*lcp)->lc_ld = NULL; LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) ); /* lc here must be the regular lc, reset and ready for init */ rc = ldap_back_prepare_conn( *lcp, op, rs, sendok ); if ( rc != LDAP_SUCCESS ) { /* freeit, because lc_refcnt == 1 */ (*lcp)->lc_refcnt = 0; (void)ldap_back_freeconn( li, *lcp, 0 ); *lcp = NULL; rc = 0; } else if ( ( sendok & LDAP_BACK_BINDING ) ) { if ( binding ) { LDAP_BACK_CONN_BINDING_SET( *lcp ); } rc = 1; } else { rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 ); if ( rc == 0 && *lcp != NULL ) { /* freeit, because lc_refcnt == 1 */ (*lcp)->lc_refcnt = 0; LDAP_BACK_CONN_TAINTED_SET( *lcp ); (void)ldap_back_freeconn( li, *lcp, 0 ); *lcp = NULL; } } } else { Debug( LDAP_DEBUG_TRACE, "ldap_back_retry: conn %p refcnt=%u unable to retry.\n", (void *)(*lcp), (*lcp)->lc_refcnt, 0 ); LDAP_BACK_CONN_TAINTED_SET( *lcp ); ldap_back_release_conn_lock( li, lcp, 0 ); assert( *lcp == NULL ); if ( sendok & LDAP_BACK_SENDERR ) { rs->sr_err = LDAP_UNAVAILABLE; rs->sr_text = "Unable to retry"; send_ldap_result( op, rs ); } } ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); return rc;}static intldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; struct berval ndn; int dobind = 0; if ( op->o_conn == NULL || op->o_do_not_cache ) { goto done; } /* don't proxyAuthz if protocol is not LDAPv3 */ switch ( li->li_version ) { case LDAP_VERSION3: break; case 0: if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { break; } /* fall thru */ default: rs->sr_err = LDAP_UNWILLING_TO_PERFORM; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); dobind = -1; } goto done; } /* safe default */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -