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

@ -194,6 +194,9 @@ ObtainSessionToken(
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

@ -181,6 +181,10 @@ GetUserCredentials(
DbgTrace(0, "-GetUserCredentials- Failed to obtain credentials for pw authentication\n", 0); DbgTrace(0, "-GetUserCredentials- Failed to obtain credentials for pw authentication\n", 0);
} }
// Clear out the credential structure to make sure that we are not leaving sensitive
// information on the stack.
memset(&credential, 0, sizeof(credential));
// Return the buffers to the caller if successful // Return the buffers to the caller if successful
if (CASA_SUCCESS(retStatus)) if (CASA_SUCCESS(retStatus))
{ {
@ -324,11 +328,15 @@ 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
// it to avoid leaking sensitive information.
memset(pEncodedToken, 0, strlen(pEncodedToken));
free(pEncodedToken); free(pEncodedToken);
} }
// Free the buffer allocated for the token // Free the buffer allocated for the token after clearing it
// to avoid leaving sensitive information behind.
memset(pToken, 0, strlen(pToken));
free(pToken); free(pToken);
} }
else else
@ -339,8 +347,9 @@ AuthTokenIf_GetAuthToken(
CASA_STATUS_INSUFFICIENT_RESOURCES); CASA_STATUS_INSUFFICIENT_RESOURCES);
} }
// Free allocated buffers // Free allocated buffers after clearing memory holding the password
free(pUsername); free(pUsername);
memset(pPassword, 0, strlen(pPassword));
free(pPassword); free(pPassword);
} }
else else

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);