conn.c
来自「ldap服务器源码」· C语言 代码 · 共 1,810 行 · 第 1/3 页
C
1,810 行
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/conn.c,v 1.31.2.28 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"/* * meta_back_conndn_cmp * * compares two struct metaconn based on the value of the conn pointer * and of the local DN; used by avl stuff */intmeta_back_conndn_cmp( const void *c1, const void *c2 ){ metaconn_t *mc1 = ( metaconn_t * )c1; metaconn_t *mc2 = ( metaconn_t * )c2; int rc; /* If local DNs don't match, it is definitely not a match */ /* For shared sessions, conn is NULL. Only explicitly * bound sessions will have non-NULL conn. */ rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); if ( rc == 0 ) { rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); } return rc;}/* * meta_back_conndnmc_cmp * * compares two struct metaconn based on the value of the conn pointer, * the local DN and the struct pointer; used by avl stuff */static intmeta_back_conndnmc_cmp( const void *c1, const void *c2 ){ metaconn_t *mc1 = ( metaconn_t * )c1; metaconn_t *mc2 = ( metaconn_t * )c2; int rc; /* If local DNs don't match, it is definitely not a match */ /* For shared sessions, conn is NULL. Only explicitly * bound sessions will have non-NULL conn. */ rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); if ( rc == 0 ) { rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); if ( rc == 0 ) { rc = SLAP_PTRCMP( mc1, mc2 ); } } return rc;}/* * meta_back_conn_cmp * * compares two struct metaconn based on the value of the conn pointer; * used by avl stuff */intmeta_back_conn_cmp( const void *c1, const void *c2 ){ metaconn_t *mc1 = ( metaconn_t * )c1; metaconn_t *mc2 = ( metaconn_t * )c2; /* For shared sessions, conn is NULL. Only explicitly * bound sessions will have non-NULL conn. */ return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );}/* * meta_back_conndn_dup * * returns -1 in case a duplicate struct metaconn has been inserted; * used by avl stuff */intmeta_back_conndn_dup( void *c1, void *c2 ){ metaconn_t *mc1 = ( metaconn_t * )c1; metaconn_t *mc2 = ( metaconn_t * )c2; /* Cannot have more than one shared session with same DN */ if ( mc1->mc_conn == mc2->mc_conn && dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) ) { return -1; } return 0;}/* * Debug stuff (got it from libavl) */#if META_BACK_PRINT_CONNTREE > 0static voidmeta_back_ravl_print( Avlnode *root, int depth ){ int i; metaconn_t *mc; if ( root == 0 ) { return; } meta_back_ravl_print( root->avl_right, depth + 1 ); for ( i = 0; i < depth; i++ ) { fprintf( stderr, "-" ); } mc = (metaconn_t *)root->avl_data; fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d%s\n", (void *)mc, mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", (void *)mc->mc_conn, avl_bf2str( root->avl_bf ), mc->mc_refcnt, LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" ); meta_back_ravl_print( root->avl_left, depth + 1 );}/* NOTE: duplicate from back-ldap/bind.c */static char* priv2str[] = { "privileged", "privileged/TLS", "anonymous", "anonymous/TLS", "bind", "bind/TLS", NULL};voidmeta_back_print_conntree( metainfo_t *mi, char *msg ){ int c; fprintf( stderr, "========> %s\n", msg ); for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) { int i = 0; metaconn_t *mc; fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num ); LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q ) { fprintf( stderr, " [%d] mc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n", i, (void *)mc, mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", (void *)mc->mc_conn, mc->mc_refcnt, mc->msc_mscflags ); i++; } } if ( mi->mi_conninfo.lai_tree == NULL ) { fprintf( stderr, "\t(empty)\n" ); } else { meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 ); } fprintf( stderr, "<======== %s\n", msg );}#endif /* META_BACK_PRINT_CONNTREE *//* * End of debug stuff *//* * metaconn_alloc * * Allocates a connection structure, making room for all the referenced targets */static metaconn_t *metaconn_alloc( Operation *op ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metaconn_t *mc; int ntargets = mi->mi_ntargets; assert( ntargets > 0 ); /* malloc all in one */ mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t ) + sizeof( metasingleconn_t ) * ( ntargets - 1 ) ); if ( mc == NULL ) { return NULL; } mc->mc_info = mi; mc->mc_authz_target = META_BOUND_NONE; mc->mc_refcnt = 1; return mc;}/* * meta_back_init_one_conn * * Initializes one connection */intmeta_back_init_one_conn( Operation *op, SlapReply *rs, metaconn_t *mc, int candidate, int ispriv, ldap_back_send_t sendok, int dolock ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int version; dncookie dc; int isauthz = ( candidate == mc->mc_authz_target ); int do_return = 0;#ifdef HAVE_TLS int is_ldaps = 0;#endif /* HAVE_TLS */ /* 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 ( mt->mt_isquarantined ) { slap_retry_info_t *ri = &mt->mt_quarantine; int dont_retry = 1; if ( mt->mt_quarantine.ri_interval ) { ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); if ( mt->mt_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 ) { if ( StatslogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_back_init_one_conn[%d]: quarantine " "retry block #%d try #%d", candidate, ri->ri_idx, ri->ri_count ); Debug( LDAP_DEBUG_ANY, "%s %s.\n", op->o_log_prefix, buf, 0 ); } } mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING; } ldap_pvt_thread_mutex_unlock( &mt->mt_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 rs->sr_err; } }retry_lock:; if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } /* * Already init'ed */ if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { assert( msc->msc_ld != NULL ); rs->sr_err = LDAP_SUCCESS; do_return = 1; } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) { if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } ldap_pvt_thread_yield(); goto retry_lock; } /* sounds more appropriate */ rs->sr_err = LDAP_BUSY; rs->sr_text = "No connections to target are available"; do_return = 1; } else if ( META_BACK_CONN_INITED( msc ) ) { assert( msc->msc_ld != NULL ); rs->sr_err = LDAP_SUCCESS; do_return = 1; } else { /* * creating... */ META_BACK_CONN_CREATING_SET( msc ); } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } if ( do_return ) { if ( rs->sr_err != LDAP_SUCCESS && op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { send_ldap_result( op, rs ); } return rs->sr_err; } assert( msc->msc_ld == NULL ); /* * Attempts to initialize the connection to the target ds */ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri );#ifdef HAVE_TLS is_ldaps = ldap_is_ldaps_url( mt->mt_uri );#endif /* HAVE_TLS */ ldap_pvt_thread_mutex_unlock( &mt->mt_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 ( mt->mt_version != 0 ) { version = mt->mt_version; } else if ( op->o_conn->c_protocol != 0 ) { version = op->o_conn->c_protocol; } else { version = LDAP_VERSION3; } ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version ); /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, LDAP_BACK_CHASE_REFERRALS( mi ) ? LDAP_OPT_ON : LDAP_OPT_OFF );#ifdef HAVE_TLS /* start TLS ("tls [try-]{start|propagate}" statement) */ if ( ( LDAP_BACK_USE_TLS( mi ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( mi ) ) ) && !is_ldaps ) {#ifdef SLAP_STARTTLS_ASYNCHRONOUS /* * use asynchronous StartTLS; in case, chase referral * FIXME: OpenLDAP does not return referral on StartTLS yet */ int msgid; rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid ); if ( rs->sr_err == LDAP_SUCCESS ) { LDAPMessage *res = NULL; int rc, nretries = mt->mt_nretries; struct timeval tv; LDAP_BACK_TV_SET( &tv );retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case -1: rs->sr_err = LDAP_OTHER; break; case 0: if ( nretries != 0 ) { if ( nretries > 0 ) { nretries--; } LDAP_BACK_TV_SET( &tv ); goto retry; } rs->sr_err = LDAP_OTHER; 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; } break; } if ( rc == LDAP_RES_EXTENDED ) { struct berval *data = NULL; /* NOTE: right now, data is unused, so don't get it */ rs->sr_err = ldap_parse_extended_result( msc->msc_ld, res, NULL, NULL /* &data */ , 0 ); if ( rs->sr_err == LDAP_SUCCESS ) { int err; /* FIXME: matched? referrals? response controls? */ rs->sr_err = ldap_parse_result( msc->msc_ld, res, &err, NULL, NULL, NULL, NULL, 1 ); res = NULL; if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = err; } /* FIXME: in case a referral * is returned, should we try * using it instead of the * configured URI? */ if ( rs->sr_err == LDAP_SUCCESS ) { ldap_install_tls( msc->msc_ld ); } else if ( rs->sr_err == LDAP_REFERRAL ) { /* FIXME: LDAP_OPERATIONS_ERROR? */ rs->sr_err = LDAP_OTHER; rs->sr_text = "Unwilling to chase referral " "returned by Start TLS exop"; } if ( data ) { ber_bvfree( data ); } } } else { rs->sr_err = LDAP_OTHER; } if ( res != NULL ) { ldap_msgfree( res ); } }#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* * use synchronous StartTLS */ rs->sr_err = ldap_start_tls_s( msc->msc_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 */ if ( rs->sr_err == LDAP_SERVER_DOWN || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) ) {#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(TLS) " "ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld );#endif /* DEBUG_205 */ /* need to trash a failed Start TLS */ meta_clear_one_candidate( op, mc, candidate ); goto error_return; } }#endif /* HAVE_TLS */ /* * Set the network timeout if set */ if ( mt->mt_network_timeout != 0 ) { struct timeval network_timeout; network_timeout.tv_usec = 0; network_timeout.tv_sec = mt->mt_network_timeout; ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)&network_timeout ); } /* * If the connection DN is not null, an attempt to rewrite it is made */ if ( ispriv ) { if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ); if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); } ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd ); } } else { ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv ); } } else { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ber_memfree_x( msc->msc_cred.bv_val, NULL ); BER_BVZERO( &msc->msc_cred ); } if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL ); BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISEMPTY( &op->o_ndn ) && SLAP_IS_AUTHZ_BACKEND( op ) && isauthz ) { dc.target = mt; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "bindDN"; /* * Rewrite the bind dn if needed */ if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, &msc->msc_bound_ndn ) ) {#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(rewrite) " "ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld );#endif /* DEBUG_205 */ /* need to trash a connection not fully established */ meta_clear_one_candidate( op, mc, candidate ); goto error_return; } /* copy the DN if needed */ if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?