|
|
/*
File: Passwd.cpp
Title: Protected Storage User Confirm wrappers Author: Matt Thomlinson Date: 2/25/97
Passwd.cpp simply houses a few of the password-management functions. These functions are called on to return the user-confirmation derived buffer, and check synchronization in certain cases.
As the Authentication provider interface gets defined, this could end up getting moved into a seperate provider.
*/
#include <pch.cpp>
#pragma hdrstop
#include "provui.h"
#include "storage.h"
#include "passwd.h"
extern DISPIF_CALLBACKS g_sCallbacks; extern PRIVATE_CALLBACKS g_sPrivateCallbacks; extern CUAList* g_pCUAList;
///////////////////////////////////////////////////////////////////////
// non-user editable passwords
BOOL FIsUserMasterKey(LPCWSTR szMasterKey) { if (0 == wcscmp(szMasterKey, WSZ_PASSWORD_WINDOWS)) return FALSE;
return TRUE; }
BOOL FMyGetWinPassword( PST_PROVIDER_HANDLE* phPSTProv, LPCWSTR szUser, BYTE rgbPwd[A_SHA_DIGEST_LEN] ) { // nab pwd
if (0 == wcscmp(szUser, WSZ_LOCAL_MACHINE)) { CopyMemory(rgbPwd, RGB_LOCALMACHINE_KEY, A_SHA_DIGEST_LEN); } else { /*
if (! g_sPrivateCallbacks.pfnFGetWindowsPassword( phPSTProv, rgbPwd, A_SHA_DIGEST_LEN)) return FALSE; */ A_SHA_CTX context; DWORD cb = lstrlenW(szUser) * sizeof(WCHAR); BYTE Magic1[] = {0x66, 0x41, 0xa3, 0x29}; BYTE Magic2[] = {0x14, 0x9a, 0xef, 0x82};
A_SHAInit(&context); // note: the three Update calls get buffered up internally to
// multiples of 64 bytes.
//
A_SHAUpdate(&context, Magic1, sizeof(Magic1)); A_SHAUpdate(&context, (LPBYTE)szUser, cb); A_SHAUpdate(&context, Magic2, (cb+sizeof(Magic2)) % sizeof(Magic2)); A_SHAFinal(&context, rgbPwd); }
return TRUE; }
// Base Provider specific fxn: check the password
DWORD BPVerifyPwd( PST_PROVIDER_HANDLE* phPSTProv, LPCWSTR szUser, LPCWSTR szMasterKey, BYTE rgbPwd[], DWORD dwPasswordOption) { DWORD dwRet = (DWORD)PST_E_WRONG_PASSWORD;
if (dwPasswordOption != BP_CONFIRM_PASSWORDUI) { // only non-user keys can be silent (WinPWs only, to be exact)
if (FIsUserMasterKey(szMasterKey)) goto Ret;
// get the Windows pwd
if (!FMyGetWinPassword(phPSTProv, szUser, rgbPwd)) goto Ret;
// check
if (!FCheckPWConfirm( szUser, szMasterKey, rgbPwd)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } } else // UI wanted
{ // is it the windows password?
if (0 == wcscmp(szMasterKey, WSZ_PASSWORD_WINDOWS)) { BYTE rgbWinPwd[A_SHA_DIGEST_LEN];
// we need to keep user, WinPW in sync
if(!FMyGetWinPassword( phPSTProv, szUser, rgbWinPwd )) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; }
if (0 != memcmp(rgbWinPwd, rgbPwd, sizeof(rgbWinPwd) )) { // no match: user entered old password?
if (FCheckPWConfirm( szUser, szMasterKey, rgbPwd)) { // err: user entered neither old nor new password
dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } } else { // matched: user entered password we consider good
if (!FCheckPWConfirm( szUser, szMasterKey, rgbPwd)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } }
} else { // else: not win pw, just do pw correctness check
if (!FCheckPWConfirm( szUser, szMasterKey, rgbPwd)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } } }
dwRet = (DWORD)PST_E_OK; Ret: return dwRet; }
HRESULT GetUserConfirmDefaults( PST_PROVIDER_HANDLE* phPSTProv, DWORD* pdwDefaultConfirmationStyle, LPWSTR* ppszMasterKey) { SS_ASSERT(ppszMasterKey != NULL); SS_ASSERT(pdwDefaultConfirmationStyle != NULL);
PBYTE pbData = NULL; DWORD cbData; HRESULT hr = PST_E_FAIL;
// if not found, restore the machine defaults
// alloc sizeof string + dword
cbData = sizeof(WSZ_PASSWORD_WINDOWS) + sizeof(DWORD); pbData = (PBYTE)SSAlloc(cbData); if(pbData == NULL) return PST_E_FAIL;
// copy string, DWORD confirmation type
*(DWORD*)pbData = BP_CONFIRM_OKCANCEL; CopyMemory(pbData+sizeof(DWORD), WSZ_PASSWORD_WINDOWS, sizeof(WSZ_PASSWORD_WINDOWS));
// format: confirmation style DWORD, sz
*pdwDefaultConfirmationStyle = *(DWORD*)pbData; *ppszMasterKey = (LPWSTR)SSAlloc(WSZ_BYTECOUNT((LPWSTR)(pbData+sizeof(DWORD))));
if(*ppszMasterKey != NULL) { wcscpy(*ppszMasterKey, (LPWSTR) (pbData+sizeof(DWORD)) ); hr = PST_E_OK; }
// free what ConfigData returned
if (pbData) SSFree(pbData);
return hr; }
void NotifyOfWrongPassword( HWND hwnd, LPCWSTR szItemName, LPCWSTR szPasswordName) { LPWSTR szMessage;
if (0 == wcscmp(szPasswordName, WSZ_PASSWORD_WINDOWS)) szMessage = g_PasswordWinNoVerify; else szMessage = g_PasswordNoVerify; // error doesn't deal with win pw
MessageBoxW(hwnd, szMessage, szItemName, MB_OK | MB_SERVICE_NOTIFICATION); }
// #define to force an unreadable confirmation to bail from read proc
#define PST_CF_STORED_ONLY 0xcf000001
HRESULT GetUserConfirmBuf( PST_PROVIDER_HANDLE* phPSTProv, LPCWSTR szUser, PST_KEY Key, LPCWSTR szType, const GUID* pguidType, LPCWSTR szSubtype, const GUID* pguidSubtype, LPCWSTR szItemName, PPST_PROMPTINFO psPrompt, LPCWSTR szAction, LPWSTR* ppszMasterKey, BYTE rgbPwd[A_SHA_DIGEST_LEN], DWORD dwFlags) { return GetUserConfirmBuf( phPSTProv, szUser, Key, szType, pguidType, szSubtype, pguidSubtype, szItemName, psPrompt, szAction, PST_CF_STORED_ONLY, // hardcoded: must be able to retreive in order to show ui
ppszMasterKey, rgbPwd, dwFlags); }
#define MAX_PASSWD_TRIALS 3
HRESULT GetUserConfirmBuf( PST_PROVIDER_HANDLE* phPSTProv, LPCWSTR szUser, PST_KEY Key, LPCWSTR szType, const GUID* pguidType, LPCWSTR szSubtype, const GUID* pguidSubtype, LPCWSTR szItemName, PPST_PROMPTINFO psPrompt, LPCWSTR szAction, DWORD dwDefaultConfirmationStyle, LPWSTR* ppszMasterKey, BYTE rgbOutPwd[A_SHA_DIGEST_LEN], DWORD dwFlags) { HRESULT hr; DWORD dwStoredConfirm, dwChosenConfirm; LPWSTR szCallerName = NULL; BOOL fPromptedUser = FALSE;
BOOL fIsCached = FALSE; BOOL fCacheItNow = FALSE;
BOOL fPwdVerified = FALSE;
SS_ASSERT(*ppszMasterKey == NULL); // don't whack existing memory
if (Key == PST_KEY_LOCAL_MACHINE) { // short-circuit password gathering, setting
*ppszMasterKey = (LPWSTR) SSAlloc(sizeof(WSZ_PASSWORD_WINDOWS)); if( *ppszMasterKey == NULL ) { hr = PST_E_FAIL; goto Ret; }
wcscpy(*ppszMasterKey, WSZ_PASSWORD_WINDOWS);
CopyMemory(rgbOutPwd, RGB_LOCALMACHINE_KEY, A_SHA_DIGEST_LEN);
// done
hr = PST_E_OK; goto Ret; }
if (!g_sCallbacks.pfnFGetCallerName(phPSTProv, &szCallerName, NULL)) { hr = PST_E_FAIL; goto Ret; }
// Which is this: item creation, item access?
// item access does user authentication
SS_ASSERT(szItemName != NULL);
// per-item key
if (PST_E_OK != (hr = BPGetItemConfirm( phPSTProv, szUser, pguidType, pguidSubtype, szItemName, &dwStoredConfirm, ppszMasterKey)) ) { // this could be a failure in
// * confirmation: tampering detected!!
// * password: couldn't grab user pwd
if (dwDefaultConfirmationStyle == PST_CF_STORED_ONLY) goto Ret;
//
// if UI is not allowed (eg, Local System account), over-ride
// confirmation style.
//
if (dwDefaultConfirmationStyle != PST_CF_NONE) { if(!FIsProviderUIAllowed( szUser )) dwDefaultConfirmationStyle = PST_CF_NONE; }
// if app asked to have no confirm, set item that way
if (dwDefaultConfirmationStyle == PST_CF_NONE) { dwChosenConfirm = BP_CONFIRM_NONE;
// short-circuit password gathering, setting
*ppszMasterKey = (LPWSTR) SSAlloc(sizeof(WSZ_PASSWORD_WINDOWS)); if(*ppszMasterKey == NULL) { hr = PST_E_FAIL; goto Ret; } wcscpy(*ppszMasterKey, WSZ_PASSWORD_WINDOWS); } else // app allows user to decide
{ // get user default
if (PST_E_OK != (hr = GetUserConfirmDefaults( phPSTProv, &dwChosenConfirm, ppszMasterKey)) ) goto Ret; }
// if user default is silent, don't bother user
switch(dwChosenConfirm) { // if no confirm
case BP_CONFIRM_NONE: break;
// if we know the confirm type
case BP_CONFIRM_PASSWORDUI: { // make sure we're not asking the user for a password he can't satisfy
if (!FIsUserMasterKey(*ppszMasterKey)) { hr = PST_E_NO_PERMISSIONS; goto Ret; }
// else fall through to prompting case
}
case BP_CONFIRM_OKCANCEL: { int i; fPromptedUser = TRUE;
for(i=1; ; i++) { BYTE rgbOutPwdLowerCase[A_SHA_DIGEST_LEN];
// Request the user apply a new password
if (!FSimplifiedPasswordConfirm( phPSTProv, szUser, szCallerName, szType, szSubtype, szItemName, psPrompt, szAction, ppszMasterKey, &dwChosenConfirm, TRUE, // user select which pwd
rgbOutPwd, A_SHA_DIGEST_LEN, rgbOutPwdLowerCase, A_SHA_DIGEST_LEN, dwFlags )) { hr = PST_E_NO_PERMISSIONS; goto Ret; }
// verify whatever password we got
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, *ppszMasterKey, rgbOutPwd, dwChosenConfirm)) ) {
//
// try lower-case form to handle Win9x migration case.
//
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, *ppszMasterKey, rgbOutPwdLowerCase, dwChosenConfirm)) ) { // too many trials? break out of loop
if (i < MAX_PASSWD_TRIALS) { // notify user, give them another chance
NotifyOfWrongPassword((HWND)psPrompt->hwndApp, szItemName, *ppszMasterKey);
continue; } else { break; // break out
} } else {
CopyMemory( rgbOutPwd, rgbOutPwdLowerCase, A_SHA_DIGEST_LEN );
} }
// passed verify password test: break out of loop!
fPwdVerified = TRUE; break; }
if (!fPwdVerified) { hr = PST_E_NO_PERMISSIONS; goto Ret; } } }
// and remember the selections made
if (PST_E_OK != (hr = BPSetItemConfirm( phPSTProv, szUser, pguidType, pguidSubtype, szItemName, dwChosenConfirm, *ppszMasterKey)) ) goto Ret;
// now, _this_ is the stored confirm
dwStoredConfirm = dwChosenConfirm; } else { // keep a copy of the stored key
LPWSTR szStoredMasterKey = (LPWSTR)SSAlloc(WSZ_BYTECOUNT(*ppszMasterKey)); if(NULL != szStoredMasterKey) { CopyMemory(szStoredMasterKey, *ppszMasterKey, WSZ_BYTECOUNT(*ppszMasterKey)); }
// we retrieved confirmation behavior
dwChosenConfirm = dwStoredConfirm; // already chosen for you
switch (dwStoredConfirm) { // if no confirm
case BP_CONFIRM_NONE: break;
// if we know the confirm type
case BP_CONFIRM_PASSWORDUI: { // else fall through to prompting case
}
case BP_CONFIRM_OKCANCEL: { // retrieved item, must show ui, but not allowed to show ui
if (psPrompt->dwPromptFlags & PST_PF_NEVER_SHOW) { hr = ERROR_PASSWORD_RESTRICTION; goto Ret; }
// found that a pwd is req'd
fPromptedUser = TRUE; fCacheItNow = fIsCached;
int i;
for(i=1; ; i++) { BYTE rgbOutPwdLowerCase[A_SHA_DIGEST_LEN];
// ask the user for it
if (!FSimplifiedPasswordConfirm( phPSTProv, szUser, szCallerName, szType, szSubtype, szItemName, psPrompt, szAction, ppszMasterKey, &dwChosenConfirm, TRUE, // allow user to select pwd
rgbOutPwd, A_SHA_DIGEST_LEN, rgbOutPwdLowerCase, A_SHA_DIGEST_LEN, dwFlags )) { hr = PST_E_NO_PERMISSIONS; goto Ret; }
// if we got it from the cache and user left it alone
{ // verify whatever password we got
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, *ppszMasterKey, rgbOutPwd, dwChosenConfirm)) ) { //
// check lower case form.
//
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, *ppszMasterKey, rgbOutPwdLowerCase, dwChosenConfirm)) ) {
// too many trials? break out of loop
if (i < MAX_PASSWD_TRIALS) { // notify user, give them another chance
NotifyOfWrongPassword((HWND)psPrompt->hwndApp, szItemName, *ppszMasterKey);
continue; } else { hr = PST_E_NO_PERMISSIONS; goto Ret; } } else {
CopyMemory( rgbOutPwd, rgbOutPwdLowerCase, A_SHA_DIGEST_LEN ); } }
fPwdVerified = TRUE; }
// passed verify password test: break out of loop!
break; }
break; }
} // end switch
// have we received all data we need from the user?
// user may choose to change the way items are encrypted;
// if stored under password, we must make them enter the old pwd
if ((dwStoredConfirm != dwChosenConfirm) || // confirm type changed OR
(NULL == szStoredMasterKey) || (0 != wcscmp(*ppszMasterKey, szStoredMasterKey)) ) // difft master key
{ BYTE rgbOldPwd[A_SHA_DIGEST_LEN]; BOOL fDontAllowCache = FALSE; BOOL fOldPwdVerified = FALSE;
PST_PROMPTINFO sGetOldPWPrompt = {sizeof(PST_PROMPTINFO), psPrompt->dwPromptFlags, psPrompt->hwndApp, g_PasswordSolicitOld};
// only re-display if originally passworded
if (dwStoredConfirm == BP_CONFIRM_PASSWORDUI) { for(int i=1; ; i++) { BYTE rgbOldPwdLowerCase[A_SHA_DIGEST_LEN];
// ask the user for it
if (!FSimplifiedPasswordConfirm( phPSTProv, szUser, szCallerName, szType, szSubtype, szItemName, &sGetOldPWPrompt, szAction, &szStoredMasterKey, &dwStoredConfirm, FALSE, // don't allow user to get around this one
rgbOldPwd, sizeof(rgbOldPwd), rgbOldPwdLowerCase, sizeof(rgbOldPwdLowerCase), dwFlags )) { hr = PST_E_NO_PERMISSIONS; goto Ret; }
// verify whatever password we got
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, szStoredMasterKey, rgbOldPwd, dwStoredConfirm)) ) { if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, szStoredMasterKey, rgbOldPwdLowerCase, dwStoredConfirm)) ) { // too many trials? break out of loop
if (i < MAX_PASSWD_TRIALS) { // notify user, give them another chance
NotifyOfWrongPassword((HWND)sGetOldPWPrompt.hwndApp, szItemName, szStoredMasterKey);
continue; } else { break; // break out
} } else { CopyMemory( rgbOldPwd, rgbOldPwdLowerCase, A_SHA_DIGEST_LEN ); } }
// passed verify password test: break out of loop!
fOldPwdVerified = TRUE; break; }
if (!fOldPwdVerified) { hr = PST_E_NO_PERMISSIONS; goto Ret; } } else { // ok/cancel; silent pwd usage
// use VerifyPwd fxn to retrieve the pwd
if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, szStoredMasterKey, rgbOldPwd, dwStoredConfirm)) ) { hr = PST_E_NO_PERMISSIONS; goto Ret; } }
//////
// execute pwd change HERE
{ PBYTE pbData = NULL; DWORD cbData;
// FBPGetSecuredItemData // decrypt data with old
if (!FBPGetSecuredItemData( szUser, szStoredMasterKey, rgbOldPwd, pguidType, pguidSubtype, szItemName, &pbData, &cbData)) { hr = PST_E_STORAGE_ERROR; goto Ret; }
// FBPSetSecuredItemData // encrypt data with new
if (!FBPSetSecuredItemData( szUser, *ppszMasterKey, rgbOutPwd, pguidType, pguidSubtype, szItemName, pbData, cbData)) { hr = PST_E_STORAGE_ERROR; goto Ret; }
if (pbData) SSFree(pbData);
// BPSetItemConfirm // store new confirm type
if (PST_E_OK != BPSetItemConfirm( phPSTProv, szUser, pguidType, pguidSubtype, szItemName, dwChosenConfirm, *ppszMasterKey)) { hr = PST_E_STORAGE_ERROR; goto Ret; } }
}
if (szStoredMasterKey) { SSFree(szStoredMasterKey); szStoredMasterKey = NULL; } }
// verify whatever password we got if not yet verified
if (!fPwdVerified) { if (PST_E_OK != (hr = BPVerifyPwd( phPSTProv, szUser, *ppszMasterKey, rgbOutPwd, dwChosenConfirm)) ) goto Ret; }
// Now correct pwd is in rgbOutPwd ALWAYS
// if we haven't prompted user and were supposed to
if (!fPromptedUser && (psPrompt->dwPromptFlags == PST_PF_ALWAYS_SHOW)) { // we must've retrieved from cache OR Automagic WinPW
SS_ASSERT(fIsCached || (BP_CONFIRM_NONE == dwStoredConfirm));
BYTE rgbBarfPwd[A_SHA_DIGEST_LEN*2]; BYTE rgbBarfPwdLowerCase[A_SHA_DIGEST_LEN];
// haven't prompted user but must confirm
if (!FSimplifiedPasswordConfirm( phPSTProv, szUser, szCallerName, szType, szSubtype, szItemName, psPrompt, szAction, ppszMasterKey, &dwChosenConfirm, FALSE, rgbBarfPwd, sizeof(rgbBarfPwd), rgbBarfPwdLowerCase, sizeof(rgbBarfPwdLowerCase), dwFlags ) ) { hr = PST_E_NO_PERMISSIONS; goto Ret; }
}
hr = PST_E_OK; Ret:
if (szCallerName) SSFree(szCallerName);
return hr; }
HRESULT ShowOKCancelUI( PST_PROVIDER_HANDLE* phPSTProv, LPCWSTR szUser, PST_KEY Key, LPCWSTR szType, LPCWSTR szSubtype, LPCWSTR szItemName, PPST_PROMPTINFO psPrompt, LPCWSTR szAction) { BOOL fCache = FALSE; BYTE rgbTrash[A_SHA_DIGEST_LEN*2]; BYTE rgbTrashLowerCase[A_SHA_DIGEST_LEN]; DWORD dwConfirmOptions = BP_CONFIRM_OKCANCEL;
LPWSTR szMasterKey = NULL; LPWSTR szCallerName = NULL;
DWORD dwRet = PST_E_FAIL;
if (Key == PST_KEY_LOCAL_MACHINE) { // done
dwRet = PST_E_OK; goto Ret; }
szMasterKey = (LPWSTR)SSAlloc(sizeof(WSZ_NULLSTRING));
if(szMasterKey) { wcscpy(szMasterKey, WSZ_NULLSTRING); }
if (!g_sCallbacks.pfnFGetCallerName(phPSTProv, &szCallerName, NULL)) goto Ret;
if (!FSimplifiedPasswordConfirm( phPSTProv, szUser, szCallerName, szType, szSubtype, szItemName, psPrompt, szAction, &szMasterKey, &dwConfirmOptions, FALSE, rgbTrash, sizeof(rgbTrash), rgbTrashLowerCase, sizeof(rgbTrashLowerCase), 0 ) ) goto Ret;
dwRet = PST_E_OK; Ret: if (szCallerName) SSFree(szCallerName);
if (szMasterKey) SSFree(szMasterKey);
return dwRet; }
|