CASA/CASA-auth-token/client/library/engine.c
S Rahul b9fa3eab0c Multiple changes for Bug #543064
1. Provided SetATSHostList() API for changing the ATS address dynamically
2. Not using CASA enabled server as ATS. ATS address has to be explicitly set
   in client.conf or through SetATSHostList()
3. Not normalizing CASA enabled server's host name while obtaining CASA tokens.
   Callers of ObtainAuthTokenEx() have to pass normalized name as argument
2009-10-09 08:46:35 +00:00

1409 lines
49 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.
*
* Author: Juan Carlos Luciani <jluciani@novell.com>
*
***********************************************************************/
//===[ 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 <server>:<port>
//
// 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;
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);
}
//++=======================================================================
//++=======================================================================
//++=======================================================================