/*********************************************************************** * * 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; } //++======================================================================= //++======================================================================= //++=======================================================================