diff --git a/CASA-auth-token/native/client/cache.c b/CASA-auth-token/native/client/cache.c new file mode 100644 index 00000000..81e8dab2 --- /dev/null +++ b/CASA-auth-token/native/client/cache.c @@ -0,0 +1,615 @@ +/*********************************************************************** + * + * 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" +#include + +//===[ Type definitions ]================================================== + +// +// Registry Key/Value defines used in the AuthCache +// +#define CASA_AUTH_CACHE_REG_KEY "CASA_Auth_Cache" +#define CREATION_TIME_REG_VALUE "CreationTime" +#define EXPIRATION_TIME_REG_VALUE "ExpirationTime" +#define DOES_NOT_EXPIRE_REG_VALUE "DoesNotExpire" +#define STATUS_REG_VALUE "Status" +#define TOKEN_REG_VALUE "Token" + + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Non-host specific key name +static +char g_allHosts[] = "AllHosts"; + +static +int g_cacheEntryCount = 0; + +HANDLE g_hCASAContext; + +//++======================================================================= +AuthCacheEntry* +CreateAuthTokenCacheEntry( + IN const char *pCacheKey, + IN const char *pGroupOrHostName, + IN CasaStatus status, + IN unsigned char *pToken, + IN int entryLifetime // seconds (0 == Lives forever) + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {27, "CASA_AUTHENTICATION_TOKENS"}; + uint32_t tokenSize, entrySize, keySize; + AuthCacheEntry *pEntry = NULL; + unsigned char *pKey; + + + DbgTrace(1, "-CreateAuthTokenCacheEntry- Start\n", 0); + + if (status == CASA_STATUS_SUCCESS) + { + tokenSize = (uint32_t)strlen(pToken); + } + else + { + tokenSize = 0; + } + + entrySize = tokenSize + sizeof(AuthCacheEntry); + + // Allocate space for the entry + // The AuthCacheEntry structure contains room for the tokens NULL terminator + pEntry = (AuthCacheEntry*) malloc(entrySize); + if (pEntry) + { + // 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; + } + + keySize = (uint32_t)strlen(pCacheKey) + (uint32_t)strlen(pGroupOrHostName) + 2; + + pKey = malloc(keySize); + + if (pKey) + { + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); + + retStatus = miCASAWriteBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + pKey, + keySize, + (uint8_t *)pEntry, + &entrySize, + NULL, + NULL); + + + free(pKey); + } + else + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(1, "-CreateAuthTokenCacheEntry- End, pEntry = %08X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +AuthCacheEntry* +CreateSessionTokenCacheEntry( + IN const char *pCacheKey, + IN CasaStatus status, + IN unsigned char *pToken, + IN int entryLifetime // seconds (0 == Lives forever) + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + uint32_t tokenSize, entrySize; + AuthCacheEntry *pEntry = NULL; + + + DbgTrace(1, "-CreateSessionTokenCacheEntry- Start\n", 0); + + if (status == CASA_STATUS_SUCCESS) + { + tokenSize = (uint32_t)strlen(pToken); + } + else + { + tokenSize = 0; + } + + entrySize = tokenSize + sizeof(AuthCacheEntry); + + // Allocate space for the entry + // The AuthCacheEntry structure contains room for the tokens NULL terminator + pEntry = (AuthCacheEntry*) malloc(entrySize); + if (pEntry) + { + // 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; + } + + retStatus = miCASAWriteBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (char *)pCacheKey, + (uint32_t)strlen(pCacheKey) + 1, + (uint8_t *)pEntry, + &entrySize, + NULL, + NULL); + } + else + { + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(1, "-CreateSessionTokenCacheEntry- End, pEntry = %08X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +void +FreeAuthCacheEntry( + IN AuthCacheEntry *pEntry + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-FreeAuthCacheEntry- Start, pEntry = %08X\n", pEntry); + + // Free the entry + free(pEntry); + + 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 + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + SSCS_KEYCHAIN_ID_T sessionKeyChain = {26, "SSCS_SESSION_KEY_CHAIN_ID"}; + SSCS_SECRET_ID_T sharedId = {20, "CASA_SESSION_TOKENS"}; + uint32_t valueLength, bytesRequired; + AuthCacheEntry *pEntry = NULL; + + + DbgTrace(1, "-FindSessionTokenEntryInCache- Start\n", 0); + + valueLength = 0; + bytesRequired = 0; + + retStatus = miCASAReadBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (char *)pCacheKey, + (uint32_t)strlen(pCacheKey) + 1, + NULL, + &valueLength, + NULL, + &bytesRequired, + NULL); + + if (retStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT + && bytesRequired != 0) + { + pEntry = (AuthCacheEntry*) malloc(bytesRequired); + + if (pEntry) + { + valueLength = bytesRequired; + bytesRequired = 0; + + retStatus = miCASAReadBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + (char *)pCacheKey, + (uint32_t)strlen(pCacheKey) + 1, + (uint8_t *)pEntry, + &valueLength, + NULL, + &bytesRequired, + NULL); + + if (CASA_SUCCESS(retStatus)) + { + if (pEntry->doesNotExpire == FALSE + && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) + { + // Remove the entry ??? + //miCASARemoveBinaryKey(); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + + if (!CASA_SUCCESS(retStatus)) + { + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + } + + DbgTrace(1, "-FindSessionTokenEntryInCache- End, pEntry = %08X\n", pEntry); + + return pEntry; +} + +//++======================================================================= +AuthCacheEntry* +FindAuthTokenEntryInCache( + IN const char *pCacheKey, + IN const char *pGroupOrHostName + ) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + 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; + AuthCacheEntry *pEntry = NULL; + unsigned char *pKey; + + + DbgTrace(1, "-FindAuthTokenEntryInCache- Start\n", 0); + + keySize = (uint32_t)strlen(pCacheKey) + (uint32_t)strlen(pGroupOrHostName) + 2; + + pKey = malloc(keySize); + + if (pKey) + { + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); + + valueLength = 0; + bytesRequired = 0; + + retStatus = miCASAReadBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + pKey, + keySize, + NULL, + &valueLength, + NULL, + &bytesRequired, + NULL); + + if (retStatus == NSSCS_E_ENUM_BUFF_TOO_SHORT + && bytesRequired != 0) + { + pEntry = (AuthCacheEntry*) malloc(bytesRequired); + + if (pEntry) + { + valueLength = bytesRequired; + bytesRequired = 0; + + retStatus = miCASAReadBinaryKey( + g_hCASAContext, + 0, + &sessionKeyChain, + &sharedId, + pKey, + keySize, + (uint8_t *)pEntry, + &valueLength, + NULL, + &bytesRequired, + NULL); + + if (CASA_SUCCESS(retStatus)) + { + if (pEntry->doesNotExpire == FALSE + && CacheEntryLifetimeExpired(pEntry->creationTime, pEntry->expirationTime)) + { + // Remove the entry ??? + //miCASARemoveBinaryKey(); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + + if (!CASA_SUCCESS(retStatus)) + { + FreeAuthCacheEntry(pEntry); + pEntry = NULL; + } + } + } + + free(pKey); + } + + DbgTrace(1, "-FindAuthTokenEntryInCache- End, pEntry = %08X\n", pEntry); + + return pEntry; +} + + +//++======================================================================= +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 + { + retStatus = CASA_STATUS_SUCCESS; + } + + DbgTrace(1, "-InitializeAuthCache- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= +