CASA/CASA-auth-token/client/library/cache.c
2007-02-06 22:09:00 +00:00

790 lines
26 KiB
C

/***********************************************************************
*
* 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 <jluciani@novell.com>
* Todd Throne <tthrone@novell.com>
*
***********************************************************************/
//===[ Include files ]=====================================================
#include "internal.h"
#include <micasa.h>
//===[ Type definitions ]==================================================
//
// Auth Cache Entry Wrapper definition
//
typedef struct _WrapperAuthCacheEntry
{
int size;
AuthCacheEntry entry;
} WrapperAuthCacheEntry, *PWrapperAuthCacheEntry;
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
static
bool g_authCacheInitialized = false;
HANDLE g_hCASAContext;
//++=======================================================================
AuthCacheEntry*
CreateAuthTokenCacheEntry(
IN const char *pCacheKey,
IN const char *pGroupOrHostName,
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;
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);
// 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,
0,
&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 = %0lX\n", (long) 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,
0,
&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 = %0lX\n", (long) 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 = %0lX\n", (long) 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 = %0lX\n", (long) pEntry);
return pEntry;
}
//++=======================================================================
AuthCacheEntry*
FindAuthTokenEntryInCache(
IN const char *pCacheKey,
IN const char *pGroupOrHostName,
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;
WrapperAuthCacheEntry *pWrapperEntry = NULL;
AuthCacheEntry *pEntry = NULL;
char *pKey;
DbgTrace(1, "-FindAuthTokenEntryInCache- Start\n", 0);
cacheKeyStrLen = strlen(pCacheKey);
groupOrHostNameStrLen = strlen(pGroupOrHostName);
// 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);
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 = %0lX\n", (long) 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);
}
//++=======================================================================
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);
}
//++=======================================================================
//++=======================================================================
//++=======================================================================