Updates resulting from self-code review.

This commit is contained in:
Juan Carlos Luciani 2006-12-01 12:42:52 +00:00
parent 74dce09720
commit d55ac482ac
7 changed files with 734 additions and 669 deletions

View File

@ -193,7 +193,10 @@ ObtainSessionToken(
// Free resources that may be hanging around // Free resources that may be hanging around
if (pRespMsg) if (pRespMsg)
free(pRespMsg); free(pRespMsg);
// Clear and free the memory associated with the request message since
// it may contain sensitive information.
memset(pReqMsg, 0, strlen(pReqMsg));
free(pReqMsg); free(pReqMsg);
} }
else else
@ -223,6 +226,8 @@ ObtainSessionToken(
} }
// Free up the buffer associated with the authentication mechanism token // 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); free(pAuthMechToken);
} }
else else

View File

@ -101,7 +101,6 @@ AuthTokenIf_GetAuthToken(
TimeStamp expiry; TimeStamp expiry;
CredHandle hCredentials = {0}; CredHandle hCredentials = {0};
DbgTrace(1, "-AuthTokenIf_GetAuthToken- Start\n", 0); DbgTrace(1, "-AuthTokenIf_GetAuthToken- Start\n", 0);
// Validate input parameters // Validate input parameters
@ -211,7 +210,9 @@ AuthTokenIf_GetAuthToken(
// Return the actual size or the size required // Return the actual size or the size required
*pTokenBufLen = encodedTokenLen; *pTokenBufLen = encodedTokenLen;
// Free the buffer containing the encoded token // Free the buffer containing the encoded token after clearing
// its memory to avoid leaking sensitive information.
memset(pEncodedToken, 0, strlen(pEncodedToken));
free(pEncodedToken); free(pEncodedToken);
} }
@ -229,7 +230,10 @@ AuthTokenIf_GetAuthToken(
// Free any buffer associated with the sendToken // Free any buffer associated with the sendToken
if (sendTok.pvBuffer) if (sendTok.pvBuffer)
{
memset(sendTok.pvBuffer, 0, sendTok.cbBuffer);
FreeContextBuffer(sendTok.pvBuffer); FreeContextBuffer(sendTok.pvBuffer);
}
// Free the credential handle obtained // Free the credential handle obtained
FreeCredentialsHandle(&hCredentials); FreeCredentialsHandle(&hCredentials);

View File

@ -1,362 +1,371 @@
/*********************************************************************** /***********************************************************************
* *
* Copyright (C) 2006 Novell, Inc. All Rights Reserved. * Copyright (C) 2006 Novell, Inc. All Rights Reserved.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version 2.1 * License as published by the Free Software Foundation; version 2.1
* of the License. * of the License.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library Lesser General Public License for more details. * Library Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, Novell, Inc. * License along with this library; if not, Novell, Inc.
* *
* To contact Novell about this file by physical or electronic mail, * To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com. * you may find current contact information at www.novell.com.
* *
* Author: Juan Carlos Luciani <jluciani@novell.com> * Author: Juan Carlos Luciani <jluciani@novell.com>
* *
***********************************************************************/ ***********************************************************************/
//===[ Include files ]===================================================== //===[ Include files ]=====================================================
#include "internal.h" #include "internal.h"
//===[ Type definitions ]================================================== //===[ Type definitions ]==================================================
//===[ Function prototypes ]=============================================== //===[ Function prototypes ]===============================================
//===[ Global variables ]================================================== //===[ Global variables ]==================================================
//++======================================================================= //++=======================================================================
static static
CasaStatus CasaStatus
GetUserCredentials( GetUserCredentials(
IN const char *pRealm, IN const char *pRealm,
IN void *pCredStoreScope, IN void *pCredStoreScope,
INOUT char **ppUsername, INOUT char **ppUsername,
INOUT char **ppPassword) INOUT char **ppPassword)
// //
// Arguments: // Arguments:
// pRealm - // pRealm -
// The realm to which the credentials apply. // The realm to which the credentials apply.
// //
// pCredStoreScope - // pCredStoreScope -
// Pointer to CASA structure for scoping credential store access // Pointer to CASA structure for scoping credential store access
// to specific users. This can only be leveraged when running in // to specific users. This can only be leveraged when running in
// the context of System under Windows. // the context of System under Windows.
// //
// ppUsername - // ppUsername -
// Pointer to variable that will receive buffer with the username. // Pointer to variable that will receive buffer with the username.
// //
// ppPassword - // ppPassword -
// Pointer to variable that will receive buffer with the password. // Pointer to variable that will receive buffer with the password.
// //
// Returns: // Returns:
// Casa Status // Casa Status
// //
// Description: // Description:
// Get authentication credentials for the specified realm. // Get authentication credentials for the specified realm.
// //
// L2 // L2
//=======================================================================-- //=======================================================================--
{ {
CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
char *pUsername; char *pUsername;
char *pPassword; char *pPassword;
int rcode = NSSCS_E_OBJECT_NOT_FOUND; int rcode = NSSCS_E_OBJECT_NOT_FOUND;
uint32_t credtype = SSCS_CRED_TYPE_BASIC_F; uint32_t credtype = SSCS_CRED_TYPE_BASIC_F;
SSCS_BASIC_CREDENTIAL credential = {0}; SSCS_BASIC_CREDENTIAL credential = {0};
SSCS_SECRET_ID_T secretId = {0}; SSCS_SECRET_ID_T secretId = {0};
DbgTrace(1, "-GetUserCredentials- Start\n", 0); DbgTrace(1, "-GetUserCredentials- Start\n", 0);
// Initialize output parameters // Initialize output parameters
*ppUsername = NULL; *ppUsername = NULL;
*ppPassword = NULL; *ppPassword = NULL;
// Get the length of the realm string into the secret id structure // Get the length of the realm string into the secret id structure
// and verify thatr it is not too long. // and verify thatr it is not too long.
secretId.len = sscs_Utf8Strlen(pRealm) + 1; secretId.len = sscs_Utf8Strlen(pRealm) + 1;
if (secretId.len <= NSSCS_MAX_SECRET_ID_LEN) if (secretId.len <= NSSCS_MAX_SECRET_ID_LEN)
{ {
// Set the secret id in the structure // Set the secret id in the structure
sscs_Utf8Strcpy((char*) secretId.id, pRealm); sscs_Utf8Strcpy((char*) secretId.id, pRealm);
// Specify that we want the common name // Specify that we want the common name
credential.unFlags = USERNAME_TYPE_CN_F; credential.unFlags = USERNAME_TYPE_CN_F;
// Now try to get the credentials // Now try to get the credentials
rcode = miCASAGetCredential(0, rcode = miCASAGetCredential(0,
&secretId, &secretId,
NULL, NULL,
&credtype, &credtype,
&credential, &credential,
(SSCS_EXT_T*) pCredStoreScope); (SSCS_EXT_T*) pCredStoreScope);
if (rcode != NSSCS_SUCCESS) if (rcode != NSSCS_SUCCESS)
{ {
// There were no credentials for the realm, now try to obtain the // There were no credentials for the realm, now try to obtain the
// desktop credentials. // desktop credentials.
secretId.len = sscs_Utf8Strlen("Desktop") + 1; secretId.len = sscs_Utf8Strlen("Desktop") + 1;
if (secretId.len <= NSSCS_MAX_SECRET_ID_LEN) if (secretId.len <= NSSCS_MAX_SECRET_ID_LEN)
{ {
sscs_Utf8Strcpy((char*) secretId.id, "Desktop"); sscs_Utf8Strcpy((char*) secretId.id, "Desktop");
rcode = miCASAGetCredential(0, rcode = miCASAGetCredential(0,
&secretId, &secretId,
NULL, NULL,
&credtype, &credtype,
&credential, &credential,
(SSCS_EXT_T*) pCredStoreScope); (SSCS_EXT_T*) pCredStoreScope);
} }
else else
{ {
DbgTrace(0, "-GetUserCredentials- Desktop name too long\n", 0); DbgTrace(0, "-GetUserCredentials- Desktop name too long\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
} }
} }
} }
else else
{ {
DbgTrace(0, "-GetUserCredentials- Realm name too long\n", 0); DbgTrace(0, "-GetUserCredentials- Realm name too long\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
} }
// Proceed based on the result of the operatiosn above // Proceed based on the result of the operatiosn above
if (rcode == NSSCS_SUCCESS if (rcode == NSSCS_SUCCESS
&& credential.username != NULL && credential.username != NULL
&& credential.password != NULL) && credential.password != NULL)
{ {
// Allocate a buffer to return the username // Allocate a buffer to return the username
pUsername = (char*) malloc(strlen((char*) credential.username) + 1); pUsername = (char*) malloc(strlen((char*) credential.username) + 1);
if (pUsername) if (pUsername)
{ {
// Copy the username into the buffer that we will be returning // Copy the username into the buffer that we will be returning
strcpy(pUsername, (char*) credential.username); strcpy(pUsername, (char*) credential.username);
// Allocate a buffer to return the password // Allocate a buffer to return the password
pPassword = (char*) malloc(strlen((char*) credential.password) + 1); pPassword = (char*) malloc(strlen((char*) credential.password) + 1);
if (pPassword) if (pPassword)
{ {
// Copy the password into the buffer that we will be returning // Copy the password into the buffer that we will be returning
strcpy(pPassword, (char*) credential.password); strcpy(pPassword, (char*) credential.password);
DbgTrace(1, "-GetUserCredentials- Username = %s\n", pUsername); DbgTrace(1, "-GetUserCredentials- Username = %s\n", pUsername);
// Success // Success
retStatus = CASA_STATUS_SUCCESS; retStatus = CASA_STATUS_SUCCESS;
} }
else else
{ {
DbgTrace(0, "-GetUserCredentials- Buffer allocation error\n", 0); DbgTrace(0, "-GetUserCredentials- Buffer allocation error\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES); CASA_STATUS_INSUFFICIENT_RESOURCES);
// Free the buffer allocated for the username // Free the buffer allocated for the username
free(pUsername); free(pUsername);
} }
} }
else else
{ {
DbgTrace(0, "-GetUserCredentials- Buffer allocation error\n", 0); DbgTrace(0, "-GetUserCredentials- Buffer allocation error\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES); CASA_STATUS_INSUFFICIENT_RESOURCES);
} }
} }
else else
{ {
DbgTrace(0, "-GetUserCredentials- Failed to obtain credentials for pw authentication\n", 0); DbgTrace(0, "-GetUserCredentials- Failed to obtain credentials for pw authentication\n", 0);
} }
// Return the buffers to the caller if successful // Clear out the credential structure to make sure that we are not leaving sensitive
if (CASA_SUCCESS(retStatus)) // information on the stack.
{ memset(&credential, 0, sizeof(credential));
*ppUsername = pUsername;
*ppPassword = pPassword; // Return the buffers to the caller if successful
} if (CASA_SUCCESS(retStatus))
{
DbgTrace(1, "-GetUserCredentials- End, retStatus = %0X\n", retStatus); *ppUsername = pUsername;
*ppPassword = pPassword;
return retStatus; }
}
DbgTrace(1, "-GetUserCredentials- End, retStatus = %0X\n", retStatus);
//++======================================================================= return retStatus;
CasaStatus SSCS_CALL }
AuthTokenIf_GetAuthToken(
IN const void *pIfInstance,
IN const char *pContext, //++=======================================================================
IN const char *pMechInfo, CasaStatus SSCS_CALL
IN const char *pHostName, AuthTokenIf_GetAuthToken(
IN const void *pIfInstance,
IN const char *pContext,
IN const char *pMechInfo,
IN const char *pHostName,
IN void *pCredStoreScope, IN void *pCredStoreScope,
INOUT char *pTokenBuf, INOUT char *pTokenBuf,
INOUT int *pTokenBufLen) INOUT int *pTokenBufLen)
// //
// Arguments: // Arguments:
// pIfInstance - // pIfInstance -
// Pointer to interface object. // Pointer to interface object.
// //
// pContext - // pContext -
// Pointer to null terminated string containing mechanism specific // Pointer to null terminated string containing mechanism specific
// context information. Another name for context is Authentication // context information. Another name for context is Authentication
// Realm. // Realm.
// //
// pMechInfo - // pMechInfo -
// Pointer to null terminated string containing mechanism specific // Pointer to null terminated string containing mechanism specific
// information. This is information is provided by the server to // information. This is information is provided by the server to
// aid the mechanism to generate an authentication token. For // aid the mechanism to generate an authentication token. For
// example, the mechanism information for a Kerberos mechanism // example, the mechanism information for a Kerberos mechanism
// may be the service principal name to which the user will be // may be the service principal name to which the user will be
// authenticating. // authenticating.
// //
// pHostName - // pHostName -
// Pointer to null terminated string containing the name of the // Pointer to null terminated string containing the name of the
// host where the ATS resides. // host where the ATS resides.
// //
// pCredStoreScope - // pCredStoreScope -
// Pointer to CASA structure for scoping credential store access // Pointer to CASA structure for scoping credential store access
// to specific users. This can only be leveraged when running in // to specific users. This can only be leveraged when running in
// the context of System under Windows. // the context of System under Windows.
// //
// pTokenBuf - // pTokenBuf -
// Pointer to buffer that will receive the authentication // Pointer to buffer that will receive the authentication
// token. The length of this buffer is specified by the // token. The length of this buffer is specified by the
// pTokenBufLen parameter. Note that the the authentication // pTokenBufLen parameter. Note that the the authentication
// token will be in the form of a NULL terminated string. // token will be in the form of a NULL terminated string.
// //
// pTokenBufLen - // pTokenBufLen -
// Pointer to integer that contains the length of the // Pointer to integer that contains the length of the
// buffer pointed at by pTokenBuf. Upon return of the // buffer pointed at by pTokenBuf. Upon return of the
// function, the integer will contain the actual length // function, the integer will contain the actual length
// of the authentication token if the function successfully // of the authentication token if the function successfully
// completes or the buffer length required if the function // completes or the buffer length required if the function
// fails because the buffer pointed at by pUserNameBuf is // fails because the buffer pointed at by pUserNameBuf is
// not large enough. // not large enough.
// //
// Returns: // Returns:
// Casa Status // Casa Status
// //
// Description: // Description:
// Get authentication token to authenticate user to specified service. // Get authentication token to authenticate user to specified service.
// //
// L2 // L2
//=======================================================================-- //=======================================================================--
{ {
CasaStatus retStatus; CasaStatus retStatus;
char *pUsername = NULL; char *pUsername = NULL;
char *pPassword = NULL; char *pPassword = NULL;
char *pToken; char *pToken;
DbgTrace(1, "-AuthTokenIf_GetAuthToken- Start\n", 0); DbgTrace(1, "-AuthTokenIf_GetAuthToken- Start\n", 0);
// Validate input parameters // Validate input parameters
if (pIfInstance == NULL if (pIfInstance == NULL
|| pContext == NULL || pContext == NULL
|| pHostName == NULL || pHostName == NULL
|| pTokenBufLen == NULL || pTokenBufLen == NULL
|| (pTokenBuf == NULL && *pTokenBufLen != 0)) || (pTokenBuf == NULL && *pTokenBufLen != 0))
{ {
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Invalid input parameter\n", 0); DbgTrace(0, "-AuthTokenIf_GetAuthToken- Invalid input parameter\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_INVALID_PARAMETER); CASA_STATUS_INVALID_PARAMETER);
goto exit; goto exit;
} }
// Get the user credentials // Get the user credentials
retStatus = GetUserCredentials(pContext, retStatus = GetUserCredentials(pContext,
pCredStoreScope, pCredStoreScope,
&pUsername, &pUsername,
&pPassword); &pPassword);
if (CASA_SUCCESS(retStatus)) if (CASA_SUCCESS(retStatus))
{ {
// Now construct the PW token with the following format: // Now construct the PW token with the following format:
// "username\r\n" + "password\r\n" // "username\r\n" + "password\r\n"
// //
// First allocate a buffer large enough to hold the token // First allocate a buffer large enough to hold the token
pToken = (char*) malloc(strlen(pUsername) + 2 + strlen(pPassword) + 2 + 1); pToken = (char*) malloc(strlen(pUsername) + 2 + strlen(pPassword) + 2 + 1);
if (pToken) if (pToken)
{ {
char *pEncodedToken; char *pEncodedToken;
int encodedTokenLen; int encodedTokenLen;
// Now assemble the token // Now assemble the token
sprintf(pToken, "%s\r\n%s\r\n", pUsername, pPassword); sprintf(pToken, "%s\r\n%s\r\n", pUsername, pPassword);
// The token has been assembled, now encode it. // The token has been assembled, now encode it.
retStatus = EncodeData(pToken, retStatus = EncodeData(pToken,
(const int) strlen(pToken), (const int) strlen(pToken),
&pEncodedToken, &pEncodedToken,
&encodedTokenLen); &encodedTokenLen);
if (CASA_SUCCESS(retStatus)) if (CASA_SUCCESS(retStatus))
{ {
// Verify that the caller provided a buffer that is big enough // Verify that the caller provided a buffer that is big enough
if (encodedTokenLen > *pTokenBufLen) if (encodedTokenLen > *pTokenBufLen)
{ {
// The buffer is not big enough // The buffer is not big enough
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_PWTOKEN, CASA_FACILITY_PWTOKEN,
CASA_STATUS_BUFFER_OVERFLOW); CASA_STATUS_BUFFER_OVERFLOW);
} }
else else
{ {
// The buffer provided is large enough, copy the data. // The buffer provided is large enough, copy the data.
memcpy((void*) pTokenBuf, pEncodedToken, encodedTokenLen); memcpy((void*) pTokenBuf, pEncodedToken, encodedTokenLen);
// Success // Success
retStatus = CASA_STATUS_SUCCESS; retStatus = CASA_STATUS_SUCCESS;
} }
// Return the actual size or the size required // Return the actual size or the size required
*pTokenBufLen = encodedTokenLen; *pTokenBufLen = encodedTokenLen;
// Free the buffer containing the encoded token // Free the buffer containing the encoded token after clearing
free(pEncodedToken); // it to avoid leaking sensitive information.
} memset(pEncodedToken, 0, strlen(pEncodedToken));
free(pEncodedToken);
// Free the buffer allocated for the token }
free(pToken);
} // Free the buffer allocated for the token after clearing it
else // to avoid leaving sensitive information behind.
{ memset(pToken, 0, strlen(pToken));
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Buffer allocation error\n", 0); free(pToken);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, }
CASA_FACILITY_PWTOKEN, else
CASA_STATUS_INSUFFICIENT_RESOURCES); {
} DbgTrace(0, "-AuthTokenIf_GetAuthToken- Buffer allocation error\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
// Free allocated buffers CASA_FACILITY_PWTOKEN,
free(pUsername); CASA_STATUS_INSUFFICIENT_RESOURCES);
free(pPassword); }
}
else // Free allocated buffers after clearing memory holding the password
{ free(pUsername);
DbgTrace(1, "-AuthTokenIf_GetAuthToken- Failed to obtain the user credentials\n", 0); memset(pPassword, 0, strlen(pPassword));
} free(pPassword);
}
exit: else
{
DbgTrace(1, "-AuthTokenIf_GetAuthToken- End, retStatus = %08X\n", retStatus); DbgTrace(1, "-AuthTokenIf_GetAuthToken- Failed to obtain the user credentials\n", 0);
}
return retStatus;
} exit:
DbgTrace(1, "-AuthTokenIf_GetAuthToken- End, retStatus = %08X\n", retStatus);
//++=======================================================================
//++======================================================================= return retStatus;
//++======================================================================= }
//++=======================================================================
//++=======================================================================
//++=======================================================================

View File

@ -28,5 +28,5 @@ LibraryName \Program Files\novell\casa\lib\pwmech.dll
# tools such as DbgView. Under Linux, debug statements are logged # tools such as DbgView. Under Linux, debug statements are logged
# to /var/log/messages. # to /var/log/messages.
# #
#DebugLevel 0 #DebugLevel 0

View File

@ -128,7 +128,7 @@ BOOL APIENTRY DllMain(
//=======================================================================-- //=======================================================================--
{ {
BOOL retStatus = TRUE; BOOL retStatus = TRUE;
char programFilesFolder[MAX_PATH]; char programFilesFolder[MAX_PATH] = {0};
switch (ul_reason_for_call) switch (ul_reason_for_call)
{ {

View File

@ -54,12 +54,12 @@ static
HANDLE hNormalizedHostNameCacheMutex; HANDLE hNormalizedHostNameCacheMutex;
// Client configuration file folder // Client configuration file folder
char clientConfigFolder[MAX_PATH];
char clientConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth"; char clientConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth";
char clientConfigFolder[MAX_PATH + sizeof(clientConfigFolderPartialPath)];
// Authentication mechanism configuration file folder // Authentication mechanism configuration file folder
char mechConfigFolder[MAX_PATH];
char mechConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth\\Mechanisms"; char mechConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth\\Mechanisms";
char mechConfigFolder[MAX_PATH + sizeof(mechConfigFolderPartialPath)];
// Path separator // Path separator
char pathCharString[] = "\\"; char pathCharString[] = "\\";
@ -81,6 +81,8 @@ CreateUserMutex(
// L2 // L2
//=======================================================================-- //=======================================================================--
{ {
#define USER_MUTEX_NAME_FMT_STRING "Global\\CASA_Auth_Mutex_%s"
CasaStatus retStatus = CASA_STATUS_SUCCESS; CasaStatus retStatus = CASA_STATUS_SUCCESS;
char *pUsername = NULL; char *pUsername = NULL;
DWORD nameLength = 0; DWORD nameLength = 0;
@ -99,32 +101,47 @@ CreateUserMutex(
if (GetUserName(pUsername, &nameLength)) if (GetUserName(pUsername, &nameLength))
{ {
SECURITY_ATTRIBUTES mutexAttributes; SECURITY_ATTRIBUTES mutexAttributes;
char mutexName[256]; char *pMutexName;
// Now lets create a global semaphore for the // Allocate a buffer to hold the mutex name
// user and allow its handle to be inherited. pMutexName = (char*) malloc(sizeof(USER_MUTEX_NAME_FMT_STRING) + nameLength);
mutexAttributes.nLength = sizeof(mutexAttributes); if (pMutexName)
mutexAttributes.lpSecurityDescriptor = NULL;
mutexAttributes.bInheritHandle = TRUE;
if (sprintf(mutexName, "Global\\CASA_Auth_Mutex_%s", pUsername) != -1)
{ {
*phMutex = CreateMutex(&mutexAttributes, // Now lets create a global semaphore for the
FALSE, // user and allow its handle to be inherited.
mutexName); mutexAttributes.nLength = sizeof(mutexAttributes);
if (*phMutex == NULL) mutexAttributes.lpSecurityDescriptor = NULL;
mutexAttributes.bInheritHandle = TRUE;
if (sprintf(pMutexName, USER_MUTEX_NAME_FMT_STRING, pUsername) != -1)
{ {
DbgTrace(0, "-CreateUserMutex- CreateMutex failed, error = %d\n", GetLastError()); *phMutex = CreateMutex(&mutexAttributes,
FALSE,
pMutexName);
if (*phMutex == NULL)
{
DbgTrace(0, "-CreateUserMutex- CreateMutex failed, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
DbgTrace(0, "-CreateUserMutex- sprintf failed, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
} }
// Free the buffer used to hold the user mutex name
free(pMutexName);
} }
else else
{ {
DbgTrace(0, "-CreateUserMutex- sprintf failed, error = %d\n", GetLastError()); DbgTrace(0, "-CreateUserMutex- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_INSUFFICIENT_RESOURCES);
} }
} }
else else
@ -415,53 +432,65 @@ NormalizeHostName(
// Now try to resolve the normalized name // Now try to resolve the normalized name
pLookupResult = gethostbyname(pHostName); pLookupResult = gethostbyname(pHostName);
if (pLookupResult && pLookupResult->h_addrtype == AF_INET) if (pLookupResult
&& pLookupResult->h_addrtype == AF_INET
&& pLookupResult->h_length > 0
&& pLookupResult->h_addr_list[0] != NULL)
{ {
char dnsHostName[NI_MAXHOST]; char *pDnsHostName = (char*) malloc(NI_MAXHOST + 1);
if (pDnsHostName)
// Set up a sockaddr structure
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.S_un.S_addr = *((int*) pLookupResult->h_addr_list[0]);
// Now try to resolve the name using DNS
if (getnameinfo((const struct sockaddr*) &sockAddr,
sizeof(sockAddr),
dnsHostName,
sizeof(dnsHostName),
NULL,
0,
NI_NAMEREQD) == 0)
{ {
// We resolved the address to a DNS name, use it as the normalized name. // Set up a sockaddr structure
pEntry->buffLengthRequired = (int) strlen(dnsHostName) + 1; sockAddr.sin_family = AF_INET;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired); sockAddr.sin_addr.S_un.S_addr = *((int*) pLookupResult->h_addr_list[0]);
if (pEntry->pNormalizedHostName)
// Now try to resolve the name using DNS
if (getnameinfo((const struct sockaddr*) &sockAddr,
sizeof(sockAddr),
pDnsHostName,
NI_MAXHOST,
NULL,
0,
NI_NAMEREQD) == 0)
{ {
// Copy the dns name // We resolved the address to a DNS name, use it as the normalized name.
strcpy(pEntry->pNormalizedHostName, dnsHostName); pEntry->buffLengthRequired = (int) strlen(pDnsHostName) + 1;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired);
if (pEntry->pNormalizedHostName)
{
// Copy the dns name
strcpy(pEntry->pNormalizedHostName, pDnsHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
} }
else else
{ {
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); DbgTrace(0, "-NormalizeHostName- getnameInfo failed, error %d\n", WSAGetLastError());
// Not able to resolve the name in DNS, just use the host name as
// the normalized name.
pEntry->buffLengthRequired = (int) strlen(pHostName) + 1;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired);
if (pEntry->pNormalizedHostName)
{
// Copy the host name
strcpy(pEntry->pNormalizedHostName, pHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
} }
// Free the buffer allocated to hold the DNS name
free(pDnsHostName);
} }
else else
{ {
DbgTrace(0, "-NormalizeHostName- getnameInfo failed, error %d\n", WSAGetLastError()); DbgTrace(0, "-NormalizeHostName- Buffer allocation failure\n", 0);
// Not able to resolve the name in DNS, just use the host name as
// the normalized name.
pEntry->buffLengthRequired = (int) strlen(pHostName) + 1;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired);
if (pEntry->pNormalizedHostName)
{
// Copy the host name
strcpy(pEntry->pNormalizedHostName, pHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
} }
} }
else else

View File

@ -356,10 +356,14 @@ InternalRpc(
// L2 // L2
//=======================================================================-- //=======================================================================--
{ {
#define RPC_TARGET_FMT_STRING "CasaAuthTokenSvc/Rpc?method=%s"
#ifndef CASA_STATUS_INVALID_SERVER_CERTIFICATE
#define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated #define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated
#endif
CasaStatus retStatus = CASA_STATUS_SUCCESS; CasaStatus retStatus = CASA_STATUS_SUCCESS;
char rpcTarget[256]; char *pRpcTarget;
LPWSTR pWideRpcTarget; LPWSTR pWideRpcTarget;
int wideRpcTargetLen; int wideRpcTargetLen;
WCHAR sendHeaders[] = L"Content-Type: text/html"; WCHAR sendHeaders[] = L"Content-Type: text/html";
@ -373,173 +377,184 @@ InternalRpc(
*ppResponseData = NULL; *ppResponseData = NULL;
// Create rpc target string and convert it to a wide string // Create rpc target string and convert it to a wide string
sprintf(rpcTarget, "CasaAuthTokenSvc/Rpc?method=%s", pMethod); pRpcTarget = (char*) malloc(sizeof(RPC_TARGET_FMT_STRING) + strlen(pMethod));
retStatus = CopyMultiToWideAlloc(rpcTarget, if (pRpcTarget)
(int) strlen(rpcTarget),
&pWideRpcTarget,
&wideRpcTargetLen);
if (CASA_SUCCESS(retStatus))
{ {
HINTERNET hRequest; sprintf(pRpcTarget, RPC_TARGET_FMT_STRING, pMethod);
retStatus = CopyMultiToWideAlloc(pRpcTarget,
do (int) strlen(pRpcTarget),
&pWideRpcTarget,
&wideRpcTargetLen);
if (CASA_SUCCESS(retStatus))
{ {
// Forget about having been told to retry HINTERNET hRequest;
attemptRetry = false;
// Open a request handle do
hRequest = WinHttpOpenRequest(pSession->hConnection,
L"POST",
pWideRpcTarget,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
flags & SECURE_RPC_FLAG? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH);
if (hRequest)
{ {
int reqDataLen = (int) strlen(pRequestData); // Forget about having been told to retry
attemptRetry = false;
// Check if we need to set options to deal with secure connections // Open a request handle
if (flags & SECURE_RPC_FLAG) hRequest = WinHttpOpenRequest(pSession->hConnection,
{ L"POST",
// We are using secure connections, now proceed based on whether or not pWideRpcTarget,
// we are configured to allow invalid certificates.
if (flags & ALLOW_INVALID_CERTS_RPC_FLAG
|| (flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG
&& InvalidCertsFromHostAllowed(pSession->pHostName)))
{
DWORD secFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
// We are configured to allow invalid certificates, inform the HTTP stack.
if (WinHttpSetOption(hRequest,
WINHTTP_OPTION_SECURITY_FLAGS,
&secFlags,
sizeof(secFlags)) == FALSE)
{
DbgTrace(0, "-InternalRpc- Failed setting options to ignore invalid certs, error = %d\n", GetLastError());
}
}
else
{
// We are not configured to allow invalid certificates, set a callback handler
// to detect invalid certificate conditions.
if (WinHttpSetStatusCallback(hRequest,
SecureFailureStatusCallback,
WINHTTP_CALLBACK_FLAG_SECURE_FAILURE,
(DWORD_PTR) NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{
DbgTrace(0, "-InternalRpc- Failed setting status callback, error = %d\n", GetLastError());
}
}
}
// Send the request
securityFailureStatusFlags = 0;
if (WinHttpSendRequest(hRequest,
sendHeaders,
-1,
pRequestData,
reqDataLen,
reqDataLen,
(DWORD_PTR) &securityFailureStatusFlags))
{
// Request sent, now await for the response.
if (WinHttpReceiveResponse(hRequest, NULL))
{
WCHAR httpCompStatus[4] = {0};
DWORD httpCompStatusLen = sizeof(httpCompStatus);
// Response received, make sure that it completed successfully.
if (WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE,
NULL, NULL,
&httpCompStatus, WINHTTP_NO_REFERER,
&httpCompStatusLen, WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_NO_HEADER_INDEX)) flags & SECURE_RPC_FLAG? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH);
if (hRequest)
{
int reqDataLen = (int) strlen(pRequestData);
// Check if we need to set options to deal with secure connections
if (flags & SECURE_RPC_FLAG)
{
// We are using secure connections, now proceed based on whether or not
// we are configured to allow invalid certificates.
if (flags & ALLOW_INVALID_CERTS_RPC_FLAG
|| (flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG
&& InvalidCertsFromHostAllowed(pSession->pHostName)))
{ {
// Check that the request completed successfully DWORD secFlags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0)
// We are configured to allow invalid certificates, inform the HTTP stack.
if (WinHttpSetOption(hRequest,
WINHTTP_OPTION_SECURITY_FLAGS,
&secFlags,
sizeof(secFlags)) == FALSE)
{ {
char *pResponseData; DbgTrace(0, "-InternalRpc- Failed setting options to ignore invalid certs, error = %d\n", GetLastError());
int responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE; }
int responseDataRead = 0; }
else
{
// We are not configured to allow invalid certificates, set a callback handler
// to detect invalid certificate conditions.
if (WinHttpSetStatusCallback(hRequest,
SecureFailureStatusCallback,
WINHTTP_CALLBACK_FLAG_SECURE_FAILURE,
(DWORD_PTR) NULL) == WINHTTP_INVALID_STATUS_CALLBACK)
{
DbgTrace(0, "-InternalRpc- Failed setting status callback, error = %d\n", GetLastError());
}
}
}
// Now read the response data, to do so we need to allocate a buffer. // Send the request
pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE); securityFailureStatusFlags = 0;
if (pResponseData) if (WinHttpSendRequest(hRequest,
sendHeaders,
-1,
pRequestData,
reqDataLen,
reqDataLen,
(DWORD_PTR) &securityFailureStatusFlags))
{
// Request sent, now await for the response.
if (WinHttpReceiveResponse(hRequest, NULL))
{
WCHAR httpCompStatus[4] = {0};
DWORD httpCompStatusLen = sizeof(httpCompStatus);
// Response received, make sure that it completed successfully.
if (WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE,
NULL,
&httpCompStatus,
&httpCompStatusLen,
WINHTTP_NO_HEADER_INDEX))
{
// Check that the request completed successfully
if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0)
{ {
char *pCurrLocation = pResponseData; char *pResponseData;
DWORD bytesRead; int responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE;
int responseDataRead = 0;
do // Now read the response data, to do so we need to allocate a buffer.
pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE);
if (pResponseData)
{ {
bytesRead = 0; char *pCurrLocation = pResponseData;
if (WinHttpReadData(hRequest, DWORD bytesRead;
(LPVOID) pCurrLocation,
responseDataBufSize - responseDataRead, do
&bytesRead))
{ {
pCurrLocation += bytesRead; bytesRead = 0;
responseDataRead += bytesRead; if (WinHttpReadData(hRequest,
(LPVOID) pCurrLocation,
// Check if we need to allocate a larger buffer responseDataBufSize - responseDataRead,
if (responseDataRead == responseDataBufSize) &bytesRead))
{ {
char *pTmpBuf; pCurrLocation += bytesRead;
responseDataRead += bytesRead;
// We need to upgrade the receive buffer // Check if we need to allocate a larger buffer
pTmpBuf = (char*) malloc(responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE); if (responseDataRead == responseDataBufSize)
if (pTmpBuf)
{ {
memcpy(pTmpBuf, pResponseData, responseDataBufSize); char *pTmpBuf;
free(pResponseData);
pResponseData = pTmpBuf; // We need to upgrade the receive buffer
pCurrLocation = pResponseData + responseDataBufSize; pTmpBuf = (char*) malloc(responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE);
responseDataBufSize += INCREMENT_RESPONSE_DATA_BUF_SIZE; if (pTmpBuf)
} {
else memcpy(pTmpBuf, pResponseData, responseDataBufSize);
{ free(pResponseData);
DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); pResponseData = pTmpBuf;
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, pCurrLocation = pResponseData + responseDataBufSize;
CASA_FACILITY_AUTHTOKEN, responseDataBufSize += INCREMENT_RESPONSE_DATA_BUF_SIZE;
CASA_STATUS_INSUFFICIENT_RESOURCES); }
else
{
DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
} }
} }
else
{
DbgTrace(0, "-InternalRpc- Failed reading response data, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
} while (CASA_SUCCESS(retStatus)
&& bytesRead != 0);
// Check if the response data was successfully received
if (CASA_SUCCESS(retStatus))
{
// The response data was received, return it to the caller.
*ppResponseData = pResponseData;
*pResponseDataLen = responseDataRead;
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Failed reading response data, error = %d\n", GetLastError()); // Failed to receive the response data, free the allocated buffer.
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, free(pResponseData);
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
} }
} while (CASA_SUCCESS(retStatus)
&& bytesRead != 0);
// Check if the response data was successfully received
if (CASA_SUCCESS(retStatus))
{
// The response data was received, return it to the caller.
*ppResponseData = pResponseData;
*pResponseDataLen = responseDataRead;
} }
else else
{ {
// Failed to receive the response data, free the allocated buffer. DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
free(pResponseData); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
} }
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0); DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %S\n", httpCompStatus);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES); CASA_STATUS_UNSUCCESSFUL);
} }
} }
else else
{ {
DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %S\n", httpCompStatus); DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
@ -547,7 +562,7 @@ InternalRpc(
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError()); DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL); CASA_STATUS_UNSUCCESSFUL);
@ -555,160 +570,163 @@ InternalRpc(
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError()); int error = GetLastError();
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
int error = GetLastError();
if (error == ERROR_WINHTTP_CANNOT_CONNECT) if (error == ERROR_WINHTTP_CANNOT_CONNECT)
{
DbgTrace(0, "-InternalRpc- Unable to connect to server\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_AUTH_SERVER_UNAVAILABLE);
}
else if (error == ERROR_WINHTTP_SECURE_FAILURE)
{
DbgTrace(1, "-InternalRpc- Secure connection failure, flags = %0x\n", securityFailureStatusFlags);
// Try to deal with the issue
if ((securityFailureStatusFlags & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA
| WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID
| WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) == 0
&& flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG)
{ {
WINHTTP_CERTIFICATE_INFO certInfo; DbgTrace(0, "-InternalRpc- Unable to connect to server\n", 0);
DWORD certInfoLen = sizeof(certInfo); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_AUTH_SERVER_UNAVAILABLE);
}
else if (error == ERROR_WINHTTP_SECURE_FAILURE)
{
DbgTrace(1, "-InternalRpc- Secure connection failure, flags = %0x\n", securityFailureStatusFlags);
// The failure was due to an invalid CN, CA, or both. // Try to deal with the issue
// if ((securityFailureStatusFlags & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA
// Obtain information about the server certificate to give user | WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID
// the choice of accepting it. | WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)) == 0
if (WinHttpQueryOption(hRequest, && flags & ALLOW_INVALID_CERTS_USER_APPROVAL_RPC_FLAG)
WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT,
&certInfo,
&certInfoLen)
&& certInfo.lpszSubjectInfo != NULL
&& certInfo.lpszIssuerInfo != NULL)
{ {
char *pSubjectInfo; WINHTTP_CERTIFICATE_INFO certInfo;
int subjectInfoLen; DWORD certInfoLen = sizeof(certInfo);
// Convert the subjectInfo to multi-byte // The failure was due to an invalid CN, CA, or both.
retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo, //
(int) wcslen(certInfo.lpszSubjectInfo), // Obtain information about the server certificate to give user
&pSubjectInfo, // the choice of accepting it.
&subjectInfoLen); if (WinHttpQueryOption(hRequest,
if (CASA_SUCCESS(retStatus)) WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT,
&certInfo,
&certInfoLen)
&& certInfo.lpszSubjectInfo != NULL
&& certInfo.lpszIssuerInfo != NULL)
{ {
char *pIssuerInfo; char *pSubjectInfo;
int issuerInfoLen; int subjectInfoLen;
// Convert the issuerInfo to multi-byte // Convert the subjectInfo to multi-byte
retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo, retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo,
(int) wcslen(certInfo.lpszIssuerInfo), (int) wcslen(certInfo.lpszSubjectInfo),
&pIssuerInfo, &pSubjectInfo,
&issuerInfoLen); &subjectInfoLen);
if (CASA_SUCCESS(retStatus)) if (CASA_SUCCESS(retStatus))
{ {
long invalidCertFlags = 0; char *pIssuerInfo;
int issuerInfoLen;
// Setup the invalid cert flags // Convert the issuerInfo to multi-byte
if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo,
invalidCertFlags |= INVALID_CERT_CA_FLAG; (int) wcslen(certInfo.lpszIssuerInfo),
&pIssuerInfo,
if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) &issuerInfoLen);
invalidCertFlags |= INVALID_CERT_CN_FLAG; if (CASA_SUCCESS(retStatus))
if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
invalidCertFlags |= INVALID_CERT_DATE_FLAG;
// Give user the choice to accept the certificate
if (UserApprovedCert(pSession->pHostName,
pSubjectInfo,
pIssuerInfo,
invalidCertFlags))
{ {
DbgTrace(1, "-InternalRpc- User approved invalid certificate from %s\n", pSession->pHostName); long invalidCertFlags = 0;
// tbd - Investigate if there is a way to set the accepted certificate in a store so that // Setup the invalid cert flags
// it can be utilized by the SSL stack directly. This would be a better method for dealing with if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
// this issue. invalidCertFlags |= INVALID_CERT_CA_FLAG;
AllowInvalidCertsFromHost(pSession->pHostName); if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
invalidCertFlags |= INVALID_CERT_CN_FLAG;
// Try to retry the request if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
attemptRetry = true; invalidCertFlags |= INVALID_CERT_DATE_FLAG;
}
else
{
DbgTrace(1, "-InternalRpc- User did not approve invalid certificate from %s\n", pSession->pHostName);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, // Give user the choice to accept the certificate
CASA_FACILITY_AUTHTOKEN, if (UserApprovedCert(pSession->pHostName,
CASA_STATUS_INVALID_SERVER_CERTIFICATE); pSubjectInfo,
pIssuerInfo,
invalidCertFlags))
{
DbgTrace(1, "-InternalRpc- User approved invalid certificate from %s\n", pSession->pHostName);
// tbd - Investigate if there is a way to set the accepted certificate in a store so that
// it can be utilized by the SSL stack directly. This would be a better method for dealing with
// this issue.
AllowInvalidCertsFromHost(pSession->pHostName);
// Try to retry the request
attemptRetry = true;
}
else
{
DbgTrace(1, "-InternalRpc- User did not approve invalid certificate from %s\n", pSession->pHostName);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INVALID_SERVER_CERTIFICATE);
}
// Free the buffer containing the issuerInfo
free(pIssuerInfo);
} }
// Free the buffer containing the issuerInfo // Free the buffer containing the subjectInfo
free(pIssuerInfo); free(pSubjectInfo);
} }
// Free the buffer containing the subjectInfo // Free necessary certificate information
free(pSubjectInfo); if (certInfo.lpszSubjectInfo) LocalFree(certInfo.lpszSubjectInfo);
if (certInfo.lpszIssuerInfo) LocalFree(certInfo.lpszIssuerInfo);
if (certInfo.lpszProtocolName) LocalFree(certInfo.lpszProtocolName);
if (certInfo.lpszSignatureAlgName) LocalFree(certInfo.lpszSignatureAlgName);
if (certInfo.lpszEncryptionAlgName) LocalFree(certInfo.lpszEncryptionAlgName);
}
else
{
DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError());
} }
// Free necessary certificate information
if (certInfo.lpszSubjectInfo) LocalFree(certInfo.lpszSubjectInfo);
if (certInfo.lpszIssuerInfo) LocalFree(certInfo.lpszIssuerInfo);
if (certInfo.lpszProtocolName) LocalFree(certInfo.lpszProtocolName);
if (certInfo.lpszSignatureAlgName) LocalFree(certInfo.lpszSignatureAlgName);
if (certInfo.lpszEncryptionAlgName) LocalFree(certInfo.lpszEncryptionAlgName);
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError()); // Decided to no give the user a choice to accept invalid server certificate
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INVALID_SERVER_CERTIFICATE);
} }
} }
else else
{ {
// Decided to no give the user a choice to accept invalid server certificate DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN, CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INVALID_SERVER_CERTIFICATE); CASA_STATUS_UNSUCCESSFUL);
} }
} }
else
{ // Close the request handle
DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error); WinHttpCloseHandle(hRequest);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
} }
else
{
DbgTrace(0, "-InternalRpc- Unable to open http request, error = %d\n", GetLastError());
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
} while (attemptRetry && retriesAllowed--);
// Close the request handle // Free the rpc target wide string buffer
WinHttpCloseHandle(hRequest); free(pWideRpcTarget);
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Unable to open http request, error = %d\n", GetLastError()); DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, }
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
} while (attemptRetry && retriesAllowed--);
// Free the rpc target wide string buffer // Free buffer used to hold the rpc target string
free(pWideRpcTarget); free(pRpcTarget);
} }
else else
{ {
DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0); DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
} }
DbgTrace(1, "-InternalRpc- End, retStatus = %d\n", retStatus); DbgTrace(1, "-InternalRpc- End, retStatus = %d\n", retStatus);