Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

927 lines
28 KiB

/*
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;
}