📄 bind.c
字号:
if ( rc == LDAP_SUCCESS ) { rc = ldap_start_tls( ld, NULL, NULL, &msgid ); } if ( rc == LDAP_SUCCESS ) { LDAPMessage *res = NULL; struct timeval tv; LDAP_BACK_TV_SET( &tv );retry:; rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ); if ( rc < 0 ) { rc = LDAP_UNAVAILABLE; } else if ( rc == 0 ) { if ( retries != LDAP_BACK_RETRY_NEVER ) { ldap_pvt_thread_yield(); if ( retries > 0 ) { retries--; } LDAP_BACK_TV_SET( &tv ); goto retry; } rc = LDAP_UNAVAILABLE; } else if ( rc == LDAP_RES_EXTENDED ) { struct berval *data = NULL; rc = ldap_parse_extended_result( ld, res, NULL, &data, 0 ); if ( rc == LDAP_SUCCESS ) { int err; rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 ); if ( rc == LDAP_SUCCESS ) { rc = err; } res = NULL; /* FIXME: in case a referral * is returned, should we try * using it instead of the * configured URI? */ if ( rc == LDAP_SUCCESS ) { rc = ldap_install_tls( ld ); } else if ( rc == LDAP_REFERRAL ) { rc = LDAP_UNWILLING_TO_PERFORM; *text = "unwilling to chase referral returned by Start TLS exop"; } if ( data ) { if ( data->bv_val ) { ber_memfree( data->bv_val ); } ber_memfree( data ); } } } else { rc = LDAP_OTHER; } if ( res != NULL ) { ldap_msgfree( res ); } }#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* * use synchronous StartTLS */ rc = ldap_start_tls_s( ld, NULL, NULL );#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* 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 */ switch ( rc ) { case LDAP_SUCCESS: *is_tls = 1; break; case LDAP_SERVER_DOWN: break; default: if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) { *text = "could not start TLS"; break; } /* in case Start TLS is not critical */ *is_tls = 0; rc = LDAP_SUCCESS; break; } } else { *is_tls = 0; } return rc;}#endif /* HAVE_TLS */static intldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; int version; LDAP *ld = NULL;#ifdef HAVE_TLS 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 ( op->o_tag == LDAP_REQ_BIND ) { op->o_dn = save_o_dn; op->o_ndn = save_o_ndn; } if ( isproxyauthz == -1 ) { return NULL; } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -