windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/ui/cryptui/pwdui.c
2020-09-26 16:20:57 +08:00

1978 lines
54 KiB
C

/*++
Copyright (C) Microsoft Corporation, 1999 - 1999
Module Name:
pwdui.c
Abstract:
This module contains routines for displaying Data Protection API
related UI, originating from client process address space.
For the future, there is support planned for causing UI to originate
from the secure desktop, via Secure Authentication Sequence (SAS).
Author:
Scott Field (sfield) 12-May-99
--*/
#define UNICODE
#define _UNICODE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wincrypt.h>
#include <sha.h>
#include <unicode5.h>
#include "resource.h"
#include "pwdui.h"
typedef struct {
DATA_BLOB *pDataIn; // input DATA_BLOB* to CryptProtect or CryptUnprotect
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct; // PromptStruct describing UI operations to perform
LPWSTR szDataDescription; // Application supplied data descr
PBYTE rgbPasswordHash; // resultant passwordhash for strong security
BOOL fCachedPassword; // did we find password in cache?
BOOL fProtect; // protect or unprotect?
BOOL fValidPassword; // does rgbPasswordHash contain a valid value?
} DIALOGARGS, *PDIALOGARGS, *LPDIALOGARGS;
typedef struct {
LIST_ENTRY Next;
LUID LogonId;
FILETIME ftLastAccess;
BYTE rgbDataInHash[A_SHA_DIGEST_LEN];
BYTE rgbPasswordHash[A_SHA_DIGEST_LEN];
} PASSWORD_CACHE_ENTRY, *PPASSWORD_CACHE_ENTRY, *LPPASSWORD_CACHE_ENTRY;
DWORD
ProtectUIConfirm(
IN DIALOGARGS *pDialogArgs
);
DWORD
UnprotectUIConfirm(
IN DIALOGARGS *pDialogArgs
);
BOOL
ChooseSecurityLevel(
IN HWND hWndParent,
IN DIALOGARGS *pDialogArgs
);
VOID
AdvancedSecurityDetails(
IN HWND hWndParent,
IN DIALOGARGS *pDialogArgs
);
//
// dialog box handling routines.
//
INT_PTR
CALLBACK
DialogConfirmProtect(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
INT_PTR
CALLBACK
DialogConfirmAccess(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
INT_PTR
CALLBACK
DialogChooseSecurityLevel(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
INT_PTR
CALLBACK
DialogChooseSecurityLevelMedium(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
INT_PTR
CALLBACK
DialogChooseSecurityLevelHigh(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
INT_PTR
CALLBACK
DialogAdvancedSecurityDetails(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
//
// helper routines.
//
#ifndef SSAlloc
#define SSAlloc(x) LocalAlloc(LMEM_FIXED, x)
#endif
#ifndef SSFree
#define SSFree(x) LocalFree(x)
#endif
VOID
ComputePasswordHash(
IN PVOID pvPassword,
IN DWORD cbPassword,
IN OUT BYTE rgbPasswordHash[A_SHA_DIGEST_LEN]
);
BOOL
GetEffectiveLogonId(
IN OUT LUID *pLogonId
);
BOOL
InitializeDetailGlobals(
VOID
);
//
// password cache related routines.
//
BOOL
InitializeProtectPasswordCache(
VOID
);
VOID
DeleteProtectPasswordCache(
VOID
);
BOOL
AddProtectPasswordCache(
IN DATA_BLOB* pDataIn,
IN BYTE rgbPassword[A_SHA_DIGEST_LEN]
);
BOOL
SearchProtectPasswordCache(
IN DATA_BLOB* pDataIn,
IN OUT BYTE rgbPassword[A_SHA_DIGEST_LEN],
IN BOOL fDeleteFoundEntry
);
VOID
PurgeProtectPasswordCache(
VOID
);
BOOL
IsCachePWAllowed(
VOID
);
//
// global variables.
//
HINSTANCE g_hInstProtectUI;
CRITICAL_SECTION g_csProtectPasswordCache;
LIST_ENTRY g_ProtectPasswordCache;
#define ALLOW_CACHE_UNKNOWN 0
#define ALLOW_CACHE_NO 1
#define ALLOW_CACHE_YES 2
DWORD g_dwAllowCachePW = 0;
WCHAR g_szGooPassword[] = L"(*&#$(^(#%^))(*&(^(*{}_SAF^^%";
BOOL g_fDetailGlobalsInitialized = FALSE;
LPWSTR g_szDetailApplicationName = NULL;
LPWSTR g_szDetailApplicationPath = NULL;
BOOL
WINAPI
ProtectUI_DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
)
{
BOOL fRet = TRUE;
if( fdwReason == DLL_PROCESS_ATTACH ) {
g_hInstProtectUI = hinstDLL;
fRet = InitializeProtectPasswordCache();
} else if ( fdwReason == DLL_PROCESS_DETACH ) {
DeleteProtectPasswordCache();
}
return fRet;
}
DWORD
WINAPI
I_CryptUIProtect(
IN PVOID pvReserved1,
IN PVOID pvReserved2,
IN DWORD dwReserved3,
IN PVOID *pvReserved4,
IN BOOL fReserved5,
IN PVOID pvReserved6
)
{
DIALOGARGS DialogArgs;
DWORD dwLastError = ERROR_SUCCESS;
DATA_BLOB* pDataIn = (DATA_BLOB*)pvReserved1;
CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct = (CRYPTPROTECT_PROMPTSTRUCT*)pvReserved2;
DWORD dwFlags = (DWORD)dwReserved3;
LPCWSTR szDescription = (LPCWSTR)*pvReserved4;
BOOL fProtectOperation = (BOOL)fReserved5;
PBYTE rgbPasswordHash = (PBYTE)pvReserved6;
BOOL fEmptyDescription;
//
// for protect:
// szDescription, if NULL or empty, get from user
// if PROMPT_STRONG is set, grey out medium security.
//
// for unprotect:
// szDescription, get from datablob.
// pPromptStruct->dwPromptFlags from datablob.
// if PROMPT_STRONG is set, enable password field and
//
if( pPromptStruct == NULL )
return ERROR_INVALID_PARAMETER;
if( pPromptStruct->cbSize != sizeof( CRYPTPROTECT_PROMPTSTRUCT) )
return ERROR_INVALID_PARAMETER;
if( fProtectOperation ) {
//
// if unprotect was specified, protect is implicitly specified.
// vice-versa is true, too.
//
if ( ((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT) == 0) &&
((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) == 0)
)
{
//
// nothing to do, bail out.
//
return ERROR_SUCCESS;
}
pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_ON_PROTECT;
pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_ON_UNPROTECT;
}
if ( dwFlags & CRYPTPROTECT_UI_FORBIDDEN ) {
return ERROR_PASSWORD_RESTRICTION;
}
//
// build dialog box arguments block.
//
DialogArgs.pDataIn = pDataIn;
DialogArgs.pPromptStruct = pPromptStruct;
if( szDescription != NULL && szDescription[0] != L'\0' ) {
DialogArgs.szDataDescription = (LPWSTR)szDescription;
fEmptyDescription = FALSE;
} else {
DialogArgs.szDataDescription = NULL;
fEmptyDescription = TRUE;
}
DialogArgs.rgbPasswordHash = rgbPasswordHash;
DialogArgs.fCachedPassword = FALSE;
DialogArgs.fProtect = fProtectOperation;
DialogArgs.fValidPassword = FALSE;
if( fProtectOperation ) {
//
// now, throw the UI for the protect operation.
//
dwLastError = ProtectUIConfirm( &DialogArgs );
if( dwLastError == ERROR_SUCCESS && fEmptyDescription &&
DialogArgs.szDataDescription ) {
//
// output modified data description to caller.
//
*pvReserved4 = DialogArgs.szDataDescription;
}
} else {
//
// now, throw the UI for the unprotect operation.
//
dwLastError = UnprotectUIConfirm( &DialogArgs );
}
if( fEmptyDescription && dwLastError != ERROR_SUCCESS &&
DialogArgs.szDataDescription ) {
SSFree( DialogArgs.szDataDescription );
}
return dwLastError;
}
DWORD
WINAPI
I_CryptUIProtectFailure(
IN PVOID pvReserved1,
IN DWORD dwReserved2,
IN PVOID *pvReserved3)
{
CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct = (CRYPTPROTECT_PROMPTSTRUCT*)pvReserved1;
DWORD dwFlags = (DWORD)dwReserved2;
LPCWSTR szDescription = (LPCWSTR)*pvReserved3;
WCHAR szTitle[512];
WCHAR szText[512];
if((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) == 0)
{
return ERROR_SUCCESS;
}
if(dwFlags & CRYPTPROTECT_UI_FORBIDDEN)
{
return ERROR_PASSWORD_RESTRICTION;
}
LoadStringU(g_hInstProtectUI, IDS_PROTECT_DECRYPTION_ERROR, szTitle, sizeof(szTitle)/sizeof(WCHAR));
LoadStringU(g_hInstProtectUI, IDS_PROTECT_CANNOT_DECRYPT, szText, sizeof(szText)/sizeof(WCHAR));
MessageBoxU(pPromptStruct->hwndApp, szText, szTitle, MB_OK | MB_ICONWARNING);
return ERROR_SUCCESS;
}
DWORD
ProtectUIConfirm(
IN DIALOGARGS *pDialogArgs
)
{
INT_PTR iRet;
iRet = DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_CONFIRM_PROTECT),
pDialogArgs->pPromptStruct->hwndApp,
DialogConfirmProtect,
(LPARAM)pDialogArgs
);
return (DWORD)iRet;
}
DWORD
UnprotectUIConfirm(
IN DIALOGARGS *pDialogArgs
)
{
INT_PTR iRet;
iRet = DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_CONFIRM_SECURITY),
pDialogArgs->pPromptStruct->hwndApp,
DialogConfirmAccess,
(LPARAM)pDialogArgs
);
return (DWORD)iRet;
}
INT_PTR
CALLBACK
DialogConfirmProtect(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
DIALOGARGS *pDialogArgs;
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
switch (message)
{
case WM_INITDIALOG:
{
SetLastError( 0 ); // as per win32 documentation
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
if(GetLastError() != ERROR_SUCCESS) {
EndDialog(hDlg, GetLastError());
return FALSE;
}
}
// lParam is DIALOGARGS *
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
//
// set the dialog title
//
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
//
// display dynamic stuff.
//
SendMessage( hDlg, WM_COMMAND, IDC_PROTECT_UPDATE_DYNAMIC, 0 );
return FALSE; // don't default the Focus..
} // WM_INITDIALOG
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDOK:
{
EndDialog(hDlg, ERROR_SUCCESS);
return TRUE;
}
case IDCANCEL:
{
EndDialog(hDlg, ERROR_CANCELLED);
return TRUE;
}
case IDC_PROTECT_ADVANCED:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
//
// show details dialog.
//
AdvancedSecurityDetails(
hDlg,
pDialogArgs
);
return FALSE;
}
case IDC_PROTECT_UPDATE_DYNAMIC:
{
WCHAR szResource[ 256 ];
int cchResource = sizeof(szResource) / sizeof(WCHAR);
UINT ResourceId;
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
pPromptStruct = pDialogArgs->pPromptStruct;
//
// description.
//
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_LABEL_EDIT1), pDialogArgs->szDataDescription);
// Disable the OK button if we're defaulting to strong protection,
// unless a password has already been set.
if((pPromptStruct->dwPromptFlags & (CRYPTPROTECT_PROMPT_STRONG |
CRYPTPROTECT_PROMPT_REQUIRE_STRONG)) &&
(pDialogArgs->fValidPassword == FALSE))
{
EnableWindow( GetDlgItem(hDlg, IDOK), FALSE );
SendMessage(hDlg, DM_SETDEFID, IDC_PROTECT_CHANGE_SECURITY, 0);
SetFocus(GetDlgItem(hDlg, IDC_PROTECT_CHANGE_SECURITY));
}
else
{
EnableWindow( GetDlgItem(hDlg, IDOK), TRUE );
SendMessage(hDlg, DM_SETDEFID, IDOK,0);
SetFocus(GetDlgItem(hDlg, IDOK));
}
//
// security level.
//
if( pPromptStruct->dwPromptFlags & (CRYPTPROTECT_PROMPT_STRONG |
CRYPTPROTECT_PROMPT_REQUIRE_STRONG))
{
ResourceId = IDS_PROTECT_SECURITY_LEVEL_SET_HIGH;
} else {
ResourceId = IDS_PROTECT_SECURITY_LEVEL_SET_MEDIUM;
}
cchResource = LoadStringU(g_hInstProtectUI,
ResourceId,
szResource,
cchResource
);
SetWindowTextU( GetDlgItem(hDlg,IDC_PROTECT_SECURITY_LEVEL),
szResource
);
return FALSE;
}
case IDC_PROTECT_CHANGE_SECURITY:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
//
// spawn child dialog to handle prompting for security level.
//
if(!ChooseSecurityLevel( hDlg, pDialogArgs )) {
EndDialog(hDlg, ERROR_CANCELLED);
return TRUE;
}
//
// display dynamic stuff that may have changed.
//
SendMessage( hDlg, WM_COMMAND, IDC_PROTECT_UPDATE_DYNAMIC, 0 );
break;
}
default:
{
return FALSE;
}
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // message
}
INT_PTR
CALLBACK
DialogConfirmAccess(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
DIALOGARGS *pDialogArgs;
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
switch (message)
{
case WM_INITDIALOG:
{
SetLastError( 0 ); // as per win32 documentation
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
if(GetLastError() != ERROR_SUCCESS) {
EndDialog(hDlg, GetLastError());
return FALSE;
}
}
// lParam is DIALOGARGS *
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
//
// set the dialog title
//
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
//
// description.
//
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_LABEL_EDIT1), pDialogArgs->szDataDescription);
if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
//
// If policy doesn't allow, disable caching of password.
//
// Otherwise, search password cache to see if user cached password
// for this item.
//
if( g_dwAllowCachePW == ALLOW_CACHE_UNKNOWN )
{
if(!IsCachePWAllowed()) {
g_dwAllowCachePW = ALLOW_CACHE_NO;
} else {
g_dwAllowCachePW = ALLOW_CACHE_YES;
}
}
if((g_dwAllowCachePW == ALLOW_CACHE_NO) ||
(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG))
{
ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), SW_HIDE );
EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), FALSE );
} else if(SearchProtectPasswordCache( pDialogArgs->pDataIn, pDialogArgs->rgbPasswordHash, FALSE ))
{
//
// enable checkbox for cached password, fill edit control
// with password.
//
SetWindowTextU(GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
g_szGooPassword
);
SendMessage(GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), BM_SETCHECK, BST_CHECKED, 0);
pDialogArgs->fCachedPassword = TRUE;
pDialogArgs->fValidPassword = TRUE;
}
} else {
//
// disable irrelevant fields in dialog.
//
ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), SW_HIDE );
EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), FALSE );
ShowWindow( GetDlgItem(hDlg, IDC_PROTECT_PASSWORD1), SW_HIDE );
EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_PASSWORD1), FALSE );
}
return TRUE;
} // WM_INITDIALOG
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDOK:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
pPromptStruct = pDialogArgs->pPromptStruct;
if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
{
WCHAR szPassword[ 256 ];
int cchPassword = sizeof(szPassword) / sizeof(WCHAR);
BOOL fCachePassword;
//
// check if remember password is checked.
// if so, check if password is untypable goo.
//
if( g_dwAllowCachePW != ALLOW_CACHE_NO &&
(BST_CHECKED == SendMessage(GetDlgItem(hDlg, IDC_PROTECT_CACHEPW), BM_GETCHECK, 0, 0))
)
{
fCachePassword = TRUE;
} else {
fCachePassword = FALSE;
}
cchPassword = GetWindowTextU(
GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
szPassword,
cchPassword
);
if( !fCachePassword && pDialogArgs->fCachedPassword ) {
//
// user un-checked cachePW button, and item was cached.
// remove it from cache.
//
SearchProtectPasswordCache(
pDialogArgs->pDataIn,
pDialogArgs->rgbPasswordHash,
TRUE
);
}
if(
pDialogArgs->fCachedPassword &&
(cchPassword*sizeof(WCHAR) == sizeof(g_szGooPassword)-sizeof(WCHAR)) &&
(memcmp(szPassword, g_szGooPassword, cchPassword*sizeof(WCHAR)) == 0)
)
{
//
// nothing to do, rgbPasswordHash was updated by
// cache search...
//
} else {
ComputePasswordHash(
szPassword,
(DWORD)(cchPassword * sizeof(WCHAR)),
pDialogArgs->rgbPasswordHash
);
pDialogArgs->fValidPassword = TRUE;
//
// if user chose to cache password, add it.
//
if( fCachePassword )
{
AddProtectPasswordCache(
pDialogArgs->pDataIn,
pDialogArgs->rgbPasswordHash
);
}
}
}
EndDialog(hDlg, ERROR_SUCCESS);
return TRUE;
}
case IDCANCEL:
{
EndDialog(hDlg, ERROR_CANCELLED);
return TRUE;
}
case IDC_PROTECT_ADVANCED:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
//
// show details dialog.
//
AdvancedSecurityDetails(
hDlg,
pDialogArgs
);
return FALSE;
}
default:
{
return FALSE;
}
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // message
}
//
// security level chooser routines.
//
BOOL
ChooseSecurityLevel(
IN HWND hWndParent,
IN DIALOGARGS *pDialogArgs
)
{
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
DWORD dwOriginalPromptFlags;
BOOL fEmptyDescription;
INT_PTR iRet;
pPromptStruct = pDialogArgs->pPromptStruct;
dwOriginalPromptFlags = pPromptStruct->dwPromptFlags;
fEmptyDescription = (pDialogArgs->szDataDescription == NULL);
Step1:
if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
{
//
// Force strong protection.
//
pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_STRONG;
}
else
{
//
// The "require strong" flag is not set, so allow the user to select
// between medium and strong protection.
//
iRet = DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY),
hWndParent,
DialogChooseSecurityLevel,
(LPARAM)pDialogArgs
);
// if user decides not to choose, bail
if( iRet == IDCANCEL )
return TRUE;
if( iRet != IDOK )
return FALSE;
}
if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
//
// display dialog 'page' confirming high security.
//
iRet = DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY_H),
hWndParent,
DialogChooseSecurityLevelHigh,
(LPARAM)pDialogArgs
);
} else {
//
// display dialog 'page' confirming medium security.
//
iRet = DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_CHOOSE_SECURITY_M),
hWndParent,
DialogChooseSecurityLevelMedium,
(LPARAM)pDialogArgs
);
}
if( iRet == IDC_PROTECT_BACK ) {
//
// put original prompt flags back so we don't end up with undefined
// pwd at high-security level.
// free allocated description if that happened, too.
//
pPromptStruct->dwPromptFlags = dwOriginalPromptFlags;
if( fEmptyDescription && pDialogArgs->szDataDescription ) {
SSFree( pDialogArgs->szDataDescription );
pDialogArgs->szDataDescription = NULL;
}
goto Step1;
}
if( iRet != IDOK )
return FALSE;
return TRUE;
}
INT_PTR
CALLBACK
DialogChooseSecurityLevel(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (message)
{
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
DIALOGARGS *pDialogArgs;
case WM_INITDIALOG:
{
SetLastError( 0 ); // as per win32 documentation
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
if(GetLastError() != ERROR_SUCCESS) {
EndDialog(hDlg, IDCANCEL);
return FALSE;
}
}
// lParam is DIALOGARGS*
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
// set the dialog title
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG ) {
SendDlgItemMessage(hDlg, IDC_PROTECT_RADIO_HIGH, BM_SETCHECK, BST_CHECKED, 0);
SendMessage(hDlg, WM_COMMAND, (WORD)IDC_PROTECT_RADIO_HIGH, 0);
} else {
SendDlgItemMessage(hDlg, IDC_PROTECT_RADIO_MEDIUM, BM_SETCHECK, BST_CHECKED, 0);
SendMessage(hDlg, WM_COMMAND, (WORD)IDC_PROTECT_RADIO_MEDIUM, 0);
}
return TRUE;
} // WM_INITDIALOG
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_PROTECT_NEXT:
case IDOK:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
pPromptStruct = pDialogArgs->pPromptStruct;
if (BST_CHECKED == SendDlgItemMessageW(
hDlg,
IDC_PROTECT_RADIO_HIGH,
BM_GETCHECK,
0,
0
))
{
pPromptStruct->dwPromptFlags |= CRYPTPROTECT_PROMPT_STRONG;
} else {
pPromptStruct->dwPromptFlags &= ~(CRYPTPROTECT_PROMPT_STRONG);
}
break;
}
default:
{
break;
}
}
if (
(LOWORD(wParam) == IDOK) ||
(LOWORD(wParam) == IDCANCEL) ||
(LOWORD(wParam) == IDC_PROTECT_NEXT)
)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // message
}
INT_PTR
CALLBACK
DialogChooseSecurityLevelMedium(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (message)
{
case WM_INITDIALOG:
{
DIALOGARGS *pDialogArgs;
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
// lParam is DIALOGARGS*
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
// set the dialog title
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
return TRUE;
} // WM_INITDIALOG
case WM_COMMAND:
{
if (
(LOWORD(wParam) == IDOK) ||
(LOWORD(wParam) == IDCANCEL) ||
(LOWORD(wParam) == IDC_PROTECT_BACK)
)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // message
}
INT_PTR
CALLBACK
DialogChooseSecurityLevelHigh(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (message)
{
DIALOGARGS *pDialogArgs;
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
case WM_INITDIALOG:
{
SetLastError( 0 ); // as per win32 documentation
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
if(GetLastError() != ERROR_SUCCESS) {
EndDialog(hDlg, IDCANCEL);
return FALSE;
}
}
// lParam is DIALOGARGS*
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
// set the dialog title
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
// Disable <Back and Finished buttons
if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
{
EnableWindow( GetDlgItem(hDlg, IDC_PROTECT_BACK), FALSE );
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
//
// description.
//
if( pDialogArgs->szDataDescription ) {
HWND hwndProtectEdit1 = GetDlgItem( hDlg, IDC_PROTECT_PASSWORD1 );
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_PW_NEWNAME), pDialogArgs->szDataDescription);
//
// set focus to Password entry box.
//
EnableWindow(hwndProtectEdit1, TRUE);
SetFocus(hwndProtectEdit1);
//
// default dialog template disabled input.
//
} else {
HWND hwndProtectPWNew = GetDlgItem( hDlg, IDC_PROTECT_PW_NEWNAME );
//
// enable edit box entry.
//
EnableWindow(hwndProtectPWNew, TRUE);
//
// set focus to description box
//
SetFocus(hwndProtectPWNew);
}
return FALSE;
} // WM_INITDIALOG
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDOK:
{
WCHAR szPassword[ 256 ];
int cchPassword;
BYTE rgbPasswordHashConfirm[A_SHA_DIGEST_LEN];
BOOL fPasswordsMatch = TRUE; // assume passwords match.
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
pPromptStruct = pDialogArgs->pPromptStruct;
//
// nothing more to do if not STRONG
//
if( (pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG) == 0 ) {
EndDialog( hDlg, IDOK );
}
cchPassword = sizeof(szPassword) / sizeof(WCHAR);
cchPassword = GetWindowTextU(
GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
szPassword,
cchPassword
);
ComputePasswordHash(
szPassword,
cchPassword * sizeof(WCHAR),
pDialogArgs->rgbPasswordHash
);
ZeroMemory( szPassword, cchPassword*sizeof(WCHAR) );
cchPassword = sizeof(szPassword) / sizeof(WCHAR);
cchPassword = GetWindowTextU(
GetDlgItem(hDlg,IDC_PROTECT_EDIT2),
szPassword,
cchPassword
);
ComputePasswordHash(
szPassword,
cchPassword * sizeof(WCHAR),
rgbPasswordHashConfirm
);
ZeroMemory( szPassword, cchPassword*sizeof(WCHAR) );
//
// check if both passwords entered by user match.
//
if( memcmp(rgbPasswordHashConfirm, pDialogArgs->rgbPasswordHash, sizeof(rgbPasswordHashConfirm)) != 0 )
{
fPasswordsMatch = FALSE;
}
ZeroMemory( rgbPasswordHashConfirm, sizeof(rgbPasswordHashConfirm) );
if( !fPasswordsMatch )
{
WCHAR szText[256];
WCHAR szCaption[256];
//
// passwords must match: tell user.
//
LoadStringU(g_hInstProtectUI,
IDS_PROTECT_PASSWORD_NOMATCH,
szText,
sizeof(szText) / sizeof(WCHAR)
);
LoadStringU(g_hInstProtectUI,
IDS_PROTECT_PASSWORD_ERROR_DLGTITLE,
szCaption,
sizeof(szCaption) / sizeof(WCHAR)
);
MessageBoxW(hDlg,
szText,
szCaption,
MB_OK | MB_ICONEXCLAMATION
);
return FALSE;
}
//
// if no description provided, make sure user entered one,
// and grab it..
//
if( pDialogArgs->szDataDescription == NULL ) {
cchPassword = sizeof(szPassword) / sizeof(WCHAR);
cchPassword = GetWindowTextU(
GetDlgItem(hDlg,IDC_PROTECT_PW_NEWNAME),
szPassword,
cchPassword
);
if( cchPassword == 0 ) {
WCHAR szText[256];
WCHAR szCaption[256];
//
// password must be named: tell user.
//
LoadStringU(g_hInstProtectUI,
IDS_PROTECT_PASSWORD_MUSTNAME,
szText,
sizeof(szText) / sizeof(WCHAR)
);
LoadStringU(g_hInstProtectUI,
IDS_PROTECT_PASSWORD_ERROR_DLGTITLE,
szCaption,
sizeof(szCaption) / sizeof(WCHAR)
);
MessageBoxW(hDlg,
szText,
szCaption,
MB_OK | MB_ICONEXCLAMATION
);
return FALSE;
}
pDialogArgs->szDataDescription = (LPWSTR)SSAlloc( (cchPassword+1) * sizeof(WCHAR) );
if( pDialogArgs->szDataDescription == NULL )
return FALSE;
CopyMemory( pDialogArgs->szDataDescription, szPassword, cchPassword*sizeof(WCHAR) );
(pDialogArgs->szDataDescription)[cchPassword] = L'\0';
}
pDialogArgs->fValidPassword = TRUE;
EndDialog(hDlg, IDOK);
return TRUE;
}
case IDC_PROTECT_PASSWORD1:
{
pDialogArgs = (DIALOGARGS*)GetWindowLongPtr(
hDlg,
GWLP_USERDATA
);
if(pDialogArgs == NULL)
break; // TODO: bail out
pPromptStruct = pDialogArgs->pPromptStruct;
if(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG)
{
WCHAR szPassword[ 256 ];
int cchPassword;
//
// Disable the Finish button until a password has been entered.
//
cchPassword = sizeof(szPassword) / sizeof(WCHAR);
cchPassword = GetWindowTextU(
GetDlgItem(hDlg,IDC_PROTECT_PASSWORD1),
szPassword,
cchPassword
);
if(cchPassword)
{
ZeroMemory(szPassword, cchPassword * sizeof(WCHAR));
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
}
break;
}
case IDC_PROTECT_BACK:
case IDCANCEL:
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
default:
{
break;
}
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // message
}
VOID
AdvancedSecurityDetails(
IN HWND hWndParent,
IN DIALOGARGS *pDialogArgs
)
{
DialogBoxParamU(
g_hInstProtectUI,
MAKEINTRESOURCE(IDD_PROTECT_SECURITY_DETAILS),
hWndParent,
DialogAdvancedSecurityDetails,
(LPARAM)pDialogArgs
);
}
INT_PTR
CALLBACK
DialogAdvancedSecurityDetails(
HWND hDlg, // handle to dialog box
UINT message, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch (message) {
DIALOGARGS *pDialogArgs;
CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct;
case WM_INITDIALOG:
{
WCHAR szResource[ 256 ];
UINT ResourceId;
SetLastError( 0 ); // as per win32 documentation
if(SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)lParam) == 0) {
if(GetLastError() != ERROR_SUCCESS) {
EndDialog(hDlg, IDCANCEL);
return FALSE;
}
}
// lParam is DIALOGARGS*
pDialogArgs = (DIALOGARGS*)lParam;
pPromptStruct = pDialogArgs->pPromptStruct;
// set the dialog title
SetWindowTextU(hDlg, pPromptStruct->szPrompt);
InitializeDetailGlobals();
if(g_szDetailApplicationPath)
{
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_APP_PATH), g_szDetailApplicationPath);
}
if( pDialogArgs->fProtect ) {
ResourceId = IDS_PROTECT_OPERATION_PROTECT;
} else {
ResourceId = IDS_PROTECT_OPERATION_UNPROTECT;
}
LoadStringU(g_hInstProtectUI,
ResourceId,
szResource,
sizeof(szResource) / sizeof(WCHAR)
);
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_OPERATION_TYPE), szResource);
if( pDialogArgs->szDataDescription ) {
SetWindowTextU(GetDlgItem(hDlg, IDC_PROTECT_APP_DESCRIPTION), pDialogArgs->szDataDescription);
}
return FALSE;
} // WM_INITDIALOG
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
default:
{
break;
}
}
} // WM_COMMAND
default:
{
return FALSE;
}
} // switch
return FALSE;
}
VOID
ComputePasswordHash(
IN PVOID pvPassword,
IN DWORD cbPassword,
IN OUT BYTE rgbPasswordHash[A_SHA_DIGEST_LEN]
)
/*++
Compute SHA-1 hash of supplied pvPassword of size cbPassword, returning
resultant hash in rgbPasswordHash buffer.
--*/
{
A_SHA_CTX shaCtx;
if( pvPassword == NULL )
return;
A_SHAInit( &shaCtx );
A_SHAUpdate( &shaCtx, (unsigned char*)pvPassword, (unsigned int)cbPassword );
A_SHAFinal( &shaCtx, rgbPasswordHash );
ZeroMemory( &shaCtx, sizeof(shaCtx) );
return;
}
BOOL
GetEffectiveLogonId(
IN OUT LUID *pLogonId
)
{
HANDLE hToken;
TOKEN_STATISTICS TokenInformation;
DWORD cbTokenInformation;
BOOL fSuccess;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) {
if(GetLastError() != ERROR_NO_TOKEN)
return FALSE;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return FALSE;
}
fSuccess = GetTokenInformation(
hToken,
TokenStatistics,
&TokenInformation,
sizeof(TokenInformation),
&cbTokenInformation
);
CloseHandle( hToken );
if( fSuccess ) {
CopyMemory( pLogonId, &TokenInformation.AuthenticationId, sizeof(*pLogonId) );
}
return fSuccess;
}
BOOL
InitializeDetailGlobals(
VOID
)
{
WCHAR szStackBuffer[ 256 ];
DWORD cchStackBuffer;
LPWSTR szDetailApplicationName = NULL;
LPWSTR szDetailApplicationPath = NULL;
if( g_fDetailGlobalsInitialized )
return TRUE;
cchStackBuffer = sizeof(szStackBuffer) / sizeof(WCHAR);
cchStackBuffer = GetModuleFileNameU( NULL, szStackBuffer, cchStackBuffer );
if( cchStackBuffer ) {
cchStackBuffer++; // include terminal NULL.
szDetailApplicationPath = (LPWSTR)SSAlloc( cchStackBuffer * sizeof(WCHAR) );
if( szDetailApplicationPath ) {
CopyMemory( szDetailApplicationPath, szStackBuffer, cchStackBuffer*sizeof(WCHAR) );
}
}
EnterCriticalSection( &g_csProtectPasswordCache );
if( !g_fDetailGlobalsInitialized ) {
g_szDetailApplicationName = szDetailApplicationName;
g_szDetailApplicationPath = szDetailApplicationPath;
g_fDetailGlobalsInitialized = TRUE;
szDetailApplicationName = NULL;
szDetailApplicationPath = NULL;
}
LeaveCriticalSection( &g_csProtectPasswordCache );
if( szDetailApplicationName )
SSFree( szDetailApplicationName );
if( szDetailApplicationPath )
SSFree( szDetailApplicationPath );
return TRUE;
}
BOOL
InitializeProtectPasswordCache(
VOID
)
{
__try
{
InitializeCriticalSection( &g_csProtectPasswordCache );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
memset(&g_csProtectPasswordCache, 0, sizeof(g_csProtectPasswordCache));
SetLastError(GetExceptionCode());
return FALSE;
}
InitializeListHead( &g_ProtectPasswordCache );
g_fDetailGlobalsInitialized = FALSE;
g_szDetailApplicationName = NULL;
g_szDetailApplicationPath = NULL;
return TRUE;
}
VOID
DeleteProtectPasswordCache(
VOID
)
{
if( g_szDetailApplicationName )
{
SSFree(g_szDetailApplicationName);
g_szDetailApplicationName = NULL;
}
if( g_szDetailApplicationPath )
{
SSFree(g_szDetailApplicationPath);
g_szDetailApplicationPath = NULL;
}
g_fDetailGlobalsInitialized = FALSE;
EnterCriticalSection( &g_csProtectPasswordCache );
while ( !IsListEmpty( &g_ProtectPasswordCache ) ) {
PPASSWORD_CACHE_ENTRY pCacheEntry;
pCacheEntry = CONTAINING_RECORD(
g_ProtectPasswordCache.Flink,
PASSWORD_CACHE_ENTRY,
Next
);
RemoveEntryList( &pCacheEntry->Next );
ZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
SSFree( pCacheEntry );
}
LeaveCriticalSection( &g_csProtectPasswordCache );
DeleteCriticalSection( &g_csProtectPasswordCache );
}
BOOL
AddProtectPasswordCache(
IN DATA_BLOB* pDataIn,
IN BYTE rgbPassword[A_SHA_DIGEST_LEN]
)
{
PPASSWORD_CACHE_ENTRY pCacheEntry = NULL;
A_SHA_CTX shaCtx;
pCacheEntry = (PPASSWORD_CACHE_ENTRY)SSAlloc( sizeof(PASSWORD_CACHE_ENTRY) );
if( pCacheEntry == NULL )
return FALSE;
GetEffectiveLogonId( &pCacheEntry->LogonId );
GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
A_SHAInit( &shaCtx );
A_SHAUpdate( &shaCtx, (unsigned char*)pDataIn->pbData, pDataIn->cbData );
A_SHAFinal( &shaCtx, pCacheEntry->rgbDataInHash );
ZeroMemory( &shaCtx, sizeof(shaCtx) );
CopyMemory( pCacheEntry->rgbPasswordHash, rgbPassword, A_SHA_DIGEST_LEN );
EnterCriticalSection( &g_csProtectPasswordCache );
InsertHeadList( &g_ProtectPasswordCache, &pCacheEntry->Next );
LeaveCriticalSection( &g_csProtectPasswordCache );
return TRUE;
}
BOOL
SearchProtectPasswordCache(
IN DATA_BLOB* pDataIn,
IN OUT BYTE rgbPassword[A_SHA_DIGEST_LEN],
IN BOOL fDeleteFoundEntry
)
{
A_SHA_CTX shaCtx;
BYTE rgbDataInHashCandidate[A_SHA_DIGEST_LEN];
LUID LogonIdCandidate;
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
BOOL fFoundMatch = FALSE;
if(!GetEffectiveLogonId( &LogonIdCandidate ))
return FALSE;
A_SHAInit( &shaCtx );
A_SHAUpdate( &shaCtx, (unsigned char*)pDataIn->pbData, pDataIn->cbData );
A_SHAFinal( &shaCtx, rgbDataInHashCandidate );
EnterCriticalSection( &g_csProtectPasswordCache );
ListHead = &g_ProtectPasswordCache;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
PPASSWORD_CACHE_ENTRY pCacheEntry;
signed int comparator;
pCacheEntry = CONTAINING_RECORD( ListEntry, PASSWORD_CACHE_ENTRY, Next );
//
// search by hash, then LogonId
// note that most usage scenarios, all cache entries will correspond
// to same LogonId.
//
comparator = memcmp( rgbDataInHashCandidate, pCacheEntry->rgbDataInHash, sizeof(rgbDataInHashCandidate) );
if( comparator != 0 )
continue;
comparator = memcmp(&LogonIdCandidate, &pCacheEntry->LogonId, sizeof(LUID));
if( comparator != 0 )
continue;
//
// match found.
//
fFoundMatch = TRUE;
if( fDeleteFoundEntry ) {
RemoveEntryList( &pCacheEntry->Next );
ZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
SSFree( pCacheEntry );
} else {
CopyMemory( rgbPassword, pCacheEntry->rgbPasswordHash, A_SHA_DIGEST_LEN );
//
// update last access time.
//
GetSystemTimeAsFileTime( &pCacheEntry->ftLastAccess );
}
break;
}
LeaveCriticalSection( &g_csProtectPasswordCache );
PurgeProtectPasswordCache();
return fFoundMatch;
}
VOID
PurgeProtectPasswordCache(
VOID
)
/*++
This routine purges entries in the password cache that are greater than
1 hour in age, via the ftLastAccess time.
--*/
{
// static FILETIME ftLastPurge = {0xffffffff,0xffffffff};
static FILETIME ftLastPurge;
FILETIME ftStaleEntry;
PLIST_ENTRY ListEntry;
PLIST_ENTRY ListHead;
unsigned __int64 ui64;
//
// get current time, and subtract an hour off it.
//
GetSystemTimeAsFileTime( &ftStaleEntry );
ui64 = ftStaleEntry.dwHighDateTime;
ui64 <<= 32;
ui64 |= ftStaleEntry.dwLowDateTime;
// ui64 -= (600000000*60);
ui64 -= 0x861c46800;
ftStaleEntry.dwLowDateTime = (DWORD)(ui64 & 0xffffffff);
ftStaleEntry.dwHighDateTime = (DWORD)(ui64 >> 32);
//
// only purge list once per hour.
//
if( CompareFileTime( &ftStaleEntry, &ftLastPurge ) < 0 ) {
return;
}
//
// update last purge time.
//
GetSystemTimeAsFileTime( &ftLastPurge );
EnterCriticalSection( &g_csProtectPasswordCache );
ListHead = &g_ProtectPasswordCache;
for( ListEntry = ListHead->Flink;
ListEntry != ListHead;
ListEntry = ListEntry->Flink ) {
PPASSWORD_CACHE_ENTRY pCacheEntry;
signed int comparator;
pCacheEntry = CONTAINING_RECORD( ListEntry, PASSWORD_CACHE_ENTRY, Next );
if( CompareFileTime( &ftStaleEntry, &pCacheEntry->ftLastAccess ) > 0 )
{
ListEntry = ListEntry->Blink;
RemoveEntryList( &pCacheEntry->Next );
ZeroMemory( pCacheEntry, sizeof(*pCacheEntry) );
SSFree( pCacheEntry );
}
}
LeaveCriticalSection( &g_csProtectPasswordCache );
return;
}
BOOL
IsCachePWAllowed(
VOID
)
{
HKEY hKeyProtect;
DWORD dwType;
DWORD dwValue;
DWORD cbValue;
LONG lRet;
lRet = RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Policies\\Microsoft\\Cryptography\\Protect",
0,
KEY_QUERY_VALUE,
&hKeyProtect
);
if( lRet != ERROR_SUCCESS )
return TRUE;
cbValue = sizeof(dwValue);
lRet = RegQueryValueExU(
hKeyProtect,
L"AllowCachePW",
NULL,
&dwType,
(PBYTE)&dwValue,
&cbValue
);
RegCloseKey( hKeyProtect );
if( lRet == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 0 ) {
return FALSE;
}
return TRUE;
}