524 lines
18 KiB
C
524 lines
18 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
|
|
|
|
//===[ 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;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
RpcSession*
|
|
OpenRpcSession(
|
|
IN char *pHostName,
|
|
IN uint16_t hostPort)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
RpcSession *pSession;
|
|
|
|
DbgTrace(1, "-OpenRpcSession- Start\n", 0);
|
|
|
|
// Allocate space for the session
|
|
pSession = (RpcSession*) malloc(sizeof(*pSession));
|
|
if (pSession)
|
|
{
|
|
// Zero the session structure
|
|
memset(pSession, 0, sizeof(*pSession));
|
|
|
|
// 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());
|
|
|
|
// Free allocated resources
|
|
WinHttpCloseHandle(pSession->hSession);
|
|
free(pSession);
|
|
pSession = NULL;
|
|
}
|
|
|
|
// Free the host name wide string buffer
|
|
free(pWideHostName);
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Error converting host name to wide string\n", 0);
|
|
|
|
// Free allocated resources
|
|
WinHttpCloseHandle(pSession->hSession);
|
|
free(pSession);
|
|
pSession = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to open session, error = %d\n", GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0);
|
|
}
|
|
|
|
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 the space allocated for the session
|
|
free(pSession);
|
|
|
|
DbgTrace(1, "-CloseRpcSession- End\n", 0);
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
static
|
|
CasaStatus
|
|
InternalRpc(
|
|
IN RpcSession *pSession,
|
|
IN char *pMethod,
|
|
IN bool secure,
|
|
IN char *pRequestData,
|
|
INOUT char **ppResponseData,
|
|
INOUT int *pResponseDataLen)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
CasaStatus retStatus = CASA_STATUS_SUCCESS;
|
|
char rpcTarget[256];
|
|
LPWSTR pWideRpcTarget;
|
|
int wideRpcTargetLen;
|
|
WCHAR sendHeaders[] = L"Content-Type: text/html";
|
|
|
|
DbgTrace(1, "-InternalRpc- Start\n", 0);
|
|
|
|
// Initialize output parameter
|
|
*ppResponseData = NULL;
|
|
|
|
// Create rpc target string and convert it to a wide string
|
|
sprintf(rpcTarget, "CasaAuthTokenSvc/Rpc?method=%s", pMethod);
|
|
retStatus = CopyMultiToWideAlloc(rpcTarget,
|
|
(int) strlen(rpcTarget),
|
|
&pWideRpcTarget,
|
|
&wideRpcTargetLen);
|
|
if (CASA_SUCCESS(retStatus))
|
|
{
|
|
HINTERNET hRequest;
|
|
|
|
// Open a request handle
|
|
hRequest = WinHttpOpenRequest(pSession->hConnection,
|
|
L"POST",
|
|
pWideRpcTarget,
|
|
NULL,
|
|
WINHTTP_NO_REFERER,
|
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
|
secure? WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE : WINHTTP_FLAG_REFRESH);
|
|
if (hRequest)
|
|
{
|
|
int reqDataLen = (int) strlen(pRequestData);
|
|
|
|
// Send the request
|
|
if (WinHttpSendRequest(hRequest,
|
|
sendHeaders,
|
|
-1,
|
|
pRequestData,
|
|
reqDataLen,
|
|
reqDataLen,
|
|
0))
|
|
{
|
|
// 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;
|
|
int responseDataBufSize = INITIAL_RESPONSE_DATA_BUF_SIZE;
|
|
int 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
|
|
pTmpBuf = (char*) malloc(responseDataBufSize + INCREMENT_RESPONSE_DATA_BUF_SIZE);
|
|
if (pTmpBuf)
|
|
{
|
|
memcpy(pTmpBuf, pResponseData, responseDataBufSize);
|
|
free(pResponseData);
|
|
pResponseData = pTmpBuf;
|
|
pCurrLocation = pResponseData + responseDataBufSize;
|
|
responseDataBufSize += INCREMENT_RESPONSE_DATA_BUF_SIZE;
|
|
}
|
|
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
|
|
{
|
|
// 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_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int error = GetLastError();
|
|
|
|
DbgTrace(0, "-InternalRpc- Unsuccessful send http request, error = %d\n", error);
|
|
if (error == ERROR_WINHTTP_CANNOT_CONNECT)
|
|
{
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_AUTH_SERVER_UNAVAILABLE);
|
|
}
|
|
else
|
|
{
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_AUTHTOKEN,
|
|
CASA_STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Free the rpc target wide string buffer
|
|
free(pWideRpcTarget);
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-InternalRpc- Error converting method name to wide string\n", 0);
|
|
}
|
|
|
|
DbgTrace(1, "-InternalRpc- End, retStatus = %d\n", retStatus);
|
|
|
|
return retStatus;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
CasaStatus
|
|
Rpc(
|
|
IN RpcSession *pSession,
|
|
IN char *pMethod,
|
|
IN bool secure,
|
|
IN char *pRequestData,
|
|
INOUT char **ppResponseData,
|
|
INOUT int *pResponseDataLen)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Notes:
|
|
//
|
|
// L2
|
|
//=======================================================================--
|
|
{
|
|
CasaStatus retStatus;
|
|
int retries = 0;
|
|
|
|
DbgTrace(1, "-Rpc- Start\n", 0);
|
|
|
|
// Retry the RPC as needed
|
|
do
|
|
{
|
|
// Issue the RPC
|
|
retStatus = InternalRpc(pSession,
|
|
pMethod,
|
|
secure,
|
|
pRequestData,
|
|
ppResponseData,
|
|
pResponseDataLen);
|
|
|
|
// Account for this try
|
|
retries ++;
|
|
|
|
} while (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE
|
|
&& retries < MAX_RPC_RETRIES);
|
|
|
|
DbgTrace(1, "-Rpc- End, retStatus = %d\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;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
|