diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
commit | 3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (patch) | |
tree | 197c810e5f5bce17b1233a7cb8d7b50c0bcd25e2 /TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp | |
parent | 6b846cf03c0bcbd8c276cb0af61a181e5f98eaae (diff) | |
download | ATCD-3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c.tar.gz |
Repo restructuring
Diffstat (limited to 'TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp')
-rw-r--r-- | TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp | 862 |
1 files changed, 862 insertions, 0 deletions
diff --git a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp new file mode 100644 index 00000000000..3635555cb98 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Connector.cpp @@ -0,0 +1,862 @@ +#include "orbsvcs/SSLIOP/SSLIOP_Connector.h" +#include "orbsvcs/SSLIOP/SSLIOP_OwnCredentials.h" +#include "orbsvcs/SSLIOP/SSLIOP_Profile.h" +#include "orbsvcs/SSLIOP/SSLIOP_X509.h" + +#include "orbsvcs/SecurityLevel2C.h" + +#include "tao/debug.h" +#include "tao/ORB_Core.h" +#include "tao/Client_Strategy_Factory.h" +#include "tao/Environment.h" +#include "tao/Base_Transport_Property.h" +#include "tao/Transport_Cache_Manager.h" +#include "tao/Thread_Lane_Resources.h" +#include "tao/Stub.h" +#include "tao/Transport_Connector.h" +#include "tao/Blocked_Connect_Strategy.h" +#include "tao/Wait_Strategy.h" +#include "tao/Profile_Transport_Resolver.h" +#include "ace/Auto_Ptr.h" +#include "ace/os_include/os_netdb.h" + +ACE_RCSID (SSLIOP, + SSLIOP_Connector, + "$Id$") + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO::SSLIOP::Connector::Connector (::Security::QOP qop) + : TAO::IIOP_SSL_Connector (), + qop_ (qop), + connect_strategy_ (), + base_connector_ () +{ +} + +int +TAO::SSLIOP::Connector::open (TAO_ORB_Core *orb_core) +{ + // Since the ACE_Strategy_Connector (and ACE_Connector) cannot + // handle non-blocking connections with protocols that have more + // than one handshake, such as SSL, force blocking connections for + // SSLIOP. This deficiency will be addressed soon. + ACE_NEW_RETURN (this->active_connect_strategy_, + TAO_Blocked_Connect_Strategy (orb_core), + -1); + + if (this->TAO::IIOP_SSL_Connector::open (orb_core) == -1) + return -1; + + // Our connect creation strategy + CONNECT_CREATION_STRATEGY *connect_creation_strategy = 0; + + ACE_NEW_RETURN (connect_creation_strategy, + CONNECT_CREATION_STRATEGY + (orb_core->thr_mgr (), + orb_core, + 0 /* Forcibly disable TAO's GIOPlite feature. + It introduces a security hole. */), + -1); + + // Our activation strategy + CONNECT_CONCURRENCY_STRATEGY *concurrency_strategy = 0; + + ACE_NEW_RETURN (concurrency_strategy, + CONNECT_CONCURRENCY_STRATEGY (orb_core), + -1); + + ACE_Reactor *r = this->orb_core ()->reactor (); + + return this->base_connector_.open (r, + connect_creation_strategy, + &this->connect_strategy_, + concurrency_strategy); +} + +int +TAO::SSLIOP::Connector::close (void) +{ + (void) this->TAO::IIOP_SSL_Connector::close (); + + delete this->base_connector_.creation_strategy (); + delete this->base_connector_.concurrency_strategy (); + return this->base_connector_.close (); +} + +TAO_Transport * +TAO::SSLIOP::Connector::connect (TAO::Profile_Transport_Resolver *resolver, + TAO_Transport_Descriptor_Interface *desc, + ACE_Time_Value *timeout + ACE_ENV_ARG_DECL) +{ + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO (%P|%t) - Connector::connect, ") + ACE_TEXT ("looking for SSLIOP connection.\n"))); + + TAO_Endpoint *endpoint = desc->endpoint (); + + if (endpoint->tag () != IOP::TAG_INTERNET_IOP) + return 0; + + TAO_SSLIOP_Endpoint *ssl_endpoint = + dynamic_cast<TAO_SSLIOP_Endpoint *> (endpoint); + + if (ssl_endpoint == 0) + return 0; + + // @@ TODO: The EstablishTrust policy should be evaluated once per + // connection, not once per invocation. This should + // improve performance. + // + // Check if the user overrode the default establishment of trust + // policy for the current object. + CORBA::Policy_var policy = + resolver->stub ()->get_policy (::Security::SecEstablishTrustPolicy + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + SecurityLevel2::EstablishTrustPolicy_var trust_policy = + SecurityLevel2::EstablishTrustPolicy::_narrow (policy.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + // We use a pointer and temporary to make it obvious to determine + // if no establishment of trust policy was set. Specifically, if + // the "trust" pointer below is zero, then the SSLIOP pluggable + // protocol default value will be used. + ::Security::EstablishTrust trust = { 0 , 0 }; + if (!CORBA::is_nil (trust_policy.in ())) + { + trust = trust_policy->trust (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + + // Flag that states whether any form of establishment of trust + // should occur. + CORBA::Boolean const establish_trust = + trust.trust_in_target || trust.trust_in_client; + + // @@ Should this be in a "policy validator?" + // + // If the SSL port is zero, then no SSLIOP tagged component was + // available in the IOR, meaning that there is no way to establish + // trust. Throw an exception. + if (ssl_endpoint->ssl_component ().port == 0 + && establish_trust) + { + if (TAO_debug_level > 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO_SSLIOP (%P|%t) ERROR: ") + ACE_TEXT ("Cannot establish trust since ") + ACE_TEXT ("no SSLIOP tagged component was ") + ACE_TEXT ("found in the IOR.\n"))); + } + + ACE_THROW_RETURN (CORBA::INV_POLICY (), // @@ Correct exception? + 0); + } + + // Check if the user overrode the default Quality-of-Protection for + // the current object. + policy = resolver->stub ()->get_policy (::Security::SecQOPPolicy + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + SecurityLevel2::QOPPolicy_var qop_policy = + SecurityLevel2::QOPPolicy::_narrow (policy.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + // Temporary variable used to avoid overwriting the default value + // set when the ORB was initialized. + ::Security::QOP qop = this->qop_; + + if (!CORBA::is_nil (qop_policy.in ())) + { + qop = qop_policy->qop (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + + // If the SSL port is zero, then no SSLIOP tagged component was + // available in the IOR, meaning that there is no way to make a + // secure invocation. Throw an exception. + if (qop != ::Security::SecQOPNoProtection + && ssl_endpoint->ssl_component ().port == 0) + { + if (TAO_debug_level > 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO_SSLIOP (%P|%t) ERROR: ") + ACE_TEXT ("Cannot make secure invocation since ") + ACE_TEXT ("no SSLIOP tagged component was ") + ACE_TEXT ("found in the IOR.\n"))); + } + + ACE_THROW_RETURN (CORBA::INV_POLICY (), // @@ Correct exception? + 0); + } + + if ((!establish_trust && qop == ::Security::SecQOPNoProtection) + || ssl_endpoint->ssl_component ().port == 0) + { + return this->iiop_connect (ssl_endpoint, + resolver, + timeout + ACE_ENV_ARG_PARAMETER); + } + + return this->ssliop_connect (ssl_endpoint, + qop, + trust, + resolver, + desc, + timeout + ACE_ENV_ARG_PARAMETER); +} + + +TAO_Profile * +TAO::SSLIOP::Connector::create_profile (TAO_InputCDR& cdr) +{ + TAO_Profile *pfile = 0; + ACE_NEW_RETURN (pfile, + TAO_SSLIOP_Profile (this->orb_core ()), + 0); + + const int r = pfile->decode (cdr); + if (r == -1) + { + pfile->_decr_refcnt (); + pfile = 0; + } + + return pfile; +} + +TAO_Profile * +TAO::SSLIOP::Connector::make_profile (ACE_ENV_SINGLE_ARG_DECL) +{ + // The endpoint should be of the form: + // N.n@host:port/object_key + // or: + // host:port/object_key + + TAO_Profile *profile = 0; + ACE_NEW_THROW_EX (profile, + TAO_SSLIOP_Profile (this->orb_core (), + 0), // SSL component + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK_RETURN (0); + + return profile; +} + + +TAO_Profile * +TAO::SSLIOP::Connector::make_secure_profile (ACE_ENV_SINGLE_ARG_DECL) +{ + // The endpoint should be of the form: + // N.n@host:port/object_key + // or: + // host:port/object_key + + TAO_Profile *profile = 0; + ACE_NEW_THROW_EX (profile, + TAO_SSLIOP_Profile (this->orb_core (), + 1), // SSL component + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + ACE_CHECK_RETURN (0); + + return profile; +} + + + +TAO_Profile * +TAO::SSLIOP::Connector::corbaloc_scan (const char *endpoint, + size_t &len + ACE_ENV_ARG_DECL) +{ + int ssl_only = 0; + if (this->check_prefix (endpoint) == 0) + { + ssl_only = 1; + } + else + { + if (this->TAO_IIOP_Connector::check_prefix (endpoint) != 0) + return 0; + } + + // Determine the (first in a list of possibly > 1) endpoint address + const char *comma_pos = ACE_OS::strchr (endpoint,','); + const char *slash_pos = ACE_OS::strchr (endpoint,'/'); + if (comma_pos == 0 && slash_pos == 0) + { + if (TAO_debug_level) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("(%P|%t) SSLIOP_Connector::corbaloc_scan warning: ") + ACE_TEXT("supplied string contains no comma or slash: %s\n"), + endpoint)); + } + len = ACE_OS::strlen (endpoint); + } + else if (slash_pos != 0 || comma_pos > slash_pos) + { + // The endpoint address does not extend past the first '/' or ',' + len = slash_pos - endpoint; + } + else + { + len = comma_pos - endpoint; + } + + //Create the corresponding profile + TAO_Profile *ptmp = 0; + if (ssl_only) + { + ptmp = this->make_secure_profile (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else + { + ptmp = this->make_profile (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + + return ptmp; +} + + +int +TAO::SSLIOP::Connector::check_prefix (const char *endpoint) +{ + // Check for a valid string + if (!endpoint || !*endpoint) return -1; // Failure + + const char *protocol[] = { "ssliop", "sslioploc" }; + + size_t first_slot = ACE_OS::strchr (endpoint, ':') - endpoint; + + size_t len0 = ACE_OS::strlen (protocol[0]); + size_t len1 = ACE_OS::strlen (protocol[1]); + + // Check for the proper prefix in the IOR. If the proper prefix + // isn't in the IOR then it is not an IOR we can use. + if (first_slot == len0 && ACE_OS::strncmp (endpoint, protocol[0], len0) == 0) + return 0; + + if (first_slot == len1 && ACE_OS::strncmp (endpoint, protocol[1], len1) == 0) + return 0; + + // Failure: not an SSLIOP IOR + // DO NOT throw an exception here. + return -1; +} + + +TAO_Transport* +TAO::SSLIOP::Connector::iiop_connect ( + TAO_SSLIOP_Endpoint *ssl_endpoint, + TAO::Profile_Transport_Resolver *resolver, + ACE_Time_Value *timeout + ACE_ENV_ARG_DECL) +{ + const ::SSLIOP::SSL &ssl_component = ssl_endpoint->ssl_component (); + + // Only allow connection to the insecure IIOP port if the endpoint + // explicitly allows it, i.e. if the Security::NoProtection security + // association bit is set in the SSLIOP::SSL::target_supports field. + // The server performs the same permission check, so this check is + // an optimization since a connection will not be established + // needlessly, i.e. rejected due to lack of permission. + // + // Note that it is still possible for the standard non-SSLIOP aware + // IIOP pluggable protocol to attempt to connect to the insecure + // port. In that case, the server will have to prevent the + // connection, and subsequently the request, from completing. + if (ACE_BIT_DISABLED (ssl_component.target_supports, + ::Security::NoProtection)) + ACE_THROW_RETURN (CORBA::NO_PERMISSION ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + EPERM), + CORBA::COMPLETED_NO), + 0); + + TAO_IIOP_Endpoint *iiop_endpoint = ssl_endpoint->iiop_endpoint (); + + // An IIOP-only transport descriptor must be used instead of the one + // passed to this method since the latter is used for SSLIOP + // connections. Doing so prevents an IIOP-only cached transport + // from being associated with an SSLIOP connection. + TAO_Base_Transport_Property iiop_desc (iiop_endpoint); + + // Note that the IIOP-only transport descriptor is used! + return + this->TAO::IIOP_SSL_Connector::connect ( + resolver, + &iiop_desc, + timeout + ACE_ENV_ARG_PARAMETER); +} + +TAO_Transport * +TAO::SSLIOP::Connector::ssliop_connect ( + TAO_SSLIOP_Endpoint *ssl_endpoint, + ::Security::QOP qop, + const ::Security::EstablishTrust &trust, + TAO::Profile_Transport_Resolver *resolver, + TAO_Transport_Descriptor_Interface *desc, + ACE_Time_Value *max_wait_time + ACE_ENV_ARG_DECL) +{ + const ::SSLIOP::SSL &ssl_component = ssl_endpoint->ssl_component (); + + // @@ The following check for "required insecurity" seems odd, but + // I haven't seen anything in the Security spec that says this + // policy isn't possible. + // -Ossama + + // If the endpoint requires an insecure connection, i.e. the + // Security::NoProtection security association bit in the + // SSLIOP::SSL::target_requires field is enabled, then prevent an + // SSL connection from occuring. + if (ACE_BIT_ENABLED (ssl_component.target_requires, + ::Security::NoProtection)) + ACE_THROW_RETURN (CORBA::NO_PERMISSION ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + EPERM), + CORBA::COMPLETED_NO), + 0); + + // If the invocation wants integrity without confidentiality but the + // server does not support "no protection," then it won't be + // possible to provide integrity. In order to support integrity + // without confidentiality, encryption must be disabled but secure + // hashes must remain enabled. This is achieved using the "eNULL" + // cipher. However, the "eNULL" cipher is only enabled on the + // server side if "no protection" is enabled. + if (ACE_BIT_DISABLED (ssl_component.target_supports, + ::Security::NoProtection) + && qop == ::Security::SecQOPIntegrity) + ACE_THROW_RETURN (CORBA::INV_POLICY (), 0); + + const ACE_INET_Addr &remote_address = + ssl_endpoint->object_addr (); + + // Verify that the remote ACE_INET_Addr was initialized + // properly. Failure can occur if hostname lookup failed when + // initializing the remote ACE_INET_Addr. + if (remote_address.get_type () != AF_INET) + { + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO (%P|%t) SSLIOP connection failed.\n") + ACE_TEXT ("TAO (%P|%t) This is most likely ") + ACE_TEXT ("due to a hostname lookup ") + ACE_TEXT ("failure.\n"))); + } + + return 0; + } + + int result = 0; + TAO::SSLIOP::Connection_Handler *svc_handler = 0; + TAO_Transport *transport = 0; + + // Before we can check the cache to find an existing connection, we + // need to make sure the ssl_endpoint is fully initialized with the + // local security information. This endpoint initalized by the + // profile does not (and cannot) contain the desired QOP, trust, or + // credential information which is necesary to uniquely identify + // this connection. + if (!ssl_endpoint->credentials_set ()) + { + if (TAO_debug_level > 2) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) Initializing SSLIOP_Endpoint \n") + )); + + if (this->base_connector_.creation_strategy ()->make_svc_handler ( + svc_handler) != 0) + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) Unable to create SSLIOP ") + ACE_TEXT ("service handler.\n"))); + + return 0; + } + + ACE_Auto_Basic_Ptr<TAO::SSLIOP::Connection_Handler> + safe_handler (svc_handler); + TAO::SSLIOP::OwnCredentials_var credentials = + this->retrieve_credentials (resolver->stub (), + svc_handler->peer ().ssl () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + svc_handler = safe_handler.release (); + ssl_endpoint->set_sec_attrs (qop, trust, credentials.in()); + } + + // Check the Cache first for connections + if (this->orb_core ()->lane_resources ().transport_cache ().find_transport ( + desc, + transport) == 0) + { + if (TAO_debug_level > 2) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO (%P|%t) - SSLIOP_Connector::ssliop_connect, ") + ACE_TEXT ("got existing transport[%d]\n"), + transport->id ())); + + // When the transport is not connected wait for completion + if (!transport->is_connected()) + { + if (!this->wait_for_connection_completion (resolver, + transport, + max_wait_time)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) - SSLIOP_Connector::ssliop_connect,") + ACE_TEXT ("wait for completion failed\n"))); + + } + } + } + else + { + if (TAO_debug_level > 4) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO (%P|%t) - SSLIOP_Connector::ssliop_connect, ") + ACE_TEXT ("making a new connection \n"))); + + // Purge connections (if necessary) + this->orb_core ()->lane_resources ().transport_cache ().purge (); + + // The svc_handler is created beforehand so that we can get + // access to the underlying ACE_SSL_SOCK_Stream (the peer) and + // its SSL pointer member prior to descending into the + // ACE_Strategy_Connector (the "base_connector_"). This is + // thread-safe and reentrant, hence no synchronization is + // necessary. + // + // The make_svc_handler() method creates the service handler and + // bumps the #REFCOUNT# up one extra. The extra reference count + // in TAO_Connect_Creation_Strategy::make_svc_handler() is + // needed in the case when connection completion is pending and + // we are going to wait on a variable in the handler to changes, + // signifying success or failure. Note, that this increment + // cannot be done once the connect() returns since this might be + // too late if another thread pick up the completion and + // potentially deletes the handler before we get a chance to + // increment the reference count. + if (svc_handler == 0 && + this->base_connector_.creation_strategy ()->make_svc_handler ( + svc_handler) != 0) + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) Unable to create SSLIOP ") + ACE_TEXT ("service handler.\n"))); + + return 0; + } + + ACE_Auto_Basic_Ptr<TAO::SSLIOP::Connection_Handler> + safe_handler (svc_handler); + + // Setup the establishment of trust connection properties, if + // any. + int verify_mode = 0; + + // On the server side, "trust_in_client" requires that a peer + // (client) certificate exist. Fail if one doesn't exist. + // + // In SSLIOP's case, trust_in_client also implies + // trust_in_target. + if (trust.trust_in_client) + verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + + // Require verification of the target's certificate. + else if (trust.trust_in_target) + verify_mode = SSL_VERIFY_PEER; + + // Trust in neither the client nor the target is explicitly + // specified. Use the default setting. + else + verify_mode = + ACE_SSL_Context::instance ()->default_verify_mode (); + + ::SSL_set_verify (svc_handler->peer ().ssl (), + verify_mode, + 0); + + // The "eNULL" cipher disables encryption but still uses a + // secure hash (e.g. SHA1 or MD5) to ensure integrity. (Try the + // command "openssl ciphers -v eNULL".) + // + // Note that it is not possible to completely disable protection + // here. + if ((qop == ::Security::SecQOPNoProtection + || qop == ::Security::SecQOPIntegrity) + && ::SSL_set_cipher_list (svc_handler->peer ().ssl (), + "eNULL") == 0) + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Unable to set eNULL ") + ACE_TEXT ("SSL cipher.\n"))); + + ACE_THROW_RETURN (CORBA::INV_POLICY (), 0); + } + + svc_handler = safe_handler.release (); + + // Get the right synch options + ACE_Synch_Options synch_options; + + this->active_connect_strategy_->synch_options (max_wait_time, + synch_options); + + // If we don't need to block for a transport just set the timeout to + // be zero. + ACE_Time_Value tmp_zero (ACE_Time_Value::zero); + if (!resolver->blocked_connect ()) + { + synch_options.timeout (ACE_Time_Value::zero); + max_wait_time = &tmp_zero; + } + + // We obtain the transport in the <svc_handler> variable. As we + // know now that the connection is not available in Cache we can + // make a new connection + result = this->base_connector_.connect (svc_handler, + remote_address, + synch_options); + + // There are three possibilities from calling connect(): (a) + // connection succeeds immediately - in this case, the + // #REFCOUNT# on the handler is two; (b) connection completion + // is pending - in this case, the #REFCOUNT# on the handler is + // also two; (c) connection fails immediately - in this case, + // the #REFCOUNT# on the handler is one since close() gets + // called on the handler. + + // Make sure that we always do a remove_reference + ACE_Event_Handler_var svc_handler_auto_ptr (svc_handler); + + transport = + svc_handler->transport (); + + if (result == -1) + { + // No immediate result, wait for completion + if (errno == EWOULDBLOCK) + { + // Try to wait until connection completion. Incase we block, then we + // get a connected transport or not. In case of non block we get + // a connected or not connected transport + if (!this->wait_for_connection_completion (resolver, + transport, + max_wait_time)) + { + if (TAO_debug_level > 2) + ACE_ERROR ((LM_ERROR, "TAO (%P|%t) - SSLIOP_Connector::" + "ssliop_connect, " + "wait for completion failed\n")); + } + } + else + { + // Transport is not usable + transport = 0; + } + } + + // In case of errors transport is zero + if (transport == 0) + { + // Give users a clue to the problem. + if (TAO_debug_level) + { + char buffer [MAXHOSTNAMELEN + 6 + 1]; + ssl_endpoint->addr_to_string (buffer, + sizeof (buffer) - 1); + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) - SSL connection to ") + ACE_TEXT ("<%s:%d> failed (%p)\n"), + buffer, + remote_address.get_port_number (), + ACE_TEXT ("errno"))); + } + + return 0; + } + + // At this point, the connection has be successfully connected. + // #REFCOUNT# is one. + if (TAO_debug_level > 2) + ACE_DEBUG ((LM_DEBUG, + "TAO (%P|%t) - SSLIOP_Connector::ssliop_connect, " + "new SSL connection to port %d on transport[%d]\n", + remote_address.get_port_number (), + svc_handler->peer ().get_handle ())); + + // Add the handler to Cache + int retval = + this->orb_core ()-> + lane_resources ().transport_cache ().cache_transport (desc, + transport); + + // Failure in adding to cache. + if (retval != 0) + { + // Close the handler. + svc_handler->close (); + + if (TAO_debug_level > 0) + { + ACE_ERROR ((LM_ERROR, + "TAO (%P|%t) - SLIIOP_Connector::ssliop_connect, " + "could not add the new connection to cache\n")); + } + + return 0; + } + + if (transport->is_connected () && + transport->wait_strategy ()->register_handler () != 0) + { + // Registration failures. + + // Purge from the connection cache, if we are not in the cache, this + // just does nothing. + (void) transport->purge_entry (); + + // Close the handler. + (void) transport->close_connection (); + + if (TAO_debug_level > 0) + ACE_ERROR ((LM_ERROR, + "TAO (%P|%t) - SSLIOP_Connector [%d]::ssliop_connect, " + "could not register the transport " + "in the reactor.\n", + transport->id ())); + + return 0; + } + } + + return transport; +} + +TAO::SSLIOP::OwnCredentials * +TAO::SSLIOP::Connector::retrieve_credentials (TAO_Stub *stub, + SSL *ssl + ACE_ENV_ARG_DECL) +{ + // Check if the user overrode the default invocation credentials. + CORBA::Policy_var policy = + stub->get_policy (::SecurityLevel3::ContextEstablishmentPolicyType + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (TAO::SSLIOP::OwnCredentials::_nil ()); + + SecurityLevel3::ContextEstablishmentPolicy_var creds_policy = + SecurityLevel3::ContextEstablishmentPolicy::_narrow ( + policy.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (TAO::SSLIOP::OwnCredentials::_nil ()); + + TAO::SSLIOP::OwnCredentials_var ssliop_credentials; + + // Set the Credentials (X.509 certificates and corresponding private + // keys) to be used for this invocation. + if (!CORBA::is_nil (creds_policy.in ())) + { + SecurityLevel3::OwnCredentialsList_var creds_list = + creds_policy->creds_list (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (TAO::SSLIOP::OwnCredentials::_nil ()); + + if (creds_list->length () > 0) + { + // Assume that we've got an SSLIOP credential. + SecurityLevel3::Credentials_ptr credentials = + creds_list[0u]; + + ssliop_credentials = + TAO::SSLIOP::OwnCredentials::_narrow (credentials + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (TAO::SSLIOP::OwnCredentials::_nil ()); + + if (!CORBA::is_nil (ssliop_credentials.in ())) + { + TAO::SSLIOP::X509_var x509 = ssliop_credentials->x509 (); + if (::SSL_use_certificate (ssl, x509.in ()) != 1) + return TAO::SSLIOP::OwnCredentials::_nil (); + + TAO::SSLIOP::EVP_PKEY_var evp = ssliop_credentials->evp (); + if (evp.in () != 0 + && ::SSL_use_PrivateKey (ssl, evp.in ()) != 1) + { + // Invalidate the certificate we just set. + (void) ::SSL_use_certificate (ssl, 0); + return TAO::SSLIOP::OwnCredentials::_nil (); + } + } + } + } + else + { + // Use the default certificate and private key, i.e. the one set + // in the SSL_CTX that was used when creating the SSL data + // structure. + + /** + * @todo Check if the CredentialsCurator contains a default set + * of SSLIOP OwnCredentials. + */ + + TAO::SSLIOP::OwnCredentials_ptr & c = ssliop_credentials.out (); + ACE_NEW_THROW_EX (c, + TAO::SSLIOP::OwnCredentials ( + ::SSL_get_certificate (ssl), + ::SSL_get_privatekey (ssl)), + CORBA::NO_MEMORY ()); + ACE_CHECK_RETURN (TAO::SSLIOP::OwnCredentials::_nil ()); + } + + return ssliop_credentials._retn (); +} + +int +TAO::SSLIOP::Connector::cancel_svc_handler ( + TAO_Connection_Handler * svc_handler) +{ + TAO::SSLIOP::Connection_Handler* handler= + dynamic_cast<TAO::SSLIOP::Connection_Handler*> (svc_handler); + + if (handler) + // Cancel from the connector + return this->base_connector_.cancel (handler); + + return -1; +} + +TAO_END_VERSIONED_NAMESPACE_DECL |