summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp
diff options
context:
space:
mode:
authorJohn Sonnenschein <johns@joyent.com>2012-05-17 18:26:57 +0000
committerJohn Sonnenschein <johns@joyent.com>2012-05-17 18:26:57 +0000
commit04b244dd661c24b510ac22936decfc0972d202d3 (patch)
tree3ebfef98afc303fddf3415d6fba64e8682f495e8 /usr/src/lib/libkmsagent/common/KMSAgentLoadBalancer.cpp
parenteac250589e41f1b705e1b7427b02b3379aac9f9e (diff)
parenta69187741b83640a90dd8586195456dd50c016a8 (diff)
downloadillumos-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.cpp1169
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;
- }
- }
-}