886 lines
32 KiB
C
886 lines
32 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 INITIAL_RESPONSE_DATA_BUF_SIZE 1028
|
|
#define INCREMENT_RESPONSE_DATA_BUF_SIZE 256
|
|
|
|
#define MAX_RPC_RETRIES 3
|
|
#define MILLISECONDS_BETWEEN_RPC_RETRIES 3000
|
|
#define MAX_RPC_TIME_MILLISECONDS 60000
|
|
|
|
//===[ Function prototypes ]===============================================
|
|
|
|
//===[ Global variables ]==================================================
|
|
|
|
//++=======================================================================
|
|
static
|
|
CasaStatus
|
|
CopyMultiToWideAlloc(
|
|
IN char *pMulti,
|
|
IN int multiSize,
|
|
INOUT LPWSTR *ppWide,
|
|
INOUT int *pWideSize)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
int retStatus;
|
|
int size, i;
|
|
|
|
DbgTrace(2, "-CopyMultiToWideAlloc- Start\n", 0);
|
|
|
|
size = (multiSize + 1) * sizeof(WCHAR);
|
|
|
|
if ((*ppWide = (PWCHAR) malloc(size)) != NULL)
|
|
{
|
|
for (i = 0; i < multiSize; i++)
|
|
{
|
|
*(*ppWide + i) = (unsigned char) *(pMulti + i);
|
|
}
|
|
|
|
*(*ppWide + i) = L'\0';
|
|
|
|
if (pWideSize)
|
|
{
|
|
*pWideSize = size - sizeof(WCHAR);
|
|
}
|
|
|
|
retStatus = CASA_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
DbgTrace(2, "-CopyMultiToWideAlloc- End, retStatus = %08X\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
static
|
|
CasaStatus
|
|
CopyWideToMultiAlloc(
|
|
IN LPWSTR pWide,
|
|
IN int wideSize,
|
|
INOUT char **ppMulti,
|
|
INOUT int *pMultiSize)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
int retStatus;
|
|
int size, i;
|
|
|
|
DbgTrace(2, "-CopyWideToMultiAlloc- Start\n", 0);
|
|
|
|
size = wideSize + 1;
|
|
|
|
if ((*ppMulti = malloc(size)) != NULL)
|
|
{
|
|
for (i = 0; i < wideSize; i++)
|
|
{
|
|
*(*ppMulti + i) = (char) *(pWide + i);
|
|
}
|
|
|
|
*(*ppMulti + i) = '\0';
|
|
|
|
if (pMultiSize)
|
|
{
|
|
*pMultiSize = size - 1;
|
|
}
|
|
|
|
retStatus = CASA_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
DbgTrace(2, "-CopyWideToMultiAlloc- End, retStatus = %08X\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
RpcSession*
|
|
OpenRpcSession(
|
|
IN const char *pHostName,
|
|
IN const uint16_t hostPort)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
RpcSession *pSession;
|
|
bool success = false;
|
|
|
|
DbgTrace(1, "-OpenRpcSession- Start\n", 0);
|
|
DbgTrace(2, "-OpenRpcSession- Host = %s\n", pHostName);
|
|
DbgTrace(2, "-OpenRpcSession- HostPort = %d\n", hostPort);
|
|
|
|
// Allocate space for the session
|
|
pSession = (RpcSession*) malloc(sizeof(*pSession));
|
|
if (pSession)
|
|
{
|
|
// Zero the session structure
|
|
memset(pSession, 0, sizeof(*pSession));
|
|
|
|
// Save copy of the hostname
|
|
pSession->pHostName = malloc(strlen(pHostName) + 1);
|
|
if (pSession->pHostName)
|
|
{
|
|
strcpy(pSession->pHostName, pHostName);
|
|
|
|
// Open a Winhttp session
|
|
pSession->hSession = WinHttpOpen(L"CASA Client/1.0",
|
|
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
|
WINHTTP_NO_PROXY_NAME,
|
|
WINHTTP_NO_PROXY_BYPASS,
|
|
0);
|
|
if (pSession->hSession)
|
|
{
|
|
LPWSTR pWideHostName;
|
|
int wideHostLen;
|
|
|
|
// Session opened, now convert the host name to Unicode so that
|
|
// we can open a connection.
|
|
if (CopyMultiToWideAlloc(pHostName,
|
|
(int) strlen(pHostName),
|
|
&pWideHostName,
|
|
&wideHostLen) == CASA_STATUS_SUCCESS)
|
|
{
|
|
// Now open connection
|
|
pSession->hConnection = WinHttpConnect(pSession->hSession,
|
|
pWideHostName,
|
|
hostPort,
|
|
0);
|
|
if (pSession->hConnection == NULL)
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to open connection, error = %d\n", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
success = true;
|
|
}
|
|
|
|
// Free the host name wide string buffer
|
|
free(pWideHostName);
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Error converting host name to wide string\n", 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to open session, error = %d\n", GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for host name\n", 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0);
|
|
}
|
|
|
|
// Clean up if we did not succeed
|
|
if (!success)
|
|
{
|
|
if (pSession)
|
|
{
|
|
if (pSession->hConnection)
|
|
WinHttpCloseHandle(pSession->hConnection);
|
|
|
|
if (pSession->hSession)
|
|
WinHttpCloseHandle(pSession->hSession);
|
|
|
|
if (pSession->pHostName)
|
|
free(pSession->pHostName);
|
|
|
|
free(pSession);
|
|
pSession = NULL;
|
|
}
|
|
}
|
|
|
|
DbgTrace(2, "-OpenRpcSession- End, pSession = %08X\n", pSession);
|
|
|
|
return pSession;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
void
|
|
CloseRpcSession(
|
|
IN RpcSession *pSession)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
DbgTrace(1, "-CloseRpcSession- Start\n", 0);
|
|
|
|
// Close the connection handle
|
|
WinHttpCloseHandle(pSession->hConnection);
|
|
|
|
// Close the session handle
|
|
WinHttpCloseHandle(pSession->hSession);
|
|
|
|
// Free hostname buffer if necessary
|
|
if (pSession->pHostName)
|
|
free(pSession->pHostName);
|
|
|
|
// Free the space allocated for the session
|
|
free(pSession);
|
|
|
|
DbgTrace(1, "-CloseRpcSession- End\n", 0);
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
static
|
|
void CALLBACK
|
|
SecureFailureStatusCallback(
|
|
IN HINTERNET hRequest,
|
|
IN DWORD_PTR *pContext,
|
|
IN DWORD internetStatus,
|
|
IN LPVOID pStatusInformation,
|
|
IN DWORD statusInformationLength)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L0
|
|
//=======================================================================--
|
|
{
|
|
DbgTrace(1, "-SecureFailureStatusCallback- Start\n", 0);
|
|
|
|
// Only deal with failures related to certificates
|
|
if (internetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
|
|
{
|
|
// Save the specific failure status
|
|
*pContext = *(DWORD*) pStatusInformation;
|
|
}
|
|
|
|
DbgTrace(1, "-SecureFailureStatusCallback- End\n", 0);
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
static
|
|
CasaStatus
|
|
InternalRpc(
|
|
IN RpcSession *pSession,
|
|
IN char *pMethod,
|
|
IN long flags,
|
|
IN char *pRequestData,
|
|
INOUT char **ppResponseData,
|
|
INOUT size_t *pResponseDataLen)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
#define RPC_TARGET_FMT_STRING "CasaAuthTokenSvc/Rpc?method=%s"
|
|
|
|
CasaStatus retStatus = CASA_STATUS_SUCCESS;
|
|
char *pRpcTarget;
|
|
LPWSTR pWideRpcTarget;
|
|
int wideRpcTargetLen;
|
|
WCHAR sendHeaders[] = L"Content-Type: text/html";
|
|
DWORD securityFailureStatusFlags;
|
|
int retriesAllowed = 1;
|
|
bool attemptRetry;
|
|
|
|
DbgTrace(1, "-InternalRpc- Start\n", 0);
|
|
|
|
// Initialize output parameter
|
|
*ppResponseData = NULL;
|
|
|
|
// Create rpc target string and convert it to a wide string
|
|
pRpcTarget = (char*) malloc(sizeof(RPC_TARGET_FMT_STRING) + strlen(pMethod));
|
|
if (pRpcTarget)
|
|
{
|
|
sprintf(pRpcTarget, RPC_TARGET_FMT_STRING, pMethod);
|
|
retStatus = CopyMultiToWideAlloc(pRpcTarget,
|
|
(int) strlen(pRpcTarget),
|
|
&pWideRpcTarget,
|
|
&wideRpcTargetLen);
|
|
if (CASA_SUCCESS(retStatus))
|
|
{
|
|
HINTERNET hRequest;
|
|
|
|
do
|
|
{
|
|
// Forget about having been told to retry
|
|
attemptRetry = false;
|
|
|
|
// Open a request handle
|
|
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);
|
|
|
|
// 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)))
|
|
{
|
|
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,
|
|
&httpCompStatus,
|
|
&httpCompStatusLen,
|
|
WINHTTP_NO_HEADER_INDEX))
|
|
{
|
|
// Check that the request completed successfully
|
|
if (memcmp(httpCompStatus, L"200", sizeof(httpCompStatus)) == 0)
|
|
{
|
|
char *pResponseData;
|
|
size_t responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE;
|
|
size_t responseDataRead = 0;
|
|
|
|
// Now read the response data, to do so we need to allocate a buffer.
|
|
pResponseData = (char*) malloc(INITIAL_RESPONSE_DATA_BUF_SIZE);
|
|
if (pResponseData)
|
|
{
|
|
char *pCurrLocation = pResponseData;
|
|
DWORD bytesRead;
|
|
|
|
do
|
|
{
|
|
bytesRead = 0;
|
|
if (WinHttpReadData(hRequest,
|
|
(LPVOID) pCurrLocation,
|
|
responseDataBufSize - responseDataRead,
|
|
&bytesRead))
|
|
{
|
|
pCurrLocation += bytesRead;
|
|
responseDataRead += bytesRead;
|
|
|
|
// Check if we need to allocate a larger buffer
|
|
if (responseDataRead == responseDataBufSize)
|
|
{
|
|
char *pTmpBuf;
|
|
|
|
// We need to upgrade the receive buffer.
|
|
//
|
|
// Do not allow the reply to exceed our maximum
|
|
if (responseDataBufSize < MAX_RPC_REPLY_SZ)
|
|
{
|
|
size_t incrementSz;
|
|
|
|
// Determine the buffer size imcrement so that the maximum rpc reply
|
|
// size is not exceeded.
|
|
if ((responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE) <= MAX_RPC_REPLY_SZ)
|
|
incrementSz = INCREMENT_RESPONSE_DATA_BUF_SIZE;
|
|
else
|
|
incrementSz = MAX_RPC_REPLY_SZ - responseDataBufSize;
|
|
|
|
pTmpBuf = (char*) malloc(responseDataBufSize + incrementSz);
|
|
if (pTmpBuf)
|
|
{
|
|
memcpy(pTmpBuf, pResponseData, responseDataBufSize);
|
|
free(pResponseData);
|
|
pResponseData = pTmpBuf;
|
|
pCurrLocation = pResponseData + responseDataBufSize;
|
|
responseDataBufSize += incrementSz;
|
|
}
|
|
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- Reply maximum exceeded\n", 0);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
}
|
|
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
|
|
{
|
|
// Failed to receive the response data, free the allocated buffer.
|
|
free(pResponseData);
|
|
}
|
|
}
|
|
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- HTTP request did not complete successfully, status = %S\n", httpCompStatus);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Unable to obtain http request completion status, error = %d\n", GetLastError());
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Unable to receive response, error = %d\n", GetLastError());
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_CONNECTION_ERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int error = GetLastError();
|
|
|
|
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;
|
|
DWORD certInfoLen = sizeof(certInfo);
|
|
|
|
// The failure was due to an invalid CN, CA, or both.
|
|
//
|
|
// Obtain information about the server certificate to give user
|
|
// the choice of accepting it.
|
|
if (WinHttpQueryOption(hRequest,
|
|
WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT,
|
|
&certInfo,
|
|
&certInfoLen)
|
|
&& certInfo.lpszSubjectInfo != NULL
|
|
&& certInfo.lpszIssuerInfo != NULL)
|
|
{
|
|
char *pSubjectInfo;
|
|
int subjectInfoLen;
|
|
|
|
// Convert the subjectInfo to multi-byte
|
|
retStatus = CopyWideToMultiAlloc(certInfo.lpszSubjectInfo,
|
|
(int) wcslen(certInfo.lpszSubjectInfo),
|
|
&pSubjectInfo,
|
|
&subjectInfoLen);
|
|
if (CASA_SUCCESS(retStatus))
|
|
{
|
|
char *pIssuerInfo;
|
|
int issuerInfoLen;
|
|
|
|
// Convert the issuerInfo to multi-byte
|
|
retStatus = CopyWideToMultiAlloc(certInfo.lpszIssuerInfo,
|
|
(int) wcslen(certInfo.lpszIssuerInfo),
|
|
&pIssuerInfo,
|
|
&issuerInfoLen);
|
|
if (CASA_SUCCESS(retStatus))
|
|
{
|
|
long invalidCertFlags = 0;
|
|
|
|
// Setup the invalid cert flags
|
|
if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
|
|
invalidCertFlags |= INVALID_CERT_CA_FLAG;
|
|
|
|
if (securityFailureStatusFlags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
|
|
invalidCertFlags |= INVALID_CERT_CN_FLAG;
|
|
|
|
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);
|
|
|
|
// 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 subjectInfo
|
|
free(pSubjectInfo);
|
|
}
|
|
|
|
// 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
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Unable to obtain server certificate struct, error = %0x\n", GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 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
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_CONNECTION_ERROR);
|
|
}
|
|
}
|
|
|
|
// Close the request handle
|
|
WinHttpCloseHandle(hRequest);
|
|
}
|
|
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--);
|
|
|
|
// Free the rpc target wide string buffer
|
|
free(pWideRpcTarget);
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0);
|
|
}
|
|
|
|
// Free buffer used to hold the rpc target string
|
|
free(pRpcTarget);
|
|
}
|
|
else
|
|
{
|
|
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 = %0X\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
CasaStatus
|
|
Rpc(
|
|
IN RpcSession *pSession,
|
|
IN char *pMethod,
|
|
IN long flags,
|
|
IN char *pRequestData,
|
|
INOUT char **ppResponseData,
|
|
INOUT size_t *pResponseDataLen)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
CasaStatus retStatus;
|
|
int retries = 0;
|
|
DWORD startTime = GetTickCount();
|
|
DWORD currentTime;
|
|
|
|
DbgTrace(1, "-Rpc- Start\n", 0);
|
|
|
|
// Retry the RPC as needed
|
|
do
|
|
{
|
|
// Check if this is a retry
|
|
if (retries != 0)
|
|
{
|
|
// This is a retry, check if we should keep retrying.
|
|
currentTime = GetTickCount();
|
|
if (currentTime > startTime)
|
|
{
|
|
if ((currentTime - startTime) > MAX_RPC_TIME_MILLISECONDS)
|
|
{
|
|
DbgTrace(1, "-Rpc- Stopping after %d retries\n", retries);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The clock must have wrapped, treat it as if no time has elapsed.
|
|
startTime = currentTime;
|
|
}
|
|
|
|
// Pause before the next retry
|
|
Sleep(MILLISECONDS_BETWEEN_RPC_RETRIES);
|
|
}
|
|
|
|
// Issue the RPC
|
|
retStatus = InternalRpc(pSession,
|
|
pMethod,
|
|
flags,
|
|
pRequestData,
|
|
ppResponseData,
|
|
pResponseDataLen);
|
|
|
|
// Account for this try
|
|
retries ++;
|
|
|
|
} while (CasaStatusCode(retStatus) == CASA_STATUS_CONNECTION_ERROR);
|
|
|
|
DbgTrace(1, "-Rpc- End, retStatus = %0X\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
CasaStatus
|
|
InitializeRpc(void)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
CasaStatus retStatus = CASA_STATUS_SUCCESS;
|
|
|
|
DbgTrace(1, "-InitializeRpc- Start\n", 0);
|
|
|
|
// Nothing to do for windows
|
|
|
|
DbgTrace(1, "-InitializeRpc- End, retStatus = %08X\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
void
|
|
UnInitializeRpc(void)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
DbgTrace(1, "-UnInitializeRpc- Start\n", 0);
|
|
|
|
// Nothing to do for windows
|
|
|
|
DbgTrace(1, "-UnInitializeRpc- End\n", 0);
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
|