From 3cc4067ab108326089e27cf73e00f6158855a359 Mon Sep 17 00:00:00 2001 From: Juan Carlos Luciani Date: Tue, 29 May 2007 22:59:50 +0000 Subject: [PATCH] Modified client to try to authenticate a user against a list of configured ATSs instead of only utilizing a single configured ATS. The client also tries to contact the ATS using port 443 as well as port 2645 if the port number is not hard configured. --- CASA-auth-token/client/library/cache.c | 199 +++++++-- CASA-auth-token/client/library/client.conf | 33 +- CASA-auth-token/client/library/engine.c | 469 ++++++++++++++------- CASA-auth-token/client/library/internal.h | 15 + 4 files changed, 521 insertions(+), 195 deletions(-) diff --git a/CASA-auth-token/client/library/cache.c b/CASA-auth-token/client/library/cache.c index 80557554..408fd461 100644 --- a/CASA-auth-token/client/library/cache.c +++ b/CASA-auth-token/client/library/cache.c @@ -60,6 +60,7 @@ 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) @@ -81,7 +82,7 @@ CreateAuthTokenCacheEntry( 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; + size_t tokenSize, wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; WrapperAuthCacheEntry *pWrapperEntry = NULL; AuthCacheEntry *pEntry = NULL; char *pKey; @@ -145,43 +146,97 @@ CreateAuthTokenCacheEntry( cacheKeyStrLen = strlen(pCacheKey); groupOrHostNameStrLen = strlen(pGroupOrHostName); - // Verify that keySize will not overflow - if ((cacheKeyStrLen + groupOrHostNameStrLen + 2) <= UINT32_MAX) + // Build the cache entry key based on the status + if (status == CASA_STATUS_SUCCESS) { - keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + 2); - - pKey = malloc(keySize); - if (pKey) + // 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) { - strncpy(pKey, pCacheKey, keySize); - strncat(pKey, "@", keySize); - strncat(pKey, pGroupOrHostName, keySize); + keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + 2); - 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) + pKey = malloc(keySize); + if (pKey) { - DbgTrace(0, "-CreateAuthTokenCacheEntry- miCASAWriteBinaryKey failure, status = %0X\n", miCasaStatus); - } + strncpy(pKey, pCacheKey, keySize); + strncat(pKey, "@", keySize); + strncat(pKey, pGroupOrHostName, keySize); - free(pKey); + 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- Memory allocation failure\n", 0); + DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); } } else { - DbgTrace(0, "-CreateAuthTokenCacheEntry- keySize overflow prevented\n", 0); + // 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 @@ -543,6 +598,7 @@ AuthCacheEntry* FindAuthTokenEntryInCache( IN const char *pCacheKey, IN const char *pGroupOrHostName, + IN const ATSHostEntry *pATSHost, IN void *pCredStoreScope ) // @@ -561,7 +617,7 @@ FindAuthTokenEntryInCache( 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; + size_t wrapperEntrySize, cacheKeyStrLen, groupOrHostNameStrLen, hostAndPortStrLen; WrapperAuthCacheEntry *pWrapperEntry = NULL; AuthCacheEntry *pEntry = NULL; char *pKey; @@ -571,15 +627,18 @@ FindAuthTokenEntryInCache( cacheKeyStrLen = strlen(pCacheKey); groupOrHostNameStrLen = strlen(pGroupOrHostName); + hostAndPortStrLen = strlen(pATSHost->pNameAndPort); - // Verify that keySize will not overflow - if ((cacheKeyStrLen + groupOrHostNameStrLen + 2) <= UINT32_MAX) + // Verify that the worst case keySize will not overflow + if ((cacheKeyStrLen + groupOrHostNameStrLen + hostAndPortStrLen + 3) <= UINT32_MAX) { - keySize = (uint32_t) (cacheKeyStrLen + groupOrHostNameStrLen + 2); + // 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); @@ -592,7 +651,7 @@ FindAuthTokenEntryInCache( &sessionKeyChain, &sharedId, (SS_UTF8_T*) pKey, - keySize, + strlen(pKey) + 1, NULL, &valueLength, (SSCS_PASSWORD_T*) NULL, @@ -615,7 +674,7 @@ FindAuthTokenEntryInCache( &sessionKeyChain, &sharedId, (SS_UTF8_T*) pKey, - keySize, + strlen(pKey) + 1, (uint8_t *) pEntry, &valueLength, (SSCS_PASSWORD_T*) NULL, @@ -652,6 +711,82 @@ FindAuthTokenEntryInCache( } } } + 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); } diff --git a/CASA-auth-token/client/library/client.conf b/CASA-auth-token/client/library/client.conf index e2932908..95658062 100644 --- a/CASA-auth-token/client/library/client.conf +++ b/CASA-auth-token/client/library/client.conf @@ -6,28 +6,23 @@ ####################################################### # -# ATS-hostname setting. +# ATSHostList setting. # -# Description: Used to configure the address of the -# ATS that should be used for obtaining -# authentication tokens. +# Description: Used to configure the addresses of the +# ATSs that should be used for obtaining +# authentication tokens. Use semicolons +# and no spaces to separate the host +# entries. To also configure the ports +# utilized by a host specify the +# port number after the hostname using +# a colon to separate the fields. # -# If this parameter is not set, the client -# assummes that the ATS resides in the same -# host as the authentication token consuming -# services. +# Note that the client will try all of the +# ATSs on this list in the specified order +# in addition to the host for which an +# Authentication Token has been requested. # -#ATS-hostname hostname or IP address - -# -# ATS-port setting. -# -# Description: Used to configure the port utilized by the -# ATS to listen for connections. -# -# If this parameter is not set .... -# -#ATS-port 2645 +#ATSHostList hostname1:2645;ip_address:443;hosname2 # # DisableSecureConnections setting. diff --git a/CASA-auth-token/client/library/engine.c b/CASA-auth-token/client/library/engine.c index 58aa37ac..8322e7b4 100644 --- a/CASA-auth-token/client/library/engine.c +++ b/CASA-auth-token/client/library/engine.c @@ -29,7 +29,9 @@ //===[ Type definitions ]================================================== -#define DEFAULT_RETRY_LIFETIME 5 // seconds +#define DEFAULT_RETRY_LIFETIME 300 // seconds + +#define DEFAULT_ATS_PORT 2645 #define LOG_FILE_NAME "\\casaauthtoken.log" @@ -51,8 +53,7 @@ char *g_pDebugLogFilePath = NULL; // bool g_bInitialized = false; long g_rpcFlags = SECURE_RPC_FLAG | ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG; -char *g_pATSHostName = NULL; -uint16_t g_ATSPort = 2645; +LIST_ENTRY g_ATSHostList; //++======================================================================= @@ -298,6 +299,7 @@ ObtainAuthTokenFromServer( IN const char *pServiceName, IN const char *pHostName, IN const char *pNormalizedHostName, + IN const ATSHostEntry *pATSHost, IN const void *pCredStoreScope, INOUT char **ppAuthToken, INOUT int *pTokenLifetime, @@ -324,8 +326,8 @@ ObtainAuthTokenFromServer( *pAdvisedToRetry = false; // Open Rpc Session to the auth service at the specified host - pRpcSession = OpenRpcSession((g_pATSHostName != NULL) ? g_pATSHostName : pHostName, - g_ATSPort); + pRpcSession = OpenRpcSession(pATSHost->pName, + pATSHost->port); if (pRpcSession) { char *pReqMsg = NULL; @@ -337,7 +339,15 @@ ObtainAuthTokenFromServer( char *pSessionToken = NULL; // Request the auth parameters associated with this service - pReqMsg = BuildGetAuthPolicyMsg(pServiceName, "localhost"); // tbd - This will be changed in the future so that we can support services residing in a different host than the ATS + if (strcmp(pHostName, pATSHost->pName) == 0 + || strcmp(pNormalizedHostName, pATSHost->pName) == 0) + { + pReqMsg = BuildGetAuthPolicyMsg(pServiceName, "localhost"); + } + else + { + pReqMsg = BuildGetAuthPolicyMsg(pServiceName, pNormalizedHostName); + } if (pReqMsg) { // Issue rpc @@ -367,15 +377,24 @@ ObtainAuthTokenFromServer( // Now try to obtain a session token retStatus = ObtainSessionToken(pRpcSession, pAuthPolicy, - (g_pATSHostName != NULL) ? g_pATSHostName : pHostName, + (const char*) pATSHost->pName, pCredStoreScope, &pSessionToken, &pSessionTokenAuthContext); if (CASA_SUCCESS(retStatus)) { - // Request auth token for the service free(pReqMsg); - pReqMsg = BuildGetAuthTokenMsg(pServiceName, "localhost", pSessionToken); // tbd - This will be changed in the future so that we can support services residing in a different host than the ATS + + // Request auth token for the service + if (strcmp(pHostName, pATSHost->pName) == 0 + || strcmp(pNormalizedHostName, pATSHost->pName) == 0) + { + pReqMsg = BuildGetAuthTokenMsg(pServiceName, "localhost", pSessionToken); + } + else + { + pReqMsg = BuildGetAuthTokenMsg(pServiceName, pNormalizedHostName, pSessionToken); + } if (pReqMsg) { // Free the previous response msg buffer @@ -620,16 +639,16 @@ ObtainAuthTokenInt( // Make sure we are fully initialized if (g_bInitialized == false) { - retStatus = InitializeLibrary(); + retStatus = InitializeLibrary(); - if (retStatus == CASA_STATUS_SUCCESS) - { - g_bInitialized = true; - } - else - { - goto exit; - } + if (retStatus == CASA_STATUS_SUCCESS) + { + g_bInitialized = true; + } + else + { + goto exit; + } } // Release our synchronization mutex @@ -639,116 +658,202 @@ ObtainAuthTokenInt( pNormalizedHostName = NormalizeHostName(pHostName); if (pNormalizedHostName) { + bool setupHostEntries = true; + char *pHostNameAnd443 = NULL; + char *pHostNameAnd2645 = NULL; + ATSHostEntry serviceHostEntry443 = {}; + ATSHostEntry serviceHostEntry2645 = {}; + LIST_ENTRY *pListEntry; + ATSHostEntry *pHostEntryInUse; + // Start user process synchronization AcquireUserMutex(hUserMutex); - // Try to find a cache entry for the service - pCacheEntry = FindAuthTokenEntryInCache(pServiceName, - pNormalizedHostName, - pCredStoreScope); - if (pCacheEntry == NULL) + // Determine if we should setup host entries for the + // host where the service resides. + pListEntry = g_ATSHostList.Flink; + while(pListEntry != &g_ATSHostList) { - // Initialize to retry in case of failure - int cacheEntryLifetime = DEFAULT_RETRY_LIFETIME; - bool advisedToRetry; - - // Cache entry created, now try to obtain auth token from the CASA Server - pToken = NULL; - retStatus = ObtainAuthTokenFromServer(pServiceName, - pHostName, - pNormalizedHostName, - pCredStoreScope, - &pToken, - &cacheEntryLifetime, - &advisedToRetry); - - // Retry if not successful and if advised to do so - if (!CASA_SUCCESS(retStatus) - && advisedToRetry) + pHostEntryInUse = CONTAINING_RECORD(pListEntry, ATSHostEntry, listEntry); + if (strcmp(pHostEntryInUse->pName, pHostName) == 0 + || strcmp(pHostEntryInUse->pName, pNormalizedHostName) == 0) { + // The service's host is already in our list + setupHostEntries = false; + break; + } + + // Advance to the next entry + pListEntry = pListEntry->Flink; + } + + // Setup host entries for the service's host if necessary + if (setupHostEntries) + { + // Allocate space for the host name and port strings + pHostNameAnd443 = malloc(strlen(pHostName) + 5); + pHostNameAnd2645 = malloc(strlen(pHostName) + 6); + if (pHostNameAnd443 != NULL + && pHostNameAnd2645 != NULL) + { + sprintf(pHostNameAnd443, "%s:%d", pHostName, 443); + sprintf(pHostNameAnd2645, "%s:%d", pHostName, 2645); + + serviceHostEntry2645.pNameAndPort = pHostNameAnd2645; + serviceHostEntry2645.pName = pHostName; + serviceHostEntry2645.port = 2645; + InsertHeadList(&g_ATSHostList, &serviceHostEntry2645.listEntry); + + serviceHostEntry443.pNameAndPort = pHostNameAnd443; + serviceHostEntry443.pName = pHostName; + serviceHostEntry443.port = 443; + InsertHeadList(&g_ATSHostList, &serviceHostEntry443.listEntry); + } + else + { + DbgTrace(0, "-ObtainAuthTokenInt- Buffer allocation failure\n", 0); + setupHostEntries = false; // To keep us from de-linking the entries later + } + } + + // Now try to obtain an authentication token using the + // host entries at our disposal. + pListEntry = g_ATSHostList.Flink; + while(pListEntry != &g_ATSHostList) + { + // Get pointer to the host entry + pHostEntryInUse = CONTAINING_RECORD(pListEntry, ATSHostEntry, listEntry); + + // Try to find a cache entry for the service + pCacheEntry = FindAuthTokenEntryInCache(pServiceName, + pNormalizedHostName, + pHostEntryInUse, + pCredStoreScope); + if (pCacheEntry == NULL) + { + // Initialize to retry in case of failure + int cacheEntryLifetime = DEFAULT_RETRY_LIFETIME; + bool advisedToRetry; + + // Cache entry created, now try to obtain auth token from the CASA Server + pToken = NULL; retStatus = ObtainAuthTokenFromServer(pServiceName, pHostName, pNormalizedHostName, + pHostEntryInUse, pCredStoreScope, &pToken, &cacheEntryLifetime, &advisedToRetry); - } - // Add the entry to the cache if successful or if the reason that we failed - // was because the server was un-available. - if (CASA_SUCCESS(retStatus) - || CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE) - { - pCacheEntry = CreateAuthTokenCacheEntry(pServiceName, - pNormalizedHostName, - retStatus, - pToken, - cacheEntryLifetime, - pCredStoreScope); - if (pCacheEntry) + // Retry if not successful and if advised to do so + if (!CASA_SUCCESS(retStatus) + && advisedToRetry) { - // Release the cache entry if the resulting status is not successful - if (!CASA_SUCCESS(retStatus)) + retStatus = ObtainAuthTokenFromServer(pServiceName, + pHostName, + pNormalizedHostName, + pHostEntryInUse, + pCredStoreScope, + &pToken, + &cacheEntryLifetime, + &advisedToRetry); + } + + // Add the entry to the cache if we did not fail due to authentication + // failure. + if (CasaStatusCode(retStatus) != CASA_STATUS_AUTHENTICATION_FAILURE) + { + pCacheEntry = CreateAuthTokenCacheEntry(pServiceName, + pNormalizedHostName, + pHostEntryInUse, + retStatus, + pToken, + cacheEntryLifetime, + pCredStoreScope); + if (pCacheEntry) { - FreeAuthCacheEntry(pCacheEntry); + // Release the cache entry if the resulting status is not successful + if (!CASA_SUCCESS(retStatus)) + { + FreeAuthCacheEntry(pCacheEntry); + } } } - } - // Release authentication token if present - if (pToken) - { - // Clear the memory before releasing the buffer since it contains - // security sensitive data. - memset(pToken, 0, strlen(pToken)); - free(pToken); - } - } - else - { - // Cache entry found, update the return status with the information saved in it - // and release it if its status is not successful. - if (!CASA_SUCCESS(retStatus = pCacheEntry->status)) - { - FreeAuthCacheEntry(pCacheEntry); - } - } - - // Try to return auth token if we have one to return - if (CASA_SUCCESS(retStatus)) - { - int tokenLen = (int) strlen(pCacheEntry->token) + 1; - - // We have an authentication token, try to return it to the caller - // after verifying that the supplied buffer is big enough. - if (*pAuthTokenBufLen >= tokenLen) - { - // Return the auth token to the caller - DbgTrace(2, "-ObtainAuthTokenInt- Copying the token into the callers buffer\n", 0); - strcpy(pAuthTokenBuf, pCacheEntry->token); + // Release authentication token if present + if (pToken) + { + // Clear the memory before releasing the buffer since it contains + // security sensitive data. + memset(pToken, 0, strlen(pToken)); + free(pToken); + } } else { - if (*pAuthTokenBufLen != 0) + // Cache entry found, update the return status with the information saved in it + // and release it if its status is not successful. + if (!CASA_SUCCESS(retStatus = pCacheEntry->status)) { - DbgTrace(0, "-ObtainAuthTokenInt- The supplied buffer is not large enough", 0); + FreeAuthCacheEntry(pCacheEntry); } - retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, - CASA_FACILITY_AUTHTOKEN, - CASA_STATUS_BUFFER_OVERFLOW); } - // Return the token length to the caller - *pAuthTokenBufLen = tokenLen; + // Try to return auth token if we have one to return + if (CASA_SUCCESS(retStatus)) + { + int tokenLen = (int) strlen(pCacheEntry->token) + 1; - FreeAuthCacheEntry(pCacheEntry); + // We have an authentication token, try to return it to the caller + // after verifying that the supplied buffer is big enough. + if (*pAuthTokenBufLen >= tokenLen) + { + // Return the auth token to the caller + DbgTrace(2, "-ObtainAuthTokenInt- Copying the token into the callers buffer\n", 0); + strcpy(pAuthTokenBuf, pCacheEntry->token); + } + else + { + if (*pAuthTokenBufLen != 0) + { + DbgTrace(0, "-ObtainAuthTokenInt- The supplied buffer is not large enough", 0); + } + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_BUFFER_OVERFLOW); + } + + // Return the token length to the caller + *pAuthTokenBufLen = tokenLen; + + FreeAuthCacheEntry(pCacheEntry); + + // No need to loop any longer + break; + } + + // Advance to the next host entry + pListEntry = pListEntry->Flink; + } + + // Unlink the service host entries if necessary + if (setupHostEntries) + { + RemoveEntryList(&serviceHostEntry2645.listEntry); + RemoveEntryList(&serviceHostEntry443.listEntry); } // Stop user process synchronization ReleaseUserMutex(hUserMutex); - // Free the space allocated for the normalized host name + // Free the space allocated during processing of the request + if (pHostNameAnd443) + free(pHostNameAnd443); + + if (pHostNameAnd2645) + free(pHostNameAnd2645); + free(pNormalizedHostName); } else @@ -928,6 +1033,64 @@ CleanUpAuthTokenCache(void) } +//++======================================================================= +void +CreateATSHostEntry( + IN const char *pHostName, + IN uint16_t port) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + DbgTrace(1, "-CreateATSHostEntry- Start\n", 0); + + // Create host entry + ATSHostEntry *pHostEntry = malloc(sizeof(ATSHostEntry)); + if (pHostEntry != NULL) + { + // Allocate buffers to keep copies of the strings provided + pHostEntry->pNameAndPort = malloc(strlen(pHostName) + 7); + pHostEntry->pName = malloc(strlen(pHostName) + 1); + if (pHostEntry->pNameAndPort != NULL + && pHostEntry->pName != NULL) + { + // Setup the strings into the corresponding buffers + sprintf(pHostEntry->pNameAndPort, "%s:%d", pHostName, port); + strcpy(pHostEntry->pName, pHostName); + + // Save host port in entry + pHostEntry->port = port; + + // Insert the entry at the tail of the list + InsertTailList(&g_ATSHostList, &pHostEntry->listEntry); + } + else + { + DbgTrace(0, "-CreateATSHostEntry- Failed to allocate buffer\n", 0); + if (pHostEntry->pNameAndPort) + free(pHostEntry->pNameAndPort); + if (pHostEntry->pName) + free(pHostEntry->pName); + free(pHostEntry); + } + } + else + { + DbgTrace(0, "-CreateATSHostEntry- Failed to allocate buffer for host entry\n", 0); + } + + DbgTrace(1, "-CreateATSHostEntry- Exit\n", 0); +} + + //++======================================================================= int InitializeLibrary(void) @@ -948,14 +1111,16 @@ InitializeLibrary(void) ConfigIf *pClientConfigIf; char *pDebugLevelSetting; char *pDebugLogFolderPathSetting; - char *pATSPortSetting; - char *pATSHostNameSetting; + char *pATSHostListSetting; char *pDisableSecureConnections; char *pAllowInvalidCerts; char *pUsersCannotAllowInvalidCerts; DbgTrace(1, "-InitializeLibrary- Start\n", 0); + // Initialize the ATSHostList + InitializeListHead(&g_ATSHostList); + // Try to obtain client configuration settings getConfigStatus = GetConfigInterface(clientConfigFolder, "client", @@ -998,25 +1163,59 @@ InitializeLibrary(void) pClientConfigIf->freeValueString(pClientConfigIf, pDebugLogFolderPathSetting); } - // Check if an ATS hostname has been configured - pATSHostNameSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "ATS-hostname"); - if (pATSHostNameSetting != NULL) + // Check if an ATS Host List has been configured + pATSHostListSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "ATSHostList"); + if (pATSHostListSetting != NULL) { - DbgTrace(0, "-InitializeLibrary- ATS hostname configured = %s\n", pATSHostNameSetting); + char *pSavePtr; + char *pHostAndPort; - // Remember the ATS host name - g_pATSHostName = malloc(strlen(pATSHostNameSetting) + 1); - if (g_pATSHostName) + DbgTrace(0, "-InitializeLibrary- ATSHostList configured = %s\n", pATSHostListSetting); + + // Go through all configured host addresses + pHostAndPort = strtok_r(pATSHostListSetting, ";", &pSavePtr); + while (pHostAndPort != NULL) { - strcpy(g_pATSHostName, pATSHostNameSetting); - } - else - { - DbgTrace(0, "-InitializeLibrary- Failed to allocate buffer for ATS host name\n", 0); + char *pSavePtr2; + char *pHostName; + + // Check if the host address includes the listen port number. + pHostName = strtok_r(pHostAndPort, ":", &pSavePtr2); + if (pHostName != NULL) + { + uint16_t port = 0; + char *pHostPort = strtok_r(NULL, ":", &pSavePtr2); + if (pHostPort != NULL) + { + // Convert the number to hex + port = (uint16_t) dtoul(pHostPort, strlen(pHostPort)); + } + + // Now create the necessary ATS Host entries + if (port == 0) + { + // The port number was not configured, create an ATS Host entry + // for each possible listen port. + CreateATSHostEntry(pHostName, 443); + CreateATSHostEntry(pHostName, 2645); + } + else + { + // Create ATS Host entry for configured port + CreateATSHostEntry(pHostName, port); + } + } + else + { + DbgTrace(0, "-InitializeLibrary- Error parsing configured host address\n", 0); + } + + // Advance to the next entry + pHostAndPort = strtok_r(NULL, ";", &pSavePtr); } - // Free the buffer holding the ats host name setting - pClientConfigIf->freeValueString(pClientConfigIf, pATSHostNameSetting); + // Free the buffer holding the ats host list setting + pClientConfigIf->freeValueString(pClientConfigIf, pATSHostListSetting); } // Check if the DisableSecureConnections setting has been configured @@ -1087,19 +1286,6 @@ InitializeLibrary(void) } } - // Check if an ATS port number has been configured - pATSPortSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "ATS-port"); - if (pATSPortSetting != NULL) - { - DbgTrace(0, "-InitializeLibrary- ATS port number configured = %s\n", pATSPortSetting); - - // Convert the number to hex - g_ATSPort = (int) dtoul(pATSPortSetting, strlen(pATSPortSetting)); - - // Free the buffer holding the port number - pClientConfigIf->freeValueString(pClientConfigIf, pATSPortSetting); - } - // Release config interface instance pClientConfigIf->releaseReference(pClientConfigIf); } @@ -1108,22 +1294,6 @@ InitializeLibrary(void) retStatus = InitializeHostNameNormalization(); if (CASA_SUCCESS(retStatus)) { - // Normalize ATS host name if configured - if (g_pATSHostName) - { - char *pNormalizedHostName = NormalizeHostName(g_pATSHostName); - if (pNormalizedHostName) - { - // Use this name instead of the one that we already have - free(g_pATSHostName); - g_pATSHostName = pNormalizedHostName; - } - else - { - DbgTrace(0, "-InitializeLibrary- ATS Hostname normalization failed\n", 0); - } - } - // Initialize the auth cache retStatus = InitializeAuthCache(); if (CASA_SUCCESS(retStatus)) @@ -1161,6 +1331,9 @@ UnInitializeLibrary(void) // L2 //=======================================================================-- { + LIST_ENTRY *pListEntry; + ATSHostEntry *pHostEntry; + DbgTrace(1, "-UnInitializeLibrary- Start\n", 0); // Un-initialize the host name normalization @@ -1180,8 +1353,16 @@ UnInitializeLibrary(void) free(pBuffer); } - if (g_pATSHostName) - free(g_pATSHostName); + pListEntry = g_ATSHostList.Flink; + while (pListEntry != &g_ATSHostList) + { + pHostEntry = CONTAINING_RECORD(pListEntry, ATSHostEntry, listEntry); + RemoveEntryList(pListEntry); + free(pHostEntry->pNameAndPort); + free(pHostEntry->pName); + free(pHostEntry); + pListEntry = g_ATSHostList.Flink; + } DbgTrace(1, "-UnInitializeLibrary- End\n", 0); } diff --git a/CASA-auth-token/client/library/internal.h b/CASA-auth-token/client/library/internal.h index 25040527..50f7f495 100644 --- a/CASA-auth-token/client/library/internal.h +++ b/CASA-auth-token/client/library/internal.h @@ -41,6 +41,19 @@ #define MAX_RPC_REPLY_SZ (256 * 1024) +// +// ATS Host Entry structure +// +typedef struct _ATSHostEntry +{ + LIST_ENTRY listEntry; + char *pNameAndPort; + char *pName; + uint16_t port; + + +} ATSHostEntry, *PATSHostEntry; + // // Authentication Context structure // @@ -270,6 +283,7 @@ AuthCacheEntry* CreateAuthTokenCacheEntry( IN const char *pCacheKey, IN const char *pHostName, + IN const ATSHostEntry *pATSHost, IN CasaStatus status, IN char *pToken, IN int entryLifetime, @@ -291,6 +305,7 @@ AuthCacheEntry* FindAuthTokenEntryInCache( IN const char *pCacheKey, IN const char *pGroupOrHostName, + IN const ATSHostEntry *pATSHost, IN void *pCredStoreScope); extern