diff options
author | John Sonnenschein <johns@joyent.com> | 2012-05-17 18:26:57 +0000 |
---|---|---|
committer | John Sonnenschein <johns@joyent.com> | 2012-05-17 18:26:57 +0000 |
commit | 04b244dd661c24b510ac22936decfc0972d202d3 (patch) | |
tree | 3ebfef98afc303fddf3415d6fba64e8682f495e8 /usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp | |
parent | eac250589e41f1b705e1b7427b02b3379aac9f9e (diff) | |
parent | a69187741b83640a90dd8586195456dd50c016a8 (diff) | |
download | illumos-joyent-20120517.tar.gz |
Merge git.joyent.com:illumos-joyent20120517
Diffstat (limited to 'usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp')
-rw-r--r-- | usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp | 1169 |
1 files changed, 0 insertions, 1169 deletions
diff --git a/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp b/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp deleted file mode 100644 index 9f2c8dcf49..0000000000 --- a/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - */ - -/** - * \file KMSAgentLoadBalancer.cpp - */ - -#ifdef WIN32 -#define _WIN32_WINNT 0x0400 -#include <windows.h> -#include <process.h> -#endif - -#include <stdlib.h> - -#include "KMS_AgentH.h" -#include "KMSClientProfile.h" -#include "KMSAgentSoapUtilities.h" -#include "KMSAgentStringUtilities.h" -#include "KMSClientProfileImpl.h" -#include "KMSAgent.h" -#include "KMSAuditLogger.h" -#include "ApplianceParameters.h" -#include "KMSAgentCryptoUtilities.h" - -#ifdef METAWARE -#include "debug.h" -#include "sizet.h" -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -#endif -#include "KMSAgentAESKeyWrap.h" - -#ifdef METAWARE -#include "stdsoap2.h" /* makes fewer platform assumptions - than the standard stdsoap2.h */ - -int time (char *); -#include "literals.h" -#else -#include "stdsoap2.h" -#endif - -#include "AutoMutex.h" - -// real declaration of soap * -#include "KMSAgentDataUnitCache.h" - -#include "ClientSoapFaultCodes.h" -#include "KMSAgentPKICommon.h" -#include "KMSAgentLoadBalancer.h" // needs to be after stdsoap2.h to use the - -CAgentLoadBalancer::CAgentLoadBalancer (KMSClientProfile * const i_pProfile) -: m_pProfile (i_pProfile), -m_iTransactionStartTimeInMilliseconds (0), -m_bFIPS (false), -m_iKWKEntryNum (0), -m_iLastAttemptedWhenNoneResponding (0) -{ - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - // initialize the aCluster, let it contain the default appliance - m_iClusterNum = 1; - memset(&(m_aCluster[0]), 0, sizeof (KMSClusterEntry)); - strncpy(m_aCluster[0].m_wsApplianceNetworkAddress, - i_pProfile->m_wsApplianceAddress, - sizeof(m_aCluster[0].m_wsApplianceNetworkAddress)); - m_aCluster[0].m_wsApplianceNetworkAddress[sizeof(m_aCluster[0].m_wsApplianceNetworkAddress)-1] = '\0'; - - // This may not be known because the initial - // appliance's Alias is not yet entered. - strcpy(m_aCluster[0].m_wsApplianceAlias, ""); - strcpy(m_sURL, ""); - memset(m_aKWKEntries, 0, KMS_MAX_CLUSTER_NUM * sizeof(struct KWKEntry *)); -} - -CAgentLoadBalancer::~CAgentLoadBalancer () -{ - // free up KWK entries - for( int i=0; i < m_iKWKEntryNum && i < KMS_MAX_CLUSTER_NUM; i++) - { - if (m_aKWKEntries[i] != NULL) - { - delete m_aKWKEntries[i]; - } - } - return; -} - -char *CAgentLoadBalancer::GetHTTPSURL (int i_iIndex, int i_iPort) -{ - if (i_iIndex < 0 || i_iIndex >= m_iClusterNum) - { - strcpy(m_sURL, ""); - } - else - { - K_snprintf(m_sURL, KMS_MAX_URL, "https://%s:%d", - m_aCluster[i_iIndex].m_wsApplianceNetworkAddress, - i_iPort); - } - - return m_sURL; -} - -char *CAgentLoadBalancer::GetHTTPURL (int i_iIndex, int i_iPort) -{ - if (i_iIndex < 0 || i_iIndex >= m_iClusterNum) - { - strcpy(m_sURL, ""); - } - else - { - K_snprintf(m_sURL, KMS_MAX_URL, "http://%s:%d", - m_aCluster[i_iIndex].m_wsApplianceNetworkAddress, - i_iPort); - } - - return m_sURL; -} - -int CAgentLoadBalancer::Balance () -{ - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - int i; - unsigned int iSelected = 0; - unsigned int iSelected2 = 0; - - // clear the failover attempts - m_pProfile->m_iFailoverAttempts = 0; - - // This assumes Balance()/BalanceBy...() are called at the top of - // each Agent Library transaction - // m_iTransactionStartTimeInMilliseconds is used to determine if - // enough time remains - // (vs. KMSClientProfile::m_iTransactionTimeout) to retry a - // request if there was a Server Busy error. - - m_iTransactionStartTimeInMilliseconds = K_GetTickCount(); - - // if not enabling load balancing, return the default appliance & if - // its FIPS compatible when running in FIPS_MODE - - if (m_pProfile->m_iClusterDiscoveryFrequency == 0) - { - if (m_bFIPS && !FIPScompatibleKMA(m_aCluster[0].m_sKMAVersion)) - { - return NO_FIPS_KMA_AVAILABLE; - } - return 0; - } - - int iCurrentTime = K_GetTickCount() / 1000; - - // if it is the first time or time to get cluster information - if ((!m_pProfile->m_bIsClusterDiscoveryCalled) || - ((iCurrentTime - m_pProfile->m_iLastClusterDiscoveryTime) > - m_pProfile->m_iClusterDiscoveryFrequency)) - { - if (!KMSClient_GetClusterInformation(m_pProfile, - m_pProfile->m_wsEntitySiteID, - sizeof (m_pProfile->m_wsEntitySiteID), - &(m_pProfile->m_iClusterNum), - m_pProfile->m_aCluster, - KMS_MAX_CLUSTER_NUM)) - { - // if failed due to some error, return default one - // KMSClient_GetClusterInformation logs - - return 0; - } - - m_pProfile->m_bIsClusterDiscoveryCalled = true; - - // Reset the transaction start time to not include the time spent - // calling KMSClient_GetClusterInformation. - - m_iTransactionStartTimeInMilliseconds = K_GetTickCount(); - - // reset this index since cluster size may have changed - m_iLastAttemptedWhenNoneResponding = 0; - - // TODO: Adjust timeouts to guarentee a response to the Agent - // Library called in m_iTransactionTimeout seconds? This means - // not adjusting m_iTransactionStartTimeInMilliseconds, but also - // reducing socket timeouts for subsequent calls. - } - - // sort the cluster array by Load - - KMSClient_SortClusterArray(m_pProfile); - - // copy all Appliances to this object - - for (i = 0; i < m_pProfile->m_iClusterNum; i++) - { - m_aCluster[i] = m_pProfile->m_aCluster[i]; - } - - m_iClusterNum = m_pProfile->m_iClusterNum; - - int iCandidateAppliances = 0; - - // the initial set of candidates for load balancing are all enabled, - // responding and unlocked KMAs (assumes they are at the top of the sort - // order) & FIPS compatible if we're in that mode - - for (i = 0; i < m_iClusterNum; i++) - { - if ((m_aCluster[i].m_iResponding == TRUE) && - (m_aCluster[i].m_iEnabled == TRUE ) && - (m_aCluster[i].m_iKMALocked == FALSE)) - { - iCandidateAppliances++; - } - } - - // check if there are any enabled and responding Appliances in the - // same site as this Agent, and if so make those the candidates - // (assumes they are at the top of the sort order) - - int iCandidateAppliancesInSameSite = 0; - - if (strlen(m_pProfile->m_wsEntitySiteID) > 0) - { - for (i = 0; i < iCandidateAppliances; i++) - { - if (strncmp(m_aCluster[i].m_wsApplianceSiteID, - m_pProfile->m_wsEntitySiteID, - sizeof(m_aCluster[i].m_wsApplianceSiteID)) == 0) - { - iCandidateAppliancesInSameSite++; - } - } - } - - // reduce the candidate set to just KMAs within the site - if (iCandidateAppliancesInSameSite > 0) - { - iCandidateAppliances = iCandidateAppliancesInSameSite; - } - - // constrain the candidate set to just FIPS compatible KMAs - if (m_bFIPS) - { - int iCandidateFIPSKMAs = 0; - - for (i = 0; i < iCandidateAppliances; i++) - { - if ( FIPScompatibleKMA(m_aCluster[i].m_sKMAVersion )) - { - iCandidateFIPSKMAs++; - } - } - - // select only from FIPS capable KMAs - iCandidateAppliances = iCandidateFIPSKMAs; - } - - // if there are no candidate Appliances, use the default Appliance unless - // we're in FIPS mode - - if (!m_bFIPS && iCandidateAppliances <= 1) - { - return 0; - } - - // FIPS mode - else if (iCandidateAppliances <= 0) - { - return NO_FIPS_KMA_AVAILABLE; - } - else if (iCandidateAppliances == 1) - { - return 0; - } - - // randomly select two candidate Appliances and select the one - // with the smaller load - - // choose one random number between 0 -- iCandidateAppliances - 1 - iSelected = rand() % iCandidateAppliances; - iSelected2 = (iSelected + 1) % iCandidateAppliances; - - // select the one with the smaller load - - if (m_aCluster[iSelected2].m_lLoad < m_aCluster[iSelected].m_lLoad) - { - iSelected = iSelected2; - } - - return iSelected; -} - -int CAgentLoadBalancer::BalanceByDataUnitID ( - const unsigned char * const i_pDataUnitID, - int i_iDataUnitIDMaxLen) -{ - FATAL_ASSERT(i_pDataUnitID); - - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - // clear the failover attempts - m_pProfile->m_iFailoverAttempts = 0; - - // This assumes Balance(), or BalanceBy...(), - // is called at the top of each Agent Library transaction - // m_iTransactionStartTimeInMilliseconds is used to determine if enough time remains - // (vs. KMSClientProfile::m_iTransactionTimeout) to retry a request if there was - // a Server Busy error. - - m_iTransactionStartTimeInMilliseconds = K_GetTickCount(); - - // look in cache - - CDataUnitCache *pDataUnitCache = (CDataUnitCache *) m_pProfile->m_pDataUnitCache; - - // if not enabling load balancing, return the default appliance & if - // its FIPS compatible when running in FIPS_MODE - - if (m_pProfile->m_iClusterDiscoveryFrequency == 0) - { - if (m_bFIPS && !FIPScompatibleKMA(m_aCluster[0].m_sKMAVersion)) - { - return NO_FIPS_KMA_AVAILABLE; - } - return 0; - } - - // if the Data Unit ID is in the server affinity cache, use that Appliance - - utf8char wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS]; - int iIndex = CLIENT_SIDE_ERROR; - - if (pDataUnitCache->GetApplianceByDataUnitID( - i_pDataUnitID, - i_iDataUnitIDMaxLen, - wsApplianceNetworkAddress, - sizeof(wsApplianceNetworkAddress))) - { - iIndex = FindIndexByNetworkAddress(wsApplianceNetworkAddress); - } - - if (iIndex != CLIENT_SIDE_ERROR) - { - if (m_bFIPS && !FIPScompatibleKMA(m_aCluster[iIndex].m_sKMAVersion)) - { - // in spite of caching we need to attempt an alternate KMA due - // to the FIPS mode setting - return Balance(); - } - return iIndex; - } - - // normal balancing - return Balance(); -} - -int CAgentLoadBalancer::BalanceByDataUnitKeyID ( - const unsigned char * const i_pDataUnitKeyID, - int i_iDataUnitKeyIDMaxLen) -{ - FATAL_ASSERT(i_pDataUnitKeyID); - - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - // clear the failover attempts - m_pProfile->m_iFailoverAttempts = 0; - - // This assumes Balance()/BalanceBy...() - // are called at the top of each Agent Library transaction - // m_iTransactionStartTimeInMilliseconds is used to determine if enough time remains - // (vs. KMSClientProfile::m_iTransactionTimeout) to retry a request if there was - // a Server Busy error. - - m_iTransactionStartTimeInMilliseconds = K_GetTickCount(); - - // look in cache - - CDataUnitCache *pDataUnitCache = (CDataUnitCache *) m_pProfile->m_pDataUnitCache; - - // if not enabling load balancing, return the default appliance & if - // its FIPS compatible when running in FIPS_MODE - - if (m_pProfile->m_iClusterDiscoveryFrequency == 0) - { - if (m_bFIPS && !FIPScompatibleKMA(m_aCluster[0].m_sKMAVersion)) - { - return NO_FIPS_KMA_AVAILABLE; - } - return 0; - } - - // if the Data Unit Key ID is in the server affinity cache, use that Appliance - - utf8char sApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS]; - int iIndex = CLIENT_SIDE_ERROR; - - if (pDataUnitCache->GetApplianceByDataUnitKeyID( - i_pDataUnitKeyID, - i_iDataUnitKeyIDMaxLen, - sApplianceNetworkAddress, - sizeof(sApplianceNetworkAddress))) - { - iIndex = FindIndexByNetworkAddress(sApplianceNetworkAddress); - } - - if (iIndex != CLIENT_SIDE_ERROR) - { - if (m_bFIPS && !FIPScompatibleKMA(m_aCluster[iIndex].m_sKMAVersion)) - { - // in spite of caching we need to attempt an alternate KMA due - // to the FIPS mode setting - return Balance(); - } - return iIndex; - } - - // normal balancing - return Balance(); -} - -int CAgentLoadBalancer::FindIndexByNetworkAddress -(char * i_wsApplianceNetworkAddress) -{ - FATAL_ASSERT(i_wsApplianceNetworkAddress); - - for (int i = 0; i < m_iClusterNum; i++) - { - - if ((strncmp(m_aCluster[i].m_wsApplianceNetworkAddress, - i_wsApplianceNetworkAddress, - sizeof(m_aCluster[i].m_wsApplianceNetworkAddress)) == 0) && - m_aCluster[i].m_iEnabled == TRUE && - m_aCluster[i].m_iResponding == TRUE) - { - return i; - } - - } - - return CLIENT_SIDE_ERROR; -} - -char* CAgentLoadBalancer::GetApplianceNetworkAddress (int i_iIndex) -{ - if (i_iIndex < 0 || i_iIndex >= m_iClusterNum) - { - return (char *)""; - } - - return m_aCluster[i_iIndex].m_wsApplianceNetworkAddress; -} - -bool CAgentLoadBalancer::FailOverLimit (void) -{ - if (m_pProfile->m_iFailoverLimit >= 0 && - m_pProfile->m_iFailoverAttempts > m_pProfile->m_iFailoverLimit) - return true; - else - return false; -} - -int CAgentLoadBalancer::FailOver (int i_iFailedApplianceIndex, - struct soap *i_pstSoap) -{ - FATAL_ASSERT(i_pstSoap); - - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - const char *strError = GET_SOAP_FAULTSTRING(i_pstSoap); - int iSoapErrno = i_pstSoap->errnum; - int iErrorCode = GET_FAULT_CODE(strError); - int i; - - if ( m_bFIPS && - KMSClient_NoFIPSCompatibleKMAs(m_pProfile)) - { - return NO_FIPS_KMA_AVAILABLE; - } - - m_pProfile->m_iFailoverAttempts++; - - /* - * if KWK is not registered, or mismatched, most likely KMA lost its key due to a service - * restart. Call RegisterKWK to re-register the KWK. - * If RegisterKWK fails proceed from here with new failover info - */ - if ( iErrorCode == CLIENT_ERROR_AGENT_KWK_NOT_REGISTERED || - iErrorCode == CLIENT_ERROR_AGENT_KWK_ID_MISMATCH ) - { - LogError(m_pProfile, - AGENT_LOADBALANCER_FAILOVER, - NULL, - m_aCluster[i_iFailedApplianceIndex].m_wsApplianceNetworkAddress, - "KWK not registered or ID mismatch - registering"); - // delete the KWK entry since the KMA no longer has it - DeleteKWKEntry( GetKMAID(i_iFailedApplianceIndex)); - - return i_iFailedApplianceIndex; - } - - bool bServerError = false; - - // if the request failed due to a Server Busy error, and if - // - transaction timeout has not been exceeded OR - // - failover attempts remain - // then failover - - if (iErrorCode == CLIENT_ERROR_SERVER_BUSY && - (K_GetTickCount() < m_iTransactionStartTimeInMilliseconds + (m_pProfile->m_iTransactionTimeout * 1000) || - !CAgentLoadBalancer::FailOverLimit())) - { - LogError(m_pProfile, - AGENT_LOADBALANCER_FAILOVER, - NULL, - m_aCluster[i_iFailedApplianceIndex].m_wsApplianceNetworkAddress, - "Server Busy - failing over"); - bServerError = true; - } - else if (ServerError(strError,iSoapErrno)) - { - bServerError = true; - } - else - { - if (i_iFailedApplianceIndex == AES_KEY_WRAP_SETUP_ERROR) - { - return AES_KEY_WRAP_SETUP_ERROR; - } - else - { - return CLIENT_SIDE_ERROR; // it is a client side problem, don't fail over - } - } - - // disable the failed Appliance in the profile, and - // re-sort the cluster array, so transactions in other threads - // will not send requests to the same failed Appliance -#if defined(METAWARE) - log_cond_printf(ECPT_LOG_AGENT, "CAgentLoadBalancer::Failover(): FailoverAttempts=%d\n", - m_pProfile->m_iFailoverAttempts); -#endif - for (i = 0; i < m_pProfile->m_iClusterNum; i++) - { - if (m_pProfile->m_aCluster[i].m_lApplianceID == - m_aCluster[i_iFailedApplianceIndex].m_lApplianceID) - { - m_pProfile->m_aCluster[i].m_iResponding = FALSE; - break; - } - } - - KMSClient_SortClusterArray(m_pProfile); - - // mark the failed Appliance as not responding (unlike the case - // above which is conditional on bServerError, this marking is - // only local to this transaction; it must be done to ensure that - // this transaction does not cycle in its fail-over loop.) - - m_aCluster[i_iFailedApplianceIndex].m_iResponding = FALSE; - - if (!CAgentLoadBalancer::FailOverLimit()) - { - // now try to fail over to all other Appliances that are - // apparently enabled and responding - - for (i = 0; i < m_iClusterNum; i++) - { - if (m_aCluster[i].m_iEnabled == TRUE && - m_aCluster[i].m_iResponding == TRUE && - m_aCluster[i].m_iKMALocked == FALSE) - { - Log(AGENT_LOADBALANCER_FAILOVER, - NULL, - m_aCluster[i].m_wsApplianceNetworkAddress, - "Failing over to this addr"); - - return i; - } - } - - // now retry KMAs previously reported as not responding - - m_iLastAttemptedWhenNoneResponding++; - - if (m_iLastAttemptedWhenNoneResponding >= m_iClusterNum) - { - m_iLastAttemptedWhenNoneResponding = m_iLastAttemptedWhenNoneResponding % m_iClusterNum; - } - - Log(AGENT_LOADBALANCER_FAILOVER, - NULL, - m_aCluster[m_iLastAttemptedWhenNoneResponding].m_wsApplianceNetworkAddress, - "Failing over to retry this addr"); - - return m_iLastAttemptedWhenNoneResponding; - } - else - { - Log(AGENT_LOADBALANCER_FAILOVER, - NULL, - NULL, - "Failover limit reached"); - } - - return m_bFIPS ? NO_FIPS_KMA_AVAILABLE : NO_KMA_AVAILABLE; -} - -void CAgentLoadBalancer::UpdateResponseStatus(int i_iIndex) -{ - bool bStatusChanged = false; - - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) m_pProfile->m_pLock); - - // enable the responding Appliance in the profile, and - // re-sort the cluster array, so transactions in other threads - // will not send requests to the same failed Appliance - - for (int i = 0; i < m_pProfile->m_iClusterNum; i++) - { - if (m_pProfile->m_aCluster[i].m_lApplianceID == - m_aCluster[i_iIndex].m_lApplianceID) - { - if (m_pProfile->m_aCluster[i].m_iResponding == FALSE) - { - bStatusChanged = true; - } - m_pProfile->m_aCluster[i].m_iResponding = TRUE; - break; - } - } - - // only resort if the responding status actually changed - if (bStatusChanged) - { - KMSClient_SortClusterArray(m_pProfile); - } - - // mark the Appliance as now responding - m_aCluster[i_iIndex].m_iResponding = TRUE; - - return; -} - -Long64 CAgentLoadBalancer::GetKMAID ( - int i_iIndex) -{ - if (i_iIndex < 0 || i_iIndex >= m_iClusterNum) - { - return -1; - } - - return m_aCluster[i_iIndex].m_lApplianceID; -} - -CAgentLoadBalancer::KWKEntry *CAgentLoadBalancer::GetKWK ( - Long64 i_lKMAID) -{ - if (i_lKMAID == -1) - { - return NULL; - } - - for (int i = 0; i < m_iKWKEntryNum && i < KMS_MAX_CLUSTER_NUM; i++) - { - if (m_aKWKEntries[i] != NULL && - m_aKWKEntries[i]->m_lKMAID == i_lKMAID ) - { - return m_aKWKEntries[i]; - } - } - - return NULL; -} - -CAgentLoadBalancer::KWKEntry *CAgentLoadBalancer::CreateKWK ( - Long64 i_lKMAID, - struct soap * const i_pstSoap, - const char * const i_sURL, - bool * const o_pbClientAESKeyWrapSetupError) -{ - FATAL_ASSERT(i_pstSoap); - FATAL_ASSERT(i_sURL); - - int bSuccess = FALSE; - KWKEntry *oKWKEntry = new KWKEntry; - - oKWKEntry->m_lKMAID = i_lKMAID; - *o_pbClientAESKeyWrapSetupError = false; - - bSuccess = GetPseudorandomBytes(sizeof (oKWKEntry->m_acKWK), - oKWKEntry->m_acKWK); - if (!bSuccess) - { - Log(AUDIT_CLIENT_AGENT_CREATE_KWK_RNG_ERROR, - NULL, - NULL, - "Error from RNG"); - *o_pbClientAESKeyWrapSetupError = true; - delete(oKWKEntry); - return NULL; - } - -#if defined(DEBUG) - char sHexKWK[2*KMS_MAX_KEY_SIZE+1]; - ConvertBinaryToUTF8HexString( sHexKWK, oKWKEntry->m_acKWK, sizeof (oKWKEntry->m_acKWK)); -#if defined(METAWARE) - log_printf("CAgentLoadBalancer::CreateKWK(): KWK hex=%s\n", - sHexKWK); -#else -// printf("CAgentLoadBalancer::CreateKWK(): KWK hex=%s\n", -// sHexKWK); -#endif -#endif - - CPublicKey oPublicKEK; - - bSuccess = GetKWKWrappingKey(i_pstSoap, i_sURL, &oPublicKEK); - - if (!bSuccess) - { - // GetKWKWrappingKey logs errors - - if (!ServerError(GET_SOAP_FAULTSTRING(i_pstSoap),i_pstSoap->errnum)) - { - *o_pbClientAESKeyWrapSetupError = true; - } - delete(oKWKEntry); - return NULL; - } - - unsigned char acWrappedKWK[MAX_RSA_PUB_KEY_LENGTH]; - int iWrappedKWKLength; - bSuccess = oPublicKEK.Encrypt(sizeof (oKWKEntry->m_acKWK), - oKWKEntry->m_acKWK, (unsigned char *) acWrappedKWK, &iWrappedKWKLength); - - if (!bSuccess) - { - Log(AUDIT_CLIENT_AGENT_CREATE_KWK_PUBLIC_ENCRYPT_ERROR, - NULL, - NULL, - "Error encrypting KWK with KMA public key"); - *o_pbClientAESKeyWrapSetupError = true; - delete(oKWKEntry); - return NULL; - } -//#if defined(DEBUG) && !defined(METAWARE) -// char sHexWrappedKWK[2*MAX_RSA_PUB_KEY_LENGTH+1]; -// ConvertBinaryToUTF8HexString( sHexWrappedKWK, acWrappedKWK, iWrappedKWKLength); -// printf("CAgentLoadBalancer::CreateKWK(): wrapped KWK hex=%s\n", -// sHexWrappedKWK); -//#endif - - // register the new KWK - bSuccess = RegisterKWK(iWrappedKWKLength, acWrappedKWK, i_pstSoap, - i_sURL, oKWKEntry->m_acKWKID); - - if (!bSuccess) - { - // RegisterKWK logs errors - if (!ServerError(GET_SOAP_FAULTSTRING(i_pstSoap), i_pstSoap->error)) - { - *o_pbClientAESKeyWrapSetupError = true; - } - delete(oKWKEntry); - return NULL; - } - - // save the new KWK entry in an empty slot in the array - for (int i=0; i < m_iKWKEntryNum && i < KMS_MAX_CLUSTER_NUM; i++) - { - if (m_aKWKEntries[i] == NULL) - { - m_aKWKEntries[i] = oKWKEntry; - return oKWKEntry; - } - } - - // no empty slots so add it to the end - m_aKWKEntries[m_iKWKEntryNum++] = oKWKEntry; - - return oKWKEntry; -} - -void CAgentLoadBalancer::DeleteKWKEntry(Long64 i_lKMAID) -{ - for (int i=0; i < m_iKWKEntryNum && i < KMS_MAX_CLUSTER_NUM; i++) - { - if (m_aKWKEntries[i] && m_aKWKEntries[i]->m_lKMAID == i_lKMAID) - { - delete(m_aKWKEntries[i]); - m_aKWKEntries[i] = NULL; - return; - } - } - // should not occur - FATAL_ASSERT(0); - return; -} - -bool CAgentLoadBalancer::AESKeyWrapSupported (int i_iIndex) -{ - if (i_iIndex < 0 || i_iIndex >= m_iClusterNum) - { - return false; - } - return (strcmp(m_aCluster[i_iIndex].m_sKMAVersion, - FIPS_COMPATIBLE_KMA_VERSION) >= 0); -} - -int CAgentLoadBalancer::GetKWKID ( - int i_Index, - Long64 i_lKMAID, - struct soap * const i_pstSoap, - UTF8_KEYID o_pKWKID, - bool * const o_pbClientAESKeyWrapSetupError) -{ - FATAL_ASSERT(i_Index >= 0 && i_Index <= m_iClusterNum); - FATAL_ASSERT(i_lKMAID != 0); - FATAL_ASSERT(i_pstSoap); - FATAL_ASSERT(o_pKWKID); - FATAL_ASSERT(o_pbClientAESKeyWrapSetupError); - - *o_pbClientAESKeyWrapSetupError = false; - - // check if the KMA for this cluster index is at a version supporting - // AES key wrap - if (!AESKeyWrapSupported(i_Index)) - { - strcpy(o_pKWKID, ""); - return TRUE; - } - - // AES Key Wrap Mode - - struct KWKEntry* pKWKentry = GetKWK(i_lKMAID); - - if (pKWKentry == NULL) - { - const char* sURL = GetHTTPSURL( - i_Index, - m_pProfile->m_iPortForAgentService); - - pKWKentry = CreateKWK(i_lKMAID, i_pstSoap, sURL, o_pbClientAESKeyWrapSetupError); - - if (pKWKentry == NULL) - { - return FALSE; - } - } - -#if defined(DEBUG) && defined(METAWARE) - log_printf("CAgentLoadBalancer::GetKWKID(): KWK IDhex=%s\n", - pKWKentry->m_acKWKID, - sizeof (UTF8_KEYID)); -#endif - - strncpy(o_pKWKID, pKWKentry->m_acKWKID, sizeof(UTF8_KEYID)); - o_pKWKID[sizeof(UTF8_KEYID)-1] = '\0'; - - return TRUE; -}; - -int CAgentLoadBalancer::GetKWKWrappingKey ( - struct soap * const i_pstSoap, - const char * const i_sURL, - CPublicKey * const o_opPublicKEK) -{ - FATAL_ASSERT(i_pstSoap); - FATAL_ASSERT(i_sURL); - FATAL_ASSERT(o_opPublicKEK); - - int bSuccess = TRUE; - struct KMS_Agent::KMS_Agent__GetAgentKWKPublicKeyResponse oResponse; - char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; - char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; - - bSuccess = KMS_Agent::soap_call_KMS_Agent__GetAgentKWKPublicKey( - const_cast<struct soap *> (i_pstSoap), - i_sURL, - NULL, - oResponse) == SOAP_OK; - - if (!bSuccess) - { - GetSoapFault(sSoapFaultMsg, const_cast<struct soap *> (i_pstSoap)); - GetPeerNetworkAddress(sKmaAddress, const_cast<struct soap *> (i_pstSoap)); - - LogError(m_pProfile, - AUDIT_CLIENT_GET_KWK_WRAPPING_KEY_SOAP_ERROR, - NULL, - sKmaAddress, - sSoapFaultMsg); - - return FALSE; - } - - // Validate the response structure - if (bSuccess) - { - if (oResponse.KWKPublicKey.__ptr == NULL - || oResponse.KWKPublicKey.__size < 1) - { - bSuccess = FALSE; - - GetPeerNetworkAddress(sKmaAddress, const_cast<struct soap *> (i_pstSoap)); - - LogError(m_pProfile, - AUDIT_CLIENT_GET_KWK_WRAPPING_KEY_INVALID_KEY_RESPONSE, - NULL, - sKmaAddress, - NULL); - } - else - { - bSuccess = o_opPublicKEK->Load(oResponse.KWKPublicKey.__ptr, - oResponse.KWKPublicKey.__size, PKI_FORMAT); - if (!bSuccess) - { - GetPeerNetworkAddress(sKmaAddress, const_cast<struct soap *> (i_pstSoap)); - - LogError(m_pProfile, - AUDIT_CLIENT_GET_KWK_WRAPPING_KEY_INVALID_RSA_PUB_KEY, - NULL, - sKmaAddress, - NULL); - } - } - } - - // Note: no SOAP cleanup as caller's environment will get destroyed - - return bSuccess; -}; - -int CAgentLoadBalancer::RegisterKWK ( - int i_iWrappedKWKSize, - const unsigned char * const i_acWrappedKWK, - struct soap * const i_pstSoap, - const char * const i_sURL, - UTF8_KEYID o_acUTF8KeyID) -{ - FATAL_ASSERT(i_iWrappedKWKSize > 0); - FATAL_ASSERT(i_acWrappedKWK); - FATAL_ASSERT(i_pstSoap); - FATAL_ASSERT(i_sURL); - FATAL_ASSERT(o_acUTF8KeyID); - - int bSuccess; - - struct KMS_Agent::xsd__hexBinary oKWK; - -#if defined(DEBUG) && defined(METAWARE) - char sHexWrappedKWK[512]; - ConvertBinaryToUTF8HexString( sHexWrappedKWK, i_acWrappedKWK, i_iWrappedKWKSize); - log_printf("CAgentLoadBalancer::RegisterKWK(): Wrapped KWK hex=%s, len=%d\n", - sHexWrappedKWK, i_iWrappedKWKSize); -#endif - - if (!PutBinaryIntoSoapBinary(i_pstSoap, - i_acWrappedKWK, - i_iWrappedKWKSize, - oKWK.__ptr, - oKWK.__size)) - { - return FALSE; - } - - char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH]; - char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH]; - struct KMS_Agent::KMS_Agent__RegisterAgentKWKResponse oResponse; - - bSuccess = KMS_Agent::soap_call_KMS_Agent__RegisterAgentKWK( - const_cast<struct soap *> (i_pstSoap), - i_sURL, NULL, oKWK, oResponse) == SOAP_OK; - - if (bSuccess) - { - // verify response - if (oResponse.AgentKWKID && - strlen(oResponse.AgentKWKID) == 2 * KMS_KWK_KEY_ID_SIZE) - { -#if defined(DEBUG) && defined(METAWARE) - log_printf("CAgentLoadBalancer::RegisterKWK(): KWK ID hex=%s\n", - oResponse.AgentKWKID, - sizeof (UTF8_KEYID)); -#endif - strncpy(o_acUTF8KeyID, oResponse.AgentKWKID, sizeof(UTF8_KEYID)); - o_acUTF8KeyID[sizeof(UTF8_KEYID)-1] = '\0'; - } - else - { - GetPeerNetworkAddress(sKmaAddress, const_cast<struct soap *> (i_pstSoap)); - GetSoapFault(sSoapFaultMsg, const_cast<struct soap *> (i_pstSoap)); - - Log(AUDIT_CLIENT_AGENT_REGISTER_KWK_INVALID_KEYID_RESPONSE, - NULL, - sKmaAddress, - sSoapFaultMsg); - bSuccess = FALSE; - } - } - else - { - GetPeerNetworkAddress(sKmaAddress, const_cast<struct soap *> (i_pstSoap)); - GetSoapFault(sSoapFaultMsg, const_cast<struct soap *> (i_pstSoap)); - - Log(AUDIT_CLIENT_AGENT_REGISTER_KWK_ERROR, - NULL, - sKmaAddress, - sSoapFaultMsg); - bSuccess = FALSE; - } - - // Note: Clean up SOAP must happen in caller, not here - - return bSuccess; - -}; - -bool CAgentLoadBalancer::AESKeyUnwrap ( - int * const io_pIndex, - const WRAPPED_KEY i_pAESWrappedKey, - KEY o_pPlainTextKey) -{ - FATAL_ASSERT(io_pIndex); - FATAL_ASSERT(*io_pIndex >= 0); - FATAL_ASSERT(o_pPlainTextKey); - FATAL_ASSERT(i_pAESWrappedKey); - - struct KWKEntry * pKWKEntry = GetKWK(GetKMAID(*io_pIndex)); - - if (pKWKEntry == NULL) - { - Log(AGENT_LOADBALANCER_AESKEYUNWRAP_GETKWK_RETURNED_NULL, - NULL, - m_aCluster[*io_pIndex].m_wsApplianceNetworkAddress, - NULL); - *io_pIndex = CAgentLoadBalancer::AES_KEY_UNWRAP_ERROR; - - return false; - } - -#if defined(DEBUG) && defined(METAWARE) - char sHexKWK[2*KMS_MAX_KEY_SIZE+1]; - ConvertBinaryToUTF8HexString( sHexKWK, pKWKEntry->m_acKWK, sizeof (pKWKEntry->m_acKWK)); - log_printf("CAgentLoadBalancer::AESKeyUnwrap(): KWK hex=%s\n", - sHexKWK); -#endif - - if (aes_key_unwrap(pKWKEntry->m_acKWK, - sizeof (pKWKEntry->m_acKWK), - i_pAESWrappedKey, - o_pPlainTextKey, 4) != 0) - { - Log(AGENT_LOADBALANCER_AESKEYUNWRAP_KEY_UNWRAP_FAILED, - NULL, - m_aCluster[*io_pIndex].m_wsApplianceNetworkAddress, - NULL); - *io_pIndex = CAgentLoadBalancer::AES_KEY_UNWRAP_ERROR; - return false; - } - - return true; -} - -/*--------------------------------------------------------------------------- - * Function: KMSClient_SortClusterArray - * - *--------------------------------------------------------------------------*/ -void CAgentLoadBalancer::KMSClient_SortClusterArray (KMSClientProfile * const i_pProfile) -{ - FATAL_ASSERT(i_pProfile); - - CAutoMutex oAutoMutex((K_MUTEX_HANDLE) i_pProfile->m_pLock); - - int i; - - - // adjust loads according to availability, site and FIPS compatibility - for (i = 0; i < i_pProfile->m_iClusterNum; i++) - { - if ((i_pProfile->m_aCluster[i].m_iEnabled == FALSE - || i_pProfile->m_aCluster[i].m_iResponding == FALSE - || i_pProfile->m_aCluster[i].m_iKMALocked)) - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)+1] = 1; - } - else - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)+1] = 0; - } - - if (strcmp(i_pProfile->m_aCluster[i].m_wsApplianceSiteID, - i_pProfile->m_wsEntitySiteID) != 0) - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)] = 1; - } - else - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)] = 0; - } - - if ( m_bFIPS && - !FIPScompatibleKMA(i_pProfile->m_aCluster[i].m_sKMAVersion)) - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)+2] = 1; - } - else - { - ((unsigned char*) &(i_pProfile->m_aCluster[i].m_lLoad))[sizeof (int)+2] = 0; - } - } - - // sort ascending by load - - // gnome sort: the simplest sort algoritm - // http://www.cs.vu.nl/~dick/gnomesort.html - - //void gnomesort(int n, int ar[]) { - // int i = 0; - // - // while (i < n) { - // if (i == 0 || ar[i-1] <= ar[i]) i++; - // else {int tmp = ar[i]; ar[i] = ar[i-1]; ar[--i] = tmp;} - // } - //} - - i = 0; - while (i < i_pProfile->m_iClusterNum) - { - if (i == 0 || i_pProfile->m_aCluster[i - 1].m_lLoad <= i_pProfile->m_aCluster[i].m_lLoad) - { - i++; - } - else - { - KMSClusterEntry tmp = i_pProfile->m_aCluster[i]; - i_pProfile->m_aCluster[i] = i_pProfile->m_aCluster[i - 1]; - i_pProfile->m_aCluster[--i] = tmp; - } - } -} |