From e3a00efe33143db10a78ac3c8aede46b5f4f5f71 Mon Sep 17 00:00:00 2001 From: Juan Carlos Luciani Date: Mon, 30 Jun 2008 20:41:06 +0000 Subject: [PATCH] Added retries for RPCs that fail due to connection errors. --- CASA-auth-token/client/include/casa_status.h | 215 ++ CASA-auth-token/client/library/cache.c | 2016 +++++++++--------- CASA-auth-token/client/library/linux/rpc.c | 1321 ++++++------ CASA-auth-token/client/library/windows/rpc.c | 1720 +++++++-------- CASA/include/casa_status.h | 1 + 5 files changed, 2762 insertions(+), 2511 deletions(-) create mode 100644 CASA-auth-token/client/include/casa_status.h diff --git a/CASA-auth-token/client/include/casa_status.h b/CASA-auth-token/client/include/casa_status.h new file mode 100644 index 00000000..99aab274 --- /dev/null +++ b/CASA-auth-token/client/include/casa_status.h @@ -0,0 +1,215 @@ +/*********************************************************************** + * + * Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + * + ***********************************************************************/ + + +#ifndef _CASA_STATUS_H_ +#define _CASA_STATUS_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" +{ +#endif + +//===[ Header files specific to this module ]============================== + +#include + +//===[ External data ]============================== + +//===[ External prototypes ]============================== + +//===[ Type definitions ]============================== + +// +// CasaStatus type +// +// +// The layed out of status values is as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-+---------------------+-------------------------------+ +// |Sev|r|r|r| Facility | Code | +// +---+-+-+-+---------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// r - is a reserved bit for internal use +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +typedef uint32_t CasaStatus; + + +//===[ Manifest constants ]============================== + +// +// Define severity codes to be used with CasaStatusBuild macro +// + +#define CASA_SEVERITY_SUCCESS 0x0 +#define CASA_SEVERITY_INFORMATIONAL 0x1 +#define CASA_SEVERITY_WARNING 0x2 +#define CASA_SEVERITY_ERROR 0x3 + +// +// Define the facility codes +// +// Facility codes will start at 0x800 and then work backwards +// in an effort to avoid conflict with other system components. +// + +#define CASA_FACILITY_AUTHTOKEN 0x7FF +#define CASA_FACILITY_KRB5TOKEN 0x7FE +#define CASA_FACILITY_PWTOKEN 0x7FD + +// +// Codes above FACILITY_SPECIFIC are component specific status codes. +// Facility specific status codes are defined in the facilities' header file. +// + +#define FACILITY_SPECIFIC 0x00001000 + +// +// Codes below FACILITY_SPECIFIC are common status codes shared by all components. +// + +#define CASA_STATUS_SUCCESS ((CasaStatus)0x00000000) // Call completed successfully +#define CASA_STATUS_UNSUCCESSFUL ((CasaStatus)0x00000001) // Call completed unsuccessfully +#define CASA_STATUS_INVALID_HANDLE ((CasaStatus)0x00000002) // An invalid handle was specified +#define CASA_STATUS_INVALID_PARAMETER ((CasaStatus)0x00000003) // An invalid parameter to function was specified +#define CASA_STATUS_INSUFFICIENT_RESOURCES ((CasaStatus)0x00000004) +#define CASA_STATUS_ACCESS_DENIED ((CasaStatus)0x00000005) // Caller does not have required access rights for operation +#define CASA_STATUS_BUFFER_OVERFLOW ((CasaStatus)0x00000006) // The data was too large to fit into the specified buffer +#define CASA_STATUS_NO_DATA ((CasaStatus)0x00000007) +#define CASA_STATUS_NO_MORE_ENTRIES ((CasaStatus)0x00000008) // No more entries to enumerate +#define CASA_STATUS_TIMEOUT ((CasaStatus)0x00000009) // Timed out waiting on resource +#define CASA_STATUS_OBJECT_NOT_FOUND ((CasaStatus)0x0000000A) +#define CASA_STATUS_CANCELLED ((CasaStatus)0x0000000B) // Request cancelled +#define CASA_STATUS_NOT_IMPLEMENTED ((CasaStatus)0x0000000C) +#define CASA_STATUS_PENDING ((CasaStatus)0x0000000D) // The request is being processed +#define CASA_STATUS_INVALID_STATE ((CasaStatus)0x0000000E) +#define CASA_STATUS_INVALID_REQUEST ((CasaStatus)0x0000000F) +#define CASA_STATUS_ALREADY_REGISTERED ((CasaStatus)0x00000010) +#define CASA_STATUS_ABORTED ((CasaStatus)0x00000011) +#define CASA_STATUS_REQUEST_NOT_FOUND ((CasaStatus)0x00000012) // Unable to cancel request because it was not found +#define CASA_STATUS_OBJECT_ALREADY_EXISTS ((CasaStatus)0x00000013) // The object being created already exists. +#define CASA_STATUS_UNSUPPORTED_PROTOCOL ((CasaStatus)0x00000014) // The object is only accessable through a unsupported protocol. +#define CASA_STATUS_REJECTED ((CasaStatus)0x00000015) +#define CASA_STATUS_ACCESS_VIOLATION ((CasaStatus)0x00000016) +#define CASA_STATUS_NOT_SUPPORTED ((CasaStatus)0x00000017) +#define CASA_STATUS_NO_PROVIDERS ((CasaStatus)0x00000018) // No providers are available. +#define CASA_STATUS_CONFLICT ((CasaStatus)0x00000019) +#define CASA_STATUS_INSUFFICIENT_STORAGE ((CasaStatus)0x0000001A) +#define CASA_STATUS_AUTHENTICATION_FAILURE ((CasaStatus)0x0000001B) +#define CASA_STATUS_CONFIGURATION_ERROR ((CasaStatus)0x0000001C) +#define CASA_STATUS_LIBRARY_LOAD_FAILURE ((CasaStatus)0x0000001D) +#define CASA_STATUS_AUTH_SERVER_UNAVAILABLE ((CasaStatus)0x0000001E) +#define CASA_STATUS_PROTOCOL_ERROR ((CasaStatus)0x0000001F) +#define CASA_STATUS_SERVER_ERROR ((CasaStatus)0x00000020) +#define CASA_STATUS_NO_CREDENTIALS ((CasaStatus)0x00000021) +#define CASA_STATUS_NOT_CONFIGURED ((CasaStatus)0x00000022) +#define CASA_STATUS_INVALID_SERVER_CERTIFICATE ((CasaStatus)0x00000023) +#define CASA_STATUS_NAME_RESOLVE_ERROR ((CasaStatus)0x00000024) +#define CASA_STATUS_CONNECTION_ERROR ((CasaStatus)0x00000025) + +//===[ Macro definitions ]============================== + +// +// Macro for building status error codes +// + +#define CasaStatusBuild(severity, facility, errorcode) \ + ((CasaStatus)(((severity) << 30) | ((facility) << 16) | (errorcode))) + +// +// Macro for retrieving the facility +// + +#define CasaStatusFacility(status) \ + ((CasaStatus)(((CasaStatus)(status) >> 16) & (CasaStatus)0x07FF)) + +// +// Macro for retrieving severity +// + +#define CasaStatusSeverity(status) \ + ((CasaStatus)(((CasaStatus)(status)) >> 30)) + +// +// Macro for retrieving status code +// + +#define CasaStatusCode(status) \ + ((CasaStatus)((CasaStatus)(status) & (CasaStatus)0x0000FFFF)) + +// +// Macro for checking status code for success +// + +#define CASA_SUCCESS(status) \ + ((CasaStatus)(status) >> 30 != CASA_SEVERITY_ERROR) + +// +// Macro for checking status code for information +// + +#define CASA_INFORMATION(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_INFORMATIONAL) + +// +// Macro for checking status code for warning +// + +#define CASA_WARNING(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_WARNING) + +// +// Macro for checking status code for error +// + +#define CASA_ERROR(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_ERROR) + + +//===[ Function Prototypes ]============================== + +//===[ Global Variables ]============================== + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif // #if defined(__cplusplus) || defined(c_plusplus) + +#endif // _CASA_STATUS_H_ + +//========================================================================= +//========================================================================= +// casa_status.h diff --git a/CASA-auth-token/client/library/cache.c b/CASA-auth-token/client/library/cache.c index 408fd461..fefa4de3 100644 --- a/CASA-auth-token/client/library/cache.c +++ b/CASA-auth-token/client/library/cache.c @@ -1,1000 +1,1016 @@ -/*********************************************************************** - * - * Copyright (C) 2006 Novell, Inc. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, Novell, Inc. - * - * To contact Novell about this file by physical or electronic mail, - * you may find current contact information at www.novell.com. - * - * Authors: Juan Carlos Luciani - * Todd Throne - * - ***********************************************************************/ - - -//===[ Include files ]===================================================== - -#include "internal.h" -#include - -//===[ Type definitions ]================================================== - -// -// Auth Cache Entry Wrapper definition -// -typedef struct _WrapperAuthCacheEntry -{ - int size; - AuthCacheEntry entry; - -} WrapperAuthCacheEntry, *PWrapperAuthCacheEntry; - -// Undocumented CASA Flags -#define CASA_SECRET_PERSIST_FLAG 0x10000000 -#define CASA_SECRET_DO_NOT_PERSIST_FLAG 0x20000000 - - -//===[ Function prototypes ]=============================================== - -//===[ Global variables ]================================================== - -static -bool g_authCacheInitialized = false; -HANDLE g_hCASAContext; - - -//++======================================================================= -AuthCacheEntry* -CreateAuthTokenCacheEntry( - IN const char *pCacheKey, - IN const char *pGroupOrHostName, - IN const ATSHostEntry *pATSHost, - IN CasaStatus status, - IN char *pToken, - IN int entryLifetime, // seconds (0 == Lives forever) - IN void *pCredStoreScope - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; - SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; - uint32_t entrySize, keySize; - size_t tokenSize, wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; - WrapperAuthCacheEntry *pWrapperEntry = NULL; - AuthCacheEntry *pEntry = NULL; - char *pKey; - - DbgTrace(1, "-CreateAuthTokenCacheEntry- Start\n", 0); - - if (status == CASA_STATUS_SUCCESS) - { - tokenSize = (uint32_t) strlen(pToken); - } - else - { - tokenSize = 0; - } - - wrapperEntrySize = tokenSize + sizeof(WrapperAuthCacheEntry); - - // Verify that entrySize will not overflow - if ((tokenSize + sizeof(AuthCacheEntry)) <= UINT32_MAX) - { - entrySize = tokenSize + sizeof(AuthCacheEntry); - - // Allocate space for the entry wrapper - // - // The WrapperAuthCacheEntry structure contains room for the tokens NULL terminator - pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); - if (pWrapperEntry) - { - // Save the entry size - pWrapperEntry->size = wrapperEntrySize; - - // Set the AuthCacheEntry pointer - pEntry = &pWrapperEntry->entry; - - // Set the status - pEntry->status = status; - - if (pEntry->status == CASA_STATUS_SUCCESS) - { - memcpy(&pEntry->token[0], pToken, tokenSize); - } - - pEntry->token[tokenSize] = '\0'; - - // Set the time when the entry was added to the cache - pEntry->creationTime = GetTickCount(); - - // First determine the time when the entry is due to expire - if (entryLifetime != 0) - { - pEntry->expirationTime = pEntry->creationTime + (entryLifetime * 1000); - pEntry->doesNotExpire = false; - } - else - { - // The entry does not expire - pEntry->expirationTime = 0; - pEntry->doesNotExpire = true; - } - - cacheKeyStrLen = strlen(pCacheKey); - groupOrHostNameStrLen = strlen(pGroupOrHostName); - - // Build the cache entry key based on the status - if (status == CASA_STATUS_SUCCESS) - { - // Successful cache entries have a key of the form - // cachekey@group_or_host_name. - // - // Verify that keySize will not overflow - if ((cacheKeyStrLen + groupOrHostNameStrLen + 2) <= UINT32_MAX) - { - keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + 2); - - pKey = malloc(keySize); - if (pKey) - { - strncpy(pKey, pCacheKey, keySize); - strncat(pKey, "@", keySize); - strncat(pKey, pGroupOrHostName, keySize); - - miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, - CASA_SECRET_DO_NOT_PERSIST_FLAG, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - (uint8_t *) pEntry, - &entrySize, - NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); - } - - free(pKey); - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); - } - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); - } - } - else - { - // Unsuccessful cache entries have a key of the form - // cachekey@group_or_host_name@ATSHostAddress. - // - // Verify that keySize will not overflow - hostAndPortStrLen = strlen(pATSHost->pNameAndPort); - if ((cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3) <= UINT32_MAX) - { - keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3); - - pKey = malloc(keySize); - if (pKey) - { - strncpy(pKey, pCacheKey, keySize); - strncat(pKey, "@", keySize); - strncat(pKey, pGroupOrHostName, keySize); - strncat(pKey, "@", keySize); - strncat(pKey, pATSHost->pNameAndPort, keySize); - - miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, - CASA_SECRET_DO_NOT_PERSIST_FLAG, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - (uint8_t *) pEntry, - &entrySize, - NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); - } - - free(pKey); - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); - } - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); - } - } - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); - } - } - else - { - DbgTrace(0, "-CreateAuthTokenCacheEntry- entrySize overflow prevented\n", 0); - } - - DbgTrace(1, "-CreateAuthTokenCacheEntry- End, pEntry = 0x%X\n", pEntry); - - return pEntry; -} - - -//++======================================================================= -AuthCacheEntry* -CreateSessionTokenCacheEntry( - IN const char *pCacheKey, - IN CasaStatus status, - IN char *pToken, - IN int entryLifetime, // seconds (0 == Lives forever) - IN void *pCredStoreScope - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; - SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; - uint32_t entrySize; - size_t tokenSize, wrapperEntrySize, cacheKeyStrLen; - WrapperAuthCacheEntry *pWrapperEntry = NULL; - AuthCacheEntry *pEntry = NULL; - - DbgTrace(1, "-CreateSessionTokenCacheEntry- Start\n", 0); - - if (status == CASA_STATUS_SUCCESS) - { - tokenSize = (uint32_t)strlen(pToken); - } - else - { - tokenSize = 0; - } - - wrapperEntrySize = tokenSize + sizeof(WrapperAuthCacheEntry); - - // Verify that entrySize will not overflow - if ((tokenSize + sizeof(AuthCacheEntry)) <= UINT32_MAX) - { - entrySize = tokenSize + sizeof(AuthCacheEntry); - - // Allocate space for the entry wrapper - // - // The WrapperAuthCacheEntry structure contains room for the tokens NULL terminator - pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); - if (pWrapperEntry) - { - // Save the entry size - pWrapperEntry->size = wrapperEntrySize; - - // Set the AuthCacheEntry pointer - pEntry = &pWrapperEntry->entry; - - // Set the status - pEntry->status = status; - - if (pEntry->status == CASA_STATUS_SUCCESS) - { - memcpy(&pEntry->token[0], pToken, tokenSize); - } - - pEntry->token[tokenSize] = '\0'; - - // Set the time when the entry was added to the cache - pEntry->creationTime = GetTickCount(); - - // First determine the time when the entry is due to expire - if (entryLifetime != 0) - { - pEntry->expirationTime = pEntry->creationTime + (entryLifetime * 1000); - pEntry->doesNotExpire = false; - } - else - { - // The entry does not expire - pEntry->expirationTime = 0; - pEntry->doesNotExpire = true; - } - - cacheKeyStrLen = strlen(pCacheKey) + 1; - - // Verify that the cacheKeyStrLen can be casted to a uint32_t - if (cacheKeyStrLen <= UINT32_MAX) - { - miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, - CASA_SECRET_DO_NOT_PERSIST_FLAG, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pCacheKey, - (uint32_t) cacheKeyStrLen, - (uint8_t *) pEntry, - &entrySize, - NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-CreateSessionTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); - } - } - else - { - DbgTrace(0, "-CreateSessionTokenCacheEntry- cacheKeyStrLen overflow prevented\n", 0); - } - } - else - { - DbgTrace(0, "-CreateSessionTokenCacheEntry- Memory allocation failure\n", 0); - } - } - else - { - DbgTrace(0, "-CreateSessionTokenCacheEntry- entrySize overflow prevented\n", 0); - } - - DbgTrace(1, "-CreateSessionTokenCacheEntry- End, pEntry = 0x%X\n", pEntry); - - return pEntry; -} - - -//++======================================================================= -void -FreeAuthCacheEntry( - IN AuthCacheEntry *pEntry - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - WrapperAuthCacheEntry *pWrapperEntry = CONTAINING_RECORD(pEntry, WrapperAuthCacheEntry, entry); - - DbgTrace(1, "-FreeAuthCacheEntry- Start, pEntry = 0x%X\n", pEntry); - - // Free the entry after clearing the memory holding it since it - // may contain security sensitive data. - memset(pWrapperEntry, 0, pWrapperEntry->size); - free(pWrapperEntry); - - DbgTrace(1, "-FreeAuthCacheEntry- End\n", 0); -} - - -//++======================================================================= -static -bool -CacheEntryLifetimeExpired( - IN DWORD creationTime, - IN DWORD expirationTime - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DWORD currentTime = GetTickCount(); - bool expired = false; - - DbgTrace(2, "-CacheEntryLifetimeExpired- Start\n", 0); - - // Check if the clock has wrapped - if (currentTime >= creationTime) - { - // The clock has not wrapped, check if the - // expiration time has wrapped. - if (expirationTime > creationTime) - { - // The expiration time also has not wrapped, - // do a straight compare against the current - // time. - if (currentTime >= expirationTime) - { - // It has expired - expired = true; - } - } - } - else - { - // The clock has wrapped, check if the expiration - // time also wrapped. - if (expirationTime > creationTime) - { - // The expiration time did not wrap, therefore - // it has been exceeded since the clock wrapped. - expired = true; - } - else - { - // The expiration time also wrapped, do a straight - // compare against the current time. - if (currentTime >= expirationTime) - { - // It has expired - expired = true; - } - } - } - - DbgTrace(2, "-CacheEntryLifetimeExpired- End, result = %08X\n", expired); - - return expired; -} - - -//++======================================================================= -AuthCacheEntry* -FindSessionTokenEntryInCache( - IN const char *pCacheKey, - IN void *pCredStoreScope - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; - SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; - uint32_t valueLength, bytesRequired; - size_t wrapperEntrySize, cacheKeyStrLen; - WrapperAuthCacheEntry *pWrapperEntry = NULL; - AuthCacheEntry *pEntry = NULL; - - DbgTrace(1, "-FindSessionTokenEntryInCache- Start\n", 0); - - valueLength = 0; - bytesRequired = 0; - - cacheKeyStrLen = strlen(pCacheKey) + 1; - - // Verify that the cacheKeyStrLen can be casted to a uint32_t - if (cacheKeyStrLen <= UINT32_MAX) - { - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pCacheKey, - cacheKeyStrLen, - NULL, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - - if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT - && bytesRequired != 0) - { - wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); - pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); - if (pWrapperEntry) - { - pWrapperEntry->size = wrapperEntrySize; - pEntry = &pWrapperEntry->entry; - valueLength = bytesRequired; - bytesRequired = 0; - - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pCacheKey, - cacheKeyStrLen, - (uint8_t *) pEntry, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus == NSSCS_SUCCESS) - { - if (pEntry->doesNotExpire == false - && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) - { - // Remove the entry from the cache - miCasaStatus = miCASARemoveKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pCacheKey, - cacheKeyStrLen, - (SSCS_PASSWORD_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-FindSessionTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); - } - - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - else - { - DbgTrace(0, "-FindSessionTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - } - } - else - { - DbgTrace(0, "-FindSessionTokenEntryInCache- cacheKeyStrLen overflow prevented\n", 0); - } - - DbgTrace(1, "-FindSessionTokenEntryInCache- End, pEntry = 0x%X\n", pEntry); - - return pEntry; -} - -//++======================================================================= -AuthCacheEntry* -FindAuthTokenEntryInCache( - IN const char *pCacheKey, - IN const char *pGroupOrHostName, - IN const ATSHostEntry *pATSHost, - IN void *pCredStoreScope - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; - SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; - uint32_t valueLength, bytesRequired, keySize; - size_t wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; - WrapperAuthCacheEntry *pWrapperEntry = NULL; - AuthCacheEntry *pEntry = NULL; - char *pKey; - - - DbgTrace(1, "-FindAuthTokenEntryInCache- Start\n", 0); - - cacheKeyStrLen = strlen(pCacheKey); - groupOrHostNameStrLen = strlen(pGroupOrHostName); - hostAndPortStrLen = strlen(pATSHost->pNameAndPort); - - // Verify that the worst case keySize will not overflow - if ((cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3) <= UINT32_MAX) - { - // Allocate space for the worst case key - keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3); - - pKey = malloc(keySize); - if (pKey) - { - // First try to read entry using key for successful cache entries - strncpy(pKey, pCacheKey, keySize); - strncat(pKey, "@", keySize); - strncat(pKey, pGroupOrHostName, keySize); - - valueLength = 0; - bytesRequired = 0; - - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - strlen(pKey) + 1, - NULL, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT - && bytesRequired != 0) - { - wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); - pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); - if (pWrapperEntry) - { - pWrapperEntry->size = wrapperEntrySize; - pEntry = &pWrapperEntry->entry; - valueLength = bytesRequired; - bytesRequired = 0; - - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - strlen(pKey) + 1, - (uint8_t *) pEntry, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus == NSSCS_SUCCESS) - { - if (pEntry->doesNotExpire == false - && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) - { - // Remove the entry from the cache - miCasaStatus = miCASARemoveKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - (SSCS_PASSWORD_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-FindAuthTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); - } - - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - else - { - DbgTrace(0, "-FindAuthTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - } - else - { - // We failed to obtain a cache entry using key for successful cache entry, try for using key for - // unsuccessful cache entry. - strncat(pKey, "@", keySize); - strncat(pKey, pATSHost->pNameAndPort, keySize); - - valueLength = 0; - bytesRequired = 0; - - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - NULL, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT - && bytesRequired != 0) - { - wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); - pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); - if (pWrapperEntry) - { - pWrapperEntry->size = wrapperEntrySize; - pEntry = &pWrapperEntry->entry; - valueLength = bytesRequired; - bytesRequired = 0; - - miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - (uint8_t *) pEntry, - &valueLength, - (SSCS_PASSWORD_T*) NULL, - &bytesRequired, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus == NSSCS_SUCCESS) - { - if (pEntry->doesNotExpire == false - && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) - { - // Remove the entry from the cache - miCasaStatus = miCASARemoveKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pKey, - keySize, - (SSCS_PASSWORD_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-FindAuthTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); - } - - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - else - { - DbgTrace(0, "-FindAuthTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); - FreeAuthCacheEntry(pEntry); - pEntry = NULL; - } - } - } - } - - free(pKey); - } - } - else - { - DbgTrace(0, "-FindAuthTokenEntryInCache- keySize overflow prevented\n", 0); - } - - DbgTrace(1, "-FindAuthTokenEntryInCache- End, pEntry = 0x%X\n", pEntry); - - return pEntry; -} - - -//++======================================================================= -void -RemoveSessionTokenEntryInCache( - IN const char *pCacheKey, - IN void *pCredStoreScope - ) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; - SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; - - DbgTrace(1, "-RemoveSessionTokenEntryInCache- Start\n", 0); - - // Remove the entry from the cache - miCasaStatus = miCASARemoveKey(g_hCASAContext, - 0, - &sessionKeyChain, - &sharedId, - (SS_UTF8_T*) pCacheKey, - (uint32_t) strlen(pCacheKey) + 1, - (SSCS_PASSWORD_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-RemoveSessionTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); - } - - DbgTrace(1, "-RemoveSessionTokenEntryInCache- End\n", 0); -} - - -//++======================================================================= -void -DeleteAuthTokenEntriesInCache( - IN void *pCredStoreScope -) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; - - DbgTrace(1, "-DeleteAuthTokenEntriesInCache- Start\n", 0); - - // Remove all of the auth tokens from the cache - miCasaStatus = miCASARemoveCredential(0, - &sharedId, - (SSCS_SECRET_ID_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-DeleteAuthTokenEntriesInCache- miCASADeleteCredential error = %0X\n", miCasaStatus); - } - - DbgTrace(1, "-DeleteAuthTokenEntriesInCache- End\n", 0); -} - - -//++======================================================================= -void -DeleteSessionTokenEntriesInCache( - IN void *pCredStoreScope -) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int32_t miCasaStatus; - SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; - - DbgTrace(1, "-DeleteSessionTokenEntriesInCache- Start\n", 0); - - // Remove all of the auth tokens from the cache - miCasaStatus = miCASARemoveCredential(0, - &sharedId, - (SSCS_SECRET_ID_T*) NULL, - (SSCS_EXT_T*) pCredStoreScope); - if (miCasaStatus != NSSCS_SUCCESS) - { - DbgTrace(0, "-DeleteSessionTokenEntriesInCache- miCASADeleteCredential error = %0X\n", miCasaStatus); - } - - DbgTrace(1, "-DeleteSessionTokenEntriesInCache- End\n", 0); -} - - -//++======================================================================= -CasaStatus -InitializeAuthCache() -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - CasaStatus retStatus; - SSCS_SECRETSTORE_T ssId; - - DbgTrace(1, "-InitializeAuthCache- Start\n", 0); - - ssId.version = NSSCS_VERSION_NUMBER; - strcpy((char *)ssId.ssName, (char *)SSCS_DEFAULT_SECRETSTORE_ID); - - g_hCASAContext = miCASAOpenSecretStoreCache(&ssId, - 0, - NULL); - if (!g_hCASAContext) - { - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - else - { - g_authCacheInitialized = true; - retStatus = CASA_STATUS_SUCCESS; - } - - DbgTrace(1, "-InitializeAuthCache- End, retStatus = %08X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -void -UnInitializeAuthCache(void) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DbgTrace(1, "-UnInitializeAuthCache- Start\n", 0); - - // Proceed if initialized - if (g_authCacheInitialized) - { - // Close the secret store cache - miCASACloseSecretStoreCache(g_hCASAContext, - 0, - NULL); - - // Forget about being initialized - g_hCASAContext = NULL; - g_authCacheInitialized = false; - } - - DbgTrace(1, "-UnInitializeAuthCache- End\n", 0); -} - - -//++======================================================================= -//++======================================================================= -//++======================================================================= - +/*********************************************************************** + * + * Copyright (C) 2006 Novell, Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + * + * Authors: Juan Carlos Luciani + * Todd Throne + * + ***********************************************************************/ + + +//===[ Include files ]===================================================== + +#include "internal.h" +#include + +//===[ Type definitions ]================================================== + +// +// Auth Cache Entry Wrapper definition +// +typedef struct _WrapperAuthCacheEntry +{ + int size; + AuthCacheEntry entry; + +} WrapperAuthCacheEntry, *PWrapperAuthCacheEntry; + +// Undocumented CASA Flags +#define CASA_SECRET_PERSIST_FLAG 0x10000000 +#define CASA_SECRET_DO_NOT_PERSIST_FLAG 0x20000000 + + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +static +bool g_authCacheInitialized = false; +HANDLE g_hCASAContext; + + +//++======================================================================= +AuthCacheEntry* +CreateAuthTokenCacheEntry( + IN const char *pCacheKey, + IN const char *pGroupOrHostName, + IN const ATSHostEntry *pATSHost, + IN CasaStatus status, + IN char *pToken, + IN int entryLifetime, // seconds (0 == Lives forever) + IN void *pCredStoreScope + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; + uint32_t entrySize, keySize; + size_t tokenSize, wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; + WrapperAuthCacheEntry *pWrapperEntry = NULL; + AuthCacheEntry *pEntry = NULL; + char *pKey; + + DbgTrace(1, "-CreateAuthTokenCacheEntry- Start\n", 0); + + if (status == CASA_STATUS_SUCCESS) + { + tokenSize = (uint32_t) strlen(pToken); + } + else + { + tokenSize = 0; + } + + wrapperEntrySize = tokenSize + sizeof(WrapperAuthCacheEntry); + + // Verify that entrySize will not overflow + if ((tokenSize + sizeof(AuthCacheEntry)) <= UINT32_MAX) + { + entrySize = tokenSize + sizeof(AuthCacheEntry); + + // Allocate space for the entry wrapper + // + // The WrapperAuthCacheEntry structure contains room for the tokens NULL terminator + pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); + if (pWrapperEntry) + { + // Save the entry size + pWrapperEntry->size = wrapperEntrySize; + + // Set the AuthCacheEntry pointer + pEntry = &pWrapperEntry->entry; + + // Set the status + pEntry->status = status; + + if (pEntry->status == CASA_STATUS_SUCCESS) + { + memcpy(&pEntry->token[0], pToken, tokenSize); + } + + pEntry->token[tokenSize] = '\0'; + + // Set the time when the entry was added to the cache + pEntry->creationTime = GetTickCount(); + + // First determine the time when the entry is due to expire + if (entryLifetime != 0) + { + pEntry->expirationTime = pEntry->creationTime + (entryLifetime * 1000); + pEntry->doesNotExpire = false; + } + else + { + // The entry does not expire + pEntry->expirationTime = 0; + pEntry->doesNotExpire = true; + } + + cacheKeyStrLen = strlen(pCacheKey); + groupOrHostNameStrLen = strlen(pGroupOrHostName); + + // Build the cache entry key based on the status + if (status == CASA_STATUS_SUCCESS) + { + // Successful cache entries have a key of the form + // cachekey@group_or_host_name. + // + // Verify that keySize will not overflow + if ((cacheKeyStrLen + groupOrHostNameStrLen + 2) <= UINT32_MAX) + { + keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + 2); + + pKey = malloc(keySize); + if (pKey) + { + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); + + DbgTrace(3, "-CreateAuthTokenCacheEntry- Key = %s\n", pKey); + DbgTrace(3, "-CreateAuthTokenCacheEntry- Keysize = %d\n", keySize); + DbgTrace(3, "-CreateAuthTokenCacheEntry- CredStoreScope = %X\n", pCredStoreScope); + + miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, + CASA_SECRET_DO_NOT_PERSIST_FLAG, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + (uint8_t *) pEntry, + &entrySize, + NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); + } + + free(pKey); + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); + } + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); + } + } + else + { + // Unsuccessful cache entries have a key of the form + // cachekey@group_or_host_name@ATSHostAddress. + // + // Verify that keySize will not overflow + hostAndPortStrLen = strlen(pATSHost->pNameAndPort); + if ((cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3) <= UINT32_MAX) + { + keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3); + + pKey = malloc(keySize); + if (pKey) + { + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pATSHost->pNameAndPort, keySize); + + miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, + CASA_SECRET_DO_NOT_PERSIST_FLAG, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + (uint8_t *) pEntry, + &entrySize, + NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); + } + + free(pKey); + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); + } + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); + } + } + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- Memory allocation failure\n", 0); + } + } + else + { + DbgTrace(0, "-CreateAuthTokenCacheEntry- entrySize overflow prevented\n", 0); + } + + DbgTrace(1, "-CreateAuthTokenCacheEntry- End, pEntry = 0x%X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +AuthCacheEntry* +CreateSessionTokenCacheEntry( + IN const char *pCacheKey, + IN CasaStatus status, + IN char *pToken, + IN int entryLifetime, // seconds (0 == Lives forever) + IN void *pCredStoreScope + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + uint32_t entrySize; + size_t tokenSize, wrapperEntrySize, cacheKeyStrLen; + WrapperAuthCacheEntry *pWrapperEntry = NULL; + AuthCacheEntry *pEntry = NULL; + + DbgTrace(1, "-CreateSessionTokenCacheEntry- Start\n", 0); + + if (status == CASA_STATUS_SUCCESS) + { + tokenSize = (uint32_t)strlen(pToken); + } + else + { + tokenSize = 0; + } + + wrapperEntrySize = tokenSize + sizeof(WrapperAuthCacheEntry); + + // Verify that entrySize will not overflow + if ((tokenSize + sizeof(AuthCacheEntry)) <= UINT32_MAX) + { + entrySize = tokenSize + sizeof(AuthCacheEntry); + + // Allocate space for the entry wrapper + // + // The WrapperAuthCacheEntry structure contains room for the tokens NULL terminator + pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); + if (pWrapperEntry) + { + // Save the entry size + pWrapperEntry->size = wrapperEntrySize; + + // Set the AuthCacheEntry pointer + pEntry = &pWrapperEntry->entry; + + // Set the status + pEntry->status = status; + + if (pEntry->status == CASA_STATUS_SUCCESS) + { + memcpy(&pEntry->token[0], pToken, tokenSize); + } + + pEntry->token[tokenSize] = '\0'; + + // Set the time when the entry was added to the cache + pEntry->creationTime = GetTickCount(); + + // First determine the time when the entry is due to expire + if (entryLifetime != 0) + { + pEntry->expirationTime = pEntry->creationTime + (entryLifetime * 1000); + pEntry->doesNotExpire = false; + } + else + { + // The entry does not expire + pEntry->expirationTime = 0; + pEntry->doesNotExpire = true; + } + + cacheKeyStrLen = strlen(pCacheKey) + 1; + + // Verify that the cacheKeyStrLen can be casted to a uint32_t + if (cacheKeyStrLen <= UINT32_MAX) + { + DbgTrace(3, "-CreateSessionTokenCacheEntry- Key = %s\n", pCacheKey); + DbgTrace(3, "-CreateSessionTokenCacheEntry- Keysize = %d\n", cacheKeyStrLen); + DbgTrace(3, "-CreateSessionTokenCacheEntry- CredStoreScope = %X\n", pCredStoreScope); + + miCasaStatus = miCASAWriteBinaryKey(g_hCASAContext, + CASA_SECRET_DO_NOT_PERSIST_FLAG, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pCacheKey, + (uint32_t) cacheKeyStrLen, + (uint8_t *) pEntry, + &entrySize, + NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-CreateSessionTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); + } + } + else + { + DbgTrace(0, "-CreateSessionTokenCacheEntry- cacheKeyStrLen overflow prevented\n", 0); + } + } + else + { + DbgTrace(0, "-CreateSessionTokenCacheEntry- Memory allocation failure\n", 0); + } + } + else + { + DbgTrace(0, "-CreateSessionTokenCacheEntry- entrySize overflow prevented\n", 0); + } + + DbgTrace(1, "-CreateSessionTokenCacheEntry- End, pEntry = 0x%X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +void +FreeAuthCacheEntry( + IN AuthCacheEntry *pEntry + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + WrapperAuthCacheEntry *pWrapperEntry = CONTAINING_RECORD(pEntry, WrapperAuthCacheEntry, entry); + + DbgTrace(1, "-FreeAuthCacheEntry- Start, pEntry = 0x%X\n", pEntry); + + // Free the entry after clearing the memory holding it since it + // may contain security sensitive data. + memset(pWrapperEntry, 0, pWrapperEntry->size); + free(pWrapperEntry); + + DbgTrace(1, "-FreeAuthCacheEntry- End\n", 0); +} + + +//++======================================================================= +static +bool +CacheEntryLifetimeExpired( + IN DWORD creationTime, + IN DWORD expirationTime + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DWORD currentTime = GetTickCount(); + bool expired = false; + + DbgTrace(2, "-CacheEntryLifetimeExpired- Start\n", 0); + + // Check if the clock has wrapped + if (currentTime >= creationTime) + { + // The clock has not wrapped, check if the + // expiration time has wrapped. + if (expirationTime > creationTime) + { + // The expiration time also has not wrapped, + // do a straight compare against the current + // time. + if (currentTime >= expirationTime) + { + // It has expired + expired = true; + } + } + } + else + { + // The clock has wrapped, check if the expiration + // time also wrapped. + if (expirationTime > creationTime) + { + // The expiration time did not wrap, therefore + // it has been exceeded since the clock wrapped. + expired = true; + } + else + { + // The expiration time also wrapped, do a straight + // compare against the current time. + if (currentTime >= expirationTime) + { + // It has expired + expired = true; + } + } + } + + DbgTrace(2, "-CacheEntryLifetimeExpired- End, result = %08X\n", expired); + + return expired; +} + + +//++======================================================================= +AuthCacheEntry* +FindSessionTokenEntryInCache( + IN const char *pCacheKey, + IN void *pCredStoreScope + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + uint32_t valueLength, bytesRequired; + size_t wrapperEntrySize, cacheKeyStrLen; + WrapperAuthCacheEntry *pWrapperEntry = NULL; + AuthCacheEntry *pEntry = NULL; + + DbgTrace(1, "-FindSessionTokenEntryInCache- Start\n", 0); + + valueLength = 0; + bytesRequired = 0; + + cacheKeyStrLen = strlen(pCacheKey) + 1; + + // Verify that the cacheKeyStrLen can be casted to a uint32_t + if (cacheKeyStrLen <= UINT32_MAX) + { + DbgTrace(3, "-FindSessionTokenCacheEntry- Key = %s\n", pCacheKey); + DbgTrace(3, "-FindSessionTokenCacheEntry- Keysize = %d\n", cacheKeyStrLen); + DbgTrace(3, "-FindSessionTokenCacheEntry- CredStoreScope = %X\n", pCredStoreScope); + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pCacheKey, + cacheKeyStrLen, + NULL, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + + if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT + && bytesRequired != 0) + { + wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); + pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); + if (pWrapperEntry) + { + pWrapperEntry->size = wrapperEntrySize; + pEntry = &pWrapperEntry->entry; + valueLength = bytesRequired; + bytesRequired = 0; + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pCacheKey, + cacheKeyStrLen, + (uint8_t *) pEntry, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus == NSSCS_SUCCESS) + { + if (pEntry->doesNotExpire == false + && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) + { + // Remove the entry from the cache + miCasaStatus = miCASARemoveKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pCacheKey, + cacheKeyStrLen, + (SSCS_PASSWORD_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-FindSessionTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); + } + + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + else + { + DbgTrace(0, "-FindSessionTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + } + } + else + { + DbgTrace(0, "-FindSessionTokenEntryInCache- cacheKeyStrLen overflow prevented\n", 0); + } + + DbgTrace(1, "-FindSessionTokenEntryInCache- End, pEntry = 0x%X\n", pEntry); + + return pEntry; +} + +//++======================================================================= +AuthCacheEntry* +FindAuthTokenEntryInCache( + IN const char *pCacheKey, + IN const char *pGroupOrHostName, + IN const ATSHostEntry *pATSHost, + IN void *pCredStoreScope + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; + uint32_t valueLength, bytesRequired, keySize; + size_t wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; + WrapperAuthCacheEntry *pWrapperEntry = NULL; + AuthCacheEntry *pEntry = NULL; + char *pKey; + + + DbgTrace(1, "-FindAuthTokenEntryInCache- Start\n", 0); + + cacheKeyStrLen = strlen(pCacheKey); + groupOrHostNameStrLen = strlen(pGroupOrHostName); + hostAndPortStrLen = strlen(pATSHost->pNameAndPort); + + // Verify that the worst case keySize will not overflow + if ((cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3) <= UINT32_MAX) + { + // Allocate space for the worst case key + keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3); + + pKey = malloc(keySize); + if (pKey) + { + // First try to read entry using key for successful cache entries + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); + + valueLength = 0; + bytesRequired = 0; + + DbgTrace(3, "-FindAuthTokenCacheEntry- Key = %s\n", pKey); + DbgTrace(3, "-FindAuthTokenCacheEntry- Keysize = %d\n", strlen(pKey) + 1); + DbgTrace(3, "-FindAuthTokenCacheEntry- CredStoreScope = %X\n", pCredStoreScope); + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + strlen(pKey) + 1, + NULL, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT + && bytesRequired != 0) + { + wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); + pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); + if (pWrapperEntry) + { + pWrapperEntry->size = wrapperEntrySize; + pEntry = &pWrapperEntry->entry; + valueLength = bytesRequired; + bytesRequired = 0; + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + strlen(pKey) + 1, + (uint8_t *) pEntry, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus == NSSCS_SUCCESS) + { + if (pEntry->doesNotExpire == false + && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) + { + // Remove the entry from the cache + miCasaStatus = miCASARemoveKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + (SSCS_PASSWORD_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-FindAuthTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); + } + + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + else + { + DbgTrace(0, "-FindAuthTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + } + else + { + // We failed to obtain a cache entry using key for successful cache entry, try for using key for + // unsuccessful cache entry. + strncat(pKey, "@", keySize); + strncat(pKey, pATSHost->pNameAndPort, keySize); + + valueLength = 0; + bytesRequired = 0; + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + NULL, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT + && bytesRequired != 0) + { + wrapperEntrySize = bytesRequired + sizeof(WrapperAuthCacheEntry) - sizeof(AuthCacheEntry); + pWrapperEntry = (WrapperAuthCacheEntry*) malloc(wrapperEntrySize); + if (pWrapperEntry) + { + pWrapperEntry->size = wrapperEntrySize; + pEntry = &pWrapperEntry->entry; + valueLength = bytesRequired; + bytesRequired = 0; + + miCasaStatus = miCASAReadBinaryKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + (uint8_t *) pEntry, + &valueLength, + (SSCS_PASSWORD_T*) NULL, + &bytesRequired, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus == NSSCS_SUCCESS) + { + if (pEntry->doesNotExpire == false + && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) + { + // Remove the entry from the cache + miCasaStatus = miCASARemoveKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pKey, + keySize, + (SSCS_PASSWORD_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-FindAuthTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); + } + + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + else + { + DbgTrace(0, "-FindAuthTokenEntryInCache- miCASAReadBinaryKey error = %0X\n", miCasaStatus); + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + } + } + + free(pKey); + } + } + else + { + DbgTrace(0, "-FindAuthTokenEntryInCache- keySize overflow prevented\n", 0); + } + + DbgTrace(1, "-FindAuthTokenEntryInCache- End, pEntry = 0x%X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +void +RemoveSessionTokenEntryInCache( + IN const char *pCacheKey, + IN void *pCredStoreScope + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + + DbgTrace(1, "-RemoveSessionTokenEntryInCache- Start\n", 0); + + // Remove the entry from the cache + miCasaStatus = miCASARemoveKey(g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (SS_UTF8_T*) pCacheKey, + (uint32_t) strlen(pCacheKey) + 1, + (SSCS_PASSWORD_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-RemoveSessionTokenEntryInCache- miCASARemoveKey error = %0X\n", miCasaStatus); + } + + DbgTrace(1, "-RemoveSessionTokenEntryInCache- End\n", 0); +} + + +//++======================================================================= +void +DeleteAuthTokenEntriesInCache( + IN void *pCredStoreScope +) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; + + DbgTrace(1, "-DeleteAuthTokenEntriesInCache- Start\n", 0); + + // Remove all of the auth tokens from the cache + miCasaStatus = miCASARemoveCredential(0, + &sharedId, + (SSCS_SECRET_ID_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-DeleteAuthTokenEntriesInCache- miCASADeleteCredential error = %0X\n", miCasaStatus); + } + + DbgTrace(1, "-DeleteAuthTokenEntriesInCache- End\n", 0); +} + + +//++======================================================================= +void +DeleteSessionTokenEntriesInCache( + IN void *pCredStoreScope +) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int32_t miCasaStatus; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + + DbgTrace(1, "-DeleteSessionTokenEntriesInCache- Start\n", 0); + + // Remove all of the auth tokens from the cache + miCasaStatus = miCASARemoveCredential(0, + &sharedId, + (SSCS_SECRET_ID_T*) NULL, + (SSCS_EXT_T*) pCredStoreScope); + if (miCasaStatus != NSSCS_SUCCESS) + { + DbgTrace(0, "-DeleteSessionTokenEntriesInCache- miCASADeleteCredential error = %0X\n", miCasaStatus); + } + + DbgTrace(1, "-DeleteSessionTokenEntriesInCache- End\n", 0); +} + + +//++======================================================================= +CasaStatus +InitializeAuthCache() +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + SSCS_SECRETSTORE_T ssId; + + DbgTrace(1, "-InitializeAuthCache- Start\n", 0); + + ssId.version = NSSCS_VERSION_NUMBER; + strcpy((char *)ssId.ssName, (char *)SSCS_DEFAULT_SECRETSTORE_ID); + + g_hCASAContext = miCASAOpenSecretStoreCache(&ssId, + 0, + NULL); + if (!g_hCASAContext) + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + else + { + g_authCacheInitialized = true; + retStatus = CASA_STATUS_SUCCESS; + } + + DbgTrace(1, "-InitializeAuthCache- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +void +UnInitializeAuthCache(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-UnInitializeAuthCache- Start\n", 0); + + // Proceed if initialized + if (g_authCacheInitialized) + { + // Close the secret store cache + miCASACloseSecretStoreCache(g_hCASAContext, + 0, + NULL); + + // Forget about being initialized + g_hCASAContext = NULL; + g_authCacheInitialized = false; + } + + DbgTrace(1, "-UnInitializeAuthCache- End\n", 0); +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/CASA-auth-token/client/library/linux/rpc.c b/CASA-auth-token/client/library/linux/rpc.c index c56057bd..f29366c9 100644 --- a/CASA-auth-token/client/library/linux/rpc.c +++ b/CASA-auth-token/client/library/linux/rpc.c @@ -1,652 +1,669 @@ -/*********************************************************************** - * - * Copyright (C) 2006 Novell, Inc. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, Novell, Inc. - * - * To contact Novell about this file by physical or electronic mail, - * you may find current contact information at www.novell.com. - * - * Author: Juan Carlos Luciani - * - ***********************************************************************/ - - -//===[ Include files ]===================================================== - -#include "internal.h" - -//===[ Type definitions ]================================================== - -#define MAX_RPC_RETRIES 3 - -//===[ External prototypes ]=============================================== - -extern -int -SetupOSSLSupport(void); - -extern -void -CleanupOSSLSupport(void); - -//===[ Function prototypes ]=============================================== - - -//===[ Global variables ]================================================== - -static -bool g_rpcInitialized = false; - - -//++======================================================================= -size_t -CurlWriteCallback( - IN void *pData, - IN size_t dataItemSz, - IN size_t numDataItems, - IN RpcSession *pSession) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - size_t dataConsumed = numDataItems; - - DbgTrace(1, "-CurlWriteCallback- Start\n", 0); - - // Consume the data by keeping a copy of the data. Note that we may have - // already consumed some data in which case we need to allocate a new - // buffer big enough to hold all of it. - if (pSession->pRecvData == NULL) - { - // We have not yet consumed receive data for the current Rpc - // if the data does not exceed our maximum Rpc reply size. - if ((numDataItems * dataItemSz) <= MAX_RPC_REPLY_SZ) - { - pSession->pRecvData = (char*) malloc(numDataItems * dataItemSz); - if (pSession->pRecvData) - { - // Consume the data - memcpy(pSession->pRecvData, pData, numDataItems * dataItemSz); - pSession->recvDataLen = numDataItems * dataItemSz; - } - else - { - DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0); - dataConsumed = CURLE_WRITE_ERROR; // To abort RPC - } - } - else - { - DbgTrace(0, "-CurlWriteCallback- Max Rpc reply size exceeded\n", 0); - dataConsumed = CURLE_WRITE_ERROR; // To abort RPC - } - } - else - { - // We have already consumed receive data for the current Rpc, append the new data to it - // if the data does not exceed our maximum Rpc reply size. - if ((pSession->recvDataLen + (numDataItems * dataItemSz)) <= MAX_RPC_REPLY_SZ) - { - char *pNewRecvDataBuf = (char*) malloc(pSession->recvDataLen + (numDataItems * dataItemSz)); - if (pNewRecvDataBuf) - { - memcpy(pNewRecvDataBuf, pSession->pRecvData, pSession->recvDataLen); - memcpy(pNewRecvDataBuf + pSession->recvDataLen, pData, numDataItems * dataItemSz); - pSession->recvDataLen += numDataItems * dataItemSz; - free(pSession->pRecvData); - pSession->pRecvData = pNewRecvDataBuf; - } - else - { - DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0); - dataConsumed = CURLE_WRITE_ERROR; // To abort RPC - - // Forget about already consumed data - free(pSession->pRecvData); - pSession->pRecvData = NULL; - } - } - else - { - DbgTrace(0, "-CurlWriteCallback- Max Rpc reply size exceeded\n", 0); - dataConsumed = CURLE_WRITE_ERROR; // To abort RPC - - // Forget about already consumed data - free(pSession->pRecvData); - pSession->pRecvData = NULL; - } - } - - DbgTrace(1, "-CurlWriteCallback- End\n", 0); - - return dataConsumed; -} - - -//++======================================================================= -RpcSession* -OpenRpcSession( - IN const char *pHostName, - IN const uint16_t hostPort) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - RpcSession *pSession = NULL; - char *pPartialHttpUrl = NULL; - char *pPartialHttpsUrl = NULL; - int hostNameLen = strlen(pHostName); - - DbgTrace(1, "-OpenRpcSession- Start\n", 0); - - // Build the partial URL strings that may be used with this session. - pPartialHttpUrl = (char*) malloc(7 /*"http://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/); - pPartialHttpsUrl = (char*) malloc(8 /*"https://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/); - if (pPartialHttpUrl && pPartialHttpsUrl) - { - sprintf(pPartialHttpUrl, "http://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort); - sprintf(pPartialHttpsUrl, "https://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort); - - // Allocate space for the session - pSession = (RpcSession*) malloc(sizeof(*pSession)); - if (pSession) - { - // Zero the session structure - memset(pSession, 0, sizeof(*pSession)); - - // Get a curl handle - pSession->hCurl = curl_easy_init(); - if (pSession->hCurl != NULL) - { - CURLcode result; - bool setOptError = false; - - // Set necessary options on the handle - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_NOSIGNAL, 0)) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_NOSIGNAL, code = %d\n", result); - setOptError = true; - } - - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_USERAGENT, "CASA Client/1.0")) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_USERAGENT, code = %d\n", result); - setOptError = true; - } - - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_POST, 1)) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POST, code = %d\n", result); - setOptError = true; - } - - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_CAPATH, "/etc/ssl/certs")) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_CAPATH, code = %d\n", result); - setOptError = true; - } - - pSession->headers = curl_slist_append(pSession->headers, "Content-Type: text/html"); - pSession->headers = curl_slist_append(pSession->headers, "Expect:"); - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_HTTPHEADER, pSession->headers)) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_HTTPHEADER, code = %d\n", result); - setOptError = true; - } - - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEFUNCTION, CurlWriteCallback)) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEFUNCTION, code = %d\n", result); - setOptError = true; - } - - if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEDATA, pSession)) != CURLE_OK) - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEDATA, code = %d\n", result); - setOptError = true; - } - - // Now check if we succeded - if (setOptError == false) - { - // Success, finish setting up the session object. - pSession->pPartialHttpUrl = pPartialHttpUrl; - pSession->partialHttpUrlLen = strlen(pPartialHttpUrl); - pSession->pPartialHttpsUrl = pPartialHttpsUrl; - pSession->partialHttpsUrlLen = strlen(pPartialHttpsUrl); - - // Forget about the partial URL buffers so that they do not get deleted below - pPartialHttpUrl = NULL; - pPartialHttpsUrl = NULL; - } - else - { - // Failed to set a needed curl option - if (pSession->headers) - curl_slist_free_all(pSession->headers); - - curl_easy_cleanup(pSession->hCurl); - - free(pSession); - pSession = NULL; - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Error creating curl handle\n", 0); - free(pSession); - pSession = NULL; - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for URL\n", 0); - } - - // Free buffers not utilized - if (pPartialHttpUrl) - free(pPartialHttpUrl); - - if (pPartialHttpsUrl) - free(pPartialHttpsUrl); - - DbgTrace(2, "-OpenRpcSession- End, pSession = %0lX\n", (long) pSession); - - return pSession; -} - - -//++======================================================================= -void -CloseRpcSession( - IN RpcSession *pSession) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DbgTrace(1, "-CloseRpcSession- Start\n", 0); - - // Free any HTTP headers associated with the session - if (pSession->headers) - curl_slist_free_all(pSession->headers); - - // Close the curl handle associated with this session - curl_easy_cleanup(pSession->hCurl); - - // Free the space allocated for the session - if (pSession->pRecvData) - free(pSession->pRecvData); - - free(pSession->pPartialHttpUrl); - free(pSession->pPartialHttpsUrl); - - free(pSession); - - DbgTrace(1, "-CloseRpcSession- End\n", 0); -} - - -//++======================================================================= -static -CasaStatus -InternalRpc( - IN RpcSession *pSession, - IN char *pMethod, - IN long flags, - IN char *pRequestData, - INOUT char **ppResponseData, - INOUT size_t *pResponseDataLen) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ -#ifndef CASA_STATUS_INVALID_SERVER_CERTIFICATE -#define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated -#endif - - CasaStatus retStatus; - char *pPartialUrl; - int partialUrlLen; - char *pUrl; - CURLcode curlResult; - - DbgTrace(1, "-InternalRpc- Start\n", 0); - - // Initialize output parameters - *ppResponseData = NULL; - *pResponseDataLen = 0; - - // Setup the URL using the input parameters - if (flags & SECURE_RPC_FLAG) - { - pPartialUrl = pSession->pPartialHttpsUrl; - partialUrlLen = pSession->partialHttpsUrlLen; - - // Check if we need to ignore invalid CERTS - if (flags & ALLOW_INVALID_CERTS_RPC_FLAG) - { - if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 0)) != CURLE_OK) - { - DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult); - } - - if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 0)) != CURLE_OK) - { - DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult); - } - } - else - { - if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 1)) != CURLE_OK) - { - DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult); - } - - if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 2)) != CURLE_OK) - { - DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult); - } - } - - } - else - { - pPartialUrl = pSession->pPartialHttpUrl; - partialUrlLen = pSession->partialHttpUrlLen; - } - - pUrl = (char*) malloc(partialUrlLen + strlen(pMethod) + 1); - if (pUrl) - { - strcpy(pUrl, pPartialUrl); - strcat(pUrl, pMethod); - - // Tell curl about the URL - curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_URL, pUrl); - if (curlResult == CURLE_OK) - { - // Tell curl about our post data - curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDS, pRequestData); - if (curlResult == CURLE_OK) - { - // Tell curl about our post data len - curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDSIZE, strlen(pRequestData)); - if (curlResult == CURLE_OK) - { - // Now do the HTTP request - curlResult = curl_easy_perform(pSession->hCurl); - if (curlResult == CURLE_OK) - { - // Get the HTTP Response code - long httpCompStatus; - curlResult = curl_easy_getinfo(pSession->hCurl, CURLINFO_RESPONSE_CODE, &httpCompStatus); - if (curlResult == CURLE_OK) - { - // Verify that the HTTP request was successfully completed by the server - if (httpCompStatus == 200) - { - // Success, return the response data to the caller. - retStatus = CASA_STATUS_SUCCESS; - *ppResponseData = pSession->pRecvData; - *pResponseDataLen = pSession->recvDataLen;; - - // Forget about the response data buffer to keep from freeing it. - pSession->pRecvData = NULL; - } - else - { - DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %ld\n", httpCompStatus); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Curl get info failed, code = %d\n", curlResult); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Curl perform failed, code = %d\n", curlResult); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - - // Make sure that we never exit with a recv data buffer hanging off the session - if (pSession->pRecvData) - { - free(pSession->pRecvData); - pSession->pRecvData = NULL; - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDSIZE, code = %d\n", curlResult); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDS, code = %d\n", curlResult); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_URL, code = %d\n", curlResult); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - - // Free the buffer used to hold the URL - free(pUrl); - } - else - { - DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - - DbgTrace(1, "-InternalRpc- End, retStatus = %0X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -CasaStatus -Rpc( - IN RpcSession *pSession, - IN char *pMethod, - IN long flags, - IN char *pRequestData, - INOUT char **ppResponseData, - INOUT size_t *pResponseDataLen) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - CasaStatus retStatus; - int retries = 0; - - DbgTrace(1, "-Rpc- Start\n", 0); - - // Retry the RPC as needed - do - { - // Issue the RPC - retStatus = InternalRpc(pSession, - pMethod, - flags, - pRequestData, - ppResponseData, - pResponseDataLen); - - // Account for this try - retries ++; - - } while (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE - && retries < MAX_RPC_RETRIES); - - DbgTrace(1, "-Rpc- End, retStatus = %0X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -CasaStatus -InitializeRpc(void) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - - DbgTrace(1, "-InitializeRpc- Start\n", 0); - - // Initialize OpenSSL support - if (SetupOSSLSupport() == 0) - { - // Perform libcurl initializatoin - CURLcode curlStatus = curl_global_init(CURL_GLOBAL_SSL); - if (curlStatus != 0) - { - DbgTrace(0, "-InitializeRpc- Error initializing libcurl, curlStatus = %0X\n", curlStatus); - CleanupOSSLSupport(); - } - else - { - // Success - g_rpcInitialized = true; - retStatus = CASA_STATUS_SUCCESS; - } - } - else - { - DbgTrace(0, "-InitializeRpc- OpenSSL support setup failure\n", 0); - } - - DbgTrace(1, "-InitializeRpc- End, retStatus = %0X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -void -UnInitializeRpc(void) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DbgTrace(1, "-UnInitializeRpc- Start\n", 0); - - // Only try to cleanup if we were initialized - if (g_rpcInitialized) - { - // Cleanup libcurl - curl_global_cleanup(); - - // Cleanup OpenSSL support - CleanupOSSLSupport(); - - // Forget about having been initialized - g_rpcInitialized = false; - } - - DbgTrace(1, "-UnInitializeRpc- End\n", 0); -} - - -//++======================================================================= -//++======================================================================= -//++======================================================================= - +/*********************************************************************** + * + * Copyright (C) 2006 Novell, Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + * + * Author: Juan Carlos Luciani + * + ***********************************************************************/ + + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +#define MAX_RPC_RETRIES 3 + +//===[ External prototypes ]=============================================== + +extern +int +SetupOSSLSupport(void); + +extern +void +CleanupOSSLSupport(void); + +//===[ Function prototypes ]=============================================== + + +//===[ Global variables ]================================================== + +static +bool g_rpcInitialized = false; + + +//++======================================================================= +size_t +CurlWriteCallback( + IN void *pData, + IN size_t dataItemSz, + IN size_t numDataItems, + IN RpcSession *pSession) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + size_t dataConsumed = numDataItems; + + DbgTrace(1, "-CurlWriteCallback- Start\n", 0); + + // Consume the data by keeping a copy of the data. Note that we may have + // already consumed some data in which case we need to allocate a new + // buffer big enough to hold all of it. + if (pSession->pRecvData == NULL) + { + // We have not yet consumed receive data for the current Rpc + // if the data does not exceed our maximum Rpc reply size. + if ((numDataItems * dataItemSz) <= MAX_RPC_REPLY_SZ) + { + pSession->pRecvData = (char*) malloc(numDataItems * dataItemSz); + if (pSession->pRecvData) + { + // Consume the data + memcpy(pSession->pRecvData, pData, numDataItems * dataItemSz); + pSession->recvDataLen = numDataItems * dataItemSz; + } + else + { + DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0); + dataConsumed = CURLE_WRITE_ERROR; // To abort RPC + } + } + else + { + DbgTrace(0, "-CurlWriteCallback- Max Rpc reply size exceeded\n", 0); + dataConsumed = CURLE_WRITE_ERROR; // To abort RPC + } + } + else + { + // We have already consumed receive data for the current Rpc, append the new data to it + // if the data does not exceed our maximum Rpc reply size. + if ((pSession->recvDataLen + (numDataItems * dataItemSz)) <= MAX_RPC_REPLY_SZ) + { + char *pNewRecvDataBuf = (char*) malloc(pSession->recvDataLen + (numDataItems * dataItemSz)); + if (pNewRecvDataBuf) + { + memcpy(pNewRecvDataBuf, pSession->pRecvData, pSession->recvDataLen); + memcpy(pNewRecvDataBuf + pSession->recvDataLen, pData, numDataItems * dataItemSz); + pSession->recvDataLen += numDataItems * dataItemSz; + free(pSession->pRecvData); + pSession->pRecvData = pNewRecvDataBuf; + } + else + { + DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0); + dataConsumed = CURLE_WRITE_ERROR; // To abort RPC + + // Forget about already consumed data + free(pSession->pRecvData); + pSession->pRecvData = NULL; + } + } + else + { + DbgTrace(0, "-CurlWriteCallback- Max Rpc reply size exceeded\n", 0); + dataConsumed = CURLE_WRITE_ERROR; // To abort RPC + + // Forget about already consumed data + free(pSession->pRecvData); + pSession->pRecvData = NULL; + } + } + + DbgTrace(1, "-CurlWriteCallback- End\n", 0); + + return dataConsumed; +} + + +//++======================================================================= +RpcSession* +OpenRpcSession( + IN const char *pHostName, + IN const uint16_t hostPort) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + RpcSession *pSession = NULL; + char *pPartialHttpUrl = NULL; + char *pPartialHttpsUrl = NULL; + int hostNameLen = strlen(pHostName); + + DbgTrace(1, "-OpenRpcSession- Start\n", 0); + + // Build the partial URL strings that may be used with this session. + pPartialHttpUrl = (char*) malloc(7 /*"http://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/); + pPartialHttpsUrl = (char*) malloc(8 /*"https://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/); + if (pPartialHttpUrl && pPartialHttpsUrl) + { + sprintf(pPartialHttpUrl, "http://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort); + sprintf(pPartialHttpsUrl, "https://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort); + + // Allocate space for the session + pSession = (RpcSession*) malloc(sizeof(*pSession)); + if (pSession) + { + // Zero the session structure + memset(pSession, 0, sizeof(*pSession)); + + // Get a curl handle + pSession->hCurl = curl_easy_init(); + if (pSession->hCurl != NULL) + { + CURLcode result; + bool setOptError = false; + + // Set necessary options on the handle + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_NOSIGNAL, 0)) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_NOSIGNAL, code = %d\n", result); + setOptError = true; + } + + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_USERAGENT, "CASA Client/1.0")) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_USERAGENT, code = %d\n", result); + setOptError = true; + } + + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_POST, 1)) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POST, code = %d\n", result); + setOptError = true; + } + + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_CAPATH, "/etc/ssl/certs")) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_CAPATH, code = %d\n", result); + setOptError = true; + } + + pSession->headers = curl_slist_append(pSession->headers, "Content-Type: text/html"); + pSession->headers = curl_slist_append(pSession->headers, "Expect:"); + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_HTTPHEADER, pSession->headers)) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_HTTPHEADER, code = %d\n", result); + setOptError = true; + } + + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEFUNCTION, CurlWriteCallback)) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEFUNCTION, code = %d\n", result); + setOptError = true; + } + + if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEDATA, pSession)) != CURLE_OK) + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEDATA, code = %d\n", result); + setOptError = true; + } + + // Now check if we succeded + if (setOptError == false) + { + // Success, finish setting up the session object. + pSession->pPartialHttpUrl = pPartialHttpUrl; + pSession->partialHttpUrlLen = strlen(pPartialHttpUrl); + pSession->pPartialHttpsUrl = pPartialHttpsUrl; + pSession->partialHttpsUrlLen = strlen(pPartialHttpsUrl); + + // Forget about the partial URL buffers so that they do not get deleted below + pPartialHttpUrl = NULL; + pPartialHttpsUrl = NULL; + } + else + { + // Failed to set a needed curl option + if (pSession->headers) + curl_slist_free_all(pSession->headers); + + curl_easy_cleanup(pSession->hCurl); + + free(pSession); + pSession = NULL; + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Error creating curl handle\n", 0); + free(pSession); + pSession = NULL; + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for URL\n", 0); + } + + // Free buffers not utilized + if (pPartialHttpUrl) + free(pPartialHttpUrl); + + if (pPartialHttpsUrl) + free(pPartialHttpsUrl); + + DbgTrace(2, "-OpenRpcSession- End, pSession = %0lX\n", (long) pSession); + + return pSession; +} + + +//++======================================================================= +void +CloseRpcSession( + IN RpcSession *pSession) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-CloseRpcSession- Start\n", 0); + + // Free any HTTP headers associated with the session + if (pSession->headers) + curl_slist_free_all(pSession->headers); + + // Close the curl handle associated with this session + curl_easy_cleanup(pSession->hCurl); + + // Free the space allocated for the session + if (pSession->pRecvData) + free(pSession->pRecvData); + + free(pSession->pPartialHttpUrl); + free(pSession->pPartialHttpsUrl); + + free(pSession); + + DbgTrace(1, "-CloseRpcSession- End\n", 0); +} + + +//++======================================================================= +static +CasaStatus +InternalRpc( + IN RpcSession *pSession, + IN char *pMethod, + IN long flags, + IN char *pRequestData, + INOUT char **ppResponseData, + INOUT size_t *pResponseDataLen) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ +#ifndef CASA_STATUS_INVALID_SERVER_CERTIFICATE +#define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated +#endif + + CasaStatus retStatus; + char *pPartialUrl; + int partialUrlLen; + char *pUrl; + CURLcode curlResult; + + DbgTrace(1, "-InternalRpc- Start\n", 0); + + // Initialize output parameters + *ppResponseData = NULL; + *pResponseDataLen = 0; + + // Setup the URL using the input parameters + if (flags & SECURE_RPC_FLAG) + { + pPartialUrl = pSession->pPartialHttpsUrl; + partialUrlLen = pSession->partialHttpsUrlLen; + + // Check if we need to ignore invalid CERTS + if (flags & ALLOW_INVALID_CERTS_RPC_FLAG) + { + if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 0)) != CURLE_OK) + { + DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult); + } + + if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 0)) != CURLE_OK) + { + DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult); + } + } + else + { + if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 1)) != CURLE_OK) + { + DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult); + } + + if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 2)) != CURLE_OK) + { + DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult); + } + } + + } + else + { + pPartialUrl = pSession->pPartialHttpUrl; + partialUrlLen = pSession->partialHttpUrlLen; + } + + pUrl = (char*) malloc(partialUrlLen + strlen(pMethod) + 1); + if (pUrl) + { + strcpy(pUrl, pPartialUrl); + strcat(pUrl, pMethod); + + // Tell curl about the URL + curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_URL, pUrl); + if (curlResult == CURLE_OK) + { + // Tell curl about our post data + curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDS, pRequestData); + if (curlResult == CURLE_OK) + { + // Tell curl about our post data len + curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDSIZE, strlen(pRequestData)); + if (curlResult == CURLE_OK) + { + // Now do the HTTP request + curlResult = curl_easy_perform(pSession->hCurl); + if (curlResult == CURLE_OK) + { + // Get the HTTP Response code + long httpCompStatus; + curlResult = curl_easy_getinfo(pSession->hCurl, CURLINFO_RESPONSE_CODE, &httpCompStatus); + if (curlResult == CURLE_OK) + { + // Verify that the HTTP request was successfully completed by the server + if (httpCompStatus == 200) + { + // Success, return the response data to the caller. + retStatus = CASA_STATUS_SUCCESS; + *ppResponseData = pSession->pRecvData; + *pResponseDataLen = pSession->recvDataLen;; + + // Forget about the response data buffer to keep from freeing it. + pSession->pRecvData = NULL; + } + else + { + DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %ld\n", httpCompStatus); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Curl get info failed, code = %d\n", curlResult); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Curl perform failed, code = %d\n", curlResult); + + if (curlResult == CURLE_COULDNT_CONNECT + || curlResult == CURLE_SSL_CONNECT_ERROR) + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_AUTH_SERVER_UNAVAILABLE); + } + else if (curlResult == CURLE_OPERATION_TIMEOUTED + || curlResult == CURLE_SEND_ERROR + || curlResult == CURLE_RECV_ERROR) + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONNECTION_ERROR); + } + else + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + + // Make sure that we never exit with a recv data buffer hanging off the session + if (pSession->pRecvData) + { + free(pSession->pRecvData); + pSession->pRecvData = NULL; + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDSIZE, code = %d\n", curlResult); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDS, code = %d\n", curlResult); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_URL, code = %d\n", curlResult); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + + // Free the buffer used to hold the URL + free(pUrl); + } + else + { + DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(1, "-InternalRpc- End, retStatus = %0X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus +Rpc( + IN RpcSession *pSession, + IN char *pMethod, + IN long flags, + IN char *pRequestData, + INOUT char **ppResponseData, + INOUT size_t *pResponseDataLen) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + int retries = 3; + + DbgTrace(1, "-Rpc- Start\n", 0); + + // Retry the RPC as needed + do + { + // Issue the RPC + retStatus = InternalRpc(pSession, + pMethod, + flags, + pRequestData, + ppResponseData, + pResponseDataLen); + + // Account for this try + retries ++; + + } while (CasaStatusCode(retStatus) == CASA_STATUS_CONNECTION_ERROR + && retries < MAX_RPC_RETRIES); + + DbgTrace(1, "-Rpc- End, retStatus = %0X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus +InitializeRpc(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + + DbgTrace(1, "-InitializeRpc- Start\n", 0); + + // Initialize OpenSSL support + if (SetupOSSLSupport() == 0) + { + // Perform libcurl initializatoin + CURLcode curlStatus = curl_global_init(CURL_GLOBAL_SSL); + if (curlStatus != 0) + { + DbgTrace(0, "-InitializeRpc- Error initializing libcurl, curlStatus = %0X\n", curlStatus); + CleanupOSSLSupport(); + } + else + { + // Success + g_rpcInitialized = true; + retStatus = CASA_STATUS_SUCCESS; + } + } + else + { + DbgTrace(0, "-InitializeRpc- OpenSSL support setup failure\n", 0); + } + + DbgTrace(1, "-InitializeRpc- End, retStatus = %0X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +void +UnInitializeRpc(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-UnInitializeRpc- Start\n", 0); + + // Only try to cleanup if we were initialized + if (g_rpcInitialized) + { + // Cleanup libcurl + curl_global_cleanup(); + + // Cleanup OpenSSL support + CleanupOSSLSupport(); + + // Forget about having been initialized + g_rpcInitialized = false; + } + + DbgTrace(1, "-UnInitializeRpc- End\n", 0); +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/CASA-auth-token/client/library/windows/rpc.c b/CASA-auth-token/client/library/windows/rpc.c index f4788828..8890809c 100644 --- a/CASA-auth-token/client/library/windows/rpc.c +++ b/CASA-auth-token/client/library/windows/rpc.c @@ -1,859 +1,861 @@ -/*********************************************************************** - * - * Copyright (C) 2006 Novell, Inc. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, Novell, Inc. - * - * To contact Novell about this file by physical or electronic mail, - * you may find current contact information at www.novell.com. - * - * Author: Juan Carlos Luciani - * - ***********************************************************************/ - - -//===[ Include files ]===================================================== - -#include "internal.h" - -//===[ Type definitions ]================================================== - -#define INITIAL_RESPONSE_DATA_BUF_SIZE 1028 -#define INCREMENT_RESPONSE_DATA_BUF_SIZE 256 - -#define MAX_RPC_RETRIES 3 - -//===[ Function prototypes ]=============================================== - -//===[ Global variables ]================================================== - -//++======================================================================= -static -CasaStatus -CopyMultiToWideAlloc( - IN char *pMulti, - IN int multiSize, - INOUT LPWSTR *ppWide, - INOUT int *pWideSize) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int retStatus; - int size, i; - - DbgTrace(2, "-CopyMultiToWideAlloc- Start\n", 0); - - size = (multiSize + 1) * sizeof(WCHAR); - - if ((*ppWide = (PWCHAR) malloc(size)) != NULL) - { - for (i = 0; i < multiSize; i++) - { - *(*ppWide + i) = (unsigned char) *(pMulti + i); - } - - *(*ppWide + i) = L'\0'; - - if (pWideSize) - { - *pWideSize = size - sizeof(WCHAR); - } - - retStatus = CASA_STATUS_SUCCESS; - } - else - { - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - - DbgTrace(2, "-CopyMultiToWideAlloc- End, retStatus = %08X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -static -CasaStatus -CopyWideToMultiAlloc( - IN LPWSTR pWide, - IN int wideSize, - INOUT char **ppMulti, - INOUT int *pMultiSize) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - int retStatus; - int size, i; - - DbgTrace(2, "-CopyWideToMultiAlloc- Start\n", 0); - - size = wideSize + 1; - - if ((*ppMulti = malloc(size)) != NULL) - { - for (i = 0; i < wideSize; i++) - { - *(*ppMulti + i) = (char) *(pWide + i); - } - - *(*ppMulti + i) = '\0'; - - if (pMultiSize) - { - *pMultiSize = size - 1; - } - - retStatus = CASA_STATUS_SUCCESS; - } - else - { - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - - DbgTrace(2, "-CopyWideToMultiAlloc- End, retStatus = %08X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -RpcSession* -OpenRpcSession( - IN const char *pHostName, - IN const uint16_t hostPort) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - RpcSession *pSession; - bool success = false; - - DbgTrace(1, "-OpenRpcSession- Start\n", 0); - DbgTrace(2, "-OpenRpcSession- Host = %s\n", pHostName); - DbgTrace(2, "-OpenRpcSession- HostPort = %d\n", hostPort); - - // Allocate space for the session - pSession = (RpcSession*) malloc(sizeof(*pSession)); - if (pSession) - { - // Zero the session structure - memset(pSession, 0, sizeof(*pSession)); - - // Save copy of the hostname - pSession->pHostName = malloc(strlen(pHostName) + 1); - if (pSession->pHostName) - { - strcpy(pSession->pHostName, pHostName); - - // Open a Winhttp session - pSession->hSession = WinHttpOpen(L"CASA Client/1.0", - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0); - if (pSession->hSession) - { - LPWSTR pWideHostName; - int wideHostLen; - - // Session opened, now convert the host name to Unicode so that - // we can open a connection. - if (CopyMultiToWideAlloc(pHostName, - (int) strlen(pHostName), - &pWideHostName, - &wideHostLen) == CASA_STATUS_SUCCESS) - { - // Now open connection - pSession->hConnection = WinHttpConnect(pSession->hSession, - pWideHostName, - hostPort, - 0); - if (pSession->hConnection == NULL) - { - DbgTrace(0, "-OpenRpcSession- Failed to open connection, error = %d\n", GetLastError()); - } - else - { - success = true; - } - - // Free the host name wide string buffer - free(pWideHostName); - } - else - { - DbgTrace(0, "-OpenRpcSession- Error converting host name to wide string\n", 0); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Failed to open session, error = %d\n", GetLastError()); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for host name\n", 0); - } - } - else - { - DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0); - } - - // Clean up if we did not succeed - if (!success) - { - if (pSession) - { - if (pSession->hConnection) - WinHttpCloseHandle(pSession->hConnection); - - if (pSession->hSession) - WinHttpCloseHandle(pSession->hSession); - - if (pSession->pHostName) - free(pSession->pHostName); - - free(pSession); - pSession = NULL; - } - } - - DbgTrace(2, "-OpenRpcSession- End, pSession = %08X\n", pSession); - - return pSession; -} - - -//++======================================================================= -void -CloseRpcSession( - IN RpcSession *pSession) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DbgTrace(1, "-CloseRpcSession- Start\n", 0); - - // Close the connection handle - WinHttpCloseHandle(pSession->hConnection); - - // Close the session handle - WinHttpCloseHandle(pSession->hSession); - - // Free hostname buffer if necessary - if (pSession->pHostName) - free(pSession->pHostName); - - // Free the space allocated for the session - free(pSession); - - DbgTrace(1, "-CloseRpcSession- End\n", 0); -} - - -//++======================================================================= -static -void CALLBACK -SecureFailureStatusCallback( - IN HINTERNET hRequest, - IN DWORD_PTR *pContext, - IN DWORD internetStatus, - IN LPVOID pStatusInformation, - IN DWORD statusInformationLength) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L0 -//=======================================================================-- -{ - DbgTrace(1, "-SecureFailureStatusCallback- Start\n", 0); - - // Only deal with failures related to certificates - if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) - { - // Save the specific failure status - *pContext = *(DWORD*) pStatusInformation; - } - - DbgTrace(1, "-SecureFailureStatusCallback- End\n", 0); -} - - -//++======================================================================= -static -CasaStatus -InternalRpc( - IN RpcSession *pSession, - IN char *pMethod, - IN long flags, - IN char *pRequestData, - INOUT char **ppResponseData, - INOUT size_t *pResponseDataLen) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ -#define RPC_TARGET_FMT_STRING "CasaAuthTokenSvc/Rpc?method=%s" - - CasaStatus retStatus = CASA_STATUS_SUCCESS; - char *pRpcTarget; - LPWSTR pWideRpcTarget; - int wideRpcTargetLen; - WCHAR sendHeaders[] = L"Content-Type: text/html"; - DWORD securityFailureStatusFlags; - int retriesAllowed = 1; - bool attemptRetry; - - DbgTrace(1, "-InternalRpc- Start\n", 0); - - // Initialize output parameter - *ppResponseData = NULL; - - // Create rpc target string and convert it to a wide string - pRpcTarget = (char*) malloc(sizeof(RPC_TARGET_FMT_STRING) + strlen(pMethod)); - if (pRpcTarget) - { - sprintf(pRpcTarget, RPC_TARGET_FMT_STRING, pMethod); - retStatus = CopyMultiToWideAlloc(pRpcTarget, - (int) strlen(pRpcTarget), - &pWideRpcTarget, - &wideRpcTargetLen); - if (CASA_SUCCESS(retStatus)) - { - HINTERNET hRequest; - - do - { - // Forget about having been told to retry - attemptRetry = false; - - // Open a request handle - hRequest = WinHttpOpenRequest(pSession->hConnection, - L"POST", - pWideRpcTarget, - NULL, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - flags & SECURE_RPC_FLAG? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH); - if (hRequest) - { - int reqDataLen = (int) strlen(pRequestData); - - // Check if we need to set options to deal with secure connections - if (flags & SECURE_RPC_FLAG) - { - // We are using secure connections, now proceed based on whether or not - // we are configured to allow invalid certificates. - if (flags & ALLOW_INVALID_CERTS_RPC_FLAG - || (flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG - && InvalidCertsFromHostAllowed(pSession->pHostName))) - { - DWORD secFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA; - - // We are configured to allow invalid certificates, inform the HTTP stack. - if (WinHttpSetOption(hRequest, - WINHTTP_OPTION_SECURITY_FLAGS, - &secFlags, - sizeof(secFlags)) == FALSE) - { - DbgTrace(0, "-InternalRpc- Failed setting options to ignore invalid certs, error = %d\n", GetLastError()); - } - } - else - { - // We are not configured to allow invalid certificates, set a callback handler - // to detect invalid certificate conditions. - if (WinHttpSetStatusCallback(hRequest, - SecureFailureStatusCallback, - WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, - (DWORD_PTR) NULL) == WINHTTP_INVALID_STATUS_CALLBACK) - { - DbgTrace(0, "-InternalRpc- Failed setting status callback, error = %d\n", GetLastError()); - } - } - } - - // Send the request - securityFailureStatusFlags = 0; - if (WinHttpSendRequest(hRequest, - sendHeaders, - -1, - pRequestData, - reqDataLen, - reqDataLen, - (DWORD_PTR) &securityFailureStatusFlags)) - { - // Request sent, now await for the response. - if (WinHttpReceiveResponse(hRequest, NULL)) - { - WCHAR httpCompStatus[4] = {0}; - DWORD httpCompStatusLen = sizeof(httpCompStatus); - - // Response received, make sure that it completed successfully. - if (WinHttpQueryHeaders(hRequest, - WINHTTP_QUERY_STATUS_CODE, - NULL, - &httpCompStatus, - &httpCompStatusLen, - WINHTTP_NO_HEADER_INDEX)) - { - // Check that the request completed successfully - if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0) - { - char *pResponseData; - size_t responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE; - size_t responseDataRead = 0; - - // Now read the response data, to do so we need to allocate a buffer. - pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE); - if (pResponseData) - { - char *pCurrLocation = pResponseData; - DWORD bytesRead; - - do - { - bytesRead = 0; - if (WinHttpReadData(hRequest, - (LPVOID) pCurrLocation, - responseDataBufSize - responseDataRead, - &bytesRead)) - { - pCurrLocation += bytesRead; - responseDataRead += bytesRead; - - // Check if we need to allocate a larger buffer - if (responseDataRead == responseDataBufSize) - { - char *pTmpBuf; - - // We need to upgrade the receive buffer. - // - // Do not allow the reply to exceed our maximum - if (responseDataBufSize < MAX_RPC_REPLY_SZ) - { - size_t incrementSz; - - // Determine the buffer size imcrement so that the maximum rpc reply - // size is not exceeded. - if ((responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE) <= MAX_RPC_REPLY_SZ) - incrementSz = INCREMENT_RESPONSE_DATA_BUF_SIZE; - else - incrementSz = MAX_RPC_REPLY_SZ - responseDataBufSize; - - pTmpBuf = (char*) malloc(responseDataBufSize + incrementSz); - if (pTmpBuf) - { - memcpy(pTmpBuf, pResponseData, responseDataBufSize); - free(pResponseData); - pResponseData = pTmpBuf; - pCurrLocation = pResponseData + responseDataBufSize; - responseDataBufSize += incrementSz; - } - else - { - DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - } - else - { - DbgTrace(0, "-InternalRpc- Reply maximum exceeded\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - } - else - { - DbgTrace(0, "-InternalRpc- Failed reading response data, error = %d\n", GetLastError()); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } while (CASA_SUCCESS(retStatus) - && bytesRead != 0); - - // Check if the response data was successfully received - if (CASA_SUCCESS(retStatus)) - { - // The response data was received, return it to the caller. - *ppResponseData = pResponseData; - *pResponseDataLen = responseDataRead; - } - else - { - // Failed to receive the response data, free the allocated buffer. - free(pResponseData); - } - } - else - { - DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - } - else - { - DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %S\n", httpCompStatus); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError()); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError()); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - else - { - int error = GetLastError(); - - if (error == ERROR_WINHTTP_CANNOT_CONNECT) - { - DbgTrace(0, "-InternalRpc- Unable to connect to server\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_AUTH_SERVER_UNAVAILABLE); - } - else if (error == ERROR_WINHTTP_SECURE_FAILURE) - { - DbgTrace(1, "-InternalRpc- Secure connection failure, flags = %0x\n", securityFailureStatusFlags); - - // Try to deal with the issue - if ((securityFailureStatusFlags & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA - | WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID - | WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) == 0 - && flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG) - { - WINHTTP_CERTIFICATE_INFO certInfo; - DWORD certInfoLen = sizeof(certInfo); - - // The failure was due to an invalid CN, CA, or both. - // - // Obtain information about the server certificate to give user - // the choice of accepting it. - if (WinHttpQueryOption(hRequest, - WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT, - &certInfo, - &certInfoLen) - && certInfo.lpszSubjectInfo != NULL - && certInfo.lpszIssuerInfo != NULL) - { - char *pSubjectInfo; - int subjectInfoLen; - - // Convert the subjectInfo to multi-byte - retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo, - (int) wcslen(certInfo.lpszSubjectInfo), - &pSubjectInfo, - &subjectInfoLen); - if (CASA_SUCCESS(retStatus)) - { - char *pIssuerInfo; - int issuerInfoLen; - - // Convert the issuerInfo to multi-byte - retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo, - (int) wcslen(certInfo.lpszIssuerInfo), - &pIssuerInfo, - &issuerInfoLen); - if (CASA_SUCCESS(retStatus)) - { - long invalidCertFlags = 0; - - // Setup the invalid cert flags - if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) - invalidCertFlags |= INVALID_CERT_CA_FLAG; - - if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) - invalidCertFlags |= INVALID_CERT_CN_FLAG; - - if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) - invalidCertFlags |= INVALID_CERT_DATE_FLAG; - - // Give user the choice to accept the certificate - if (UserApprovedCert(pSession->pHostName, - pSubjectInfo, - pIssuerInfo, - invalidCertFlags)) - { - DbgTrace(1, "-InternalRpc- User approved invalid certificate from %s\n", pSession->pHostName); - - // tbd - Investigate if there is a way to set the accepted certificate in a store so that - // it can be utilized by the SSL stack directly. This would be a better method for dealing with - // this issue. - - AllowInvalidCertsFromHost(pSession->pHostName); - - // Try to retry the request - attemptRetry = true; - } - else - { - DbgTrace(1, "-InternalRpc- User did not approve invalid certificate from %s\n", pSession->pHostName); - - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INVALID_SERVER_CERTIFICATE); - } - - // Free the buffer containing the issuerInfo - free(pIssuerInfo); - } - - // Free the buffer containing the subjectInfo - free(pSubjectInfo); - } - - // Free necessary certificate information - if (certInfo.lpszSubjectInfo) LocalFree(certInfo.lpszSubjectInfo); - if (certInfo.lpszIssuerInfo) LocalFree(certInfo.lpszIssuerInfo); - if (certInfo.lpszProtocolName) LocalFree(certInfo.lpszProtocolName); - if (certInfo.lpszSignatureAlgName) LocalFree(certInfo.lpszSignatureAlgName); - if (certInfo.lpszEncryptionAlgName) LocalFree(certInfo.lpszEncryptionAlgName); - } - else - { - DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError()); - } - } - else - { - // Decided to no give the user a choice to accept invalid server certificate - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INVALID_SERVER_CERTIFICATE); - } - } - else - { - DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } - - // Close the request handle - WinHttpCloseHandle(hRequest); - } - else - { - DbgTrace(0, "-InternalRpc- Unable to open http request, error = %d\n", GetLastError()); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_UNSUCCESSFUL); - } - } while (attemptRetry && retriesAllowed--); - - // Free the rpc target wide string buffer - free(pWideRpcTarget); - } - else - { - DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0); - } - - // Free buffer used to hold the rpc target string - free(pRpcTarget); - } - else - { - DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_INSUFFICIENT_RESOURCES); - } - - DbgTrace(1, "-InternalRpc- End, retStatus = %0X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -CasaStatus -Rpc( - IN RpcSession *pSession, - IN char *pMethod, - IN long flags, - IN char *pRequestData, - INOUT char **ppResponseData, - INOUT size_t *pResponseDataLen) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - CasaStatus retStatus; - int retries = 0; - - DbgTrace(1, "-Rpc- Start\n", 0); - - // Retry the RPC as needed - do - { - // Issue the RPC - retStatus = InternalRpc(pSession, - pMethod, - flags, - pRequestData, - ppResponseData, - pResponseDataLen); - - // Account for this try - retries ++; - - } while (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE - && retries < MAX_RPC_RETRIES); - - DbgTrace(1, "-Rpc- End, retStatus = %0X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -CasaStatus -InitializeRpc(void) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - CasaStatus retStatus = CASA_STATUS_SUCCESS; - - DbgTrace(1, "-InitializeRpc- Start\n", 0); - - // Nothing to do for windows - - DbgTrace(1, "-InitializeRpc- End, retStatus = %08X\n", retStatus); - - return retStatus; -} - - -//++======================================================================= -void -UnInitializeRpc(void) -// -// Arguments: -// -// Returns: -// -// Abstract: -// -// Notes: -// -// L2 -//=======================================================================-- -{ - DbgTrace(1, "-UnInitializeRpc- Start\n", 0); - - // Nothing to do for windows - - DbgTrace(1, "-UnInitializeRpc- End\n", 0); -} - - -//++======================================================================= -//++======================================================================= -//++======================================================================= - +/*********************************************************************** + * + * Copyright (C) 2006 Novell, Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, Novell, Inc. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + * + * Author: Juan Carlos Luciani + * + ***********************************************************************/ + + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +#define INITIAL_RESPONSE_DATA_BUF_SIZE 1028 +#define INCREMENT_RESPONSE_DATA_BUF_SIZE 256 + +#define MAX_RPC_RETRIES 3 + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +//++======================================================================= +static +CasaStatus +CopyMultiToWideAlloc( + IN char *pMulti, + IN int multiSize, + INOUT LPWSTR *ppWide, + INOUT int *pWideSize) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int retStatus; + int size, i; + + DbgTrace(2, "-CopyMultiToWideAlloc- Start\n", 0); + + size = (multiSize + 1) * sizeof(WCHAR); + + if ((*ppWide = (PWCHAR) malloc(size)) != NULL) + { + for (i = 0; i < multiSize; i++) + { + *(*ppWide + i) = (unsigned char) *(pMulti + i); + } + + *(*ppWide + i) = L'\0'; + + if (pWideSize) + { + *pWideSize = size - sizeof(WCHAR); + } + + retStatus = CASA_STATUS_SUCCESS; + } + else + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(2, "-CopyMultiToWideAlloc- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +static +CasaStatus +CopyWideToMultiAlloc( + IN LPWSTR pWide, + IN int wideSize, + INOUT char **ppMulti, + INOUT int *pMultiSize) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int retStatus; + int size, i; + + DbgTrace(2, "-CopyWideToMultiAlloc- Start\n", 0); + + size = wideSize + 1; + + if ((*ppMulti = malloc(size)) != NULL) + { + for (i = 0; i < wideSize; i++) + { + *(*ppMulti + i) = (char) *(pWide + i); + } + + *(*ppMulti + i) = '\0'; + + if (pMultiSize) + { + *pMultiSize = size - 1; + } + + retStatus = CASA_STATUS_SUCCESS; + } + else + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(2, "-CopyWideToMultiAlloc- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +RpcSession* +OpenRpcSession( + IN const char *pHostName, + IN const uint16_t hostPort) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + RpcSession *pSession; + bool success = false; + + DbgTrace(1, "-OpenRpcSession- Start\n", 0); + DbgTrace(2, "-OpenRpcSession- Host = %s\n", pHostName); + DbgTrace(2, "-OpenRpcSession- HostPort = %d\n", hostPort); + + // Allocate space for the session + pSession = (RpcSession*) malloc(sizeof(*pSession)); + if (pSession) + { + // Zero the session structure + memset(pSession, 0, sizeof(*pSession)); + + // Save copy of the hostname + pSession->pHostName = malloc(strlen(pHostName) + 1); + if (pSession->pHostName) + { + strcpy(pSession->pHostName, pHostName); + + // Open a Winhttp session + pSession->hSession = WinHttpOpen(L"CASA Client/1.0", + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); + if (pSession->hSession) + { + LPWSTR pWideHostName; + int wideHostLen; + + // Session opened, now convert the host name to Unicode so that + // we can open a connection. + if (CopyMultiToWideAlloc(pHostName, + (int) strlen(pHostName), + &pWideHostName, + &wideHostLen) == CASA_STATUS_SUCCESS) + { + // Now open connection + pSession->hConnection = WinHttpConnect(pSession->hSession, + pWideHostName, + hostPort, + 0); + if (pSession->hConnection == NULL) + { + DbgTrace(0, "-OpenRpcSession- Failed to open connection, error = %d\n", GetLastError()); + } + else + { + success = true; + } + + // Free the host name wide string buffer + free(pWideHostName); + } + else + { + DbgTrace(0, "-OpenRpcSession- Error converting host name to wide string\n", 0); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Failed to open session, error = %d\n", GetLastError()); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for host name\n", 0); + } + } + else + { + DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0); + } + + // Clean up if we did not succeed + if (!success) + { + if (pSession) + { + if (pSession->hConnection) + WinHttpCloseHandle(pSession->hConnection); + + if (pSession->hSession) + WinHttpCloseHandle(pSession->hSession); + + if (pSession->pHostName) + free(pSession->pHostName); + + free(pSession); + pSession = NULL; + } + } + + DbgTrace(2, "-OpenRpcSession- End, pSession = %08X\n", pSession); + + return pSession; +} + + +//++======================================================================= +void +CloseRpcSession( + IN RpcSession *pSession) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-CloseRpcSession- Start\n", 0); + + // Close the connection handle + WinHttpCloseHandle(pSession->hConnection); + + // Close the session handle + WinHttpCloseHandle(pSession->hSession); + + // Free hostname buffer if necessary + if (pSession->pHostName) + free(pSession->pHostName); + + // Free the space allocated for the session + free(pSession); + + DbgTrace(1, "-CloseRpcSession- End\n", 0); +} + + +//++======================================================================= +static +void CALLBACK +SecureFailureStatusCallback( + IN HINTERNET hRequest, + IN DWORD_PTR *pContext, + IN DWORD internetStatus, + IN LPVOID pStatusInformation, + IN DWORD statusInformationLength) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L0 +//=======================================================================-- +{ + DbgTrace(1, "-SecureFailureStatusCallback- Start\n", 0); + + // Only deal with failures related to certificates + if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) + { + // Save the specific failure status + *pContext = *(DWORD*) pStatusInformation; + } + + DbgTrace(1, "-SecureFailureStatusCallback- End\n", 0); +} + + +//++======================================================================= +static +CasaStatus +InternalRpc( + IN RpcSession *pSession, + IN char *pMethod, + IN long flags, + IN char *pRequestData, + INOUT char **ppResponseData, + INOUT size_t *pResponseDataLen) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ +#define RPC_TARGET_FMT_STRING "CasaAuthTokenSvc/Rpc?method=%s" + + CasaStatus retStatus = CASA_STATUS_SUCCESS; + char *pRpcTarget; + LPWSTR pWideRpcTarget; + int wideRpcTargetLen; + WCHAR sendHeaders[] = L"Content-Type: text/html"; + DWORD securityFailureStatusFlags; + int retriesAllowed = 1; + bool attemptRetry; + + DbgTrace(1, "-InternalRpc- Start\n", 0); + + // Initialize output parameter + *ppResponseData = NULL; + + // Create rpc target string and convert it to a wide string + pRpcTarget = (char*) malloc(sizeof(RPC_TARGET_FMT_STRING) + strlen(pMethod)); + if (pRpcTarget) + { + sprintf(pRpcTarget, RPC_TARGET_FMT_STRING, pMethod); + retStatus = CopyMultiToWideAlloc(pRpcTarget, + (int) strlen(pRpcTarget), + &pWideRpcTarget, + &wideRpcTargetLen); + if (CASA_SUCCESS(retStatus)) + { + HINTERNET hRequest; + + do + { + // Forget about having been told to retry + attemptRetry = false; + + // Open a request handle + hRequest = WinHttpOpenRequest(pSession->hConnection, + L"POST", + pWideRpcTarget, + NULL, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + flags & SECURE_RPC_FLAG? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH); + if (hRequest) + { + int reqDataLen = (int) strlen(pRequestData); + + // Check if we need to set options to deal with secure connections + if (flags & SECURE_RPC_FLAG) + { + // We are using secure connections, now proceed based on whether or not + // we are configured to allow invalid certificates. + if (flags & ALLOW_INVALID_CERTS_RPC_FLAG + || (flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG + && InvalidCertsFromHostAllowed(pSession->pHostName))) + { + DWORD secFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA; + + // We are configured to allow invalid certificates, inform the HTTP stack. + if (WinHttpSetOption(hRequest, + WINHTTP_OPTION_SECURITY_FLAGS, + &secFlags, + sizeof(secFlags)) == FALSE) + { + DbgTrace(0, "-InternalRpc- Failed setting options to ignore invalid certs, error = %d\n", GetLastError()); + } + } + else + { + // We are not configured to allow invalid certificates, set a callback handler + // to detect invalid certificate conditions. + if (WinHttpSetStatusCallback(hRequest, + SecureFailureStatusCallback, + WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, + (DWORD_PTR) NULL) == WINHTTP_INVALID_STATUS_CALLBACK) + { + DbgTrace(0, "-InternalRpc- Failed setting status callback, error = %d\n", GetLastError()); + } + } + } + + // Send the request + securityFailureStatusFlags = 0; + if (WinHttpSendRequest(hRequest, + sendHeaders, + -1, + pRequestData, + reqDataLen, + reqDataLen, + (DWORD_PTR) &securityFailureStatusFlags)) + { + // Request sent, now await for the response. + if (WinHttpReceiveResponse(hRequest, NULL)) + { + WCHAR httpCompStatus[4] = {0}; + DWORD httpCompStatusLen = sizeof(httpCompStatus); + + // Response received, make sure that it completed successfully. + if (WinHttpQueryHeaders(hRequest, + WINHTTP_QUERY_STATUS_CODE, + NULL, + &httpCompStatus, + &httpCompStatusLen, + WINHTTP_NO_HEADER_INDEX)) + { + // Check that the request completed successfully + if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0) + { + char *pResponseData; + size_t responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE; + size_t responseDataRead = 0; + + // Now read the response data, to do so we need to allocate a buffer. + pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE); + if (pResponseData) + { + char *pCurrLocation = pResponseData; + DWORD bytesRead; + + do + { + bytesRead = 0; + if (WinHttpReadData(hRequest, + (LPVOID) pCurrLocation, + responseDataBufSize - responseDataRead, + &bytesRead)) + { + pCurrLocation += bytesRead; + responseDataRead += bytesRead; + + // Check if we need to allocate a larger buffer + if (responseDataRead == responseDataBufSize) + { + char *pTmpBuf; + + // We need to upgrade the receive buffer. + // + // Do not allow the reply to exceed our maximum + if (responseDataBufSize < MAX_RPC_REPLY_SZ) + { + size_t incrementSz; + + // Determine the buffer size imcrement so that the maximum rpc reply + // size is not exceeded. + if ((responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE) <= MAX_RPC_REPLY_SZ) + incrementSz = INCREMENT_RESPONSE_DATA_BUF_SIZE; + else + incrementSz = MAX_RPC_REPLY_SZ - responseDataBufSize; + + pTmpBuf = (char*) malloc(responseDataBufSize + incrementSz); + if (pTmpBuf) + { + memcpy(pTmpBuf, pResponseData, responseDataBufSize); + free(pResponseData); + pResponseData = pTmpBuf; + pCurrLocation = pResponseData + responseDataBufSize; + responseDataBufSize += incrementSz; + } + else + { + DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + DbgTrace(0, "-InternalRpc- Reply maximum exceeded\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + } + else + { + DbgTrace(0, "-InternalRpc- Failed reading response data, error = %d\n", GetLastError()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } while (CASA_SUCCESS(retStatus) + && bytesRead != 0); + + // Check if the response data was successfully received + if (CASA_SUCCESS(retStatus)) + { + // The response data was received, return it to the caller. + *ppResponseData = pResponseData; + *pResponseDataLen = responseDataRead; + } + else + { + // Failed to receive the response data, free the allocated buffer. + free(pResponseData); + } + } + else + { + DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %S\n", httpCompStatus); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONNECTION_ERROR); + } + } + else + { + int error = GetLastError(); + + if (error == ERROR_WINHTTP_CANNOT_CONNECT) + { + DbgTrace(0, "-InternalRpc- Unable to connect to server\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_AUTH_SERVER_UNAVAILABLE); + } + else if (error == ERROR_WINHTTP_SECURE_FAILURE) + { + DbgTrace(1, "-InternalRpc- Secure connection failure, flags = %0x\n", securityFailureStatusFlags); + + // Try to deal with the issue + if ((securityFailureStatusFlags & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA + | WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID + | WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) == 0 + && flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG) + { + WINHTTP_CERTIFICATE_INFO certInfo; + DWORD certInfoLen = sizeof(certInfo); + + // The failure was due to an invalid CN, CA, or both. + // + // Obtain information about the server certificate to give user + // the choice of accepting it. + if (WinHttpQueryOption(hRequest, + WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT, + &certInfo, + &certInfoLen) + && certInfo.lpszSubjectInfo != NULL + && certInfo.lpszIssuerInfo != NULL) + { + char *pSubjectInfo; + int subjectInfoLen; + + // Convert the subjectInfo to multi-byte + retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo, + (int) wcslen(certInfo.lpszSubjectInfo), + &pSubjectInfo, + &subjectInfoLen); + if (CASA_SUCCESS(retStatus)) + { + char *pIssuerInfo; + int issuerInfoLen; + + // Convert the issuerInfo to multi-byte + retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo, + (int) wcslen(certInfo.lpszIssuerInfo), + &pIssuerInfo, + &issuerInfoLen); + if (CASA_SUCCESS(retStatus)) + { + long invalidCertFlags = 0; + + // Setup the invalid cert flags + if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) + invalidCertFlags |= INVALID_CERT_CA_FLAG; + + if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) + invalidCertFlags |= INVALID_CERT_CN_FLAG; + + if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) + invalidCertFlags |= INVALID_CERT_DATE_FLAG; + + // Give user the choice to accept the certificate + if (UserApprovedCert(pSession->pHostName, + pSubjectInfo, + pIssuerInfo, + invalidCertFlags)) + { + DbgTrace(1, "-InternalRpc- User approved invalid certificate from %s\n", pSession->pHostName); + + // tbd - Investigate if there is a way to set the accepted certificate in a store so that + // it can be utilized by the SSL stack directly. This would be a better method for dealing with + // this issue. + + AllowInvalidCertsFromHost(pSession->pHostName); + + // Try to retry the request + attemptRetry = true; + } + else + { + DbgTrace(1, "-InternalRpc- User did not approve invalid certificate from %s\n", pSession->pHostName); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INVALID_SERVER_CERTIFICATE); + } + + // Free the buffer containing the issuerInfo + free(pIssuerInfo); + } + + // Free the buffer containing the subjectInfo + free(pSubjectInfo); + } + + // Free necessary certificate information + if (certInfo.lpszSubjectInfo) LocalFree(certInfo.lpszSubjectInfo); + if (certInfo.lpszIssuerInfo) LocalFree(certInfo.lpszIssuerInfo); + if (certInfo.lpszProtocolName) LocalFree(certInfo.lpszProtocolName); + if (certInfo.lpszSignatureAlgName) LocalFree(certInfo.lpszSignatureAlgName); + if (certInfo.lpszEncryptionAlgName) LocalFree(certInfo.lpszEncryptionAlgName); + } + else + { + DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError()); + } + } + else + { + // Decided to no give the user a choice to accept invalid server certificate + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INVALID_SERVER_CERTIFICATE); + } + } + else + { + DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONNECTION_ERROR); + } + } + + // Close the request handle + WinHttpCloseHandle(hRequest); + } + else + { + DbgTrace(0, "-InternalRpc- Unable to open http request, error = %d\n", GetLastError()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } while (attemptRetry && retriesAllowed--); + + // Free the rpc target wide string buffer + free(pWideRpcTarget); + } + else + { + DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0); + } + + // Free buffer used to hold the rpc target string + free(pRpcTarget); + } + else + { + DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(1, "-InternalRpc- End, retStatus = %0X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus +Rpc( + IN RpcSession *pSession, + IN char *pMethod, + IN long flags, + IN char *pRequestData, + INOUT char **ppResponseData, + INOUT size_t *pResponseDataLen) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + int retries = 3; + + DbgTrace(1, "-Rpc- Start\n", 0); + + // Retry the RPC as needed + do + { + // Issue the RPC + retStatus = InternalRpc(pSession, + pMethod, + flags, + pRequestData, + ppResponseData, + pResponseDataLen); + + // Account for this try + retries ++; + + + + } while (CasaStatusCode(retStatus) == CASA_STATUS_CONNECTION_ERROR + && retries < MAX_RPC_RETRIES); + + DbgTrace(1, "-Rpc- End, retStatus = %0X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus +InitializeRpc(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus = CASA_STATUS_SUCCESS; + + DbgTrace(1, "-InitializeRpc- Start\n", 0); + + // Nothing to do for windows + + DbgTrace(1, "-InitializeRpc- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +void +UnInitializeRpc(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-UnInitializeRpc- Start\n", 0); + + // Nothing to do for windows + + DbgTrace(1, "-UnInitializeRpc- End\n", 0); +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/CASA/include/casa_status.h b/CASA/include/casa_status.h index 64a61405..99aab274 100644 --- a/CASA/include/casa_status.h +++ b/CASA/include/casa_status.h @@ -139,6 +139,7 @@ typedef uint32_t CasaStatus; #define CASA_STATUS_NOT_CONFIGURED ((CasaStatus)0x00000022) #define CASA_STATUS_INVALID_SERVER_CERTIFICATE ((CasaStatus)0x00000023) #define CASA_STATUS_NAME_RESOLVE_ERROR ((CasaStatus)0x00000024) +#define CASA_STATUS_CONNECTION_ERROR ((CasaStatus)0x00000025) //===[ Macro definitions ]==============================