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.
 
 
 
 
 
 

1949 lines
45 KiB

/*
File: Prov.cpp
Title: Protected Storage Base Provider
Author: Matt Thomlinson
Date: 10/22/96
Protected storage is an area to safely store user belongings.
This storage is available on both NT and Win95, and offers finer
granularity over access than do NT ACLs.
The PStore architecture resembles the CryptoAPI provider architecture.
The PStore server, PStoreS, takes requests and forwards them to any one
of a number of providers, of which PSBase is a single instance. (The
server exports some basic functionality to ease the pain of provider
writers, like impersonating the caller and checking access rules.) The
server gets requests through LPC from a client (PStoreC.dll),
which wraps a number of operations into a COM object.
The base provider supports user storage, where items are stored under
the namespace of which user called protected storage, and local machine
storage, a global area that can be accessed by everyone.
Rules can be set on subtypes describing under what conditions accesses
are allowed. Rules can specify callers be Authenticode signed, callers
simply be unmodified from access to access, and normal (arbitrary) NT Acls
be satisfied.
In addition, items stored in the user namespace have user authentication
by default, where the user gets to specify what type of user
confirmation they want to see appear. This confirmation could be
no confirmation, an ok/cancel dialog, a password, a retinal scan, a
fingerprint, etc.
The base provider stores items in the registry, DES-encrypted with a
key derived from the user password. Items are also integrity-protected
by a keyed MAC.
Interoperability and transport issues are solved by adding a provider
supporting the PFX interchange format.
The base provider is slightly more special than all other providers, since
the server stores bootstrap configuration data here. (The base provider
is guaranteed to always be present). The configuration data includes
what other providers are ok to be loaded.
*/
#include <pch.cpp>
#pragma hdrstop
#include "provif.h"
#include "provui.h"
#include "storage.h"
#include "passwd.h"
// sfield: legacy migration hack
#include "migrate.h"
BOOL g_fAllowCachePW = TRUE;
// fwd (secure.cpp)
BOOL FIsEncryptionPermitted();
HINSTANCE g_hInst = NULL;
BOOL g_fImagesIntegrid = FALSE;
DISPIF_CALLBACKS g_sCallbacks;
BOOL g_fCallbacksInitialized = FALSE;
PRIVATE_CALLBACKS g_sPrivateCallbacks;
CUAList* g_pCUAList = NULL;
COpenItemList* g_pCOpenItemList = NULL;
CCryptProvList* g_pCProvList = NULL;
extern CRITICAL_SECTION g_csUIInitialized;
/////////////////////////////////////////////////////////////////////////
// Very important to hook DllMain, do caller authentication
BOOL WINAPI DllMain (HMODULE hInst,
ULONG ul_reason_for_call,
LPVOID lpReserved)
{
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
{
g_hInst = hInst;
InitializeCriticalSection( &g_csUIInitialized );
//
// just hard-code image verification succeeded.
//
g_fImagesIntegrid = TRUE;
// set up global lists
g_pCUAList = new CUAList;
if(g_pCUAList)
{
if(!g_pCUAList->Initialize())
{
delete g_pCUAList;
g_pCUAList = NULL;
}
}
g_pCOpenItemList = new COpenItemList;
if(g_pCOpenItemList)
{
if(!g_pCOpenItemList->Initialize())
{
delete g_pCOpenItemList;
g_pCOpenItemList = NULL;
}
}
g_pCProvList = new CCryptProvList;
if(g_pCProvList)
{
if(!g_pCProvList->Initialize())
{
delete g_pCProvList;
g_pCProvList = NULL;
}
}
DisableThreadLibraryCalls(hInst);
// call EncryptionPermitted routine once to initialize globals
FIsEncryptionPermitted();
FInitProtectAPIGlobals();
break;
}
case DLL_PROCESS_DETACH:
// tear down global lists
if(g_pCUAList)
{
delete g_pCUAList;
g_pCUAList = NULL;
}
if(g_pCOpenItemList)
{
delete g_pCOpenItemList;
g_pCOpenItemList = NULL;
}
if(g_pCProvList)
{
delete g_pCProvList;
g_pCProvList = NULL;
}
ReleaseUI();
DeleteCriticalSection( &g_csUIInitialized );
break;
default:
break;
}
return TRUE;
}
HRESULT SPProviderInitialize(
DISPIF_CALLBACKS *psCallbacks)
{
// only allow one initialization (security check)
if (g_fCallbacksInitialized)
return PST_E_FAIL;
if( psCallbacks->cbSize < sizeof(DISPIF_CALLBACKS) )
return PST_E_FAIL;
// tuck these callback fxns for later use
CopyMemory(&g_sCallbacks, psCallbacks, sizeof(DISPIF_CALLBACKS));
// now, get the private callbacks from the server
DWORD cbPrivateCallbacks = sizeof(g_sPrivateCallbacks);
if(!g_sCallbacks.pfnFGetServerParam(
NULL,
SS_SERVERPARAM_CALLBACKS,
&g_sPrivateCallbacks,
&cbPrivateCallbacks
))
return PST_E_FAIL;
if(g_sPrivateCallbacks.cbSize != sizeof(g_sPrivateCallbacks))
return PST_E_FAIL;
g_fCallbacksInitialized = TRUE;
return PST_E_OK;
}
HRESULT SPAcquireContext(
/* [in] */ PST_PROVIDER_HANDLE* phPSTProv,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
BOOL fExisted = FALSE;
LPWSTR szUser = NULL;
HKEY hUserKey = NULL;
BOOL fUserExisted;
if(!InitUI())
return FALSE;
if (0 != dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!g_sCallbacks.pfnFGetUser(
phPSTProv,
&szUser))
goto Ret;
//
// migrate password data. This doesn't do anything internally if migration
// already took place.
//
MigrateData(phPSTProv, TRUE);
// One-Time WinPW Init Code
if (!BPMasterKeyExists(
szUser,
WSZ_PASSWORD_WINDOWS))
{
BYTE rgbPwd[A_SHA_DIGEST_LEN];
// Init the Users' Windows password entry
if (!FMyGetWinPassword(
phPSTProv,
szUser,
rgbPwd
))
goto Ret;
if (!FCheckPWConfirm(
szUser,
WSZ_PASSWORD_WINDOWS,
rgbPwd))
goto Ret;
//
// newly created key: data migration is not necessary.
// specify that only the migration flag need be updated
//
MigrateData(phPSTProv, FALSE);
}
dwRet = PST_E_OK;
Ret:
if (hUserKey)
RegCloseKey(hUserKey);
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPReleaseContext(
/* [in] */ PST_PROVIDER_HANDLE* phPSTProv,
/* [in] */ DWORD dwFlags)
{
return PST_E_OK;
}
HRESULT SPGetProvInfo(
PPST_PROVIDERINFO* ppPSTInfo,
DWORD dwFlags)
{
HRESULT hr = PST_E_FAIL;
if (0 != dwFlags)
return PST_E_BAD_FLAGS;
// Note: not linked to a specific context (hPSTProv)
// Note: caller not verified -- give this info to anyone
PPST_PROVIDERINFO pPSTInfo;
if (NULL == (pPSTInfo = (PST_PROVIDERINFO*)SSAlloc(sizeof(PST_PROVIDERINFO))) )
return PST_E_FAIL;
ZeroMemory(pPSTInfo, sizeof(PST_PROVIDERINFO));
pPSTInfo->cbSize = sizeof(PST_PROVIDERINFO);
GUID guidBaseProvider = MS_BASE_PSTPROVIDER_ID;
CopyMemory(&pPSTInfo->ID, &guidBaseProvider, sizeof(pPSTInfo->ID));
pPSTInfo->Capabilities = PST_PC_ROAMABLE;
if (NULL == (pPSTInfo->szProviderName = (LPWSTR)SSAlloc(sizeof(MS_BASE_PSTPROVIDER_NAME))) )
goto Ret;
wcscpy(pPSTInfo->szProviderName, MS_BASE_PSTPROVIDER_NAME);
hr = PST_E_OK;
Ret:
if (hr != PST_E_OK)
{
if (pPSTInfo->szProviderName)
SSFree(pPSTInfo->szProviderName);
SSFree(pPSTInfo);
pPSTInfo = NULL;
}
// in either case, return pPSTInfo
*ppPSTInfo = pPSTInfo;
return hr;
}
HRESULT SPGetProvParam(
/* [in] */ PST_PROVIDER_HANDLE* phPSTProv,
/* [in] */ DWORD dwParam,
/* [out] */ DWORD __RPC_FAR *pcbData,
/* [size_is][size_is][out] */
BYTE __RPC_FAR *__RPC_FAR *ppbData,
/* [in] */ DWORD dwFlags)
{
if( pcbData )
*pcbData = 0;
switch(dwParam)
{
case PST_PP_FLUSH_PW_CACHE:
{
return PST_E_OK;
}
default:
{
return PST_E_NYI;
}
}
}
HRESULT SPSetProvParam(
/* [in] */ PST_PROVIDER_HANDLE* phPSTProv,
/* [in] */ DWORD dwParam,
/* [in] */ DWORD cbData,
/* [in] */ BYTE* pbData,
/* [in] */ DWORD dwFlags)
{
HRESULT hr = PST_E_OK;
switch(dwParam)
{
case PST_PP_FLUSH_PW_CACHE:
{
if(g_pCUAList)
{
g_pCUAList->Reset();
hr = PST_E_OK;
}
else
hr = PST_E_FAIL;
break;
}
default:
{
hr = PST_E_NYI;
break;
}
}
return hr;
}
HRESULT SPEnumTypes(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [out] */ GUID *pguidType,
/* [in] */ DWORD dwIndex,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (PST_E_OK != (dwRet =
BPEnumTypes(
szUser,
dwIndex,
pguidType)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPGetTypeInfo(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ PPST_TYPEINFO *ppinfoType,
/* [in] */ DWORD dwFlags)
{
PST_TYPEINFO infoType = {sizeof(PST_TYPEINFO)};
*ppinfoType = NULL;
LPWSTR szUser = NULL;
HRESULT dwRet = PST_E_FAIL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&infoType.szDisplayName)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (dwRet == PST_E_OK)
{
*ppinfoType = (PPST_TYPEINFO)SSAlloc(sizeof(PST_TYPEINFO));
if(NULL != *ppinfoType)
{
CopyMemory(*ppinfoType, &infoType, sizeof(PST_TYPEINFO));
}
}
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPEnumSubtypes(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [out] */ GUID *pguidSubtype,
/* [in] */ DWORD dwIndex,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (PST_E_OK != (dwRet =
BPEnumSubtypes(
szUser,
dwIndex,
pguidType,
pguidSubtype)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPGetSubtypeInfo(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ PPST_TYPEINFO *ppinfoSubtype,
/* [in] */ DWORD dwFlags)
{
*ppinfoSubtype = NULL;
PST_TYPEINFO infoSubtype = {sizeof(PST_TYPEINFO)};
LPWSTR szUser = NULL;
HRESULT dwRet = PST_E_FAIL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&infoSubtype.szDisplayName)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (dwRet == PST_E_OK)
{
*ppinfoSubtype = (PPST_TYPEINFO)SSAlloc(sizeof(PST_TYPEINFO));
if(NULL != *ppinfoSubtype)
{
CopyMemory(*ppinfoSubtype, &infoSubtype, sizeof(PST_TYPEINFO));
}
}
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPEnumItems(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [out] */ LPWSTR *ppszItemName,
/* [in] */ DWORD dwIndex,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (PST_E_OK != (dwRet =
BPEnumItems(
szUser,
pguidType,
pguidSubtype,
dwIndex,
ppszItemName)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPCreateType(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ PPST_TYPEINFO pinfoType,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// Check for invalid "" input
if (pinfoType == NULL ||
pinfoType->szDisplayName == NULL ||
(wcslen(pinfoType->szDisplayName) == 0)
)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
// if fail or already exist, fail!
if (PST_E_OK != (dwRet =
BPCreateType(
szUser,
pguidType,
pinfoType)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
// if creation didn't happen, item shouldn't exist
if ((dwRet != PST_E_OK) && (dwRet != PST_E_TYPE_EXISTS))
BPDeleteType(szUser, pguidType);
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPDeleteType(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID __RPC_FAR *pguidType,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
// if fail or not empty, fail!
if (PST_E_OK != (dwRet =
BPDeleteType(
szUser,
pguidType)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPCreateSubtype(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ PPST_TYPEINFO pinfoSubtype,
/* [in] */ PPST_ACCESSRULESET psRules,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags != 0)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// NULL Rules
if (psRules == NULL)
{
dwRet = PST_E_INVALID_RULESET;
goto Ret;
}
if (pinfoSubtype == NULL)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// Check for invalid "" input
if (pinfoSubtype->szDisplayName == NULL || wcslen(pinfoSubtype->szDisplayName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
// if fail or already exist, fail!
if (PST_E_OK != (dwRet =
BPCreateSubtype(
szUser,
pguidType,
pguidSubtype,
pinfoSubtype)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
// if creation didn't happen, item shouldn't exist
if ((dwRet != PST_E_OK) && (dwRet != PST_E_TYPE_EXISTS))
BPDeleteSubtype(szUser, pguidType, pguidSubtype);
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPDeleteSubtype(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID __RPC_FAR *pguidType,
/* [in] */ const GUID __RPC_FAR *pguidSubtype,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
LPWSTR szUser = NULL;
PST_ACCESSRULESET sRules = {sizeof(sRules), 0, NULL};
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
// if fail or not empty, fail!
if (PST_E_OK != (dwRet =
BPDeleteSubtype(
szUser,
pguidType,
pguidSubtype)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
return dwRet;
}
HRESULT SPWriteItem(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ LPCWSTR szItemName,
/* [in] */ DWORD cbData,
/* [size_is][in] */ BYTE *pbData,
/* [in] */ PPST_PROMPTINFO psPrompt,
/* [in] */ DWORD dwDefaultConfirmationStyle,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
// assume we've made no change
BOOL fExisted = TRUE;
LPWSTR szUser = NULL;
PST_ACCESSRULESET sRules = {sizeof(sRules), 0, NULL};
BYTE rgbPwd[A_SHA_DIGEST_LEN];
LPWSTR szMasterKey = NULL;
LPWSTR szType=NULL, szSubtype=NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if ((dwFlags & ~(PST_UNRESTRICTED_ITEMDATA | PST_NO_OVERWRITE
)) != 0)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
if ((dwDefaultConfirmationStyle & ~( PST_CF_DEFAULT |
PST_CF_NONE
)) != 0)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
if (psPrompt == NULL)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// Disable UI on write item.
dwDefaultConfirmationStyle = PST_CF_NONE;
if(psPrompt != NULL)
{
psPrompt->dwPromptFlags = 0;
}
// Check for invalid "" input
if (wcslen(szItemName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (dwFlags & PST_UNRESTRICTED_ITEMDATA)
{
// store insecure data stream
if (PST_E_OK != (dwRet =
BPSetInsecureItemData(
szUser,
pguidType,
pguidSubtype,
szItemName,
pbData,
cbData)) )
goto Ret;
dwRet = PST_E_OK;
goto Ret;
}
// ELSE: secure stream
{
POPENITEM_LIST_ITEM pli;
OPENITEM_LIST_ITEM li;
if(NULL == g_pCOpenItemList)
{
dwRet = PST_E_FAIL;
goto Ret;
}
CreateOpenListItem(&li, phPSTProv, Key, pguidType, pguidSubtype, szItemName);
g_pCOpenItemList->LockList();
// get opened (cached) item
pli = g_pCOpenItemList->SearchList(&li);
if ((pli != NULL) && (pli->ModeFlags & PST_WRITE) )
{
// Error if cached (it must exist) and "No Overwrite" specified
if (dwFlags & PST_NO_OVERWRITE)
{
g_pCOpenItemList->UnlockList();
dwRet = PST_E_ITEM_EXISTS;
goto Ret;
}
// found cached item; pull real pwd
CopyMemory(rgbPwd, pli->rgbPwd, A_SHA_DIGEST_LEN);
szMasterKey = (LPWSTR) SSAlloc(WSZ_BYTECOUNT(pli->szMasterKey));
if( szMasterKey )
wcscpy(szMasterKey, pli->szMasterKey);
//
// unlock list.
//
g_pCOpenItemList->UnlockList();
if( szMasterKey == NULL ) {
dwRet = E_OUTOFMEMORY;
goto Ret;
}
// PST_PF_ALWAYS_SHOW always forces UI
if (PST_PF_ALWAYS_SHOW == psPrompt->dwPromptFlags)
{
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
if (PST_E_OK != (dwRet =
ShowOKCancelUI(
phPSTProv,
szUser,
Key,
szType,
szSubtype,
szItemName,
psPrompt,
g_PromptWriteItem)) )
goto Ret;
}
}
else
{
//
// unlock list.
//
g_pCOpenItemList->UnlockList();
// not cached; do actual work
// if fail or already exist
if (PST_E_OK != (dwRet =
BPCreateItem(
szUser,
pguidType,
pguidSubtype,
szItemName)) )
{
// on "No Overwrite", hr has right error code
if (dwFlags & PST_NO_OVERWRITE)
goto Ret;
// else swallow overwrite error
if (dwRet != PST_E_ITEM_EXISTS)
goto Ret;
}
fExisted = (dwRet == PST_E_ITEM_EXISTS);
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
// does ALL user confirm work
if (PST_E_OK != (dwRet =
GetUserConfirmBuf(
phPSTProv,
szUser,
Key,
szType,
pguidType,
szSubtype,
pguidSubtype,
szItemName,
psPrompt,
g_PromptWriteItem,
dwDefaultConfirmationStyle,
&szMasterKey,
rgbPwd,
0)) )
goto Ret;
}
}
// store the data itself
if (!FBPSetSecuredItemData(
szUser,
szMasterKey,
rgbPwd,
pguidType,
pguidSubtype,
szItemName,
pbData,
cbData))
{
dwRet = PST_E_STORAGE_ERROR;
goto Ret;
}
dwRet = PST_E_OK;
Ret:
// if creation didn't happen, item shouldn't exist
if ((dwRet != PST_E_OK) && (!fExisted))
BPDeleteItem(szUser, pguidType, pguidSubtype, szItemName);
if (szMasterKey)
SSFree(szMasterKey);
if (szUser)
SSFree(szUser);
if (szType)
SSFree(szType);
if (szSubtype)
SSFree(szSubtype);
return dwRet;
}
HRESULT SPReadItem(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ LPCWSTR szItemName,
/* [out] */ DWORD *pcbData,
/* [size_is][size_is][out] */ BYTE **ppbData,
/* [in] */ PPST_PROMPTINFO psPrompt,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
PST_ACCESSRULESET sRules = {sizeof(sRules), 0, NULL};
LPWSTR szUser = NULL;
LPWSTR szMasterKey = NULL;
LPWSTR szCallerName = NULL;
BYTE rgbPwd[A_SHA_DIGEST_LEN];
LPWSTR szType=NULL, szSubtype=NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if ((dwFlags & ~(PST_UNRESTRICTED_ITEMDATA | PST_PROMPT_QUERY |
PST_NO_UI_MIGRATION
)) != 0)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// Disable unnecessary UI.
dwFlags |= PST_NO_UI_MIGRATION;
if (psPrompt == NULL)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// Check for invalid "" input
if (wcslen(szItemName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
if (dwFlags & PST_UNRESTRICTED_ITEMDATA)
{
// read insecure data stream
if (PST_E_OK != (dwRet =
BPGetInsecureItemData(
szUser,
pguidType,
pguidSubtype,
szItemName,
ppbData,
pcbData)) )
goto Ret;
dwRet = PST_E_OK;
goto Ret;
}
// ELSE: secure stream
{
POPENITEM_LIST_ITEM pli;
OPENITEM_LIST_ITEM li;
if(NULL == g_pCOpenItemList)
{
dwRet = PST_E_FAIL;
goto Ret;
}
CreateOpenListItem(&li, phPSTProv, Key, pguidType, pguidSubtype, szItemName);
g_pCOpenItemList->LockList();
// get opened (cached) item
pli = g_pCOpenItemList->SearchList(&li);
if ((pli != NULL) && (pli->ModeFlags & PST_READ))
{
// found cached item; pull pwd
CopyMemory(rgbPwd, pli->rgbPwd, A_SHA_DIGEST_LEN);
szMasterKey = (LPWSTR) SSAlloc(WSZ_BYTECOUNT(pli->szMasterKey));
if( szMasterKey )
wcscpy(szMasterKey, pli->szMasterKey);
//
// unlock list.
//
g_pCOpenItemList->UnlockList();
if( szMasterKey == NULL ) {
dwRet = E_OUTOFMEMORY;
goto Ret;
}
// PST_PF_ALWAYS_SHOW always forces UI
if (PST_PF_ALWAYS_SHOW == psPrompt->dwPromptFlags)
{
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
if (PST_E_OK != (dwRet =
ShowOKCancelUI(
phPSTProv,
szUser,
Key,
szType,
szSubtype,
szItemName,
psPrompt,
g_PromptReadItem)) )
goto Ret;
}
}
else
{
//
// unlock list.
//
g_pCOpenItemList->UnlockList();
// not cached; do actual work
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
// does ALL user confirm work
if (PST_E_OK != (dwRet =
GetUserConfirmBuf(
phPSTProv,
szUser,
Key,
szType,
pguidType,
szSubtype,
pguidSubtype,
szItemName,
psPrompt,
g_PromptReadItem,
&szMasterKey,
rgbPwd,
dwFlags)) )
goto Ret;
}
}
// if checked out, then actually retrieve item
if (!FBPGetSecuredItemData(
szUser,
szMasterKey,
rgbPwd,
pguidType,
pguidSubtype,
szItemName,
ppbData,
pcbData))
{
dwRet = PST_E_STORAGE_ERROR;
goto Ret;
}
dwRet = PST_E_OK;
Ret:
//
// see if caller requested UI disposition on item.
//
if( dwRet == PST_E_OK && dwFlags & PST_PROMPT_QUERY ) {
DWORD dwStoredConfirm;
LPWSTR pszMasterKey;
DWORD dwRetVal;
dwRetVal = BPGetItemConfirm(
phPSTProv,
szUser,
pguidType,
pguidSubtype,
szItemName,
&dwStoredConfirm,
&pszMasterKey
);
if( dwRetVal == PST_E_OK ) {
SSFree( pszMasterKey );
if( !(dwStoredConfirm & BP_CONFIRM_NONE) ) {
if(FIsProviderUIAllowed( szUser ))
dwRet = PST_E_ITEM_EXISTS;
}
}
}
if (szUser)
SSFree(szUser);
if (szMasterKey)
SSFree(szMasterKey);
if (szType)
SSFree(szType);
if (szSubtype)
SSFree(szSubtype);
if (szCallerName)
SSFree(szCallerName);
return dwRet;
}
HRESULT SPDeleteItem(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ LPCWSTR szItemName,
/* [in] */ PPST_PROMPTINFO psPrompt,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
PST_ACCESSRULESET sRules = {sizeof(sRules), 0, NULL};
LPWSTR szUser = NULL;
LPWSTR szMasterKey = NULL;
LPWSTR szCallerName = NULL;
BYTE rgbPwd[A_SHA_DIGEST_LEN];
LPWSTR szType=NULL, szSubtype=NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags & ~(PST_NO_UI_MIGRATION))
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// Disable unnecessary UI.
dwFlags |= PST_NO_UI_MIGRATION;
if (psPrompt == NULL)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// Check for invalid "" input
if (wcslen(szItemName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
{
POPENITEM_LIST_ITEM pli;
OPENITEM_LIST_ITEM li;
if(NULL == g_pCOpenItemList)
{
dwRet = PST_E_FAIL;
goto Ret;
}
CreateOpenListItem(&li, phPSTProv, Key, pguidType, pguidSubtype, szItemName);
g_pCOpenItemList->LockList();
// get opened (cached) item
pli = g_pCOpenItemList->SearchList(&li);
if ((pli != NULL) && (pli->ModeFlags & PST_WRITE))
{
// found cached item; pull pwd
CopyMemory(rgbPwd, pli->rgbPwd, A_SHA_DIGEST_LEN);
szMasterKey = (LPWSTR) SSAlloc(WSZ_BYTECOUNT(pli->szMasterKey));
if( szMasterKey )
wcscpy(szMasterKey, pli->szMasterKey);
g_pCOpenItemList->UnlockList();
if( szMasterKey == NULL ) {
dwRet = E_OUTOFMEMORY;
goto Ret;
}
// PST_PF_ALWAYS_SHOW always forces UI
if (PST_PF_ALWAYS_SHOW == psPrompt->dwPromptFlags)
{
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
if (PST_E_OK != (dwRet =
ShowOKCancelUI(
phPSTProv,
szUser,
Key,
szType,
szSubtype,
szItemName,
psPrompt,
g_PromptDeleteItem)) )
goto Ret;
}
}
else
{
//
// unlock list.
//
g_pCOpenItemList->UnlockList();
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
// does ALL user confirm work
if (PST_E_OK != (dwRet =
GetUserConfirmBuf(
phPSTProv,
szUser,
Key,
szType,
pguidType,
szSubtype,
pguidSubtype,
szItemName,
psPrompt,
g_PromptDeleteItem,
&szMasterKey,
rgbPwd,
dwFlags)) )
goto Ret;
}
}
// if checked out, then actually remove item
if (PST_E_OK != (dwRet =
BPDeleteItem(
szUser,
pguidType,
pguidSubtype,
szItemName)) )
goto Ret;
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
if (szMasterKey)
SSFree(szMasterKey);
if (szType)
SSFree(szType);
if (szSubtype)
SSFree(szSubtype);
if (szCallerName)
SSFree(szCallerName);
return dwRet;
}
HRESULT SPOpenItem(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ LPCWSTR szItemName,
/* [in] */ PST_ACCESSMODE ModeFlags,
/* [in] */ PPST_PROMPTINFO psPrompt,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
PST_ACCESSRULESET sRules = {sizeof(sRules), 0, NULL};
LPWSTR szUser = NULL;
LPWSTR szMasterKey = NULL;
LPWSTR szCallerName = NULL;
BYTE rgbPwd[A_SHA_DIGEST_LEN];
LPWSTR szType=NULL, szSubtype=NULL;
POPENITEM_LIST_ITEM pli = NULL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
if(psPrompt == NULL)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// Check for invalid "" input
if (wcslen(szItemName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// check for item already open
{
OPENITEM_LIST_ITEM li;
if(NULL == g_pCOpenItemList)
{
dwRet = PST_E_FAIL;
goto Ret;
}
CreateOpenListItem(&li, phPSTProv, Key, pguidType, pguidSubtype, szItemName);
// get opened (cached) item
pli = g_pCOpenItemList->SearchList(&li);
if (pli != NULL)
{
// item already cached; error!
dwRet = (DWORD)PST_E_ALREADY_OPEN;
goto Ret;
}
}
// get current user
if (!FGetCurrentUser(
phPSTProv,
&szUser,
Key))
{
dwRet = (DWORD)PST_E_FAIL;
goto Ret;
}
// retrieve names of type, subtype
if (PST_E_OK != (dwRet =
BPGetTypeName(
szUser,
pguidType,
&szType)) )
goto Ret;
if (PST_E_OK != (dwRet =
BPGetSubtypeName(
szUser,
pguidType,
pguidSubtype,
&szSubtype)) )
goto Ret;
// does ALL user confirm work
if (PST_E_OK != (dwRet =
GetUserConfirmBuf(
phPSTProv,
szUser,
Key,
szType,
pguidType,
szSubtype,
pguidSubtype,
szItemName,
psPrompt,
g_PromptOpenItem,
&szMasterKey,
rgbPwd,
0)) )
goto Ret;
// if checked out, then add to open item list
pli = (POPENITEM_LIST_ITEM) SSAlloc(sizeof(OPENITEM_LIST_ITEM));
if(NULL == pli)
{
dwRet = PST_E_FAIL;
goto Ret;
}
// fill in contents
CreateOpenListItem(pli, phPSTProv, Key, pguidType, pguidSubtype, NULL);
pli->szItemName = (LPWSTR)SSAlloc(WSZ_BYTECOUNT(szItemName));
wcscpy(pli->szItemName, szItemName);
pli->szMasterKey = (LPWSTR)SSAlloc(WSZ_BYTECOUNT(szMasterKey));
wcscpy(pli->szMasterKey, szMasterKey);
CopyMemory(pli->rgbPwd, rgbPwd, A_SHA_DIGEST_LEN);
pli->ModeFlags = ModeFlags;
// add to the open list
g_pCOpenItemList->AddToList(pli);
dwRet = PST_E_OK;
Ret:
if (szUser)
SSFree(szUser);
if (szMasterKey)
SSFree(szMasterKey);
if (szType)
SSFree(szType);
if (szSubtype)
SSFree(szSubtype);
if (szCallerName)
SSFree(szCallerName);
return dwRet;
}
HRESULT SPCloseItem(
/* [in] */ PST_PROVIDER_HANDLE *phPSTProv,
/* [in] */ PST_KEY Key,
/* [in] */ const GUID *pguidType,
/* [in] */ const GUID *pguidSubtype,
/* [in] */ LPCWSTR szItemName,
/* [in] */ DWORD dwFlags)
{
HRESULT dwRet = PST_E_FAIL;
if (Key & ~(PST_KEY_CURRENT_USER | PST_KEY_LOCAL_MACHINE))
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
if (dwFlags)
{
dwRet = PST_E_BAD_FLAGS;
goto Ret;
}
// Check for invalid "" input
if (wcslen(szItemName) == 0)
{
dwRet = ERROR_INVALID_PARAMETER;
goto Ret;
}
// if item found in list, remove it
OPENITEM_LIST_ITEM li;
if(NULL == g_pCOpenItemList)
{
dwRet = PST_E_FAIL;
goto Ret;
}
CreateOpenListItem(&li, phPSTProv, Key, pguidType, pguidSubtype, szItemName);
if (!g_pCOpenItemList->DelFromList(&li))
{
dwRet = PST_E_NOT_OPEN;
goto Ret;
}
dwRet = PST_E_OK;
Ret:
return dwRet;
}
///////////////////////////////////////////////////
// FInitProtectAPIGlobals
//
// Checks for registry overrides for some default values
// registry entries can change what algs are being used,
// as well as what provider is used.
BOOL FInitProtectAPIGlobals()
{
HKEY hProtectKey = NULL;
HKEY hProviderKey = NULL;
DWORD dwTemp, dwType, cbSize;
DWORD dwCreate;
static const WCHAR szProtectKeyName[] = REG_CRYPTPROTECT_LOC;
static const WCHAR szProviderKeyName[] = L"\\" REG_CRYPTPROTECT_PROVIDERS_SUBKEYLOC L"\\" CRYPTPROTECT_DEFAULT_PROVIDER_GUIDSZ ;
LONG lRet;
//
// get password cache policy setting.
//
lRet = RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
L"Software\\Policies\\Microsoft\\Cryptography\\Protect",
0,
KEY_QUERY_VALUE,
&hProtectKey
);
if( lRet == ERROR_SUCCESS ) {
DWORD cbSize;
DWORD dwTemp;
DWORD dwType;
//
// query EnableCachePW value.
//
cbSize = sizeof(DWORD);
lRet = RegQueryValueExU(
hProtectKey,
REG_CRYPTPROTECT_ALLOW_CACHEPW,
NULL,
&dwType,
(PBYTE)&dwTemp,
&cbSize
);
if( lRet == ERROR_SUCCESS &&
dwType == REG_DWORD &&
dwTemp == 0 // 0 == disablePW cache
) {
g_fAllowCachePW = FALSE;
} else {
g_fAllowCachePW = TRUE;
}
RegCloseKey( hProtectKey );
hProtectKey = NULL;
} else {
g_fAllowCachePW = TRUE;
}
return TRUE;
}