/*********************************************************************** * * 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 DEFAULT_RETRY_LIFETIME 300 // seconds #define BAD_CACHE_TRIGER_TIME 30 // seconds #define DEFAULT_ATS_PORT 2645 #define LOG_FILE_NAME "\\casaauthtoken.log" //===[ Function prototypes ]=============================================== int InitializeLibrary(void); //===[ Global variables ]================================================== // // Debug tracing level and debug log file path. // int DebugLevel = 0; char *g_pDebugLogFilePath = NULL; // // Operating parameter // bool g_bInitialized = false; long g_rpcFlags = SECURE_RPC_FLAG | ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG; LIST_ENTRY g_ATSHostList; //++======================================================================= static CasaStatus ObtainSessionToken( IN RpcSession *pRpcSession, IN AuthPolicy *pAuthPolicy, IN const char *pHostName, IN void *pCredStoreScope, INOUT char **ppSessionToken, INOUT AuthContext **ppSessionTokenAuthContext) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); LIST_ENTRY *pListEntry; AuthCacheEntry *pCacheEntry = NULL; AuthContext *pAuthContext = NULL; DbgTrace(1, "-ObtainSessionToken- Start\n", 0); // Initialize output parameter *ppSessionToken = NULL; // Look in our cache for an entry that matches one of the auth // contexts specified in the AuthPolicy object. pListEntry = pAuthPolicy->authContextListHead.Flink; while (pListEntry != &pAuthPolicy->authContextListHead) { // Get pointer to AuthContext structure pAuthContext = CONTAINING_RECORD(pListEntry, AuthContext, listEntry); // Try to find a cache entry for the auth context pCacheEntry = FindSessionTokenEntryInCache(pAuthContext->pContext, pCredStoreScope); if (pCacheEntry != NULL) { // Cache entry found, check if it is of use to us. if (CASA_SUCCESS(pCacheEntry->status)) { // This entry can be used, stop looking. retStatus = pCacheEntry->status; break; } else { // Free the entry FreeAuthCacheEntry(pCacheEntry); } } // Advance to the next entry pListEntry = pListEntry->Flink; } // If we did not find a cache entry that we can use, then try to create one. pListEntry = pAuthPolicy->authContextListHead.Flink; while (!CASA_SUCCESS(retStatus) && pListEntry != &pAuthPolicy->authContextListHead) { char *pAuthMechToken; // Get pointer to AuthContext structure pAuthContext = CONTAINING_RECORD(pListEntry, AuthContext, listEntry); // Only try to create cache entry for the auth context if there is not // one already. pCacheEntry = FindSessionTokenEntryInCache(pAuthContext->pContext, pCredStoreScope); if (pCacheEntry == NULL) { char *pReqMsg = NULL; char *pRespMsg = NULL; size_t respLen; // Get authentication mechanism token retStatus = GetAuthMechToken(pAuthContext, pHostName, pCredStoreScope, &pAuthMechToken); if (!CASA_SUCCESS(retStatus)) { // We were not able to obtain an authentication mechanism token // for the context. // // Advance to the next entry pListEntry = pListEntry->Flink; continue; } // Authenticate to the ATS pReqMsg = BuildAuthenticateMsg(pAuthContext, pAuthMechToken); if (pReqMsg) { // Issue rpc retStatus = Rpc(pRpcSession, "Authenticate", g_rpcFlags, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { if (pRespMsg && respLen != 0) { AuthenticateResp *pAuthenticateResp; // Create Authenticate response object retStatus = CreateAuthenticateResp(pRespMsg, respLen, &pAuthenticateResp); if (CASA_SUCCESS(retStatus)) { // Return the auth token to the caller pCacheEntry = CreateSessionTokenCacheEntry(pAuthContext->pContext, retStatus, pAuthenticateResp->pToken, pAuthenticateResp->tokenLifetime, pCredStoreScope); pAuthenticateResp->pToken = NULL; // To keep us from freeing the buffer // Free the Authenticate response object RelAuthenticateResp(pAuthenticateResp); } } else { DbgTrace(0, "-ObtainSessionToken- Did not receive Authenticate Response data\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } } else { DbgTrace(0, "-ObtainSessionToken- Authenticate Rpc failure, error = %08X\n", retStatus); } // Free resources that may be hanging around if (pRespMsg) { // Clear and free the memory associated with the response since it may contain // security sensitive data. memset(pRespMsg, 0, respLen); free(pRespMsg); } // Clear and free the memory associated with the request message since // it may contain security sensitive information. memset(pReqMsg, 0, strlen(pReqMsg)); free(pReqMsg); } else { DbgTrace(0, "-ObtainSessionToken- Error building Authenticate msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } // Add the entry to the cache if the reason that we failed was because // the server was unavailable. if (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE) { pCacheEntry = CreateSessionTokenCacheEntry(pAuthContext->pContext, retStatus, NULL, DEFAULT_RETRY_LIFETIME, pCredStoreScope); } // Release the cache entry if the resulting status is not successful if (pCacheEntry) { if (!CASA_SUCCESS(retStatus)) { FreeAuthCacheEntry(pCacheEntry); } } // Free up the buffer associated with the authentication mechanism token // after clearing it since it may contain sensitive information. memset(pAuthMechToken, 0, strlen(pAuthMechToken)); free(pAuthMechToken); } else { // Free the entry FreeAuthCacheEntry(pCacheEntry); } // Advance to the next entry pListEntry = pListEntry->Flink; } // Return session token if successful if (CASA_SUCCESS(retStatus)) { // Allocate a buffer for the return token *ppSessionToken = (char*) malloc(strlen(pCacheEntry->token) + 1); if (*ppSessionToken) { // Copy the token onto the allocated buffer strcpy(*ppSessionToken, pCacheEntry->token); // Return pointer to AuthContext associated with the session token *ppSessionTokenAuthContext = pAuthContext; } else { DbgTrace(0, "-ObtainSessionToken- Buffer allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } FreeAuthCacheEntry(pCacheEntry); } DbgTrace(1, "-ObtainSessionToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= static CasaStatus 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, INOUT bool *pAdvisedToRetry) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; RpcSession *pRpcSession; DbgTrace(1, "-ObtainAuthTokenFromServer- Start\n", 0); // Initialize output parameters *ppAuthToken = NULL; *pAdvisedToRetry = false; // Open Rpc Session to the auth service at the specified host DbgTrace(3, "-ObtainAuthTokenFromServer- Hostname = %s\n", pATSHost->pName); DbgTrace(3, "-ObtainAuthTokenFromServer- port = %d\n", pATSHost->port); pRpcSession = OpenRpcSession(pATSHost->pName, pATSHost->port); if (pRpcSession) { char *pReqMsg = NULL; char *pRespMsg = NULL; size_t respLen; AuthPolicy *pAuthPolicy = NULL; GetAuthPolicyResp *pGetAuthPolicyResp = NULL; GetAuthTokenResp *pGetAuthTokenResp = NULL; char *pSessionToken = NULL; // Request the auth parameters associated with this service if (strcmp(pHostName, pATSHost->pName) == 0 || strcmp(pNormalizedHostName, pATSHost->pName) == 0) { pReqMsg = BuildGetAuthPolicyMsg(pServiceName, "localhost"); } else { pReqMsg = BuildGetAuthPolicyMsg(pServiceName, pNormalizedHostName); } if (pReqMsg) { // Issue rpc retStatus = Rpc(pRpcSession, "GetAuthPolicy", g_rpcFlags, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { if (pRespMsg && respLen != 0) { // Create GetAuthPolicy response object retStatus = CreateGetAuthPolicyResp(pRespMsg, respLen, &pGetAuthPolicyResp); if (CASA_SUCCESS(retStatus)) { // Create the AuthPolicy object retStatus = CreateAuthPolicy(pGetAuthPolicyResp->pPolicy, pGetAuthPolicyResp->policyLen, &pAuthPolicy); if (CASA_SUCCESS(retStatus)) { AuthContext *pSessionTokenAuthContext = NULL; // Now try to obtain a session token retStatus = ObtainSessionToken(pRpcSession, pAuthPolicy, (const char*) pATSHost->pName, pCredStoreScope, &pSessionToken, &pSessionTokenAuthContext); if (CASA_SUCCESS(retStatus)) { free(pReqMsg); // 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 free(pRespMsg); pRespMsg = NULL; // Issue rpc retStatus = Rpc(pRpcSession, "GetAuthToken", g_rpcFlags, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { if (pRespMsg && respLen != 0) { // Create GetAuthPolicy response object retStatus = CreateGetAuthTokenResp(pRespMsg, respLen, &pGetAuthTokenResp); if (CASA_SUCCESS(retStatus)) { // Return the auth token to the caller *ppAuthToken = pGetAuthTokenResp->pToken; pGetAuthTokenResp->pToken = NULL; // To keep us from freeing the buffer *pTokenLifetime = pGetAuthTokenResp->tokenLifetime; } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Failed to create GetAuthTokenResp object, error = %08X\n", retStatus); // Remove the session token from the cache in case that it was due to a bad session token if (pSessionTokenAuthContext) { RemoveSessionTokenEntryInCache(pSessionTokenAuthContext->pContext, pCredStoreScope); // Advice that a retry should be attempted *pAdvisedToRetry = true; } } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Did not receive GetAuthToken Response data\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- GetAuthToken Rpc failure, error = %08X\n", retStatus); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error building GetAuthToken msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Failed to obtain session token, error = %08X\n", retStatus); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Failed to create AuthPolicy object, error = %08X\n", retStatus); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Failed to create GetAuthPolicyResp object, error = %08X\n", retStatus); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Did not receive GetAuthPolicy Response data\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_SERVER_ERROR); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- GetAuthPolicy Rpc failure, error = %08X\n", retStatus); } // Free resources that may be hanging around if (pReqMsg) { // Clear the memory before freeing up the request message since it // may contain security sensitive data. memset(pReqMsg, 0, strlen(pReqMsg)); free(pReqMsg); } if (pRespMsg) { // Clear the memory before freeing up the response message since it // may contain security sensitive data. memset(pRespMsg, 0, respLen); free(pRespMsg); } if (pSessionToken) { // Clear the memory before freeing up the token since it is // security sensitive data. memset(pSessionToken, 0, strlen(pSessionToken)); free(pSessionToken); } if (pGetAuthTokenResp) RelGetAuthTokenResp(pGetAuthTokenResp); if (pGetAuthPolicyResp) RelGetAuthPolicyResp(pGetAuthPolicyResp); if (pAuthPolicy) RelAuthPolicy(pAuthPolicy); } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error building GetAuthPolicy msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } // Close the Rpc Session CloseRpcSession(pRpcSession); } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error opening Rpc session\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } DbgTrace(1, "-ObtainAuthTokenFromServer- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus ObtainAuthTokenInt( IN const char *pServiceName, IN const char *pHostName, IN const void *pCredStoreScope, INOUT char *pAuthTokenBuf, INOUT int *pAuthTokenBufLen) // // Arguments: // pServiceName - // Pointer to NULL terminated string that contains the // name of the service to which the client is trying to // authenticate. // // pHostName - // Pointer to NULL terminated string that contains the // name of the host where resides the service to which the // client is trying to authenticate. Note that the name // can either be a DNS name or a dotted IP address. // // pCredStoreScope - // Pointer to CASA structure for scoping credential store access // to specific users. This can only be leveraged by applications // running in the context of System. // // pAuthTokenBuf - // Pointer to buffer that will receive the authentication // token. The length of this buffer is specified by the // pAuthTokenBufLen parameter. Note that the the authentication // token will be in the form of a NULL terminated string. // // pAuthTokenBufLen - // Pointer to integer that contains the length of the // buffer pointed at by pAuthTokenBuf. Upon return of the // function, the integer will contain the actual length // of the authentication token if the function successfully // completes or the buffer length required if the function // fails because the buffer pointed at by pAuthTokenBuf is // not large enough. // // Returns: // Casa Status // // Description: // Get authentication token to authenticate user to specified // service at host. The user is scoped using the info associated // with the magic cookie. // // L2 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; AuthCacheEntry *pCacheEntry; char *pToken; HANDLE hUserMutex = NULL; DbgTrace(1, "-ObtainAuthTokenInt- Start\n", 0); // Verify the input parameters if (pServiceName == NULL || pHostName == NULL || pAuthTokenBufLen == NULL || (*pAuthTokenBufLen != 0 && pAuthTokenBuf == NULL)) { DbgTrace(0, "-ObtainAuthTokenInt- Invalid parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } DbgTrace(1, "-ObtainAuthTokenInt- ServiceName = %s\n", pServiceName); DbgTrace(1, "-ObtainAuthTokenInt- HostName = %s\n", pHostName); DbgTrace(1, "-ObtainAuthTokenInt- BufferLength = %d\n", *pAuthTokenBufLen); // Obtain our synchronization mutex AcquireModuleMutex; // Create user synchronization mutex retStatus = CreateUserMutex(&hUserMutex); if (retStatus != CASA_STATUS_SUCCESS) { DbgTrace(0, "-ObtainAuthTokenInt- Error creating mutex for the user\n", 0); goto exit; } // Make sure we are fully initialized if (g_bInitialized == false) { retStatus = InitializeLibrary(); if (retStatus == CASA_STATUS_SUCCESS) { g_bInitialized = true; } else { goto exit; } } // Release our synchronization mutex ReleaseModuleMutex; { LIST_ENTRY *pListEntry; ATSHostEntry *pHostEntryInUse; // Start user process synchronization AcquireUserMutex(hUserMutex); // 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, pHostName, pHostEntryInUse, pCredStoreScope); if (pCacheEntry == NULL) { // Initialize to retry in case of failure int cacheEntryLifetime = DEFAULT_RETRY_LIFETIME; bool advisedToRetry; DWORD opStartTime = GetTickCount(); // Cache entry created, now try to obtain auth token from the CASA Server pToken = NULL; retStatus = ObtainAuthTokenFromServer(pServiceName, pHostName, pHostName, pHostEntryInUse, pCredStoreScope, &pToken, &cacheEntryLifetime, &advisedToRetry); // Retry if not successful and if advised to do so if (!CASA_SUCCESS(retStatus) && advisedToRetry) { retStatus = ObtainAuthTokenFromServer(pServiceName, pHostName, pHostName, pHostEntryInUse, pCredStoreScope, &pToken, &cacheEntryLifetime, &advisedToRetry); } // Try to add the entry to the cache if we did not fail due // to authentication failure. if (CasaStatusCode(retStatus) != CASA_STATUS_AUTHENTICATION_FAILURE) { DWORD opEndTime = GetTickCount(); // We only want to cache bad results if the operation took a // considerable amount of time. if (CASA_SUCCESS(retStatus) || opEndTime >= (opStartTime + (BAD_CACHE_TRIGER_TIME * 1000))) { pCacheEntry = CreateAuthTokenCacheEntry(pServiceName, pHostName, pHostEntryInUse, retStatus, pToken, cacheEntryLifetime, pCredStoreScope); if (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); } 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; } // Stop user process synchronization ReleaseUserMutex(hUserMutex); } exit: if (hUserMutex != NULL) { DestroyUserMutex(hUserMutex); } DbgTrace(1, "-ObtainAuthTokenInt- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus SSCS_CALL ObtainAuthToken( IN const char *pServiceName, IN const char *pHostName, INOUT char *pAuthTokenBuf, INOUT int *pAuthTokenBufLen) // // Arguments: // pServiceName - // Pointer to NULL terminated string that contains the // name of the service to which the client is trying to // authenticate. // // pHostName - // Pointer to NULL terminated string that contains the // name of the host where resides the service to which the // client is trying to authenticate. Note that the name // can either be a DNS name or a dotted IP address. // // pAuthTokenBuf - // Pointer to buffer that will receive the authentication // token. The length of this buffer is specified by the // pAuthTokenBufLen parameter. Note that the the authentication // token will be in the form of a NULL terminated string. // // pAuthTokenBufLen - // Pointer to integer that contains the length of the // buffer pointed at by pAuthTokenBuf. Upon return of the // function, the integer will contain the actual length // of the authentication token if the function successfully // completes or the buffer length required if the function // fails because the buffer pointed at by pAuthTokenBuf is // not large enough. // // Returns: // Casa Status // // Description: // Get authentication token to authenticate user to specified // service at host. // // L2 //=======================================================================-- { CasaStatus retStatus; DbgTrace(1, "-ObtainAuthToken- Start\n", 0); // Call our internal worker retStatus = ObtainAuthTokenInt(pServiceName, pHostName, NULL, pAuthTokenBuf, pAuthTokenBufLen); DbgTrace(1, "-ObtainAuthToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= void CleanUpAuthTokenCacheInt( IN const void *pCredStoreScope) // // Arguments: // pCredStoreScope - // Pointer to CASA structure for scoping credential store access // to specific users. This can only be leveraged by applications // running in the context of System. // // Returns: // Nothing // // Description: // Flush the AuthToken cache. //=======================================================================-- { CasaStatus retStatus; HANDLE hUserMutex = NULL; DbgTrace(1, "-CleanUpAuthTokenCacheInt- Start\n", 0); // Obtain our synchronization mutex AcquireModuleMutex; // Create user synchronization mutex retStatus = CreateUserMutex(&hUserMutex); if (retStatus != CASA_STATUS_SUCCESS) { DbgTrace(0, "-CleanUpAuthTokenCacheInt- Error creating mutex for the user\n", 0); goto exit; } // Make sure we are fully initialized if (g_bInitialized == false) { retStatus = InitializeLibrary(); if (retStatus == CASA_STATUS_SUCCESS) { g_bInitialized = true; } else { goto exit; } } // Release our synchronization mutex ReleaseModuleMutex; // Start user process synchronization AcquireUserMutex(hUserMutex); // Delete all of the tokens in our cache DeleteAuthTokenEntriesInCache(pCredStoreScope); DeleteSessionTokenEntriesInCache(pCredStoreScope); // Stop user process synchronization ReleaseUserMutex(hUserMutex); exit: if (hUserMutex != NULL) { DestroyUserMutex(hUserMutex); } DbgTrace(1, "-CleanUpAuthTokenCacheInt- End\n", 0); } //++======================================================================= void SSCS_CALL CleanUpAuthTokenCache(void) // // Arguments: None. // // Returns: // Nothing // // Description: // Flush the AuthToken cache. //=======================================================================-- { DbgTrace(1, "-CleanUpAuthTokenCache- Start\n", 0); // Call our internal worker CleanUpAuthTokenCacheInt(NULL); DbgTrace(1, "-CleanUpAuthTokenCache- End\n", 0); } //++======================================================================= void CreateATSHostEntry( IN const char *pHostName, IN uint16_t port) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { ATSHostEntry *pHostEntry; DbgTrace(1, "-CreateATSHostEntry- Start\n", 0); // Create host entry 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); } //++======================================================================= CasaStatus SSCS_CALL SetATSHostList( IN const char * const ATSHostList[]) // // Arguments: // ATSHostList - // Pointer to NULL terminated array of ATS servers of form : // // Returns: // Casa Status // // Description: // Set the list of ATS servers contacted. Can be used to override the // 'ATSHostList' parameter in client.conf. //=======================================================================-- { int i, retStatus = CASA_STATUS_SUCCESS; uint16_t port; char address[256]; LIST_ENTRY *pListEntry; ATSHostEntry *pHostEntry; HANDLE hUserMutex = NULL; DbgTrace(1, "-SetATSHostList- Start\n", 0); for (i = 0; ATSHostList[i] != NULL; i++) { int ret; if (strlen(ATSHostList[i]) > 255) { DbgTrace(0, "-SetATSHostList- Host name too long: %s\n", ATSHostList[i]); retStatus = CASA_STATUS_INVALID_PARAMETER; goto exit; } ret = sscanf(ATSHostList[i], "%[^:]:%hu", address, &port); if (ret != 2) { DbgTrace(0, "-SetATSHostList- Invalid entry: %s\n", ATSHostList[i]); retStatus = CASA_STATUS_INVALID_PARAMETER; goto exit; } } /* Obtain our synchronization mutex */ AcquireModuleMutex; /* Create user synchronization mutex */ retStatus = CreateUserMutex(&hUserMutex); if (retStatus != CASA_STATUS_SUCCESS) { DbgTrace(0, "-SetATSHostList- Error creating mutex for the user\n", 0); goto exit; } /* Make sure we are fully initialized */ if (g_bInitialized == false) { retStatus = InitializeLibrary(); if (retStatus == CASA_STATUS_SUCCESS) g_bInitialized = true; else goto exit; } /* Release our synchronization mutex */ ReleaseModuleMutex; AcquireUserMutex(hUserMutex); /* Cleanup the old ATS list */ pListEntry = g_ATSHostList.Flink; if (pListEntry) { DbgTrace(0, "-SetATSHostList- Flushing ATS host list\n", 0); while (pListEntry != &g_ATSHostList) { pHostEntry = CONTAINING_RECORD(pListEntry, ATSHostEntry, listEntry); RemoveEntryList(pListEntry); free(pHostEntry->pNameAndPort); free(pHostEntry->pName); free(pHostEntry); pListEntry = g_ATSHostList.Flink; } } InitializeListHead(&g_ATSHostList); for (i = 0; ATSHostList[i] != NULL; i++) { sscanf(ATSHostList[i], "%[^:]:%hu", address, &port); CreateATSHostEntry(address, port); DbgTrace(0, "-SetATSHostList- Adding ATS host %s\n", ATSHostList[i]); } ReleaseUserMutex(hUserMutex); exit: if (hUserMutex != NULL) DestroyUserMutex(hUserMutex); DbgTrace(1, "-SetATSHostList- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= int InitializeLibrary(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int retStatus = -1; int getConfigStatus = -1; ConfigIf *pClientConfigIf; char *pDebugLevelSetting; char *pDebugLogFolderPathSetting; 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", &pClientConfigIf); if (CASA_SUCCESS(getConfigStatus) && CasaStatusCode(getConfigStatus) != CASA_STATUS_OBJECT_NOT_FOUND) { // Check if a DebugLevel has been configured pDebugLevelSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "DebugLevel"); if (pDebugLevelSetting != NULL) { DbgTrace(0, "-InitializeLibrary- DebugLevel configured = %s\n", pDebugLevelSetting); // Convert the number to hex DebugLevel = (int) dtoul(pDebugLevelSetting, strlen(pDebugLevelSetting)); // Free the buffer holding the debug level pClientConfigIf->freeValueString(pClientConfigIf, pDebugLevelSetting); } // Check if a DebugLogFolderPath has been configured pDebugLogFolderPathSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "DebugLogFolderPath"); if (pDebugLogFolderPathSetting != NULL) { DbgTrace(0, "-InitializeLibrary- DebugLogFolderPath configured = %s\n", pDebugLogFolderPathSetting); // Use the setting to come up with the path to the debug log file g_pDebugLogFilePath = malloc(strlen(LOG_FILE_NAME) + strlen(pDebugLogFolderPathSetting) + 1); if (g_pDebugLogFilePath) { strcpy(g_pDebugLogFilePath, pDebugLogFolderPathSetting); strcat(g_pDebugLogFilePath, LOG_FILE_NAME); } else { DbgTrace(0, "-InitializeLibrary- Failed to allocate buffer for debug file path\n", 0); } // Free the buffer holding the debug folder path pClientConfigIf->freeValueString(pClientConfigIf, pDebugLogFolderPathSetting); } // Check if an ATS Host List has been configured pATSHostListSetting = pClientConfigIf->getEntryValue(pClientConfigIf, "ATSHostList"); if (pATSHostListSetting != NULL) { char *pSavePtr; char *pHostAndPort; DbgTrace(0, "-InitializeLibrary- ATSHostList configured = %s\n", pATSHostListSetting); // Go through all configured host addresses pHostAndPort = strtok_r(pATSHostListSetting, ";", &pSavePtr); while (pHostAndPort != NULL) { 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 list setting pClientConfigIf->freeValueString(pClientConfigIf, pATSHostListSetting); } // Check if the DisableSecureConnections setting has been configured pDisableSecureConnections = pClientConfigIf->getEntryValue(pClientConfigIf, "DisableSecureConnections"); if (pDisableSecureConnections != NULL) { DbgTrace(0, "-InitializeLibrary- DisableSecureConnections setting configured = %s\n", pDisableSecureConnections); // Adjust the g_rpcFlags variable based on the setting if (stricmp(pDisableSecureConnections, "true") == 0) { g_rpcFlags &= ~SECURE_RPC_FLAG; } else if (stricmp(pDisableSecureConnections, "false") == 0) { g_rpcFlags |= SECURE_RPC_FLAG; } // Free the buffer holding the DisableSecureConnections setting pClientConfigIf->freeValueString(pClientConfigIf, pDisableSecureConnections); } // Check the AllowUntrustedCerts setting if using secure connections if (g_rpcFlags & SECURE_RPC_FLAG) { // Check if the AllowUntrustedCerts setting has been configured pAllowInvalidCerts = pClientConfigIf->getEntryValue(pClientConfigIf, "AllowUntrustedCerts"); if (pAllowInvalidCerts != NULL) { DbgTrace(0, "-InitializeLibrary- AllowUntrustedCerts setting configured = %s\n", pAllowInvalidCerts); // Adjust the g_rpcFlags variable based on the setting if (stricmp(pAllowInvalidCerts, "false") == 0) { g_rpcFlags &= ~ALLOW_INVALID_CERTS_RPC_FLAG; } else if (stricmp(pAllowInvalidCerts, "true") == 0) { g_rpcFlags |= ALLOW_INVALID_CERTS_RPC_FLAG; } // Free the buffer holding the AllowInvalidCerts setting pClientConfigIf->freeValueString(pClientConfigIf, pAllowInvalidCerts); } // Check the UsersCannotAllowInvalidCerts setting if not allowing invalid certs. if ((g_rpcFlags & ALLOW_INVALID_CERTS_RPC_FLAG) == 0) { // Check if the UsersCannotAllowInvalidCerts setting has been configured pUsersCannotAllowInvalidCerts = pClientConfigIf->getEntryValue(pClientConfigIf, "UsersCannotAllowInvalidCerts"); if (pUsersCannotAllowInvalidCerts != NULL) { DbgTrace(0, "-InitializeLibrary- UsersCannotAllowInvalidCerts setting configured = %s\n", pUsersCannotAllowInvalidCerts); // Adjust the g_rpcFlags variable based on the setting if (stricmp(pUsersCannotAllowInvalidCerts, "false") == 0) { g_rpcFlags |= ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG; } else if (stricmp(pUsersCannotAllowInvalidCerts, "true") == 0) { g_rpcFlags &= ~ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG; } // Free the buffer holding the UsersCannotAllowInvalidCerts setting pClientConfigIf->freeValueString(pClientConfigIf, pUsersCannotAllowInvalidCerts); } } } // Release config interface instance pClientConfigIf->releaseReference(pClientConfigIf); } // Initialize the host name normalization retStatus = InitializeHostNameNormalization(); if (CASA_SUCCESS(retStatus)) { // Initialize the auth cache retStatus = InitializeAuthCache(); if (CASA_SUCCESS(retStatus)) { retStatus = InitializeRpc(); } else { DbgTrace(0, "-InitializeLibrary- Auth cache intialization failed\n", 0); } } else { DbgTrace(0, "-InitializeLibrary- HostName Normalizer intialization failed\n", 0); } DbgTrace(1, "-InitializeLibrary- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= void UnInitializeLibrary(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { LIST_ENTRY *pListEntry; ATSHostEntry *pHostEntry; DbgTrace(1, "-UnInitializeLibrary- Start\n", 0); // Un-initialize the host name normalization UnInitializeHostNameNormalization(); // Un-initialize the auth cache UnInitializeAuthCache(); // Un-initialize the Rpc engine UnInitializeRpc(); // Free necessary buffers if (g_pDebugLogFilePath) { char *pBuffer = g_pDebugLogFilePath; g_pDebugLogFilePath = NULL; free(pBuffer); } pListEntry = g_ATSHostList.Flink; if (pListEntry) { 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); } //++======================================================================= //++======================================================================= //++=======================================================================