📄 win32unsecure.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"
#if VOLT_OS == VOLT_WINDOWS_32
#include <windows.h>
#include <tchar.h>
#include <wininet.h>
//#define _MT
#include <process.h>
/* This file contains an alternate implementation of DoHTTP. Changes to
* the "true" version may need to be reflected here. It is less
* efficient to have two copies of code, but because this is an
* unsecure version, we'll live with the inconvenience.
*/
typedef struct
{
HINTERNET hReq;
int err;
const char *header;
const char *postData;
} sendRequestDataT;
typedef struct
{
HINTERNET hReq;
char *data;
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;
}
static unsigned __stdcall DoReadData (
LPVOID pParam
)
{
int max, len;
ULONG num, read;
int changed;
VoltLibCtx *libCtx;
doReadDataT *data = (doReadDataT *)pParam;
libCtx = data->libCtx;
max = 512;
data->data = (char *)Z2Realloc (data->data, sizeof(char) * (max + 1));
len = 0;
num = 1;
while (num > 0)
{
InternetQueryDataAvailable (data->hReq, &num, 0, 0);
changed = 0;
while ((ULONG)len + num > (ULONG) max)
{
max *= 2;
changed = 1;
}
if (changed == 1)
data->data = (char *)Z2Realloc (data->data, sizeof(char) * (max + 1));
if (!InternetReadFile (data->hReq, data->data + len, num, &read))
{
Z2Free(data->data);
data->data = (char *)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 UnsecureDoHTTP (
VtLibCtx libraryCtx,
char **response,
int *responseCode,
const unsigned char *url,
const char *postData,
int allowBadCert,
unsigned char *trustStore,
void *appData
)
{
HINTERNET hInt, hCon, hReq;
int ret, tries, err , opt;
unsigned long len, size;
char header[128];
char *headerPtr;
unsigned int threadID;
HANDLE hThread;
sendRequestDataT *reqData;
doReadDataT *readData = (doReadDataT *)0;
HWND uiOwner;
char safeHost[512];
char safeURL[512];
char *relative_url = NULL;
char *hostName = NULL;
unsigned char *parsedURL = (unsigned char *)0;
URL_COMPONENTSA URLparts ;
/* HTTPS is the default
*/
INTERNET_PORT serverPort = INTERNET_DEFAULT_HTTPS_PORT;
VoltLibCtx *libCtx = (VoltLibCtx *)libraryCtx;
if (appData != (void *) 0)
uiOwner = (HWND)appData;
else
uiOwner = 0;
/* 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;
if (!InternetCrackUrlA (url, 0, 0, &URLparts) )
{
ret = GetLastError();
goto end;
}
/* Allocate the memory to hold the parsed info
*/
parsedURL = (unsigned char *)Z2Malloc (
URLparts.dwHostNameLength + URLparts.dwUrlPathLength + 2,
0);
if (parsedURL == (unsigned char *)0 )
{
ret = VT_ERROR_MEMORY;
goto end;
}
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
*/
len = sizeof (safeHost);
if (!InternetCanonicalizeUrlA (hostName, safeHost, &len, 0))
{
ret = GetLastError();
goto end;
}
len = sizeof (safeURL);
if (!InternetCanonicalizeUrlA (relative_url, safeURL, &len, 0))
{
ret = GetLastError();
goto end;
}
/* Set the type of connection and Escape both
* hostname and relative path.
*/
if (URLparts.nPort == 80)
serverPort = INTERNET_DEFAULT_HTTP_PORT;
ret = ConfirmConnected (uiOwner);
if (ret != 0)
goto end;
hInt = InternetOpenA (
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)",
INTERNET_OPEN_TYPE_PRECONFIG, (void *) 0, (void *) 0, 0);
if (!hInt)
{
ret = GetLastError ();
goto end;
}
hCon = InternetConnectA (
hInt, safeHost, serverPort, (void *) 0, (void *) 0,
INTERNET_SERVICE_HTTP, 0, 0);
if (!hCon)
{
ret = GetLastError ();
goto end;
}
if (postData != (void *) 0)
{
sprintf (header, "Content-Type: application/x-www-form-urlencoded");
headerPtr = header;
}
else
{
headerPtr = (void *) 0;
}
tries = 0;
reopen:
if (postData != (void *) 0)
hReq = HttpOpenRequestA (
hCon, "POST", safeURL, (void *) 0, (void *) 0, (void *) 0,
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE, 0);
else
hReq = HttpOpenRequestA (
hCon, "GET", safeURL, (void *) 0, (void *) 0, (void *) 0,
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE, 0);
if (!hReq)
{
ret = GetLastError ();
goto end;
}
resend:
reqData = (sendRequestDataT *)Z2Malloc (sizeof(sendRequestDataT), VOLT_MEMORY_SENSITIVE);
if (reqData == (sendRequestDataT *)0 )
{
ret = VT_ERROR_MEMORY;
goto end;
}
reqData->hReq = hReq;
reqData->postData = postData;
reqData->header = headerPtr;
hThread = (HANDLE)CreateThread (
(void *) 0, 0, DoSendRequest, reqData, 0, &threadID);
if (hThread == (void *) 0)
{
ret = GetLastError ();
goto end;
}
if (WaitForSingleObject (hThread, 30000) != WAIT_OBJECT_0)
{
TerminateThread (hThread, 0);
CloseHandle (hThread);
ret = ERR_HTTP_TIMEOUT_SEND_REQUEST;
goto end;
}
CloseHandle (hThread);
err = reqData->err;
if (reqData != (sendRequestDataT *)0 )
Z2Free (reqData);
/* 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)
{
size = sizeof(opt);
InternetQueryOption (
hReq, INTERNET_OPTION_SECURITY_FLAGS, &opt, &size);
opt |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
opt |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
opt |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
opt |= SECURITY_FLAG_IGNORE_REVOCATION;
ret = InternetSetOption (
hReq, INTERNET_OPTION_SECURITY_FLAGS, &opt, sizeof(opt));
goto resend;
}
else
{
ret = err;
goto end;
}
}
//gDummyWindow->SetWindowPos (
// HWND_TOPMOST, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE);
ret = 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 (ret == ERROR_INTERNET_FORCE_RETRY)
{
tries++;
InternetCloseHandle (hReq);
goto reopen;
}
else if (ret == ERROR_SUCCESS &&
err == ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR)
{
goto resend;
}
}
/* I think I should probably do this here, but this is too big a change
* to put in right now. Without this, we get invalid response received
* on some errors rather than can't connect to server. One problem with
* just doing this is that I think in auth failed cases, err will be
* != 0, but we want to do the HttpQueryInfo and get back the
* responseCode. One other option would be to check if
* *responseCode ==0 after the HttpQueryInfo, this might be safer.
*/
// if (err != 0)
// return -1;
len = sizeof (int);
if (!HttpQueryInfo (
hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, responseCode,
&len, (void*) 0))
{
ret = GetLastError ();
goto end;
}
if (*responseCode == 0)
{
/* We get here on connection errors, and err will actually contain
* the error we want.
*/
ret = err;
goto end;
}
readData = (doReadDataT *)Z2Malloc (
sizeof(doReadDataT), VOLT_MEMORY_SENSITIVE);
if (readData == (doReadDataT *) 0 )
{
ret = VT_ERROR_MEMORY;
goto end;
}
readData->data = (char *)0;
readData->hReq = hReq;
readData->libCtx = libCtx;
hThread = (HANDLE)CreateThread (
(void*) 0, 0, DoReadData, readData, 0, &threadID);
if (hThread == (void*) 0)
{
ret = GetLastError ();
goto end;
}
if (WaitForSingleObject (hThread, 30000) != WAIT_OBJECT_0)
{
TerminateThread (hThread, 0);
CloseHandle (hThread);
ret = ERR_HTTP_TIMEOUT_READ_DATA;
goto end;
}
CloseHandle (hThread);
*response = readData->data;
ret = 0;
end:
if (ret != 0)
{
if (readData != (doReadDataT *)0 )
{
if (readData->data != (char *)0)
Z2Free (readData->data);
}
}
if (parsedURL != (unsigned char *)0 )
Z2Free (parsedURL);
if (readData != (doReadDataT *)0 )
Z2Free (readData);
InternetCloseHandle (hReq);
InternetCloseHandle (hCon);
InternetCloseHandle (hInt);
// Flush any existing credentials
//InternetSetOption ((void *) 0, INTERNET_OPTION_END_BROWSER_SESSION, (void *) 0, 0L);
return ret;
}
#endif /* VOLT_OS == VOLT_WINDOWS_32 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -