📄 win32district.c
字号:
/* Copyright 2003-2006, Voltage Security, all rights reserved.
*/
#include "vibe.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "vsdistrict.h"
#include "derhelp.h"
#include "oidlist.h"
#include "ibe.h"
#include "vtime.h"
#include "errorctx.h"
#if VOLT_OS == VOLT_WINDOWS_32
#include <windows.h>
#include <tchar.h>
#include <wininet.h>
#include <stdio.h>
#include <process.h>
typedef struct
{
HINTERNET hReq;
int err;
const char *header;
const char *postData;
} sendRequestDataT;
typedef struct
{
HINTERNET hReq;
char *data;
ULONG space;
VoltLibCtx *libCtx;
} doReadDataT;
static unsigned __stdcall DoSendRequest (
LPVOID pParam
);
static unsigned __stdcall DoReadData (
LPVOID pParam
);
static unsigned __stdcall DoCheckNetwork (
LPVOID pParam
);
static int ConfirmConnected (
HWND uiOwner
);
static unsigned __stdcall DoSendRequest (
LPVOID pParam
)
{
sendRequestDataT *data = (sendRequestDataT *)pParam;
HttpSendRequestA (
data->hReq, data->header,
(data->header != (void *) 0 ? strlen(data->header) : 0),
(void *)data->postData,
(data->postData != (void *) 0 ? strlen(data->postData) : 0));
data->err = GetLastError();
return (0);
}
/* This is a callback, a Windows function will call this routine.
* Therefore, we'll treat this as a Windows function call and not log
* any errors.
*/
static unsigned __stdcall DoReadData (
LPVOID pParam
)
{
ULONG num, len, read, space;
VoltLibCtx *libCtx;
doReadDataT *data = (doReadDataT *)pParam;
libCtx = data->libCtx;
space = data->space;
len = 0;
num = 1;
while (num > 0)
{
InternetQueryDataAvailable (data->hReq, &num, 0, 0);
if ((len + num + 1) > space)
{
space = len + num + 1;
data->data = (char *)Z2Realloc (data->data, space);
if (data->data == (char *)0)
{
data->space = 0;
return (-1);
}
data->space = space;
}
if (!InternetReadFile (data->hReq, data->data + len, num, &read))
{
Z2Free (data->data);
data->data = (char *)0;
data->space = 0;
return (-1);
}
len += read;
}
data->data[len] = 0;
return (0);
}
static unsigned __stdcall DoCheckNetwork( LPVOID pParam )
{
return (0);
}
static int ConfirmConnected (
HWND uiOwner
)
{
return (0);
}
int mDoHTTP (
VoltHttpRequestInfo *requestInfo,
char **response,
int *responseCode,
unsigned char *url,
int allowBadCert,
unsigned char *trustStore,
unsigned long timeOut,
void *appData
)
{
int status, sysRet, tries, err;
unsigned long len;
HINTERNET hInt = (HINTERNET)0;
HINTERNET hCon = (HINTERNET)0;
HINTERNET hReq = (HINTERNET)0;
char header[128];
char *headerPtr;
unsigned int threadID;
HANDLE hThread = (HANDLE)0;
VtWinINetTransportInfo *transInfo = (VtWinINetTransportInfo *)0;
VoltLibCtx *libCtx = (VoltLibCtx *)0;
VoltTransportCtx *transCtx = (VoltTransportCtx *)0;
VoltHttpRequestInfoPost *postInfo = (VoltHttpRequestInfoPost *)0;
VoltIdentityObject *idObj = (VoltIdentityObject *)0;
sendRequestDataT *reqData = (sendRequestDataT *)0;
doReadDataT *readData = (doReadDataT *)0;
HWND uiOwner = (HWND)0;
char safeHost[512];
char safeURL[512];
char *relative_url = (char *)0;
char *hostName = (char *)0;
unsigned char *parsedURL = (unsigned char *)0;
unsigned char *postData = (unsigned char *)0;
URL_COMPONENTSA URLparts ;
/* HTTPS is the default
*/
INTERNET_PORT serverPort = INTERNET_DEFAULT_HTTPS_PORT;
DWORD flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE ;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
/* First check the type of request and set some variables accordingly
*/
if (requestInfo->requestType == VOLT_REQUEST_TYPE_GET)
{
libCtx = (VoltLibCtx *)requestInfo->requestData;
}
else
{
postInfo = (VoltHttpRequestInfoPost *)requestInfo->requestData;
transCtx = postInfo->transCtx;
idObj = postInfo->idObj;
libCtx = (VoltLibCtx *)(transCtx->voltObject.libraryCtx);
postData = postInfo->postData;
}
/* Get the user specified values from the app data.
* if appData is NULL use the default values.
*/
if (appData != (void *)0)
uiOwner = (HANDLE)appData;
/* First parse the URL to get the protocol, server and
* relative resource locations. Following determines what values
* are extracted from the URL.
*/
URLparts.dwStructSize = sizeof(URLparts);
URLparts.dwSchemeLength = 1;
URLparts.dwHostNameLength = 1;
URLparts.dwUserNameLength = 1;
URLparts.dwPasswordLength = 1;
URLparts.dwUrlPathLength = 1;
URLparts.dwExtraInfoLength = 1;
/* Initialize the values to NULL. These will be filled when
* InternetCrackUrl function is called.
*/
URLparts.lpszScheme = NULL;
URLparts.lpszHostName = NULL;
URLparts.lpszUserName = NULL;
URLparts.lpszPassword = NULL;
URLparts.lpszUrlPath = NULL;
URLparts.lpszExtraInfo = NULL;
sysRet = 0;
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
reqData = (sendRequestDataT *)Z3Malloc (sizeof (sendRequestDataT));
if (reqData == (sendRequestDataT *)0 )
goto endWin32DistrictFunction;
Z2Memset (reqData, 0, sizeof (sendRequestDataT));
VOLT_SET_FNCT_LINE (fnctLine)
readData = (doReadDataT *)Z3Malloc (sizeof (doReadDataT));
if (readData == (doReadDataT *) 0 )
goto endWin32DistrictFunction;
Z2Memset (readData, 0, sizeof (doReadDataT));
readData->libCtx = libCtx;
status = 0;
VOLT_SET_FNCT_LINE (fnctLine)
if (!InternetCrackUrlA (url, 0, 0, &URLparts))
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
/* Allocate the memory to hold the parsed info
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
parsedURL = (unsigned char *)Z2Malloc (
URLparts.dwHostNameLength + URLparts.dwUrlPathLength + 2, 0);
if (parsedURL == (unsigned char *)0 )
goto endWin32DistrictFunction;
status = 0;
hostName = parsedURL ;
relative_url = parsedURL + URLparts.dwHostNameLength + 1;
Z2Memcpy (hostName, URLparts.lpszHostName, URLparts.dwHostNameLength);
hostName [URLparts.dwHostNameLength] = 0 ;
Z2Memcpy (relative_url , URLparts.lpszUrlPath, URLparts.dwUrlPathLength);
relative_url[URLparts.dwUrlPathLength] = 0;
/* Canonicalize the URLs just in case they have unsafe chars
*/
VOLT_SET_FNCT_LINE (fnctLine)
len = sizeof (safeHost);
if (!InternetCanonicalizeUrlA (hostName, safeHost, &len, 0))
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
VOLT_SET_FNCT_LINE (fnctLine)
len = sizeof (safeURL);
if (!InternetCanonicalizeUrlA (relative_url, safeURL, &len, 0))
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
/* Set the type of connection and Escape both
* hostname and relative path.
*/
if (URLparts.nPort == 80)
{
flags = INTERNET_FLAG_KEEP_CONNECTION ;
serverPort = INTERNET_DEFAULT_HTTP_PORT;
}
VOLT_SET_FNCT_LINE (fnctLine)
hInt = InternetOpenA (
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)",
INTERNET_OPEN_TYPE_PRECONFIG, (void *) 0, (void *) 0, 0);
if (!hInt)
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
VOLT_SET_FNCT_LINE (fnctLine)
hCon = InternetConnectA (
hInt, safeHost, serverPort, (void *) 0, (void *) 0,
INTERNET_SERVICE_HTTP, 0, 0);
if (!hCon)
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
if (postData != (void *) 0)
{
sprintf (header, "Content-Type: application/x-www-form-urlencoded");
headerPtr = header;
}
else
{
headerPtr = (void *)0;
}
tries = 0;
reopen:
if (requestInfo->requestType == VOLT_REQUEST_TYPE_POST)
{
VOLT_SET_FNCT_LINE (fnctLine)
hReq = HttpOpenRequestA (
hCon, "POST", safeURL, (void *) 0, (void *) 0, (void *) 0,
flags, 0);
}
else
{
VOLT_SET_FNCT_LINE (fnctLine)
hReq = HttpOpenRequestA (
hCon, "GET", safeURL, (void *) 0, (void *) 0, (void *) 0,
flags, 0);
}
if (!hReq)
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
resend:
reqData->hReq = hReq;
reqData->postData = postData;
reqData->header = headerPtr;
VOLT_SET_FNCT_LINE (fnctLine)
hThread = (HANDLE)CreateThread (
(void *) 0, 0, DoSendRequest, reqData, 0, &threadID);
if (hThread == (void *) 0)
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
VOLT_SET_FNCT_LINE (fnctLine)
if (WaitForSingleObject (hThread, timeOut) != WAIT_OBJECT_0)
{
TerminateThread (hThread, 0);
CloseHandle (hThread);
sysRet = ERROR_INTERNET_TIMEOUT;
goto endWin32DistrictFunction;
}
CloseHandle (hThread);
err = reqData->err;
/* This part needs (a lot of) explanation:
* There are two cases in which we need to call InternetErrorDlg : bad
* auth and other (e.g. cert probs)
* 1) In the bad auth case, if we try to just go back to the
* HttpSendRequest and use the same handle, wininet for some reason
* doesn't re-POST the data. So we need to close the handle, and
* start again from HttpOpenRequest. Fortunately, Windows caches the
* credentials on the machine, not in hReq, so this works.
* 2) Unfortunately, for the other case, e.g. invalid CA, if the user
* hits OK, we still need to go retry, but wininet caches the user's
* OK selection in hReq, so if we close it and reopen, it keeps
* asking the user over and over again.
* Fortunately for us, HttpSendRequest returns two different things in
* case 1 and case 2. In case 1, it returns TRUE, so for that case we
* start over at HttpOpenRequest if InternetErrorDlg returns
* ERROR_INTERNET_FORCE_RETRY (which basically means the user entered
* their pass). In case 2, it returns FALSE, so we just go back to
* HttpSendRequest if InternetErrorDlg retursn ERROR_SUCCESS.
*
* Clearly, WinInet is very broken. I believe all of the above to be
* true, but it's very possible that there are cases I didn't account
* for. Time will tell.
*/
if (tries < 3)
{
/* Last one is OCSP failure
*/
if ( (err == ERROR_INTERNET_INVALID_CA) ||
(err == ERROR_INTERNET_SEC_CERT_CN_INVALID) ||
(err == ERROR_INTERNET_SEC_CERT_DATE_INVALID) ||
(err == ERROR_INTERNET_SECURITY_CHANNEL_ERROR) )
{
if (allowBadCert == 1)
{
VOLT_SET_FNCT_LINE (fnctLine)
sysRet = InternetErrorDlg (
uiOwner, hReq, err,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, (void *) 0);
if (sysRet == ERROR_CANCELLED)
goto endWin32DistrictFunction;
goto resend;
}
else
{
sysRet = err;
goto endWin32DistrictFunction;
}
}
sysRet = InternetErrorDlg (
uiOwner, hReq, err,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, (void *) 0);
if (sysRet == ERROR_INTERNET_FORCE_RETRY)
{
tries++;
InternetCloseHandle (hReq);
goto reopen;
}
else if ( (sysRet == ERROR_SUCCESS) &&
(err == ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR) )
{
goto resend;
}
}
VOLT_SET_FNCT_LINE (fnctLine)
len = sizeof (int);
if (!HttpQueryInfo (
hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, responseCode,
&len, (void*) 0))
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
if (*responseCode == 0)
{
/* We get here on connection errors, and err will actually contain
* the error we want.
*/
sysRet = err;
goto endWin32DistrictFunction;
}
readData->hReq = hReq;
VOLT_SET_FNCT_LINE (fnctLine)
hThread = (HANDLE)CreateThread (
(void*) 0, 0, DoReadData, readData, 0, &threadID);
if (hThread == (void*) 0)
{
sysRet = GetLastError ();
goto endWin32DistrictFunction;
}
VOLT_SET_FNCT_LINE (fnctLine)
if (WaitForSingleObject (hThread, timeOut) != WAIT_OBJECT_0)
{
TerminateThread (hThread, 0);
CloseHandle (hThread);
sysRet = ERROR_INTERNET_TIMEOUT;
goto endWin32DistrictFunction;
}
CloseHandle (hThread);
*response = readData->data;
readData->data = (char *)0;
sysRet = 0;
endWin32DistrictFunction:
/* If status is 0, but sysRet is not, figure out what status should
* be.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
if (status == 0)
{
VOLT_SET_ERROR_TYPE (
errorType, VT_ERROR_TYPE_PRIMARY | VT_ERROR_TYPE_OUTSIDE)
switch (sysRet)
{
case 0:
break;
case ERROR_INTERNET_INVALID_CA:
case ERROR_INTERNET_SEC_CERT_CN_INVALID:
case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
case ERROR_INTERNET_SECURITY_CHANNEL_ERROR:
status = VT_ERROR_DISTRICT_NOT_VERIFIED;
break;
case ERROR_INTERNET_INVALID_URL:
case ERROR_INTERNET_UNRECOGNIZED_SCHEME:
case ERROR_INTERNET_NAME_NOT_RESOLVED:
status = VT_ERROR_URL;
break;
case ERROR_INTERNET_CANNOT_CONNECT :
case ERROR_INTERNET_CONNECTION_ABORTED :
case ERROR_INTERNET_NO_DIRECT_ACCESS :
case ERROR_INTERNET_CONNECTION_RESET :
status = VT_ERROR_NETWORK_CONNECT;
break;
case ERROR_INTERNET_TIMEOUT :
status = VT_ERROR_TIMEOUT;
break;
default:
status = VT_ERROR_UNKNOWN_DISTRICT;
}
}
else
{
/* If status is not 0, then sysRet is. Set sysRet to status so that
* we can return log sysRet as the error.
*/
sysRet = status;
}
if (reqData != (sendRequestDataT *)0 )
Z2Free (reqData);
if (parsedURL != (unsigned char *)0 )
Z2Free (parsedURL);
if (readData != (doReadDataT *)0 )
{
if (readData->data != (char *)0)
Z2Free (readData->data);
Z2Free (readData);
}
InternetCloseHandle (hReq);
InternetCloseHandle (hCon);
InternetCloseHandle (hInt);
if (status == 0)
return (0);
/* If the error is a system error, it is in sysRet and errorType is
* set to OUTSIDE. If the error is toolkit, sysRet was set to status,
* so it does indeed contain the appropriate value for the call to
* Log. And errorType is PRIMARY.
*/
VOLT_LOG_ERROR (
(VtLibCtx)libCtx, sysRet, errorType, fnctLine, "mDoHTTP", (char *)0)
return (status);
}
#endif /* VOLT_OS == VOLT_WINDOWS_32 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -