📄 bind.c
字号:
int is_tls = op->o_conn->c_is_tls; time_t lc_time = (time_t)(-1);#endif /* HAVE_TLS */ ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); rs->sr_err = ldap_initialize( &ld, li->li_uri ); ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 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. */ if ( li->li_version != 0 ) { version = li->li_version; } else if ( op->o_protocol != 0 ) { version = op->o_protocol; } else { /* assume it's an internal op; set to LDAPv3 */ version = LDAP_VERSION3; } ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version ); /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); if ( li->li_network_timeout > 0 ) { struct timeval tv; tv.tv_sec = li->li_network_timeout; tv.tv_usec = 0; ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv ); }#ifdef HAVE_TLS ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls, li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text ); ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); if ( rs->sr_err != LDAP_SUCCESS ) { ldap_unbind_ext( ld, NULL, NULL ); rs->sr_text = "Start TLS failed"; goto error_return; } else if ( li->li_idle_timeout ) { /* only touch when activity actually took place... */ lc_time = op->o_time; }#endif /* HAVE_TLS */ lc->lc_ld = ld; lc->lc_refcnt = 1;#ifdef HAVE_TLS if ( is_tls ) { LDAP_BACK_CONN_ISTLS_SET( lc ); } else { LDAP_BACK_CONN_ISTLS_CLEAR( lc ); } if ( lc_time != (time_t)(-1) ) { lc->lc_time = lc_time; }#endif /* HAVE_TLS */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 = "Proxy connection initialization failed"; } send_ldap_result( op, rs ); } } else { if ( li->li_conn_ttl > 0 ) { lc->lc_create_time = op->o_time; } } return rs->sr_err;}static ldapconn_t *ldap_back_getconn( 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; ldapconn_t *lc = NULL, lc_curr = { 0 }; int refcnt = 1, lookupconn = !( sendok & LDAP_BACK_BINDING ); /* if the server is quarantined, and * - the current interval did not expire yet, or * - no more retries should occur, * don't return the connection */ if ( li->li_isquarantined ) { slap_retry_info_t *ri = &li->li_quarantine; int dont_retry = 1; if ( li->li_quarantine.ri_interval ) { ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex ); if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) { dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] ); if ( !dont_retry ) { Debug( LDAP_DEBUG_ANY, "%s: ldap_back_getconn quarantine " "retry block #%d try #%d.\n", op->o_log_prefix, ri->ri_idx, ri->ri_count ); li->li_isquarantined = LDAP_BACK_FQ_RETRYING; } } ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex ); } if ( dont_retry ) { rs->sr_err = LDAP_UNAVAILABLE; if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { rs->sr_text = "Target is quarantined"; send_ldap_result( op, rs ); } return NULL; } } /* Internal searches are privileged and shared. So is root. */ if ( op->o_do_not_cache || be_isroot( op ) ) { LDAP_BACK_CONN_ISPRIV_SET( &lc_curr ); lc_curr.lc_local_ndn = op->o_bd->be_rootndn; LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op ); } else { struct berval tmpbinddn, tmpbindcred, save_o_dn, save_o_ndn; int isproxyauthz; /* need cleanup */ if ( binddn == NULL ) { binddn = &tmpbinddn; } if ( bindcred == NULL ) { bindcred = &tmpbindcred; } if ( op->o_tag == LDAP_REQ_BIND ) { save_o_dn = op->o_dn; save_o_ndn = op->o_ndn; op->o_dn = op->o_req_dn; op->o_ndn = op->o_req_ndn; } isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred ); if ( isproxyauthz == -1 ) { return NULL; } if ( op->o_tag == LDAP_REQ_BIND ) { op->o_dn = save_o_dn; op->o_ndn = save_o_ndn; } lc_curr.lc_local_ndn = op->o_ndn; /* Explicit binds must not be shared; * however, explicit binds are piped in a special connection * when idassert is to occur with "override" set */ if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) { lc_curr.lc_conn = op->o_conn; } else { if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) { lc_curr.lc_local_ndn = *binddn; LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op ); LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr ); } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) { lc_curr.lc_local_ndn = slap_empty_bv; LDAP_BACK_PCONN_BIND_SET( &lc_curr, op ); LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr ); lookupconn = 1; } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) { lc_curr.lc_conn = op->o_conn; } else { LDAP_BACK_PCONN_ANON_SET( &lc_curr, op ); } } } /* Explicit Bind requests always get their own conn */ if ( lookupconn ) {retry_lock: ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) { /* lookup a conn that's not binding */ LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv, lc_q ) { if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) { break; } } if ( lc != NULL ) { if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, ldapconn_t, lc_q ) ) { LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q ); LDAP_TAILQ_ENTRY_INIT( lc, lc_q ); LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q ); } } else if ( !LDAP_BACK_USE_TEMPORARIES( li ) && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max ) { lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv ); } } else { /* Searches for a ldapconn in the avl tree */ lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conndn_cmp ); } if ( lc != NULL ) { /* Don't reuse connections while they're still binding */ if ( LDAP_BACK_CONN_BINDING( lc ) ) { if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_lock; } lc = NULL; } if ( lc != NULL ) { if ( op->o_tag == LDAP_REQ_BIND ) { /* right now, this is the only possible case */ assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ); LDAP_BACK_CONN_BINDING_SET( lc ); } refcnt = ++lc->lc_refcnt; } } ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } /* Looks like we didn't get a bind. Open a new session... */ if ( lc == NULL ) { lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) ); lc->lc_flags = li->li_flags; lc->lc_lcflags = lc_curr.lc_lcflags; if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) { ch_free( lc ); return NULL; } if ( sendok & LDAP_BACK_BINDING ) { LDAP_BACK_CONN_BINDING_SET( lc ); } lc->lc_conn = lc_curr.lc_conn; ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn ); /* * the rationale is: connections as the rootdn are privileged, * so acl_authcDN is to be used; however, in some cases * one already configured identity assertion with a highly * privileged idassert_authcDN, so if acl_authcDN is NULL * and idassert_authcDN is not, use the second instead. * * might change in the future, because it's preferable * to make clear what identity is being used, since * the only drawback is that one risks to configure * the same identity twice... */ if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) { if ( BER_BVISNULL( &li->li_acl_authcDN ) && !BER_BVISNULL( &li->li_idassert_authcDN ) ) { ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN ); ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd ); } else { ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN ); ber_dupbv( &lc->lc_cred, &li->li_acl_passwd ); } LDAP_BACK_CONN_ISPRIV_SET( lc ); } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) { if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) { ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN ); ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd ); } LDAP_BACK_CONN_ISIDASSERT_SET( lc ); } else { BER_BVZERO( &lc->lc_cred ); BER_BVZERO( &lc->lc_bound_ndn ); if ( !BER_BVISEMPTY( &op->o_ndn ) && SLAP_IS_AUTHZ_BACKEND( op ) ) { ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn ); } }#ifdef HAVE_TLS /* if start TLS failed but it was not mandatory, * check if the non-TLS connection was already * in cache; in case, destroy the newly created * connection and use the existing one */ if ( LDAP_BACK_PCONN_ISTLS( lc ) && !ldap_tls_inplace( lc->lc_ld ) ) { ldapconn_t *tmplc = NULL; int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1; ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); LDAP_TAILQ_FOREACH( tmplc, &li->li_conn_priv[ idx ].lic_priv, lc_q ) { if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) { break; } } if ( tmplc != NULL ) { refcnt = ++tmplc->lc_refcnt; ldap_back_conn_free( lc ); lc = tmplc; } ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); if ( tmplc != NULL ) { goto done; } }#endif /* HAVE_TLS */ /* Inserts the newly created ldapconn in the avl tree */ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); assert( lc->lc_refcnt == 1 );#if LDAP_BACK_PRINT_CONNTREE > 0 ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );#endif /* LDAP_BACK_PRINT_CONNTREE */ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) { if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) { LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q ); li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++; LDAP_BACK_CONN_CACHED_SET( lc ); } else { LDAP_BACK_CONN_TAINTED_SET( lc ); } rs->sr_err = 0; } else { rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conndn_cmp, ldap_back_conndn_dup ); LDAP_BACK_CONN_CACHED_SET( lc ); }#if LDAP_BACK_PRINT_CONNTREE > 0 ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );#endif /* LDAP_BACK_PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); if ( StatslogTest( LDAP_DEBUG_TRACE ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "lc=%p inserted refcnt=%u rc=%d", (void *)lc, refcnt, rs->sr_err ); Debug( LDAP_DEBUG_TRACE, "=>ldap_back_getconn: %s: %s\n", op->o_log_prefix, buf, 0 ); } if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) { /* Err could be -1 in case a duplicate ldapconn is inserted */ switch ( rs->sr_err ) { case 0: break; case -1: LDAP_BACK_CONN_CACHED_CLEAR( lc ); if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) { /* duplicate: free and try to get the newly created one */ ldap_back_conn_free( lc ); lc = NULL; goto retry_lock; } /* taint connection, so that it'll be freed when released */ LDAP_BACK_CONN_TAINTED_SET( lc ); break; default: LDAP_BACK_CONN_CACHED_CLEAR( lc ); ldap_back_conn_free( lc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "Proxy bind collision"; if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { send_ldap_result( op, rs ); } return NULL; } } } else { int expiring = 0; if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout ) || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) ) { expiring = 1; /* 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 ); } if ( StatslogTest( LDAP_DEBUG_TRACE ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "conn %p fetched refcnt=%u%s", (void *)lc, refcnt, expiring ? " expiring" : "" ); Debug( LDAP_DEBUG_TRACE, "=>ldap_back_getconn: %s.\n", buf, 0, 0 ); } }#ifdef HAVE_TLSdone:;#endif /* HAVE_TLS */ return lc;}voidldap_back_release_conn_lock( ldapinfo_t *li, ldapconn_t **lcp, int dolock ){ ldapconn_t *lc = *lcp; if ( dolock ) { ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); } assert( lc->lc_refcnt > 0 ); LDAP_BACK_CONN_BINDING_CLEAR( lc ); lc->lc_refcnt--; if ( LDAP_BACK_CONN_TAINTED( lc ) ) { ldap_back_freeconn( li, lc, 0 ); *lcp = NULL; } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); }}voidldap_back_quarantine( Operation *op, SlapReply *rs ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; slap_retry_info_t *ri = &li->li_quarantine; ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex ); if ( rs->sr_err == LDAP_UNAVAILABLE ) { time_t new_last = slap_get_time(); switch ( li->li_isquarantined ) { case LDAP_BACK_FQ_NO: if ( ri->ri_last == new_last ) { goto done; } Debug( LDAP_DEBUG_ANY, "%s: ldap_back_quarantine enter.\n", op->o_log_prefix, 0, 0 ); ri->ri_idx = 0; ri->ri_count = 0; break; case LDAP_BACK_FQ_RETRYING: Debug( LDAP_DEBUG_ANY, "%s: ldap_back_quarantine block #%d try #%d failed.\n", op->o_log_prefix, ri->ri_idx, ri->ri_count ); ++ri->ri_count; if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER && ri->ri_count == ri->ri_num[ ri->ri_idx ] ) { ri->ri_count = 0; ++ri->ri_idx; } break; default: break; } li->li_isquarantined = LDAP_BACK_FQ_YES; ri->ri_last = new_last; } else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) { if ( ri->ri_last == slap_get_time() ) { goto done; } Debug( LDAP_DEBUG_ANY, "%s: ldap_back_quarantine exit (%d) err=%d.\n", op->o_log_prefix, li->li_isquarantined, rs->sr_err ); if ( li->li_quarantine_f ) { (void)li->li_quarantine_f( li, li->li_quarantine_p ); } ri->ri_count = 0; ri->ri_idx = 0; li->li_isquarantined = LDAP_BACK_FQ_NO; }done:; ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );}/* * ldap_back_dobind_int * * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not */static intldap_back_dobind_int( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok, int retries, int dolock ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; ldapconn_t *lc; struct berval binddn = slap_empty_bv, bindcred = slap_empty_bv; int rc = 0, isbound, binding = 0; ber_int_t msgid; assert( lcp != NULL ); assert( retries >= 0 ); if ( sendok & LDAP_BACK_GETCONN ) { assert( *lcp == NULL ); lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -