Windows2003-3790/inetcore/wininet/common/util.cxx
2020-09-30 16:53:55 +02:00

2887 lines
70 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
util.cxx
Abstract:
Contains utility functions
Contents:
new
delete
NewString
CatString
ResizeBuffer
_memrchr
strnistr
PrivateStrChr
PlatformType
PlatformSupport
GetTimeoutValue
ProbeReadBuffer
ProbeWriteBuffer
ProbeAndSetDword
ProbeString
LoadDllEntryPoints
UnloadDllEntryPoints
MapInternetError
CalculateHashValue
GetCurrentGmtTime
GetFileExtensionFromUrl
CheckExpired
FTtoString
PrintFileTimeInInternetFormat
InternetSettingsChanged
RefreshSslState
CertHashToStr
ConvertSecurityInfoIntoCertInfoStruct
FormatCertInfo
UnicodeToUtf8
CountUnicodeToUtf8
ConvertUnicodeToUtf8
StringContainsHighAnsi
IsAddressValidIPString
IsInGUIModeSetup
Author:
Richard L Firth (rfirth) 31-Oct-1994
Revision History:
31-Oct-1994 rfirth
Created
--*/
#include <wininetp.h>
#if !defined(PAGE_SIZE)
#define PAGE_SIZE 4096
#endif
#define DEFAULT_MAX_EXTENSION_LENGTH 8
#pragma warning(disable: 4102)
//
// private prototypes
//
//
// functions
//
void * __cdecl operator new(size_t Size) {
return (void *)ALLOCATE_FIXED_MEMORY((UINT)Size);
}
void __cdecl operator delete(void * Pointer) {
FREE_MEMORY((HLOCAL)Pointer);
}
LPSTR
NewString(
IN LPCSTR lpszIn,
IN DWORD dwLen
)
/*++
Routine Description:
kind of version of strdup() but using LocalAlloc to allocate memory
Arguments:
String - pointer to string to make copy of
Return Value:
LPSTR
Success - pointer to duplicated string
Failure - NULL
--*/
{
int len = (dwLen ? dwLen : strlen(lpszIn));
LPSTR lpszOut;
if (lpszOut = (LPSTR)ALLOCATE_FIXED_MEMORY(len+1)) {
memcpy(lpszOut, lpszIn, len);
*(lpszOut + len) = '\0';
}
return lpszOut;
}
LPWSTR
NewStringW(
IN LPCWSTR lpszIn,
IN DWORD dwLen
)
/*++
Routine Description:
kind of version of strdup() but using LocalAlloc to allocate memory
Arguments:
String - pointer to string to make copy of
Return Value:
LPSTR
Success - pointer to duplicated string
Failure - NULL
--*/
{
int len = (dwLen ? dwLen : lstrlenW(lpszIn));
LPWSTR lpszOut;
if (lpszOut = (LPWSTR)ALLOCATE_FIXED_MEMORY((sizeof(WCHAR)*(len+1)))) {
memcpy(lpszOut, lpszIn, len*sizeof(WCHAR));
*(lpszOut + len) = L'\0';
}
return lpszOut;
}
/*++
Routine Description:
kind of version of strcat() but using LocalAlloc to allocate memory
Arguments:
strings to concatenate
Return Value:
LPSTR
Success - pointer to duplicated string
Failure - NULL
--*/
LPSTR
CatString (
IN LPCSTR lpszLeft,
IN LPCSTR lpszRight
)
{
int cbLeft = strlen(lpszLeft);
int cbRight = strlen(lpszRight) + 1; // include null termination
LPSTR lpszOut;
if (lpszOut = (LPSTR) ALLOCATE_FIXED_MEMORY (cbLeft + cbRight)) {
memcpy (lpszOut, lpszLeft, cbLeft);
memcpy (lpszOut + cbLeft, lpszRight, cbRight);
}
return lpszOut;
}
HLOCAL
ResizeBuffer(
IN HLOCAL BufferHandle,
IN DWORD Size,
IN BOOL Moveable
)
/*++
Routine Description:
Allocate, reallocate or free a buffer. If the buffer is moveable memory
then it must be unlocked. If reallocating, the buffer can be grown or
shrunk, depending on the current and required sizes
Caveat Programmer:
Regardless of whether a pre-existing buffer is moveable or fixed memory,
it will be reallocated with the LMEM_MOVEABLE flag, possibly causing the
output pointer to be different from the pre-existing pointer
Arguments:
BufferHandle - current handle of memory buffer. If NULL, a buffer will
be allocated
Size - size of buffer to allocate (or shrink to). If 0, the
buffer will be freed
Moveable - if TRUE and allocating memory then allocates a moveable
memory buffer, else fixed
Return Value:
HLOCAL
Success - handle of moveable memory buffer
Failure - NULL;
--*/
{
INET_ASSERT(!Moveable);
if (BufferHandle == NULL) {
//
// don't allocate anything if no size - LocalAlloc() will return pointer
// to memory object marked as discarded if we request a zero-length
// moveable buffer. But I know that if Size is also 0, I don't want a
// buffer at all, discarded or otherwise
//
if (Size != 0) {
BufferHandle = ALLOCATE_MEMORY(Moveable ? LMEM_MOVEABLE : LMEM_FIXED, Size);
}
} else if (Size == 0) {
BufferHandle = FREE_MEMORY(BufferHandle);
INET_ASSERT(BufferHandle == NULL);
} else {
HLOCAL hNewBuff = REALLOCATE_MEMORY(BufferHandle, Size, LMEM_MOVEABLE);
if(!hNewBuff)
{
FREE_MEMORY(BufferHandle);
}
BufferHandle = hNewBuff;
}
return BufferHandle;
}
LPSTR
_memrchr(
IN LPSTR lpString,
IN CHAR cTarget,
IN INT iLength
)
/*++
Routine Description:
Reverse find character in string
Arguments:
lpString - pointer to string in which to locate character
cTarget - target character to find
iLength - length of string
Return Value:
LPSTR - pointer to located character or NULL
--*/
{
for (--iLength; (iLength >= 0) && (lpString[iLength] != cTarget); --iLength) {
//
// empty loop
//
}
return (iLength < 0) ? NULL : &lpString[iLength];
}
LPSTR
strnistr(
IN LPSTR str1,
IN LPSTR str2,
IN DWORD Length
)
/*++
Routine Description:
Case-insensitive search for substring
Arguments:
str1 - string to search in
str2 - substring to find
Length - of str1
Return Value:
LPSTR - pointer to located str2 in str1 or NULL
--*/
{
if (!*str2) {
return str1;
}
for (LPSTR cp = str1; *cp && Length; ++cp, --Length) {
LPSTR s1 = cp;
LPSTR s2 = str2;
DWORD l2 = Length;
while (*s1 && *s2 && l2 && (toupper(*s1) == toupper(*s2))) {
++s1;
++s2;
--l2;
}
if (!*s2) {
return cp;
}
if (!l2) {
break;
}
}
return NULL;
}
LPSTR
FASTCALL
PrivateStrChr(
IN LPCSTR lpStart,
IN WORD wMatch
)
/*++
Routine Description:
Find first occurrence of character in string
Private implimentation of StrChrA, this code is based on
a code snipet from ShlWapi, but by placing it here,
we can remove the extra NLS support that was needed
in SHLWAPI. This piece of code is over twice as fast
as the call into SHLWAPI.
Arguments:
lpStart - points to start of null terminated string
wMatch - the character to match
Return Value:
LPSTR - ptr to the first occurrence of ch in str, NULL if not found.
--*/
{
for ( ; *lpStart; lpStart++)
{
if ((BYTE)*lpStart == LOBYTE(wMatch)) {
return((LPSTR)lpStart);
}
}
return (NULL);
}
DWORD
GetTickCountWrap()
{
#ifdef DEBUG_GETTICKCOUNT
static BOOL fInit = FALSE;
static DWORD dwDelta = 0;
static DWORD dwBasis = 0;
if (!fInit)
{
HKEY clientKey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
0, // reserved
KEY_QUERY_VALUE,
&clientKey))
{
DWORD dwSize = sizeof(dwDelta);
RegQueryValueEx(clientKey, "RollOverDelta", NULL, NULL, (LPBYTE)&dwDelta, &dwSize);
}
dwBasis = GetTickCount();
fInit = TRUE;
}
DWORD dwResult = GetTickCount() - dwBasis + dwDelta;
return dwResult;
#else
return GetTickCount();
#endif
}
DWORD
PlatformType(
IN OUT LPDWORD lpdwVersion5os
)
/*++
Routine Description:
Returns the platform type based on the operating system information. We use
our own platform types
Arguments:
lpdwVersion5os - optional pointer to value, set to TRUE if we on NT 5
Return Value:
DWORD
Failure - PLATFORM_TYPE_UNKNOWN
either GetVersionEx() failed, or we are running on an
unrecognized operating system
Success - PLATFORM_TYPE_WIN95
The world's favourite desktop O/S
PLATFORM_TYPE_WINNT
The world's best O/S on top of anything
--*/
{
#ifndef UNIX
OSVERSIONINFO versionInfo;
*lpdwVersion5os = FALSE;
versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
if (GetVersionEx(&versionInfo)) {
switch (versionInfo.dwPlatformId) {
case VER_PLATFORM_WIN32_WINDOWS:
if(versionInfo.dwMinorVersion >= 90) {
GlobalPlatformMillennium = TRUE;
}
return PLATFORM_TYPE_WIN95;
case VER_PLATFORM_WIN32_NT:
if ( lpdwVersion5os &&
versionInfo.dwMajorVersion >= 5 ) {
*lpdwVersion5os = TRUE;
if (versionInfo.dwMinorVersion >= 1) {
GlobalPlatformWhistler = TRUE;
}
}
return PLATFORM_TYPE_WINNT;
}
}
return PLATFORM_TYPE_UNKNOWN;
#else
return PLATFORM_TYPE_UNIX;
#endif /* UNIX */
}
//
//DWORD
//PlatformSupport(
// VOID
// )
//
///*++
//
//Routine Description:
//
// Returns a bitmap of capabilities supported by this operating system
//
//Arguments:
//
// None.
//
//Return Value:
//
// DWORD
//
//--*/
//
//{
// switch (PlatformType()) {
// case PLATFORM_TYPE_WINNT:
// return PLATFORM_SUPPORTS_UNICODE;
// }
// return 0;
//}
DWORD
GetTimeoutValue(
IN DWORD TimeoutOption
)
/*++
Routine Description:
Gets a timeout value. The timeout is retrieved from the current handle. If
it is not available in the current handle then the parent handle is checked
(actually the current handle is derived from the parent, so this doesn't
really do anything). If the value is still not available, then the global
default is used
Arguments:
TimeoutOption - INTERNET_OPTION_ value used to specify the timeout value
Return Value:
DWORD
Requested timeout value
--*/
{
HINTERNET hInternet;
DWORD timeout;
DWORD error;
hInternet = InternetGetMappedObjectHandle();
if (hInternet != NULL) {
error = RGetTimeout(hInternet, TimeoutOption, &timeout);
}
if ((hInternet == NULL) || (error != ERROR_SUCCESS)) {
switch (TimeoutOption) {
case INTERNET_OPTION_SEND_TIMEOUT:
timeout = GlobalSendTimeout;
break;
case INTERNET_OPTION_RECEIVE_TIMEOUT:
timeout = GlobalReceiveTimeout;
break;
case INTERNET_OPTION_DATA_SEND_TIMEOUT:
timeout = GlobalDataSendTimeout;
break;
case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
timeout = GlobalDataReceiveTimeout;
break;
case INTERNET_OPTION_CONNECT_TIMEOUT:
timeout = GlobalConnectTimeout;
break;
case INTERNET_OPTION_CONNECT_RETRIES:
timeout = GlobalConnectRetries;
break;
case INTERNET_OPTION_FROM_CACHE_TIMEOUT:
timeout = GlobalFromCacheTimeout;
break;
}
}
return timeout;
}
DWORD
ProbeReadBuffer(
IN LPVOID lpBuffer,
IN DWORD dwBufferLength
)
/*++
Routine Description:
Probes a buffer for readability. Used as part of API parameter validation,
this function tests the first and last locations in a buffer. This is not
as strict as the IsBadXPtr() Windows APIs, but it means we don't have to
test every location in the buffer
Arguments:
lpBuffer - pointer to buffer to test
dwBufferLength - length of buffer
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
--*/
{
DWORD error;
//
// the buffer can be NULL if the probe length is 0. Otherwise, its an error
//
if (lpBuffer == NULL) {
error = (dwBufferLength == 0) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
} else if (dwBufferLength != 0) {
__try {
LPBYTE p;
LPBYTE end;
volatile BYTE b;
p = (LPBYTE)lpBuffer;
end = p + dwBufferLength - 1;
b = *end;
//
// visit every page in the buffer - it doesn't matter that we may
// test a character in the middle of a page
//
for (; p < end; p += PAGE_SIZE) {
b = *p;
}
error = ERROR_SUCCESS;
} __except(EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_PARAMETER;
}
ENDEXCEPT
} else {
//
// zero-length buffer
//
error = ERROR_INVALID_PARAMETER;
}
return error;
}
DWORD
ProbeWriteBuffer(
IN LPVOID lpBuffer,
IN DWORD dwBufferLength
)
/*++
Routine Description:
Probes a buffer for writeability. Used as part of API parameter validation,
this function tests the first and last locations in a buffer. This is not
as strict as the IsBadXPtr() Windows APIs, but it means we don't have to
test every location in the buffer
Arguments:
lpBuffer - pointer to buffer to test
dwBufferLength - length of buffer
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
--*/
{
DWORD error;
//
// the buffer can be NULL if the probe length is 0. Otherwise, its an error
//
if (lpBuffer == NULL) {
error = (dwBufferLength == 0) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
} else if (dwBufferLength != 0) {
__try {
LPBYTE p;
LPBYTE end;
volatile BYTE b;
p = (LPBYTE)lpBuffer;
end = p + dwBufferLength - 1;
b = *end;
*end = b;
//
// visit every page in the buffer - it doesn't matter that we may
// test a character in the middle of a page
//
for (; p < end; p += PAGE_SIZE) {
b = *p;
*p = b;
}
error = ERROR_SUCCESS;
} __except(EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_PARAMETER;
}
ENDEXCEPT
} else {
//
// zero-length buffer
//
error = ERROR_SUCCESS;
}
return error;
}
DWORD
ProbeAndSetDword(
IN LPDWORD lpDword,
IN DWORD dwValue
)
/*++
Routine Description:
Probes a single DWORD buffer for writeability, and as a side-effect sets it
to a default value. Used as part of API parameter validation
Arguments:
lpDword - pointer to DWORD buffer to test
dwValue - default value to set
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
--*/
{
DWORD error;
__try {
*lpDword = dwValue;
error = ERROR_SUCCESS;
} __except(EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_PARAMETER;
}
ENDEXCEPT
return error;
}
DWORD
ProbeString(
IN LPSTR lpString,
OUT LPDWORD lpdwStringLength
)
/*++
Routine Description:
Probes a string buffer for readability, and returns the length of the string
Arguments:
lpString - pointer to string to check
lpdwStringLength - returned length of string
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
--*/
{
DWORD error;
DWORD length;
//
// initialize string length and return code
//
length = 0;
error = ERROR_SUCCESS;
//
// the buffer can be NULL
//
if (lpString != NULL) {
__try {
//
// unfortunately, for a string, we have to visit every location in
// the buffer to find the terminator
//
while (*lpString != '\0') {
++length;
++lpString;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_PARAMETER;
}
ENDEXCEPT
}
*lpdwStringLength = length;
return error;
}
DWORD
ProbeStringW(
IN LPWSTR lpString,
OUT LPDWORD lpdwStringLength
)
/*++
Routine Description:
Probes a wide string buffer for readability, and returns the length of the string
Arguments:
lpString - pointer to string to check
lpdwStringLength - returned length of string
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_INVALID_PARAMETER
--*/
{
DWORD error;
DWORD length;
//
// initialize string length and return code
//
length = 0;
error = ERROR_SUCCESS;
//
// the buffer can be NULL
//
if (lpString != NULL) {
__try {
//
// unfortunately, for a string, we have to visit every location in
// the buffer to find the terminator
//
while (*lpString != '\0') {
++length;
++lpString;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
error = ERROR_INVALID_PARAMETER;
}
ENDEXCEPT
}
*lpdwStringLength = length;
return error;
}
DWORD
LoadDllEntryPoints(
IN OUT LPDLL_INFO lpDllInfo,
IN DWORD dwFlags
)
/*++
Routine Description:
Dynamically loads a DLL and the entry points described in lpDllEntryPoints
Assumes: 1. Any thread serialization taken care of by caller
2. Module handle, entry point addresses and reference count
already set to 0 if this is first time the DLL_INFO is
being used to load the DLL
Arguments:
lpDllInfo - pointer to DLL_INFO structure containing all info about DLL
and entry points to load
dwFlags - flags controlling how this function operates:
LDEP_PARTIAL_LOAD_OK
- not fatal if we can't load all entry points
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - Win32 error
--*/
{
DEBUG_ENTER((DBG_UTIL,
Dword,
"LoadDllEntryPoints",
"%x [%q, %d], %#x",
lpDllInfo,
lpDllInfo->lpszDllName,
lpDllInfo->dwNumberOfEntryPoints,
dwFlags
));
DWORD error = ERROR_SUCCESS;
if (lpDllInfo->hModule == NULL) {
DWORD dwMode = SetErrorMode(SEM_FAILCRITICALERRORS);
HMODULE hDll = LoadLibrary(lpDllInfo->lpszDllName);
if (hDll != NULL) {
lpDllInfo->hModule = hDll;
lpDllInfo->LoadCount = 1;
for (DWORD i = 0; i < lpDllInfo->dwNumberOfEntryPoints; ++i) {
FARPROC proc = GetProcAddress(
hDll,
lpDllInfo->lpEntryPoints[i].lpszProcedureName
);
*lpDllInfo->lpEntryPoints[i].lplpfnProcedure = proc;
if ((proc == NULL) && !(dwFlags & LDEP_PARTIAL_LOAD_OK)) {
error = GetLastError();
UnloadDllEntryPoints(lpDllInfo, TRUE);
break;
}
}
} else {
error = GetLastError();
}
SetErrorMode(dwMode);
} else {
DEBUG_PRINT(UTIL,
INFO,
("info for %q already loaded\n",
lpDllInfo->lpszDllName
));
InterlockedIncrement(&lpDllInfo->LoadCount);
}
DEBUG_LEAVE(error);
return error;
}
DWORD
UnloadDllEntryPoints(
IN OUT LPDLL_INFO lpDllInfo,
IN BOOL bForce
)
/*++
Routine Description:
Undoes the work of LoadDllEntryPoints()
Assumes: 1. Any thread serialization taken care of by caller
Arguments:
lpDllInfo - pointer to DLL_INFO structure containing all info about DLL
and (loaded) entry points
bForce - TRUE if the DLL will be unloaded irrespective of the usage
count
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - Win32 error
--*/
{
DEBUG_ENTER((DBG_UTIL,
Dword,
"UnloadDllEntryPoints",
"%x [%q, %d], %B",
lpDllInfo,
lpDllInfo->lpszDllName,
lpDllInfo->dwNumberOfEntryPoints,
bForce
));
DWORD error = ERROR_SUCCESS;
if (bForce) {
lpDllInfo->LoadCount = 0;
} else if (InterlockedDecrement(&lpDllInfo->LoadCount) == 0) {
bForce = TRUE;
}
if (bForce && (lpDllInfo->hModule != NULL)) {
if (!FreeLibrary(lpDllInfo->hModule)) {
error = GetLastError();
}
//
// even if FreeLibrary() failed we clear out the load info
//
lpDllInfo->hModule = NULL;
for (DWORD i = 0; i < lpDllInfo->dwNumberOfEntryPoints; ++i) {
*lpDllInfo->lpEntryPoints[i].lplpfnProcedure = NULL;
}
}
DEBUG_LEAVE(error);
return error;
}
#ifndef CERT_E_WRONG_USAGE
# define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110)
#endif
DWORD
MapInternetError(
IN DWORD dwErrorCode
)
/*++
Routine Description:
Maps a winsock/RPC/transport error into a more user-friendly WinInet error,
and stores the original error in the per-thread context so that the app can
retrieve it if it really cares
N.B. We should no longer be receiving winsock errors directly at the WinInet
interface. They are available via InternetGetLastResponseInfo()
Arguments:
dwErrorCode - original (winsock) error code to map
Return Value:
DWORD
Mapped error code, or the orignal error if its not one that we handle
--*/
{
LPINTERNET_THREAD_INFO lpThreadInfo;
DEBUG_ENTER((DBG_UTIL,
Dword,
"MapInternetError",
"%#x [%s]",
dwErrorCode,
InternetMapError(dwErrorCode)
));
lpThreadInfo = InternetGetThreadInfo();
if (lpThreadInfo) {
lpThreadInfo->dwMappedErrorCode = dwErrorCode;
}
switch (dwErrorCode) {
case SEC_E_INSUFFICIENT_MEMORY :
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
break;
case SEC_E_INVALID_HANDLE :
case SEC_E_UNSUPPORTED_FUNCTION :
case SEC_E_TARGET_UNKNOWN :
case SEC_E_INTERNAL_ERROR :
case SEC_E_SECPKG_NOT_FOUND :
case SEC_E_NOT_OWNER :
case SEC_E_CANNOT_INSTALL :
case SEC_E_INVALID_TOKEN :
case SEC_E_CANNOT_PACK :
case SEC_E_QOP_NOT_SUPPORTED :
case SEC_E_NO_IMPERSONATION :
case SEC_E_LOGON_DENIED :
case SEC_E_UNKNOWN_CREDENTIALS :
case SEC_E_NO_CREDENTIALS :
case SEC_E_MESSAGE_ALTERED :
case SEC_E_OUT_OF_SEQUENCE :
case SEC_E_NO_AUTHENTICATING_AUTHORITY:
case SEC_I_CONTINUE_NEEDED :
case SEC_I_COMPLETE_NEEDED :
case SEC_I_COMPLETE_AND_CONTINUE :
case SEC_I_LOCAL_LOGON :
case SEC_E_BAD_PKGID :
case SEC_E_CONTEXT_EXPIRED :
case SEC_E_INCOMPLETE_MESSAGE :
dwErrorCode = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
break;
// Cert and Encryption errors
case CERT_E_EXPIRED:
case CERT_E_VALIDITYPERIODNESTING:
dwErrorCode = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
break;
case CERT_E_UNTRUSTEDROOT:
dwErrorCode = ERROR_INTERNET_INVALID_CA;
break;
case CERT_E_CN_NO_MATCH:
dwErrorCode = ERROR_INTERNET_SEC_CERT_CN_INVALID;
break;
case CRYPT_E_REVOKED:
dwErrorCode = ERROR_INTERNET_SEC_CERT_REVOKED;
break;
// ignore revocation if the certificate does not have a CDP
case CRYPT_E_NO_REVOCATION_CHECK:
dwErrorCode = ERROR_SUCCESS;
break;
case CRYPT_E_REVOCATION_OFFLINE:
dwErrorCode = ERROR_INTERNET_SEC_CERT_REV_FAILED;
break;
case CERT_E_ROLE:
case CERT_E_PATHLENCONST:
case CERT_E_CRITICAL:
case CERT_E_PURPOSE:
case CERT_E_ISSUERCHAINING:
case CERT_E_MALFORMED:
case CERT_E_CHAINING:
// We can't allow connection if server doesn't have a server auth certificate.
// To force CERT_E_WRONG_USAGE to error out we map it to the error below.
// In the future we need to map it to it's own non-recoverable error, so we can
// give the user a specific error message.
case CERT_E_WRONG_USAGE:
dwErrorCode = ERROR_INTERNET_SEC_INVALID_CERT;
break;
case WSAEINTR:
case WSAEBADF:
case WSAEACCES:
case WSAEFAULT:
case WSAEINVAL:
case WSAEMFILE:
case WSAEADDRINUSE:
case WSAEADDRNOTAVAIL:
dwErrorCode = ERROR_INTERNET_INTERNAL_ERROR;
break;
case WSAENOTSOCK:
//
// typically, if we see this error its because we tried to use a closed
// socket handle
//
dwErrorCode = ERROR_INTERNET_OPERATION_CANCELLED;
break;
case WSAEWOULDBLOCK:
case WSAEINPROGRESS:
case WSAEALREADY:
case WSAEDESTADDRREQ:
case WSAEPROTOTYPE:
case WSAENOPROTOOPT:
case WSAEPROTONOSUPPORT:
case WSAESOCKTNOSUPPORT:
case WSAEOPNOTSUPP:
case WSAEISCONN:
case WSAETOOMANYREFS:
case WSAELOOP:
case WSAENAMETOOLONG:
case WSAENOTEMPTY:
case WSAEPROCLIM:
case WSAEUSERS:
case WSAEDQUOT:
case WSAESTALE:
case WSAEREMOTE:
case WSAEDISCON:
case WSASYSNOTREADY:
case WSAVERNOTSUPPORTED:
case WSANOTINITIALISED:
//
// currently unmapped errors
//
break;
case WSAEMSGSIZE:
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
break;
case WSAEPFNOSUPPORT:
case WSAEAFNOSUPPORT:
dwErrorCode = ERROR_INTERNET_TCPIP_NOT_INSTALLED;
break;
case WSAECONNABORTED:
case WSAESHUTDOWN:
dwErrorCode = ERROR_INTERNET_CONNECTION_ABORTED;
break;
case WSAECONNRESET:
case WSAENETRESET:
dwErrorCode = ERROR_INTERNET_CONNECTION_RESET;
break;
case WSAENOBUFS:
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
break;
case WSAETIMEDOUT:
dwErrorCode = ERROR_INTERNET_TIMEOUT;
break;
case WSAENETDOWN:
case WSAECONNREFUSED:
case WSAENETUNREACH:
case WSAENOTCONN:
dwErrorCode = ERROR_INTERNET_CANNOT_CONNECT;
break;
case WSAEHOSTDOWN:
case WSAEHOSTUNREACH:
case WSAHOST_NOT_FOUND:
case WSATRY_AGAIN:
case WSANO_RECOVERY:
case WSANO_DATA:
dwErrorCode = ERROR_INTERNET_NAME_NOT_RESOLVED;
break;
default:
DEBUG_PRINT(UTIL,
WARNING,
("MapInternetError(): unmapped error code %d [%#x]\n",
dwErrorCode,
dwErrorCode
));
break;
}
DEBUG_LEAVE(dwErrorCode);
return dwErrorCode;
}
DWORD
CalculateHashValue(
IN LPSTR lpszString
)
/*++
Routine Description:
Calculate a hash number given a string
Arguments:
lpszString - string to hash
Return Value:
DWORD
--*/
{
DWORD hashValue = 0;
DWORD position = 1;
while (*lpszString) {
hashValue += *lpszString * position;
++lpszString;
++position;
}
return hashValue;
}
VOID GetCurrentGmtTime(
LPFILETIME lpFt
)
/*++
Routine Description:
This routine returns the current GMT time
Arguments:
lpFt FILETIME strucutre in which this is returned
Returns:
Comments:
--*/
{
SYSTEMTIME sSysT;
GetSystemTime(&sSysT);
SystemTimeToFileTime(&sSysT, lpFt);
}
///*** DwRemoveDots - Remove any dots from a path name
//**
//** Synopsis
//** DWORD DwRemoveDots (pchPath)
//** Lifted from win95 kernel.
//**
//** Input:
//** pchPath - A path string
//**
//**
//** Output:
//** returns the number of double dot levels removed from front
//**
//** Errors:
//** returns dwInvalid if invalid path
//**
//** Description:
//** Removes ..\ and .\ sequences from a path string. The path
//** string should not include the root drive or net name portion.
//** The return value of is the number of levels removed from the
//** start of the string. Levels removed from inside the string
//** will not be returned. For example:
//**
//** String Result Return
//**
//** ..\..\dir1 dir1 2
//** dir1\..\dir2 dir2 0
//** dir1\..\..\dir2 dir2 1
//** .\dir1 dir1 0
//** dir1\.\dir2 dir1\dir2 0
//**
//** A backslash at the start of the string will be ignored.
//*/
//
//// File and path definitions
//
//#define chExtSep '.'
//#define szExtSep "."
//#define chNetIni '\\'
//#define chDirSep '\\'
//#define szDirSep "\\"
//#define chDirSep2 '/'
//#define chDrvSep ':'
//#define chRelDir '.'
//#define chEnvSep ';'
//#define chWldChr '?'
//#define chWldSeq '*'
//#define chMinDrv 'A'
//#define chMaxDrv 'Z'
//#define chMinDrvLow 'a'
//#define chMaxDrvLow 'z'
//
//DWORD
//DwRemoveDots (
// char * pchPath
///*++
//
//Routine Description:
// Removes ./ ../ etc from a path to normalize it
//
//Arguments:
//
// pchPath path string
//
//Returns:
//
// Count of levels dealt with
//
//Comments:
//
// Lifted from win95 kernel
//
//--*/
//)
// {
// BOOL fInside = FALSE;
// DWORD cLevel = 0;
// DWORD cBackup;
// register char * pchR;
// register char * pchL;
//
//#ifdef MAYBE
// // Check for invalid characters
// if (!FFixPathChars(pchPath)) {
// // No code required.
// return dwInvalid;
// }
//
//#endif //MAYBE
// // Skip slashes
// for (; *pchPath == chDirSep2; pchPath++)
// ;
// pchL = pchR = pchPath;
//
// // Loop through handling each directory part
// while (*pchR) {
// // This part starts with dot. Is it one or more?
// if (*pchR++ == chRelDir) {
// for (cBackup = 0; *pchR == chRelDir; cBackup++, pchR++)
// ;
// if (cBackup) {
// // More than one dot. Back up the left pointer.
// if ((*pchR != chDirSep2) && (*pchR != '\0')) {
// // we got a [.]+X (X != '\') might be an LFN
// // process this as a name
// goto name_processing;
// }
// // Doesn't advance for ending ..
// for (; *pchR == chDirSep2; pchR++)
// ;
// if (fInside) {
// for (; cBackup; cBackup--) {
// if (pchL <= pchPath) {
// cLevel += cBackup;
// fInside = FALSE;
// break;
// }
// // Remove the previous part
// for (pchL -= 2; *pchL != chDirSep2; pchL--) {
// if (pchL <= pchPath) {
// fInside = FALSE;
// pchL--;
// break;
// }
// }
// pchL++;
// }
// } else {
// cLevel += cBackup;
// }
// // Subtract ending backslash if not root
// if ((*pchR == '\0') && (pchL != pchPath))
// pchL--;
// strcpy(pchL, pchR);
// pchR = pchL;
// } else {
// // This part starts with one dot. Throw it away.
// if (*pchR != chDirSep2) {
// // Special case "\." by converting it to ""
// // unless it is a root, when it becomes "\".
// if (*pchR == '\0') {
// if (pchL == pchPath)
// *(pchR-1) = '\0'; // root
// else
// *(pchR-2) = '\0'; // not root
// return cLevel;
// }
// // we started with a '.' and then there was no '\'
// // might be an LFN name
// goto name_processing;
// }
// pchR++;
// strcpy(pchL, pchR);
// pchR = pchL;
// }
// } else {
//name_processing:
// // This part is a name. Skip it.
// fInside = TRUE;
// for (; TRUE; pchR++) {
// if (*pchR == chDirSep2) {
// if (*(pchR-1) == chRelDir) {
// // This name has one or more dots at the end.
// // Remove the last dot (NT3.5 does this).
// pchL = pchR-1;
// strcpy(pchL, pchR);
// pchR = pchL; // point to chDirSep2 again
// }
// for (; *pchR == chDirSep2; pchR++)
// ;
// break;
// } else if (*pchR == '\0') {
// // Remove trailing dots.
// // NB Can't fall off the beginning since the first char
// // of the current path element was not chRelDir.
// for (; *(pchR-1) == chRelDir; pchR--)
// ;
// // Overstore the first trailing dot, if there is one.
// *pchR = '\0';
// break;
// }
// }
// pchL = pchR;
// }
// }
// return cLevel;
//}
//#define OLD
#define EXE_EXTENSION TEXT(".exe")
#define DLL_EXTENSION TEXT(".dll")
#define CGI_EXTENSION TEXT(".cgi")
LPSTR GetFileExtensionFromUrl(
IN LPSTR lpszUrl,
IN OUT LPDWORD lpdwLength)
/*++
Routine Description:
This routine returns a possible file extension from a URL
It does this by walking back from the end till the first dot.
Arguments:
lpszUrl Url to derive the extension from
lpdwLength max length of the extension expected
Returns:
NULL if no dot within the passed in length or a forward slash or a
backward slash encountered before the dot. Otherwise returns a pointer
pointing past the dot in the url string
Comments:
--*/
{
INET_ASSERT(lpszUrl && lpdwLength);
#ifdef OLD
if (lpszUrl != NULL) {
LPSTR p;
DWORD len=0 , lenLimit= *lpdwLength;
p = lpszUrl + (strlen(lpszUrl) - 1);
while ((*p != '.') && (p != lpszUrl)) {
// if this contains a character that the filesystems
// don't like, then return NULL
if (strchr(vszInvalidFilenameChars, *p)) {
return(NULL);
}
if ((*p == '/') || (*p == '\\')) {
break;
}
--p;
++len;
}
if ((*p == '.')
&& (len != 0)
&& (len < lenLimit)) {
*lpdwLength = len;
return p + 1;
}
}
return NULL;
#else
if (!lpszUrl)
{
*lpdwLength = 0;
return NULL;
}
LPSTR pszPeriod = NULL;
BOOL fContinue = TRUE;
// Scanning from left to right, note where we last saw a period.
// If we see a character that cannot be in an extension, and we've seen a period, forget
// about the period.
// Repeat this until we've reached the end of the url, a question mark (query) or hash (fragment)
// 1.6.98: _However_, if the file extension we've discovered is either .dll or .exe,
// we'll continue to scan beyond the query mark for a file extension.
// 1.20.98: And if we find no extension before the question mark, we'll look after it, then.
while (fContinue)
{
switch (*lpszUrl)
{
case TEXT('.'):
pszPeriod = lpszUrl;
break;
case TEXT('?'):
if (pszPeriod)
{
if ((!StrCmpNI(pszPeriod, EXE_EXTENSION, ARRAY_ELEMENTS(EXE_EXTENSION)-1))
|| (!StrCmpNI(pszPeriod, DLL_EXTENSION, ARRAY_ELEMENTS(DLL_EXTENSION)-1))
|| (!StrCmpNI(pszPeriod, CGI_EXTENSION, ARRAY_ELEMENTS(CGI_EXTENSION)-1)))
{
pszPeriod = NULL;
break;
}
}
else
{
break;
}
case TEXT('#'):
case TEXT('\0'):
fContinue = FALSE;
break;
default:
if (pszPeriod && strchr(vszInvalidFilenameChars, *lpszUrl))
{
pszPeriod = NULL;
}
}
lpszUrl++;
}
// This will be off by one
lpszUrl--;
if (pszPeriod)
{
if (*lpdwLength < (DWORD)(lpszUrl-pszPeriod))
{
pszPeriod = NULL;
}
else
{
pszPeriod++;
*lpdwLength = (DWORD)(lpszUrl-pszPeriod);
}
}
return pszPeriod;
#endif
}
DWORD
CheckExpired(
HINTERNET hRequestMapped,
BOOL* lpfIsExpired,
CACHE_ENTRY_INFO* pInfo,
LONGLONG DefaultExpiryDelta
)
/*++
Routine Description:
This routine checks whether a cache entry has expired for ftp/gopher.
It uses the globally set synchronization modes to make that decision
Arguments:
hRequestMapped a mapped request handle
lpfIsExpired returns TRUE if expired, FALSE otherwise
lpCacheEntryInfo cache entry info containing all the timestamps
DefaultExpiryDelta time delta to use for default expiry calculation
Returns:
Windows error code
Comments:
--*/
{
switch (GlobalUrlCacheSyncMode)
{
case WININET_SYNC_MODE_NEVER:
// Never check, unless the page has expired
*lpfIsExpired = FALSE;
break;
case WININET_SYNC_MODE_ALWAYS:
*lpfIsExpired = TRUE;
break;
default:
if (FT2LL (pInfo->LastSyncTime) < dwdwSessionStartTime)
*lpfIsExpired = TRUE;
else
{
FILETIME ftCurrent;
GetCurrentGmtTime (&ftCurrent);
*lpfIsExpired = (FT2LL(ftCurrent) - FT2LL (pInfo->LastSyncTime)
> DefaultExpiryDelta);
}
break;
}
return ERROR_SUCCESS;
}
LPTSTR
FTtoString(
IN FILETIME *pftTime)
/*++
FTtoString:
This routine converts a given FILETIME structure to a string representing
the given date and time in the local format.
Arguments:
pftTime supplies the FILETIME structure to convert.
Return Value:
NULL - Memory allocation failure.
Otherwise, the address of the string, allocated via LocalAlloc.
Author:
Doug Barlow (dbarlow) 4/12/1996
--*/
{
LONG cchTotal, cchNeeded;
SYSTEMTIME stTime, stLocal;
LPTSTR szDateTime = NULL;
//
// Convert the FILETIME to a SYSTEMTIME.
//
if (!FileTimeToSystemTime(pftTime, &stTime))
goto ErrorExit;
//
// For now, leave it in GMT time, function not implimented in Win'95.
//
//if ( IsPlatformWinNT() )
//{
// if (!SystemTimeToTzSpecificLocalTime(NULL, &stTime, &stLocal))
// goto ErrorExit;
//}
//else
{
stLocal = stTime;
}
//
// Calculate how long the date string will be.
//
cchTotal =
GetDateFormat(
LOCALE_SYSTEM_DEFAULT,
DATE_SHORTDATE,
&stLocal,
NULL,
NULL,
0);
if (0 >= cchTotal)
goto ErrorExit;
cchNeeded =
GetTimeFormat(
LOCALE_SYSTEM_DEFAULT,
0,
&stLocal,
NULL,
NULL,
0);
if (0 >= cchNeeded)
goto ErrorExit;
cchTotal += cchNeeded;
cchTotal += 4 * sizeof(TCHAR); // space, trailing NULL, and two extra.
szDateTime = (LPTSTR)ALLOCATE_MEMORY(LMEM_FIXED, cchTotal);
if (NULL == szDateTime)
goto ErrorExit;
//
// Fill in the time string.
//
cchNeeded =
GetDateFormat(
LOCALE_SYSTEM_DEFAULT,
DATE_SHORTDATE,
&stLocal,
NULL,
szDateTime,
cchTotal);
if (0 >= cchNeeded)
goto ErrorExit;
lstrcat(szDateTime, TEXT(" "));
cchNeeded = lstrlen(szDateTime);
cchNeeded =
GetTimeFormat(
LOCALE_SYSTEM_DEFAULT,
0,
&stLocal,
NULL,
&szDateTime[cchNeeded],
cchTotal - cchNeeded);
if (0 >= cchNeeded)
goto ErrorExit;
return szDateTime;
ErrorExit:
if (NULL != szDateTime)
FREE_MEMORY(szDateTime);
return NULL;
}
BOOL
PrintFileTimeInInternetFormat(
FILETIME *lpft,
LPSTR lpszBuff,
DWORD dwSize
)
{
SYSTEMTIME sSysTime;
if (dwSize < INTERNET_RFC1123_BUFSIZE) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return (FALSE);
}
if (!FileTimeToSystemTime(((CONST FILETIME *)lpft), &sSysTime)) {
return (FALSE);
}
return (InternetTimeFromSystemTime( &sSysTime,
INTERNET_RFC1123_FORMAT,
lpszBuff,
dwSize));
}
BOOL
InternetSettingsChanged(
VOID
)
/*++
Routine Description:
Determines if the global settings have been changed (inter-process)
Arguments:
None.
Return Value:
BOOL
--*/
{
DEBUG_ENTER((DBG_UTIL,
Bool,
"InternetSettingsChanged",
NULL
));
DWORD dwVer;
BOOL bChanged = FALSE;
if (GetCurrentSettingsVersion(&dwVer)) {
DEBUG_PRINT(UTIL,
INFO,
("current settings version = %d\n",
dwVer
));
if (!GlobalSettingsLoaded || (dwVer != GlobalSettingsVersion)) {
GlobalSettingsLoaded = TRUE;
GlobalSettingsVersion = dwVer;
bChanged = TRUE;
}
}
DEBUG_LEAVE(bChanged);
return bChanged;
}
BOOL
RefreshSslState(
VOID
)
/*++
Routine Description:
Starting with Whistler, client auth certificates are cached
for the logon session (not per process). Inetcpl now contains
a button that will clear on-demand the SSL state for the session.
If user cleared the SSL cache, then flush all cached
client auth certificates in the global cert cache for this process.
NOTE: This function leverages a cache header data value.
Clearing the state affects all processes, and
using one of these (which was never put into practice)
prevents the need for another shared registry value.
Arguments:
None.
Return Value:
BOOL If the client auth cert cache was cleared, this function will
return TRUE. Otherwise, this will return FALSE.
--*/
{
DWORD dwCount = 0;
BOOL bCleared = FALSE;
DEBUG_ENTER((DBG_UTIL,
Bool,
"RefreshSslState",
NULL
));
if (GlobalPlatformWhistler &&
GetUrlCacheHeaderData(CACHE_HEADER_DATA_DOWNLOAD_PARTIAL, &dwCount) &&
dwCount != GlobalSslStateCount)
{
GlobalSslStateCount = dwCount;
PurgeKeepAlives(PKA_NOW);
GlobalCertCache.ClearClientAuthCertChains();
bCleared = TRUE;
}
DEBUG_LEAVE(bCleared);
return bCleared;
}
BOOL
CertHashToStr(
IN LPSTR lpMD5Hash,
IN DWORD dwMD5HashSize,
IN OUT LPSTR *lplpszHashStr
)
/*++
Routine Description:
Converts a set of bytes into a neatly formated string of ':' (colon) seperated
hex digits that can be shown to the user.
Arguments:
lpMD5Hash - ptr to set of hash bytes
dwMD5HashSize - size of lpMD5Hash
lplpszHashStr - ptr to ptr where newly allocated return string will be stored.
Return Value:
BOOL
--*/
{
DWORD dwStrSize = (2*dwMD5HashSize) + dwMD5HashSize;
LPSTR lpszHashStr;
*lplpszHashStr = new CHAR[dwStrSize];
if ( *lplpszHashStr == NULL )
{
return FALSE;
}
lpszHashStr = *lplpszHashStr;
for ( DWORD i = 0 ; i < dwMD5HashSize; i++ )
{
unsigned char uHashByte;
if ( i != 0 )
{
*lpszHashStr = ':';
lpszHashStr++;
}
uHashByte = (unsigned char) * ( ((unsigned char * ) lpMD5Hash) + i);
wsprintf( lpszHashStr, "%02X", uHashByte);
lpszHashStr += 2;
}
INET_ASSERT( *lpszHashStr == '\0' );
return TRUE;
}
//
// private functions
//
DWORD
ConvertSecurityInfoIntoCertInfoStruct(
IN LPINTERNET_SECURITY_INFO pSecInfo,
OUT INTERNET_CERTIFICATE_INFO *pCertificate,
IN OUT DWORD *pcbCertificate
)
/*++
Routine Description:
Converts an X509 Certificate Structure into a WININET struct
used for storing the same info.
Arguments:
hContext - Context handle of the active SSPI session.
pCertInfo - Pointer to Structure where info is returned in.
Return Value:
DWORD
ERROR_SUCCESS - if cert cannot be converted
ERROR_NOT_ENOUGH_MEMORY
--*/
{
DWORD error = ERROR_SUCCESS;
PCERT_INFO pCertInfo = NULL;
DWORD cbCert = sizeof(INTERNET_CERTIFICATE_INFO),
cbSubject = 0,
cbIssuer = 0;
BOOL fCanAlloc = FALSE;
if(pSecInfo == NULL)
{
error = ERROR_INTERNET_INTERNAL_ERROR;
goto quit;
}
if(pCertificate == NULL || *pcbCertificate == 0)
{
*pcbCertificate = sizeof(INTERNET_CERTIFICATE_INFO);
goto quit;
}
if(*pcbCertificate < sizeof(INTERNET_CERTIFICATE_INFO) )
{
error = ERROR_INTERNET_INTERNAL_ERROR;
goto quit;
}
ZeroMemory(pCertificate, sizeof(INTERNET_CERTIFICATE_INFO));
fCanAlloc = TRUE;
if(pSecInfo->pCertificate &&
pSecInfo->pCertificate->pCertInfo )
{
pCertInfo = pSecInfo->pCertificate->pCertInfo;
//
// Now Convert Structures from SSPI format to WININET style.
// While in the process, we'll role them all into one
// big structure that we'll return to the user.
//
cbSubject = CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
&pCertInfo->Subject,
CERT_SIMPLE_NAME_STR |
CERT_NAME_STR_CRLF_FLAG |
CERT_NAME_STR_NO_PLUS_FLAG,
NULL,
0);
if ( cbSubject > 0 )
{
// freed by caller outside of wininet
pCertificate->lpszSubjectInfo = (LPSTR) LocalAlloc(LPTR, cbSubject);
if ( pCertificate->lpszSubjectInfo == NULL )
{
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
&pCertInfo->Subject,
CERT_SIMPLE_NAME_STR |
CERT_NAME_STR_CRLF_FLAG |
CERT_NAME_STR_NO_PLUS_FLAG ,
pCertificate->lpszSubjectInfo,
cbSubject);
}
cbIssuer = CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
&pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR |
CERT_NAME_STR_CRLF_FLAG |
CERT_NAME_STR_NO_PLUS_FLAG,
NULL,
0);
if ( cbIssuer > 0 )
{
// freed by caller outside of wininet
pCertificate->lpszIssuerInfo = (LPSTR) LocalAlloc(LPTR, cbIssuer);
if ( pCertificate->lpszIssuerInfo == NULL )
{
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
&pCertInfo->Issuer,
CERT_SIMPLE_NAME_STR |
CERT_NAME_STR_CRLF_FLAG |
CERT_NAME_STR_NO_PLUS_FLAG ,
pCertificate->lpszIssuerInfo,
cbIssuer);
}
CopyMemory(
(PVOID) &pCertificate->ftStart,
(PVOID) &pCertInfo->NotBefore,
sizeof(FILETIME)
);
CopyMemory(
(PVOID) &pCertificate->ftExpiry,
(PVOID) &pCertInfo->NotAfter,
sizeof(FILETIME)
);
}
/*if(pSecInfo->dwProtocol)
{
DWORD dwProtocolID;
TCHAR lpszProtocol[100];
ATTR_MAP ProtocolAttrMap[] =
{
{SP_PROT_SSL2_CLIENT, IDS_PROTOCOL_SSL2},
{SP_PROT_SSL3_CLIENT, IDS_PROTOCOL_SSL3},
{SP_PROT_PCT1_CLIENT, IDS_PROTOCOL_PCT1},
{SP_PROT_TLS1_CLIENT, IDS_PROTOCOL_TLS1}
};
for(j=0; j < sizeof(ProtocolAttrMap)/sizeof(ProtocolAttrMap[0]); j++)
{
if(ProtocolAttrMap[j].dwAttr == pSecInfo->dwProtocol)
{
dwProtocolID = ProtocolAttrMap[j].dwStringID;
break;
}
}
if(LoadString(GlobalDllHandle,
dwProtocolID,
lpszProtocol,
sizeof(lpszProtocol)/sizeof(lpszProtocol[0])))
{
pCertificate->lpszProtocolName = NewString(lpszProtocol);
}
} */
pCertificate->dwKeySize = pSecInfo->dwCipherStrength;
quit:
if ( error != ERROR_SUCCESS &&
fCanAlloc
)
{
if ( pCertificate->lpszSubjectInfo )
{
LocalFree(pCertificate->lpszSubjectInfo);
pCertificate->lpszSubjectInfo = NULL;
}
if ( pCertificate->lpszIssuerInfo )
{
LocalFree(pCertificate->lpszIssuerInfo);
pCertificate->lpszIssuerInfo = NULL;
}
}
return error;
}
/*++
FormatCertInfo:
This routine formats the information within a INTERNET_CERTIFICATE_INFO
structure suitable for display with localization.
Arguments:
pCertInfo supplies a pointer to the INTERNET_CERTIFICATE_INFO structure to
be formatted.
Return Value:
NULL - An error occurred. Otherwise, a pointer to the formatted string.
This string must be freed by the caller via LocalFree.
Author:
Doug Barlow (dbarlow) 4/30/1996
--*/
LPTSTR
FormatCertInfo(
IN INTERNET_CERTIFICATE_INFO *pCertInfo
)
{
LPVOID rgpvParams[9]; // Number of insertable elements in the
// plszStrings->szCertInfo resource
// string.
LPTSTR szResult = NULL;
int i = 0;
PLOCAL_STRINGSA plszStrings;
LPTSTR szFrom = NULL;
LPTSTR szUntil = NULL;
//
// Get the Certificate Information.
//
plszStrings = FetchLocalStringsA();
szFrom = FTtoString(&pCertInfo->ftStart);
szUntil = FTtoString(&pCertInfo->ftExpiry);
if ((NULL == szUntil) || (NULL == szFrom))
goto ErrorExit;
//ChangeCommaSpaceToCRLF(pCertInfo->lpszSubjectInfo);
//ChangeCommaSpaceToCRLF(pCertInfo->lpszIssuerInfo);
rgpvParams[i++] = (LPVOID)pCertInfo->lpszSubjectInfo;
rgpvParams[i++] = (LPVOID)pCertInfo->lpszIssuerInfo;
rgpvParams[i++] = (LPVOID)szFrom;
rgpvParams[i++] = (LPVOID)szUntil;
rgpvParams[i++] = (LPVOID)pCertInfo->lpszProtocolName;
rgpvParams[i++] = (LPVOID)pCertInfo->lpszSignatureAlgName;
rgpvParams[i++] = (LPVOID)pCertInfo->lpszEncryptionAlgName;
rgpvParams[i++] = (LPVOID)(DWORD_PTR)pCertInfo->dwKeySize;
if (96 <= pCertInfo->dwKeySize) // Recommended Key strength
rgpvParams[i++] = (LPVOID)plszStrings->szStrengthHigh;
else if (64 <= pCertInfo->dwKeySize) // Passable key strength
rgpvParams[i++] = (LPVOID)plszStrings->szStrengthMedium;
else // Ick! Low key strength.
rgpvParams[i++] = (LPVOID)plszStrings->szStrengthLow;
INET_ASSERT(i == sizeof(rgpvParams) / sizeof(LPVOID));
i = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
plszStrings->szCertInfo,
0, 0,
(LPTSTR)&szResult,
0,
(va_list *)rgpvParams);
ErrorExit:
if (NULL != szFrom)
FREE_MEMORY(szFrom);
if (NULL != szUntil)
FREE_MEMORY(szUntil);
return szResult;
}
DWORD
ConvertUnicodeToUTF8(
IN LPCWSTR pwszIn,
IN DWORD dwInBufLen,
OUT LPSTR pszOut,
OUT DWORD* pdwOutStrLen,
IN BOOL bEncode
)
/*++
Routine Description:
Convert a string of UNICODE characters to UTF-8:
0000000000000000..0000000001111111: 0xxxxxxx
0000000010000000..0000011111111111: 110xxxxx 10xxxxxx
0000100000000000..1111111111111111: 1110xxxx 10xxxxxx 10xxxxxx
Arguments:
pwszIn - pointer to input wide-character string
dwInBufLen - number of CHARACTERS in pwszIn INCLUDING terminating NULL
pszOut - pointer to output narrow-character buffer
pdwOutStrLen - STRLEN of pszOut (excl. terminating NULL); IN value discarded.
bEncode - TRUE if we are to hex encode characters >= 0x80
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - NO ERROR checking done. Make sure large enuf buffer passed
in.
--*/
{
DEBUG_ENTER((DBG_HTTP,
Dword,
"ConvertUnicodeToUtf8",
"%.100wq, %#x, %#x, %#x, %B",
pwszIn, dwInBufLen, pszOut, pdwOutStrLen, bEncode
));
INET_ASSERT(pwszIn);
INET_ASSERT((int)dwInBufLen > 0);
INET_ASSERT(pszOut);
LPSTR pszStart = pszOut;
static char hexArray[] = "0123456789ABCDEF";
while (dwInBufLen--) {
WORD wchar = *pwszIn++;
BYTE bchar;
if (wchar <= 0x007F) {
*pszOut++ = (BYTE)(wchar);
continue;
}
BYTE lead = ((wchar >= 0x0800) ? 0xE0 : 0xC0);
int shift = ((wchar >= 0x0800) ? 12 : 6);
bchar = lead | (BYTE)(wchar >> shift);
if (bEncode) {
*pszOut++ = '%';
*pszOut++ = hexArray[bchar >> 4];
bchar = hexArray[bchar & 0x0F];
}
*pszOut++ = bchar;
if (wchar >= 0x0800) {
bchar = 0x80 | (BYTE)((wchar >> 6) & 0x003F);
if (bEncode) {
*pszOut++ = '%';
*pszOut++ = hexArray[bchar >> 4];
bchar = hexArray[bchar & 0x0F];
}
*pszOut++ = bchar;
}
bchar = 0x80 | (BYTE)(wchar & 0x003F);
if (bEncode) {
*pszOut++ = '%';
*pszOut++ = hexArray[bchar >> 4];
bchar = hexArray[bchar & 0x0F];
}
*pszOut++ = bchar;
}
*pdwOutStrLen = PtrDiff32(pszOut, pszStart)-1;
DEBUG_LEAVE(ERROR_SUCCESS);
return ERROR_SUCCESS;
}
LPSTR
ConvertMBCSToUTF8(
IN LPCSTR lpszMBCSHostName,
IN DWORD dwMBCSHostNameLength,
IN DWORD dwCodePage,
OUT DWORD * pdwUTF8HostNameStrLen,
IN BOOL bLowerCase
)
{
DEBUG_ENTER((DBG_HTTP,
String,
"ConvertMBCSToUTF8",
"%.100q, %#x, %#x, %#x, %B",
lpszMBCSHostName, dwMBCSHostNameLength, dwCodePage, (pdwUTF8HostNameStrLen ? *pdwUTF8HostNameStrLen : NULL), bLowerCase
));
DEBUG_DUMP(HTTP,
"lpszMBCSHostName: strlen+1byte\n",
lpszMBCSHostName,
(dwMBCSHostNameLength+1)
);
LPSTR lpszUTF8HostName = NULL;
LPWSTR lpwszWideHostName = NULL;
if (!lpszMBCSHostName || !dwMBCSHostNameLength)
goto quit;
DWORD dwWideLen = MultiByteToWideChar(dwCodePage, 0, lpszMBCSHostName, dwMBCSHostNameLength, NULL, 0);
//IMPORTANT! NULL terminator not included in dwWideLen
if (dwWideLen)
{
lpwszWideHostName = new WCHAR[dwWideLen+1];
if (lpwszWideHostName
&& (dwWideLen = MultiByteToWideChar(dwCodePage, 0, lpszMBCSHostName, dwMBCSHostNameLength, lpwszWideHostName, dwWideLen))
&& (lpszUTF8HostName = new CHAR[dwWideLen*3+1]))
{
// *pdwUTF8HostNameLength = dwWideLen*3+1;
// Fill in the terminating NULL character since dwMBCSHostNameLength doesn't include NULL.
lpwszWideHostName[dwWideLen] = L'\0';
DEBUG_DUMP(HTTP,
"Before CharLowerW - lpwszWideHostName: strlen*2+2\n",
lpwszWideHostName,
(dwWideLen*2+2)
);
if (bLowerCase)
{
CharLowerW(lpwszWideHostName);
DEBUG_DUMP(HTTP,
"After CharLowerW - lpwszWideHostName: strlen*2+2\n",
lpwszWideHostName,
(dwWideLen*2+2)
);
}
DWORD error = ConvertUnicodeToUTF8(lpwszWideHostName, dwWideLen+1, lpszUTF8HostName, pdwUTF8HostNameStrLen, FALSE);
DEBUG_DUMP(HTTP,
"ConvertUnicodeToUTF8 - lpszUTF8HostName: strlen+1\n",
lpszUTF8HostName,
(*pdwUTF8HostNameStrLen+1)
);
// no other error possible
INET_ASSERT(error == ERROR_SUCCESS);
}
}
quit:
if (lpwszWideHostName)
{
delete [] lpwszWideHostName;
}
DEBUG_LEAVE(lpszUTF8HostName);
return lpszUTF8HostName;
}
char *FindNamedValue(char *pszHeader, const char *pszFieldName, unsigned long *pdwValSize) {
const char ChDblQuote = '\"';
char *pszBegin, *pszValue;
BOOL fFound;
int cbName;
char *pch = pszHeader;
ExpectName:
while (*pch && isspace(*pch))
pch++;
ParseName:
pszBegin = pch;
while (*pch && isalnum(*pch))
pch++;
cbName = (int) (pch-pszBegin);
fFound = (cbName>0) && !strncmp(pszBegin, pszFieldName, cbName);
ExpectEqSign:
while (*pch && isspace(*pch))
pch++;
if (*pch=='=')
pch++;
ExpectValue:
while (*pch && isspace(*pch))
pch++;
if (*pch=='\"') {
pch++;
goto ParseQuotedValue;
}
ParseValue:
pszValue = pch;
while (*pch && *pch!=',')
pch++;
goto ExpectComma;
ParseQuotedValue:
pszValue = pch;
while (*pch && *pch!=ChDblQuote)
pch++;
ExpectComma:
if (fFound) {
int cbValue = (int) (pch-pszValue);
*pdwValSize = cbValue;
return pszValue;
}
while (*pch && *pch!=',')
pch++;
if (*pch==',') {
pch++;
goto ExpectName;
}
return NULL;
}
// Helper to determine if we're currently loaded during GUI mode setup
BOOL IsInGUIModeSetup()
{
// could be called multiple times in wininet
static DWORD s_dwSystemSetupInProgress = 42;
if (42 == s_dwSystemSetupInProgress)
{
// Rule is that this value will exist and be equal to 1 if in GUI mode setup.
// Default to NO, and only do this for upgrades because this is potentially
// needed for unattended clean installs.
s_dwSystemSetupInProgress = 0;
HKEY hKeySetup = NULL;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
0,
KEY_READ,
&hKeySetup))
{
DWORD dwSize = sizeof(s_dwSystemSetupInProgress);
if (ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
TEXT("SystemSetupInProgress"),
NULL,
NULL,
(LPBYTE) &s_dwSystemSetupInProgress,
&dwSize))
{
s_dwSystemSetupInProgress = 0;
}
else
{
dwSize = sizeof(s_dwSystemSetupInProgress);
if (s_dwSystemSetupInProgress &&
ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
TEXT("UpgradeInProgress"),
NULL,
NULL,
(LPBYTE) &s_dwSystemSetupInProgress,
&dwSize))
{
s_dwSystemSetupInProgress = 0;
}
}
RegCloseKey(hKeySetup);
}
}
return s_dwSystemSetupInProgress ? TRUE : FALSE;
}
#ifdef DONT_USE_IERT
/***
*char *StrTokEx(pstring, control) - tokenize string with delimiter in control
*
*Purpose:
* StrTokEx considers the string to consist of a sequence of zero or more
* text tokens separated by spans of one or more control chars. the first
* call, with string specified, returns a pointer to the first char of the
* first token, and will write a null char into pstring immediately
* following the returned token. when no tokens remain
* in pstring a NULL pointer is returned. remember the control chars with a
* bit map, one bit per ascii char. the null char is always a control char.
*
*Entry:
* char **pstring - ptr to ptr to string to tokenize
* char *control - string of characters to use as delimiters
*
*Exit:
* returns pointer to first token in string,
* returns NULL when no more tokens remain.
* pstring points to the beginning of the next token.
*
*WARNING!!!
* upon exit, the first delimiter in the input string will be replaced with '\0'
*
*******************************************************************************/
char * StrTokEx (char ** pstring, const char * control)
{
unsigned char *str;
const unsigned char *ctrl = (const unsigned char *)control;
unsigned char map[32];
int count;
char *tokenstr;
if(*pstring == NULL)
return NULL;
/* Clear control map */
for (count = 0; count < 32; count++)
map[count] = 0;
/* Set bits in delimiter table */
do
{
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
} while (*ctrl++);
/* Initialize str. */
str = (unsigned char *)*pstring;
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token if this loop sets str to point to the terminal
* null (*str == '\0') */
while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
str++;
tokenstr = (char *)str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str ; str++ )
{
if ( map[*str >> 3] & (1 << (*str & 7)) )
{
*str++ = '\0';
break;
}
}
/* string now points to beginning of next token */
*pstring = (char *)str;
/* Determine if a token has been found. */
if ( tokenstr == (char *)str )
return NULL;
else
return tokenstr;
}
/***
* double StrToDbl(const char *str, char **strStop) - convert string to double
*
* Purpose:
* To convert a string into a double. This function supports
* simple double representations like '1.234', '.5678'. It also support
* the a killobyte computaion by appending 'k' to the end of the string
* as in '1.5k' or '.5k'. The results would then become 1536 and 512.5.
*
* Return:
* The double representation of the string.
* strStop points to the character that caused the scan to stop.
*
*******************************************************************************/
double StrToDbl(const char *str, char **strStop)
{
double dbl = 0;
char *psz;
int iMult = 1;
int iKB = 1;
int iVal = 0;
BOOL bHaveDot = FALSE;
psz = (char*)str;
while(*psz)
{
if((*psz >= '0') && (*psz <= '9'))
{
iVal = (iVal * 10) + (*psz - '0');
if(bHaveDot)
iMult *= 10;
}
else if((*psz == '.') && !bHaveDot)
{
bHaveDot = TRUE;
}
else if((*psz == 'k') || (*psz == 'K'))
{
iKB = 1024;
psz++;
break;
}
else
{
break;
}
psz++;
}
*strStop = psz;
dbl = (double) (iVal * iKB) / iMult;
return(dbl);
}
#endif // DONT_USE_IERT
// We need a DBCS-safe version of StrTokEx.
char* StrTokEx2(char ** pstring, const char * control)
{
/*unsigned*/ char *str;
const /*unsigned*/ char *ctrl = control;
unsigned char map[32];
int count;
char *tokenstr;
if(*pstring == NULL)
return NULL;
/* Clear control map */
for (count = 0; count < 32; count++)
map[count] = 0;
/* Set bits in delimiter table */
do
{
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
ctrl++;
} while (*ctrl);
/* Initialize str. */
str = *pstring;
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token if this loop sets str to point to the terminal
* null (*str == '\0') */
while ((*str>0) && ((CharNext(str)-str)==1) && (map[*str >> 3] & (1 << (*str & 7))))
str = CharNext(str);
tokenstr = str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str ; str = CharNext(str))
{
if (((CharNext(str)-str)==1) && (*str>0) && (map[*str >> 3] & (1 << (*str & 7))))
{
*str++ = '\0';
break;
}
}
/* string now points to beginning of next token */
*pstring = str;
/* Determine if a token has been found. */
if ( tokenstr == str )
return NULL;
else
return tokenstr;
}