bind.c
来自「ldap服务器源码」· C语言 代码 · 共 1,440 行 · 第 1/3 页
C
1,440 行
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/bind.c,v 1.40.2.29 2007/01/27 23:56:43 ando Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1999-2007 The OpenLDAP Foundation. * Portions Copyright 2001-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by the Howard Chu for inclusion * in OpenLDAP Software and subsequently enhanced by Pierangelo * Masarati. */#include "portable.h"#include <stdio.h>#include <ac/errno.h>#include <ac/socket.h>#include <ac/string.h>#define AVL_INTERNAL#include "slap.h"#include "../back-ldap/back-ldap.h"#include "back-meta.h"#undef ldap_debug /* silence a warning in ldap-int.h */#include "../../../libraries/libldap/ldap-int.h"#include "lutil_ldap.h"static intmeta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapReply *rs, ldap_back_send_t sendok );static intmeta_back_single_bind( Operation *op, SlapReply *rs, metaconn_t *mc, int candidate );intmeta_back_bind( Operation *op, SlapReply *rs ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metaconn_t *mc = NULL; int rc = LDAP_OTHER, i, gotit = 0, isroot = 0; SlapReply *candidates = meta_back_candidates_get( op ); rs->sr_err = LDAP_SUCCESS; Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n", op->o_log_prefix, op->o_req_dn.bv_val, 0 ); /* the test on the bind method should be superfluous */ if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { if ( !be_isroot_pw( op ) ) { rs->sr_err = LDAP_INVALID_CREDENTIALS; rs->sr_text = NULL; send_ldap_result( op, rs ); return rs->sr_err; } if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; /* frontend will return success */ return rs->sr_err; } isroot = 1; } /* we need meta_back_getconn() not send result even on error, * because we want to intercept the error and make it * invalidCredentials */ mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND ); if ( !mc ) { if ( StatslogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_back_bind: no target " "for dn \"%s\" (%d%s%s).", op->o_req_dn.bv_val, rs->sr_err, rs->sr_text ? ". " : "", rs->sr_text ? rs->sr_text : "" ); Debug( LDAP_DEBUG_ANY, "%s %s\n", op->o_log_prefix, buf, 0 ); } /* FIXME: there might be cases where we don't want * to map the error onto invalidCredentials */ switch ( rs->sr_err ) { case LDAP_NO_SUCH_OBJECT: case LDAP_UNWILLING_TO_PERFORM: rs->sr_err = LDAP_INVALID_CREDENTIALS; rs->sr_text = NULL; break; } send_ldap_result( op, rs ); return rs->sr_err; } /* * Each target is scanned ... */ mc->mc_authz_target = META_BOUND_NONE; for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; int lerr; /* * Skip non-candidates */ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { continue; } if ( gotit == 0 ) { /* set rc to LDAP_SUCCESS only if at least * one candidate has been tried */ rc = LDAP_SUCCESS; gotit = 1; } else if ( isroot == 0 ) { /* * A bind operation is expected to have * ONE CANDIDATE ONLY! */ Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind: more than one" " candidate selected...\n", op->o_log_prefix, 0, 0 ); } if ( isroot ) { if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE || BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { metasingleconn_t *msc = &mc->mc_conns[ i ]; /* skip the target if no pseudorootdn is provided */ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISNULL( &msc->msc_cred ) ) { /* destroy sensitive data */ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ch_free( msc->msc_cred.bv_val ); BER_BVZERO( &msc->msc_cred ); } continue; } (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND ); lerr = rs->sr_err; } else { lerr = meta_back_single_bind( op, rs, mc, i ); } if ( lerr != LDAP_SUCCESS ) { rc = rs->sr_err = lerr; /* FIXME: in some cases (e.g. unavailable) * do not assume it's not candidate; rather * mark this as an error to be eventually * reported to client */ META_CANDIDATE_CLEAR( &candidates[ i ] ); break; } } /* must re-insert if local DN changed as result of bind */ if ( rc == LDAP_SUCCESS ) { if ( isroot ) { mc->mc_authz_target = META_BOUND_ALL; ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) ); } if ( !LDAP_BACK_PCONN_ISPRIV( mc ) && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) { metaconn_t *tmpmc; int lerr; /* wait for all other ops to release the connection */retry_lock:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); if ( mc->mc_refcnt > 1 ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_lock; } assert( mc->mc_refcnt == 1 );#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, ">>> meta_back_bind" );#endif /* META_BACK_PRINT_CONNTREE */ tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conndn_cmp ); assert( tmpmc == mc ); /* delete all cached connections with the current connection */ if ( LDAP_BACK_SINGLECONN( mi ) ) { while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL ) { Debug( LDAP_DEBUG_TRACE, "=>meta_back_bind: destroying conn %ld (refcnt=%u)\n", LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 ); if ( tmpmc->mc_refcnt != 0 ) { /* taint it */ LDAP_BACK_CONN_TAINTED_SET( tmpmc ); } else { /* * Needs a test because the handler may be corrupted, * and calling ldap_unbind on a corrupted header results * in a segmentation fault */ meta_back_conn_free( tmpmc ); } } } ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); if ( isroot ) { LDAP_BACK_CONN_ISPRIV_SET( mc ); LDAP_BACK_PCONN_SET( mc, op ); } lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conndn_cmp, meta_back_conndn_dup );#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, "<<< meta_back_bind" );#endif /* META_BACK_PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( lerr == -1 ) { /* we can do this because mc_refcnt == 1 */ assert( mc->mc_refcnt == 1 ); mc->mc_refcnt = 0; meta_back_conn_free( mc ); mc = NULL; } } } if ( mc != NULL ) { meta_back_release_conn( mi, mc ); } /* * rc is LDAP_SUCCESS if at least one bind succeeded, * err is the last error that occurred during a bind; * if at least (and at most?) one bind succeeds, fine. */ if ( rc != LDAP_SUCCESS ) { /* * deal with bind failure ... */ /* * no target was found within the naming context, * so bind must fail with invalid credentials */ if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) { rs->sr_err = LDAP_INVALID_CREDENTIALS; } else { rs->sr_err = slap_map_api2result( rs ); } send_ldap_result( op, rs ); return rs->sr_err; } return LDAP_SUCCESS;}static intmeta_back_bind_op_result( Operation *op, SlapReply *rs, metaconn_t *mc, int candidate, int msgid, ldap_back_send_t sendok ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; LDAPMessage *res; struct timeval tv; int rc; int nretries = mt->mt_nretries; char buf[ SLAP_TEXT_BUFLEN ]; Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_bind_op_result[%d]\n", op->o_log_prefix, candidate, 0 ); if ( rs->sr_err == LDAP_SUCCESS ) { time_t stoptime = (time_t)(-1), timeout; int timeout_err = op->o_protocol >= LDAP_VERSION3 ? LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; const char *timeout_text = "Operation timed out"; slap_op_t opidx = slap_req2op( op->o_tag ); /* since timeout is not specified, compute and use * the one specific to the ongoing operation */ if ( opidx == LDAP_REQ_SEARCH ) { if ( op->ors_tlimit <= 0 ) { timeout = 0; } else { timeout = op->ors_tlimit; timeout_err = LDAP_TIMELIMIT_EXCEEDED; timeout_text = NULL; } } else { timeout = mt->mt_timeout[ opidx ]; } /* better than nothing :) */ if ( timeout == 0 ) { if ( mi->mi_idle_timeout ) { timeout = mi->mi_idle_timeout; } else if ( mi->mi_conn_ttl ) { timeout = mi->mi_conn_ttl; } } if ( timeout ) { stoptime = op->o_time + timeout; } LDAP_BACK_TV_SET( &tv ); /* * handle response!!! */retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: if ( nretries != META_RETRY_NEVER || ( timeout && slap_get_time() <= stoptime ) ) { ldap_pvt_thread_yield(); if ( nretries > 0 ) { nretries--; } tv = mt->mt_bind_timeout; goto retry; } /* don't let anyone else use this handler, * because there's a pending bind that will not * be acknowledged */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); assert( LDAP_BACK_CONN_BINDING( msc ) );#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld );#endif /* DEBUG_205 */ meta_clear_one_candidate( op, mc, candidate ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); rs->sr_err = timeout_err; rs->sr_text = timeout_text; break; case -1: ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); snprintf( buf, sizeof( buf ), "err=%d (%s) nretries=%d", rs->sr_err, ldap_err2string( rs->sr_err ), nretries ); Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result[%d]: %s.\n", op->o_log_prefix, candidate, buf ); break; default: /* only touch when activity actually took place... */ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { msc->msc_time = op->o_time; } /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } break; } } rs->sr_err = slap_map_api2result( rs ); Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_bind_op_result[%d] err=%d\n", op->o_log_prefix, candidate, rs->sr_err ); return rs->sr_err;}/* * meta_back_single_bind * * attempts to perform a bind with creds */static intmeta_back_single_bind( Operation *op, SlapReply *rs, metaconn_t *mc, int candidate ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; struct berval mdn = BER_BVNULL; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid; dncookie dc; if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISNULL( &msc->msc_cred ) ) { /* destroy sensitive data */ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ch_free( msc->msc_cred.bv_val ); BER_BVZERO( &msc->msc_cred ); } /* * Rewrite the bind dn if needed */ dc.target = mt; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "bindDN";
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?