#include #pragma hdrstop #include "guidcnvt.h" #include "passwd.h" #include "storage.h" extern DISPIF_CALLBACKS g_sCallbacks; // note: REG_PSTTREE_LOC moved to pstprv.h #define REG_DATA_LOC L"Data" #define REG_MK_LOC L"Data 2" #define REG_ACCESSRULE_LOC L"Access Rules" #define REG_DISPLAYSTRING_VALNAME L"Display String" #define REG_USER_INTERNAL_MAC_KEY L"Blocking" #define REG_ITEM_SECURE_DATA_VALNAME L"Item Data" #define REG_ITEM_INSECURE_DATA_VALNAME L"Insecure Data" #define REG_ITEM_MK_VALNAME L"Behavior" #define REG_SECURITY_SALT_VALNAME L"Value" /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // PRIMITIVIES for snagging registry keys DWORD GetPSTUserHKEY(LPCWSTR szUser, HKEY* phUserKey, BOOL* pfExisted) { HKEY hKeyBase = NULL; DWORD dwRet = (DWORD)PST_E_STORAGE_ERROR; DWORD dwCreate; DWORD cbKeyName; LPWSTR szKeyName = NULL; WCHAR FastBuffer[(sizeof(REG_PSTTREE_LOC) / sizeof(WCHAR)) + 64]; LPWSTR SlowBuffer = NULL; LPCWSTR szContainer = szUser; DWORD dwDesiredAccess = KEY_READ | KEY_WRITE; cbKeyName = sizeof(REG_PSTTREE_LOC) ; // // For Win95, we may have an empty or NULL container // name (szUser), so use a default storage area for // that scenario // if(szContainer == NULL || szContainer[0] == L'\0') { // "*" is an invalid LM username character szContainer = L"*Default*"; hKeyBase = HKEY_LOCAL_MACHINE; } else { // // see if we should go to HKEY_LOCAL_MACHINE or // HKEY_CURRENT_USER // if( _wcsicmp(WSZ_LOCAL_MACHINE, szContainer) == 0 ) { // HKEY_LOCAL_MACHINE hKeyBase = HKEY_LOCAL_MACHINE; } else { // HKEY_CURRENT_USER if(!GetUserHKEY(szContainer, dwDesiredAccess, &hKeyBase)) { if(FIsWinNT()) { goto Ret; } // // Win95, profiles may be disabled, so go to // HKEY_LOCAL_MACHINE\xxx\szContainer // hKeyBase = HKEY_LOCAL_MACHINE; } else { // // no container name when going to HKEY_CURRENT_USER // // // sfield: continue to use a container name for HKEY_CURRENT_USER // because the configuration may be shared, roamable hives // (mandatators profiles, etc, which we are telling people not // to use anymore, but never-the-less, this could come up // // szContainer = L"\0"; } } } cbKeyName += (lstrlenW(szContainer) * sizeof(WCHAR)) + sizeof(WCHAR) + // L'\\' sizeof(WCHAR) ; // terminal NULL // // use faster stack based buffer if the material fits // if(cbKeyName > sizeof(FastBuffer)) { SlowBuffer = (LPWSTR)SSAlloc( cbKeyName ); if (SlowBuffer == NULL) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } szKeyName = SlowBuffer; } else { szKeyName = FastBuffer; } wcscpy(szKeyName, REG_PSTTREE_LOC); // // work-around bug in RegCreateKeyEx that returns the wrong // creation disposition if a trailing "\" is in the key name // if(szContainer && szContainer[0] != L'\0') { wcscat(szKeyName, L"\\"); wcscat(szKeyName, szContainer); } // Open Base Key // // get current user, open (REG_PSTTREE_LOC\\CurrentUser) if (ERROR_SUCCESS != RegCreateKeyExU( hKeyBase, szKeyName, 0, NULL, // address of class string 0, dwDesiredAccess, NULL, phUserKey, &dwCreate)) { goto Ret; } if (pfExisted) { *pfExisted = (dwCreate == REG_OPENED_EXISTING_KEY); } if(dwCreate == REG_CREATED_NEW_KEY && FIsWinNT()) { // // WinNT: restrict access to Local System on newly created key. // HKEY hKeyWriteDac; // // duplicate to WRITE_DAC access key and use that // if(ERROR_SUCCESS == RegOpenKeyExW(*phUserKey, NULL, 0, WRITE_DAC, &hKeyWriteDac)) { SetRegistrySecurity(hKeyWriteDac); RegCloseKey(hKeyWriteDac); } } dwRet = PST_E_OK; Ret: if (SlowBuffer) SSFree(SlowBuffer); // // close the per-user "root" key // if(hKeyBase != NULL && hKeyBase != HKEY_LOCAL_MACHINE) RegCloseKey(hKeyBase); return dwRet; } DWORD GetPSTTypeHKEY(LPCWSTR szUser, const GUID* pguidType, HKEY* phTypeKey) { DWORD dwRet; HKEY hBaseKey = NULL; HKEY hDataKey = NULL; CHAR rgszTypeGuid[MAX_GUID_SZ_CHARS]; // Open User Key // if (PST_E_OK != (dwRet = GetPSTUserHKEY( szUser, &hBaseKey, NULL)) ) goto Ret; // Open Data Key // if (ERROR_SUCCESS != RegOpenKeyExU( hBaseKey, REG_DATA_LOC, 0, KEY_READ | KEY_WRITE, &hDataKey)) { dwRet = (DWORD)PST_E_TYPE_NO_EXISTS; goto Ret; } if (PST_E_OK != (dwRet = MyGuidToStringA( pguidType, rgszTypeGuid)) ) goto Ret; // Open Category Key // if (ERROR_SUCCESS != RegOpenKeyExA( hDataKey, rgszTypeGuid, 0, KEY_READ | KEY_WRITE, phTypeKey)) { dwRet = (DWORD)PST_E_TYPE_NO_EXISTS; goto Ret; } dwRet = PST_E_OK; Ret: if (hBaseKey) RegCloseKey(hBaseKey); if (hDataKey) RegCloseKey(hDataKey); return dwRet; } DWORD CreatePSTTypeHKEY(LPCWSTR szUser, const GUID* pguidType, HKEY* phTypeKey, BOOL* pfExisted) { DWORD dwRet; DWORD dwCreate; HKEY hBaseKey = NULL; HKEY hDataKey = NULL; CHAR rgszTypeGuid[MAX_GUID_SZ_CHARS]; // Open User Key // if (PST_E_OK != (dwRet = GetPSTUserHKEY( szUser, &hBaseKey, NULL)) ) goto Ret; // Open Data Key // if (ERROR_SUCCESS != RegCreateKeyExU( hBaseKey, REG_DATA_LOC, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, &hDataKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } if (PST_E_OK != (dwRet = MyGuidToStringA( pguidType, rgszTypeGuid)) ) goto Ret; // Open Category Key // if (ERROR_SUCCESS != RegCreateKeyExA( hDataKey, rgszTypeGuid, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, phTypeKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } if (pfExisted) *pfExisted = (dwCreate == REG_OPENED_EXISTING_KEY); dwRet = PST_E_OK; Ret: if (hBaseKey) RegCloseKey(hBaseKey); if (hDataKey) RegCloseKey(hDataKey); return dwRet; } DWORD GetPSTMasterKeyHKEY(LPCWSTR szUser, LPCWSTR szMasterKey, HKEY* phMyKey) { DWORD dwRet; DWORD dwCreate; HKEY hBaseKey = NULL; HKEY hMKKey = NULL; // Open User Key // if (PST_E_OK != (dwRet = GetPSTUserHKEY( szUser, &hBaseKey, NULL)) ) goto Ret; // Open Master Key section // if (ERROR_SUCCESS != RegCreateKeyExU( hBaseKey, REG_MK_LOC, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, &hMKKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } if (szMasterKey) { // Open specific Master Key // if (ERROR_SUCCESS != RegCreateKeyExU( hMKKey, szMasterKey, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, phMyKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } } else { // wanted master parent, not specific MK *phMyKey = hMKKey; } dwRet = PST_E_OK; Ret: if (hBaseKey) RegCloseKey(hBaseKey); // wanted parent, not specific MK if ((*phMyKey != hMKKey) && (hMKKey)) RegCloseKey(hMKKey); return dwRet; } DWORD GetPSTSubtypeHKEY(LPCWSTR szUser, const GUID* pguidType, const GUID* pguidSubtype, HKEY* phSubTypeKey) { DWORD dwRet; DWORD dwCreate; HKEY hTypeKey = NULL; CHAR rgszSubtypeGuid[MAX_GUID_SZ_CHARS]; // Open User Key // if (PST_E_OK != (dwRet = GetPSTTypeHKEY( szUser, pguidType, &hTypeKey)) ) goto Ret; if (PST_E_OK != (dwRet = MyGuidToStringA( pguidSubtype, rgszSubtypeGuid)) ) goto Ret; // Open SubType Key // if (ERROR_SUCCESS != RegOpenKeyExA( hTypeKey, rgszSubtypeGuid, 0, KEY_READ | KEY_WRITE, phSubTypeKey)) { dwRet = (DWORD)PST_E_TYPE_NO_EXISTS; goto Ret; } dwRet = PST_E_OK; Ret: if (hTypeKey) RegCloseKey(hTypeKey); return dwRet; } DWORD CreatePSTSubtypeHKEY(LPCWSTR szUser, const GUID* pguidType, const GUID* pguidSubtype, HKEY* phSubTypeKey, BOOL* pfExisted) { DWORD dwRet; DWORD dwCreate; HKEY hTypeKey = NULL; CHAR rgszSubtypeGuid[MAX_GUID_SZ_CHARS]; // Open Type Key // if (PST_E_OK != (dwRet = GetPSTTypeHKEY( szUser, pguidType, &hTypeKey)) ) goto Ret; if (PST_E_OK != (dwRet = MyGuidToStringA( pguidSubtype, rgszSubtypeGuid)) ) goto Ret; // Open SubType Key // if (ERROR_SUCCESS != RegCreateKeyExA( hTypeKey, rgszSubtypeGuid, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, phSubTypeKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } if (pfExisted) *pfExisted = (dwCreate == REG_OPENED_EXISTING_KEY); dwRet = PST_E_OK; Ret: if (hTypeKey) RegCloseKey(hTypeKey); return dwRet; } DWORD CreatePSTItemHKEY(LPCWSTR szUser, const GUID* pguidType, const GUID* pguidSubtype, LPCWSTR szItemName, HKEY* phItemKey, BOOL* pfExisted) { BOOL dwRet; DWORD dwCreate; HKEY hSubTypeKey = NULL; // Open SubType key // if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hSubTypeKey)) ) goto Ret; // Open name key // if (ERROR_SUCCESS != RegCreateKeyExU( hSubTypeKey, szItemName, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, phItemKey, &dwCreate)) { dwRet = (DWORD)PST_E_STORAGE_ERROR; goto Ret; } if (pfExisted) *pfExisted = (dwCreate == REG_OPENED_EXISTING_KEY); dwRet = PST_E_OK; Ret: if (hSubTypeKey) RegCloseKey(hSubTypeKey); return dwRet; } DWORD GetPSTItemHKEY(LPCWSTR szUser, const GUID* pguidType, const GUID* pguidSubtype, LPCWSTR szItemName, HKEY* phItemKey) { DWORD dwRet; DWORD dwCreate; HKEY hSubtypeKey = NULL; // Open SubType key // if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hSubtypeKey)) ) goto Ret; // Open name key // if (ERROR_SUCCESS != RegOpenKeyExU( hSubtypeKey, szItemName, 0, KEY_READ | KEY_WRITE, phItemKey)) { dwRet = (DWORD)PST_E_ITEM_NO_EXISTS; goto Ret; } dwRet = PST_E_OK; Ret: if (hSubtypeKey) RegCloseKey(hSubtypeKey); return dwRet; } // end PRIMITIVES /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // PICKLE routines #if 0 BOOL FAccessRulesPickle( PST_ACCESSRULESET *psRules, PBYTE* ppbPickled, DWORD* pcbPickled) { BOOL fRet = FALSE; DWORD cbTotal = 0; DWORD dwRule; // ease-of-use write pointer PBYTE pbCurrentWrite; // init out params *ppbPickled = NULL; *pcbPickled = 0; // ASSERT new size member was initialized SS_ASSERT(psRules->cbSize == sizeof(PST_ACCESSRULESET)); if (psRules->cbSize != sizeof(PST_ACCESSRULESET)) goto Ret; cbTotal += sizeof(DWORD); // Ruleset struct versioning cbTotal += sizeof(DWORD); // # Rules in Ruleset // walk through each Rule in Ruleset for (dwRule=0; dwRulecRules; dwRule++) { DWORD cClause; // ASSERT new size member was initialized SS_ASSERT(psRules->rgRules[dwRule].cbSize == sizeof(PST_ACCESSRULE)); if (psRules->rgRules[dwRule].cbSize != sizeof(PST_ACCESSRULE)) goto Ret; cbTotal += sizeof(DWORD); // Rule struct versioning cbTotal += sizeof(PST_ACCESSMODE); // mode in each Rule cbTotal += sizeof(DWORD); // # Clauses in Rule // for each Rule, we'll have array of clauses for (cClause=0; cClausergRules[dwRule].cClauses; cClause++) { // ASSERT new size member was initialized SS_ASSERT(psRules->rgRules[dwRule].rgClauses[cClause].cbSize == sizeof(PST_ACCESSCLAUSE)); if (psRules->rgRules[dwRule].rgClauses[cClause].cbSize != sizeof(PST_ACCESSCLAUSE)) goto Ret; cbTotal += sizeof(DWORD); // Clause struct versioning // we'll see every clause here cbTotal += sizeof(PST_ACCESSCLAUSETYPE); // type in each clause cbTotal += sizeof(DWORD); // # bytes in clause buffer cbTotal += psRules->rgRules[dwRule].rgClauses[cClause].cbClauseData; // buffer itself } } *ppbPickled = (BYTE*)SSAlloc(cbTotal); if(*ppbPickled == NULL) goto Ret; pbCurrentWrite = *ppbPickled; *pcbPickled = cbTotal; // copy Ruleset struct version *(DWORD*)pbCurrentWrite = psRules->cbSize; pbCurrentWrite += sizeof(DWORD); // copy # rules in ruleset *(DWORD*)pbCurrentWrite = psRules->cRules; pbCurrentWrite += sizeof(DWORD); // walk through each Rule in Ruleset for (dwRule=0; dwRulecRules; dwRule++) { // copy Rule struct version *(DWORD*)pbCurrentWrite = psRules->rgRules[dwRule].cbSize; pbCurrentWrite += sizeof(DWORD); // copy # clauses in rule *(DWORD*)pbCurrentWrite = psRules->rgRules[dwRule].cClauses; pbCurrentWrite += sizeof(DWORD); // copy rule accessmode CopyMemory(pbCurrentWrite, &psRules->rgRules[dwRule].AccessModeFlags, sizeof(PST_ACCESSMODE)); pbCurrentWrite += sizeof(PST_ACCESSMODE); // now for each Rule, we'll have array of clauses for (DWORD cClause=0; cClausergRules[dwRule].cClauses; cClause++) { PST_ACCESSCLAUSE* pTmp = &psRules->rgRules[dwRule].rgClauses[cClause]; // copy clause struct version *(DWORD*)pbCurrentWrite = pTmp->cbSize; pbCurrentWrite += sizeof(DWORD); // clause type CopyMemory(pbCurrentWrite, &pTmp->ClauseType, sizeof(PST_ACCESSCLAUSETYPE)); pbCurrentWrite += sizeof(PST_ACCESSCLAUSETYPE); // clause data buffer len *(DWORD*)pbCurrentWrite = pTmp->cbClauseData; pbCurrentWrite += sizeof(DWORD); // buffer itself CopyMemory(pbCurrentWrite, pTmp->pbClauseData, pTmp->cbClauseData); pbCurrentWrite += pTmp->cbClauseData; } } #if DBG { // ASSERT! DWORD dwWroteBytes = (DWORD) (((DWORD_PTR)pbCurrentWrite) - ((DWORD_PTR)*ppbPickled)); SS_ASSERT(dwWroteBytes == cbTotal); SS_ASSERT(cbTotal == *pcbPickled); } #endif fRet = TRUE; Ret: // on error and alloc, free if ((!fRet) && (*ppbPickled != NULL)) { SSFree(*ppbPickled); *ppbPickled = NULL; } return fRet; } BOOL FAccessRulesUnPickle( PPST_ACCESSRULESET psRules, // out PBYTE pbPickled, DWORD cbPickled) { BOOL fRet = FALSE; PBYTE pbCurrentRead = pbPickled; DWORD cRule; // Ruleset struct version psRules->cbSize = *(DWORD*)pbCurrentRead; pbCurrentRead += sizeof(DWORD); // currently only one version known if (psRules->cbSize != sizeof(PST_ACCESSRULESET)) goto Ret; // get # rules in ruleset cRule = *(DWORD*)pbCurrentRead; pbCurrentRead += sizeof(DWORD); // now we know how many Rule in Ruleset psRules->rgRules = (PST_ACCESSRULE*)SSAlloc(sizeof(PST_ACCESSRULE)*cRule); if(psRules->rgRules == NULL) goto Ret; psRules->cRules = cRule; // now unpack each Rule for (cRule=0; cRulecRules; cRule++) { DWORD cClauses; // Ruleset struct version psRules->rgRules[cRule].cbSize = *(DWORD*)pbCurrentRead; // currently only one version known if (psRules->rgRules[cRule].cbSize != sizeof(PST_ACCESSRULE)) goto Ret; pbCurrentRead += sizeof(DWORD); // get # clauses in rule cClauses = *(DWORD*)pbCurrentRead; pbCurrentRead += sizeof(DWORD); // now we know how many Clauses in Rule psRules->rgRules[cRule].rgClauses = (PST_ACCESSCLAUSE*)SSAlloc(sizeof(PST_ACCESSCLAUSE)*cClauses); if (psRules->rgRules[cRule].rgClauses == NULL) // check allocation goto Ret; psRules->rgRules[cRule].cClauses = cClauses; // copy rule accessmode flags CopyMemory(&psRules->rgRules[cRule].AccessModeFlags, pbCurrentRead, sizeof(PST_ACCESSMODE)); pbCurrentRead += sizeof(PST_ACCESSMODE); // now load each Clause for (DWORD cClause=0; cClausergRules[cRule].cClauses; cClause++) { PST_ACCESSCLAUSE* pTmp = &psRules->rgRules[cRule].rgClauses[cClause]; // Clause struct version pTmp->cbSize = *(DWORD*)pbCurrentRead; // currently only one version known if (pTmp->cbSize != sizeof(PST_ACCESSCLAUSE)) goto Ret; pbCurrentRead += sizeof(DWORD); CopyMemory(&pTmp->ClauseType, pbCurrentRead, sizeof(PST_ACCESSCLAUSETYPE)); pbCurrentRead += sizeof(PST_ACCESSCLAUSETYPE); // clause data buffer len pTmp->cbClauseData = *(DWORD*)pbCurrentRead; pbCurrentRead += sizeof(DWORD); // buffer itself pTmp->pbClauseData = (PBYTE) SSAlloc(pTmp->cbClauseData); if (pTmp->pbClauseData == NULL) // check allocation goto Ret; CopyMemory(pTmp->pbClauseData, pbCurrentRead, pTmp->cbClauseData); pbCurrentRead += pTmp->cbClauseData; } } #if DBG { // ASSERT! DWORD dwReadBytes = (DWORD) (((DWORD_PTR)pbCurrentRead) - ((DWORD_PTR)pbPickled)); SS_ASSERT(dwReadBytes == cbPickled); } #endif fRet = TRUE; Ret: if (!fRet) FreeRuleset(psRules); return fRet; } #endif // end PICKLE routines /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // TYPE management DWORD BPCreateType( LPCWSTR szUser, // in const GUID* pguidType, // in PST_TYPEINFO* pinfoType) // in { DWORD dwRet; BOOL fExisted; HKEY hKey = NULL; // now we need to create entries in hierarchy if (PST_E_OK != (dwRet = CreatePSTTypeHKEY( szUser, pguidType, &hKey, &fExisted)) ) goto Ret; // if we didn't create it, setting is an error if (fExisted) { dwRet = (DWORD)PST_E_TYPE_EXISTS; goto Ret; } if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hKey, REG_DISPLAYSTRING_VALNAME, 0, REG_SZ, (PBYTE)pinfoType->szDisplayName, WSZ_BYTECOUNT(pinfoType->szDisplayName))) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } DWORD BPDeleteType( LPCWSTR szUser, // in const GUID* pguidType) // in { DWORD dwRet; CHAR rgszTypeGuid[MAX_GUID_SZ_CHARS]; // now remove the entry in hierarchy HKEY hBaseKey = NULL; HKEY hDataKey = NULL; if (PST_E_OK != (dwRet = GetPSTUserHKEY( szUser, &hBaseKey, NULL)) ) goto Ret; // Open Data Key // if (ERROR_SUCCESS != (dwRet = RegOpenKeyExU( hBaseKey, REG_DATA_LOC, 0, KEY_READ | KEY_WRITE, &hDataKey)) ) goto Ret; if (PST_E_OK != (dwRet = MyGuidToStringA( pguidType, rgszTypeGuid)) ) goto Ret; if (!FIsWinNT()) { CHAR rgszTmp[MAX_GUID_SZ_CHARS]; DWORD cbTmp = MAX_GUID_SZ_CHARS; FILETIME ft; HKEY hTestEmptyKey = NULL; // open the type if (ERROR_SUCCESS != (dwRet = RegOpenKeyExA( hDataKey, rgszTypeGuid, 0, KEY_ALL_ACCESS, &hTestEmptyKey)) ) goto Ret; // check for emptiness if (ERROR_NO_MORE_ITEMS != RegEnumKeyExA( hTestEmptyKey, 0, rgszTmp, // address of buffer for subkey name &cbTmp, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) { RegCloseKey(hTestEmptyKey); dwRet = (DWORD)PST_E_NOTEMPTY; goto Ret; } // close key before deletion RegCloseKey(hTestEmptyKey); } // now, remove the friendly name if (ERROR_SUCCESS != (dwRet = RegDeleteKeyA( hDataKey, rgszTypeGuid)) ) { if (dwRet == ERROR_ACCESS_DENIED) dwRet = (DWORD)PST_E_NOTEMPTY; goto Ret; } dwRet = (DWORD)PST_E_OK; Ret: if (hBaseKey) RegCloseKey(hBaseKey); if (hDataKey) RegCloseKey(hDataKey); return dwRet; } DWORD BPEnumTypes( LPCWSTR szUser, // in DWORD dwIndex, // in GUID* pguidType) // out { DWORD dwRet; CHAR rgszGuidType[MAX_GUID_SZ_CHARS]; DWORD cbName = MAX_GUID_SZ_CHARS; FILETIME ft; // now walk through types, returning them one by one HKEY hKey=NULL, hDataKey=NULL; if (PST_E_OK != (dwRet = GetPSTUserHKEY( szUser, &hKey, NULL)) ) goto Ret; // Open Data Key // if (ERROR_SUCCESS != (dwRet = RegOpenKeyExU( hKey, REG_DATA_LOC, 0, KEY_READ | KEY_WRITE, &hDataKey)) ) goto Ret; // enum the dwIndex'th item, alloc & return if (ERROR_SUCCESS != (dwRet = RegEnumKeyExA( hDataKey, dwIndex, rgszGuidType, // address of buffer for subkey name &cbName, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = MyGuidFromStringA( rgszGuidType, pguidType)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); if (hDataKey) RegCloseKey(hDataKey); return dwRet; } DWORD BPGetTypeName( LPCWSTR szUser, // in const GUID* pguidType, // in LPWSTR* ppszType) // out { HKEY hKey = NULL; DWORD cbName = 0; DWORD dwRet; if (PST_E_OK != (dwRet = GetPSTTypeHKEY( szUser, pguidType, &hKey)) ) { dwRet = (DWORD)PST_E_TYPE_NO_EXISTS; goto Ret; } if (ERROR_SUCCESS != (dwRet = RegGetStringValue( hKey, REG_DISPLAYSTRING_VALNAME, (PBYTE*)ppszType, &cbName)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } // end TYPE management /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // SUBTYPE management DWORD BPCreateSubtype( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in PST_TYPEINFO* pinfoSubtype) // in { DWORD dwRet; BOOL fExisted; // now we need to create entries in hierarchy HKEY hKey = NULL; if (PST_E_OK != (dwRet = CreatePSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hKey, &fExisted)) ) goto Ret; // if we didn't create it, setting is an error if (fExisted) { dwRet = (DWORD)PST_E_TYPE_EXISTS; goto Ret; } if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hKey, REG_DISPLAYSTRING_VALNAME, 0, REG_SZ, (PBYTE)pinfoSubtype->szDisplayName, WSZ_BYTECOUNT(pinfoSubtype->szDisplayName) )) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } DWORD BPDeleteSubtype( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype) // in { DWORD dwRet; CHAR rgszSubtypeGuid[MAX_GUID_SZ_CHARS]; // now remove the entry in hierarchy HKEY hKey = NULL; if (PST_E_OK != (dwRet = GetPSTTypeHKEY( szUser, pguidType, &hKey)) ) { dwRet = (DWORD)PST_E_TYPE_NO_EXISTS; goto Ret; } if (PST_E_OK != (dwRet = MyGuidToStringA( pguidSubtype, rgszSubtypeGuid)) ) goto Ret; if (!FIsWinNT()) { CHAR rgszTmp[MAX_GUID_SZ_CHARS]; DWORD cbTmp = MAX_GUID_SZ_CHARS; FILETIME ft; HKEY hTestEmptyKey = NULL; // open the subtype if (ERROR_SUCCESS != (dwRet = RegOpenKeyExA( hKey, rgszSubtypeGuid, 0, KEY_ALL_ACCESS, &hTestEmptyKey)) ) goto Ret; // check for emptiness if (ERROR_NO_MORE_ITEMS != RegEnumKeyExA( hTestEmptyKey, 0, rgszTmp, // address of buffer for subkey name &cbTmp, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) { RegCloseKey(hTestEmptyKey); dwRet = (DWORD)PST_E_NOTEMPTY; goto Ret; } // close key before deletion RegCloseKey(hTestEmptyKey); } // now, remove the friendly name if (ERROR_SUCCESS != (dwRet = RegDeleteKeyA( hKey, rgszSubtypeGuid)) ) { if (dwRet == ERROR_ACCESS_DENIED) dwRet = (DWORD)PST_E_NOTEMPTY; goto Ret; } dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } DWORD BPEnumSubtypes( LPCWSTR szUser, // in DWORD dwIndex, // in const GUID* pguidType, // in GUID* pguidSubtype) // out { DWORD dwRet; CHAR rgszGuidSubtype[MAX_GUID_SZ_CHARS]; DWORD cbName = MAX_GUID_SZ_CHARS; FILETIME ft; // now walk through types, returning them one by one HKEY hTypeKey=NULL, hSubtypeKey=NULL; if (PST_E_OK != (dwRet = GetPSTTypeHKEY( szUser, pguidType, &hTypeKey)) ) goto Ret; // enum the dwIndex'th item, alloc & return if (ERROR_SUCCESS != (dwRet = RegEnumKeyExA( hTypeKey, dwIndex, rgszGuidSubtype, // address of buffer for subkey name &cbName, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = MyGuidFromStringA( rgszGuidSubtype, pguidSubtype)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegOpenKeyExA( hTypeKey, rgszGuidSubtype, 0, KEY_READ | KEY_WRITE, &hSubtypeKey)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hTypeKey) RegCloseKey(hTypeKey); if (hSubtypeKey) RegCloseKey(hSubtypeKey); return dwRet; } DWORD BPGetSubtypeName( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPWSTR* ppszSubtype) // out { HKEY hKey = NULL; DWORD cbName = 0; DWORD dwRet; if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegGetStringValue( hKey, REG_DISPLAYSTRING_VALNAME, (PBYTE*)ppszSubtype, &cbName)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } // end SUBTYPE management /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // ITEM management // given uuid, push entries into storage DWORD BPCreateItem( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName) // in { DWORD dwRet; BOOL fExisted; HKEY hKey = NULL; // // mattt 2/5/97: allow items with \ in them to be created. Urgh! // // mattt 4/28/97: begin restricting strings. // Cert request code has been changed to not create this type of key name // /* if (!FStringIsValidItemName(szItemName)) { dwRet = (DWORD)PST_E_INVALID_STRING; goto Ret; } */ // now we need to create entries in hierarchy if (PST_E_OK != (dwRet = CreatePSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hKey, &fExisted)) ) goto Ret; if (fExisted) { dwRet = (DWORD)PST_E_ITEM_EXISTS; goto Ret; } dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } DWORD BPDeleteItem( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName) // in { DWORD dwRet; HKEY hSubTypeKey = NULL; // now we need to remove entries in hierarchy if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hSubTypeKey)) ) goto Ret; // now, remove the friendly name if (ERROR_SUCCESS != (dwRet = RegDeleteKeyU( hSubTypeKey, szItemName)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hSubTypeKey) RegCloseKey(hSubTypeKey); return dwRet; } // Warning: Item path must be fully specified.. szName returned DWORD BPEnumItems( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in DWORD dwIndex, // in LPWSTR* ppszName) // out { DWORD dwRet; WCHAR szName[MAX_PATH]; DWORD cchName = MAX_PATH; FILETIME ft; // now walk through types, returning them one by one HKEY hKey = NULL; // Open SubType key // if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hKey)) ) goto Ret; // enum the dwIndex'th item, alloc & return if (ERROR_SUCCESS != (dwRet = RegEnumKeyExU( hKey, dwIndex, szName, // address of buffer for subkey name &cchName, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) ) goto Ret; *ppszName = (LPWSTR)SSAlloc((cchName+1)*sizeof(WCHAR)); if(*ppszName == NULL) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } wcscpy(*ppszName, szName); dwRet = (DWORD)PST_E_OK; Ret: if (hKey) RegCloseKey(hKey); return dwRet; } // end ITEM management /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // SECURED DATA BOOL FBPGetSecuredItemData( LPCWSTR szUser, // in LPCWSTR szMasterKey, // in BYTE rgbPwd[A_SHA_DIGEST_LEN], // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PBYTE* ppbData, // out DWORD* pcbData) // out { DWORD dwRet; *ppbData = NULL; // on err return NULL *pcbData = 0; HKEY hItemKey = NULL; if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; // Version | Key Block | Secure Data [...] if (ERROR_SUCCESS != (dwRet = RegGetValue( hItemKey, REG_ITEM_SECURE_DATA_VALNAME, ppbData, pcbData)) ) goto Ret; if (!FProvDecryptData( szUser, szMasterKey, rgbPwd, // in ppbData, // in out pcbData)) // in out { dwRet = (DWORD)PST_E_FAIL; goto Ret; } dwRet = PST_E_OK; Ret: if ((dwRet != PST_E_OK) && (*ppbData != NULL)) { SSFree(*ppbData); *ppbData = NULL; *pcbData = 0; } if (hItemKey) RegCloseKey(hItemKey); return (dwRet == PST_E_OK); } BOOL FBPSetSecuredItemData( LPCWSTR szUser, // in LPCWSTR szMasterKey, // in BYTE rgbPwd[A_SHA_DIGEST_LEN], // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PBYTE pbData, // in DWORD cbData) // in { #define REALLOC_FUDGESIZE 96 // 5dw + SHA_LEN + KeyBlock + DES_BLOCKLEN (block encr expansion) DWORD dwRet; HKEY hItemKey = NULL; PBYTE pbMyData = NULL; DWORD cbMyData; // make whackable copy cbMyData = cbData; pbMyData = (PBYTE)SSAlloc(cbMyData + REALLOC_FUDGESIZE); if (pbMyData == NULL) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } CopyMemory(pbMyData, pbData, cbData); if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; if (!FProvEncryptData( szUser, szMasterKey, rgbPwd, // in &pbMyData, // in out &cbMyData)) // in out { dwRet = (DWORD)PST_E_FAIL; goto Ret; } if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hItemKey, REG_ITEM_SECURE_DATA_VALNAME, 0, REG_BINARY, pbMyData, cbMyData)) ) goto Ret; dwRet = PST_E_OK; Ret: if (hItemKey) RegCloseKey(hItemKey); if (pbMyData) SSFree(pbMyData); return (dwRet == PST_E_OK); } // end SECURED DATA /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // INSECURE DATA DWORD BPGetInsecureItemData( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PBYTE* ppbData, // out DWORD* pcbData) // out { DWORD dwRet; *ppbData = NULL; HKEY hItemKey = NULL; if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegGetValue( hItemKey, REG_ITEM_INSECURE_DATA_VALNAME, ppbData, pcbData)) ) goto Ret; dwRet = PST_E_OK; Ret: if (hItemKey) RegCloseKey(hItemKey); return dwRet; } DWORD BPSetInsecureItemData( LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PBYTE pbData, // in DWORD cbData) // in { DWORD dwRet; HKEY hItemKey = NULL; if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hItemKey, REG_ITEM_INSECURE_DATA_VALNAME, 0, REG_BINARY, pbData, cbData)) ) goto Ret; dwRet = PST_E_OK; Ret: if (hItemKey) RegCloseKey(hItemKey); return dwRet; } // end INSECURE DATA /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // RULESETS // #define RULESET_VERSION 0x1 // 6-12-97 incremented version; version 0x1 contains old HMAC #define RULESET_VERSION 0x2 #if 0 DWORD BPGetSubtypeRuleset( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in PST_ACCESSRULESET* psRules) // out { DWORD dwRet; HKEY hSubtypeKey = NULL; BYTE rgbHMAC[A_SHA_DIGEST_LEN]; BYTE rgbPwd[A_SHA_DIGEST_LEN]; PBYTE pbBuf = NULL; DWORD cbBuf; PBYTE pbCurrent; DWORD cbRuleSize; PBYTE pbRuleSet; DWORD dwVersion; // Open Subtype // if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hSubtypeKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegGetValue( hSubtypeKey, REG_ACCESSRULE_LOC, &pbBuf, &cbBuf)) ) goto Ret; // RULESET DATA FORMAT: // version | size(ruleset) | ruleset | size(MAC) | MAC {of type, subtype, ruleset} pbCurrent = pbBuf; if( cbBuf < (sizeof(DWORD)*2) ) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // version check dwVersion = *(DWORD*)pbCurrent; if (dwVersion > RULESET_VERSION) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } pbCurrent += sizeof(DWORD); cbRuleSize = *(DWORD*)pbCurrent; // get WinPW if (PST_E_OK != BPVerifyPwd( phPSTProv, szUser, WSZ_PASSWORD_WINDOWS, rgbPwd, BP_CONFIRM_NONE)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } // check MAC // Compute Geographically sensitive (can't move) HMAC on { size(ruleset), ruleset } if (!FHMACGeographicallySensitiveData( szUser, WSZ_PASSWORD_WINDOWS, (dwVersion == 0x01) ? OLD_HMAC_VERSION : NEW_HMAC_VERSION, rgbPwd, pguidType, pguidSubtype, NULL, pbCurrent, cbRuleSize + sizeof(DWORD), // include the rulesize rgbHMAC)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } pbCurrent += sizeof(DWORD); // skip past cbRuleSize (already snarfed) pbRuleSet = pbCurrent; // point to rules pbCurrent += cbRuleSize; // skip past rules // check MAC len if (*(DWORD*)pbCurrent != A_SHA_DIGEST_LEN) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } pbCurrent += sizeof(DWORD); // skip past sizeof(MAC) // check MAC if (0 != memcmp(rgbHMAC, pbCurrent, A_SHA_DIGEST_LEN)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // MAC okay! shrink to rulesize MoveMemory(pbBuf, pbRuleSet, cbRuleSize); cbBuf = cbRuleSize; pbBuf = (PBYTE)SSReAlloc(pbBuf, cbBuf); if (pbBuf == NULL) // check allocation { dwRet = PST_E_FAIL; goto Ret; } // serialize rules out of the buffer if (!FAccessRulesUnPickle( psRules, pbBuf, cbBuf)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } dwRet = (DWORD)PST_E_OK; Ret: if (pbBuf) SSFree(pbBuf); if (hSubtypeKey) RegCloseKey(hSubtypeKey); return dwRet; } DWORD BPSetSubtypeRuleset( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in PST_ACCESSRULESET *psRules) // in { DWORD dwRet; HKEY hSubtypeKey = NULL; BYTE rgbHMAC[A_SHA_DIGEST_LEN]; BYTE rgbPwd[A_SHA_DIGEST_LEN]; PBYTE pbBuf = NULL; DWORD cbBuf; PBYTE pbCurPtr; DWORD cbNewSize; // serialize rules into a buffer if (!FAccessRulesPickle( psRules, &pbBuf, &cbBuf)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // RULESET DATA FORMAT: // version | size(ruleset) | ruleset | size(MAC) | Geographical MAC {size(ruleset), ruleset} cbNewSize = cbBuf + 3*sizeof(DWORD) + A_SHA_DIGEST_LEN; pbBuf = (PBYTE)SSReAlloc(pbBuf, cbNewSize); if (pbBuf == NULL) // check allocation { dwRet = PST_E_FAIL; goto Ret; } MoveMemory(pbBuf + 2*sizeof(DWORD), pbBuf, cbBuf); // helpful pointer pbCurPtr = pbBuf; // version *(DWORD*)pbCurPtr = (DWORD)RULESET_VERSION; pbCurPtr += sizeof(DWORD); // size(ruleset) *(DWORD*)pbCurPtr = (DWORD)cbBuf; pbCurPtr += sizeof(DWORD); // ruleset previously moved by MoveMemory call pbCurPtr += cbBuf; // fwd past ruleset // get WinPW if (PST_E_OK != BPVerifyPwd( phPSTProv, szUser, WSZ_PASSWORD_WINDOWS, rgbPwd, BP_CONFIRM_NONE)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } // check MAC // Compute Geographically sensitive (can't move) HMAC on { size(ruleset), ruleset } if (!FHMACGeographicallySensitiveData( szUser, WSZ_PASSWORD_WINDOWS, NEW_HMAC_VERSION, rgbPwd, pguidType, pguidSubtype, NULL, pbBuf + sizeof(DWORD), cbBuf + sizeof(DWORD), rgbHMAC)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // HMAC size *(DWORD*)pbCurPtr = (DWORD) sizeof(rgbHMAC); pbCurPtr += sizeof(DWORD); // HMAC CopyMemory(pbCurPtr, rgbHMAC, sizeof(rgbHMAC)); // done; set cbBuf = new size cbBuf = cbNewSize; // Open Subtype // if (PST_E_OK != (dwRet = GetPSTSubtypeHKEY( szUser, pguidType, pguidSubtype, &hSubtypeKey)) ) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // now write item if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hSubtypeKey, REG_ACCESSRULE_LOC, 0, REG_BINARY, pbBuf, cbBuf)) ) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } dwRet = (DWORD)PST_E_OK; Ret: if (pbBuf) SSFree(pbBuf); if (hSubtypeKey) RegCloseKey(hSubtypeKey); return dwRet; } DWORD BPGetItemRuleset( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PST_ACCESSRULESET* psRules) // out { DWORD dwRet; HKEY hItemKey = NULL; PBYTE pbBuf = NULL; DWORD cbBuf; if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; // item doesn't exist -- ouch!! if (ERROR_SUCCESS != (dwRet = RegGetValue( hItemKey, REG_ACCESSRULE_LOC, &pbBuf, &cbBuf)) ) { // item exists, rules don't // fall back on subtype ruleset if (PST_E_OK != (dwRet = BPGetSubtypeRuleset( phPSTProv, szUser, pguidType, pguidSubtype, psRules)) ) goto Ret; } else { // serialize rules into a buffer if (!FAccessRulesUnPickle( psRules, pbBuf, cbBuf)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } } dwRet = (DWORD)PST_E_OK; Ret: if (pbBuf) SSFree(pbBuf); if (hItemKey) RegCloseKey(hItemKey); return dwRet; } DWORD BPSetItemRuleset( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in PST_ACCESSRULESET *psRules) // in { DWORD dwRet; HKEY hItemKey = NULL; PBYTE pbBuf = NULL; DWORD cbBuf; // serialize rules into a buffer if (!FAccessRulesPickle( psRules, &pbBuf, &cbBuf)) { dwRet = (DWORD)PST_E_INVALID_RULESET; goto Ret; } // Open Subtype // if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; // now write item if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hItemKey, REG_ACCESSRULE_LOC, 0, REG_BINARY, pbBuf, cbBuf)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (pbBuf) SSFree(pbBuf); if (hItemKey) RegCloseKey(hItemKey); return dwRet; } #endif // end RULESETS /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // ITEM CONFIRM INFO // #define CONFIRMATION_VERSION 0x01 // 6-12-97 incremented version: version 0x1 contains old HMAC #define CONFIRMATION_VERSION 0x02 DWORD BPGetItemConfirm( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in DWORD* pdwConfirm, // in LPWSTR* pszMK) // in { DWORD dwRet; HKEY hItemKey = NULL; PBYTE pbBuf = NULL; DWORD cbBuf = 0; BYTE rgbHMAC[A_SHA_DIGEST_LEN]; BYTE rgbPwd[A_SHA_DIGEST_LEN]; // helpful pointers PBYTE pbCurPtr = NULL; PBYTE pbString; DWORD cbString; DWORD dwVersion; // Open nonexistent item master key if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegGetValue( hItemKey, REG_ITEM_MK_VALNAME, &pbBuf, &cbBuf)) ) goto Ret; // Confirmation data format // Version | dwConfirm | size(szMasterKey) | szMasterKey | size(MAC) | Geographical MAC { dwConfirm | size(szMasterKey) | szMasterKey } // version check dwVersion = *(DWORD*)pbBuf; if (CONFIRMATION_VERSION < dwVersion) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } pbCurPtr = pbBuf + sizeof(DWORD); // fwd past vers // get WinPW if (PST_E_OK != BPVerifyPwd( phPSTProv, szUser, WSZ_PASSWORD_WINDOWS, rgbPwd, BP_CONFIRM_NONE)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } // check MAC // Compute Geographically sensitive (can't move) HMAC on { dwConfirm | size(szMasterKey) | szMasterKey } if (!FHMACGeographicallySensitiveData( szUser, WSZ_PASSWORD_WINDOWS, (dwVersion == 0x01) ? OLD_HMAC_VERSION : NEW_HMAC_VERSION, rgbPwd, pguidType, pguidSubtype, szItemName, pbBuf + sizeof(DWORD), // fwd past Version cbBuf - 2*sizeof(DWORD) - A_SHA_DIGEST_LEN, // Version, size(MAC), MAC rgbHMAC)) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } // dwConfirm *pdwConfirm = *(DWORD*)pbCurPtr; // dwConfirm pbCurPtr += sizeof(DWORD); // fwd past dwConfirm // szMasterKey cbString = *(DWORD*)pbCurPtr; // strlen pbCurPtr += sizeof(DWORD); // fwd past len pbString = pbCurPtr; // save ptr to string pbCurPtr += cbString; // skip string if (*(DWORD*)pbCurPtr != A_SHA_DIGEST_LEN) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } pbCurPtr += sizeof(DWORD); if (0 != memcmp(pbCurPtr, rgbHMAC, A_SHA_DIGEST_LEN)) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } MoveMemory(pbBuf, pbString, cbString); // shift left string pbCurPtr = (PBYTE)SSReAlloc(pbBuf, cbString); // shorten to strlen if (pbCurPtr == NULL) // check allocation { dwRet = PST_E_FAIL; if (pbBuf) { SSFree(pbBuf); pbBuf = NULL; } goto Ret; } pbBuf = pbCurPtr; dwRet = (DWORD)PST_E_OK; Ret: *pszMK = (LPWSTR)pbBuf; // assign to out param if (hItemKey) RegCloseKey(hItemKey); return dwRet; } DWORD BPSetItemConfirm( PST_PROVIDER_HANDLE* phPSTProv, // in LPCWSTR szUser, // in const GUID* pguidType, // in const GUID* pguidSubtype, // in LPCWSTR szItemName, // in DWORD dwConfirm, // in LPCWSTR szMK) // in { DWORD dwRet; HKEY hItemKey = NULL; BYTE rgbHMAC[A_SHA_DIGEST_LEN]; BYTE rgbPwd[A_SHA_DIGEST_LEN]; // helpful pointer PBYTE pbCurPtr; // Confirmation data format // Version | dwConfirm | size(szMasterKey) | szMasterKey | size(MAC) | Geographical MAC { dwConfirm | size(szMasterKey) | szMasterKey } DWORD cbBuf = WSZ_BYTECOUNT(szMK)+ 4*sizeof(DWORD) + A_SHA_DIGEST_LEN; PBYTE pbBuf = (PBYTE)SSAlloc(cbBuf); if (pbBuf == NULL) // check allocation { dwRet = PST_E_FAIL; goto Ret; } pbCurPtr = pbBuf; // version *(DWORD*)pbCurPtr = (DWORD)CONFIRMATION_VERSION; pbCurPtr += sizeof(DWORD); // dwConfirm *(DWORD*)pbCurPtr = dwConfirm; pbCurPtr += sizeof(DWORD); // szMasterKey size *(DWORD*)pbCurPtr = (DWORD)WSZ_BYTECOUNT(szMK); pbCurPtr += sizeof(DWORD); // szMasterKey wcscpy((LPWSTR)pbCurPtr, szMK); pbCurPtr += WSZ_BYTECOUNT(szMK); // fwd past szMK // get WinPW if (PST_E_OK != BPVerifyPwd( phPSTProv, szUser, WSZ_PASSWORD_WINDOWS, rgbPwd, BP_CONFIRM_NONE)) { dwRet = (DWORD)PST_E_WRONG_PASSWORD; goto Ret; } // check MAC // Compute Geographically sensitive (can't move) HMAC on { dwConfirm | size(szMasterKey) | szMasterKey } if (!FHMACGeographicallySensitiveData( szUser, WSZ_PASSWORD_WINDOWS, NEW_HMAC_VERSION, rgbPwd, pguidType, pguidSubtype, szItemName, pbBuf + sizeof(DWORD), // fwd past Version cbBuf - 2*sizeof(DWORD) - A_SHA_DIGEST_LEN, // Version, size(MAC), MAC rgbHMAC)) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } // HMAC size *(DWORD*)pbCurPtr = (DWORD) sizeof(rgbHMAC); pbCurPtr += sizeof(DWORD); // HMAC CopyMemory(pbCurPtr, rgbHMAC, sizeof(rgbHMAC)); // Open Item // if (PST_E_OK != (dwRet = GetPSTItemHKEY( szUser, pguidType, pguidSubtype, szItemName, &hItemKey)) ) goto Ret; // now write item if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hItemKey, REG_ITEM_MK_VALNAME, 0, REG_BINARY, pbBuf, cbBuf)) ) goto Ret; dwRet = (DWORD)PST_E_OK; Ret: if (hItemKey) RegCloseKey(hItemKey); if (pbBuf) SSFree(pbBuf); return dwRet; } // ITEM CONFIRM INFO /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // MASTER KEYS BOOL BPMasterKeyExists( LPCWSTR szUser, // in LPWSTR szMasterKey) // in { BOOL fRet = FALSE; HKEY hMyKey = NULL; HKEY hMasterKey = NULL; // Open Master parent key // if (PST_E_OK != GetPSTMasterKeyHKEY( szUser, NULL, &hMyKey)) goto Ret; // attempt to open the master key location if (ERROR_SUCCESS != RegOpenKeyExU( hMyKey, szMasterKey, 0, KEY_QUERY_VALUE, &hMasterKey)) goto Ret; // key does exist fRet = TRUE; Ret: if (hMyKey) RegCloseKey(hMyKey); if (hMasterKey) RegCloseKey(hMasterKey); return fRet; } DWORD BPEnumMasterKeys( LPCWSTR szUser, // in DWORD dwIndex, // in LPWSTR* ppszMasterKey) // out { DWORD dwRet; HKEY hMyKey = NULL; WCHAR szName[MAX_PATH]; DWORD cchName = MAX_PATH; FILETIME ft; // Open Master parent key // if (PST_E_OK != (dwRet = GetPSTMasterKeyHKEY( szUser, NULL, &hMyKey)) ) goto Ret; // enum the dwIndex'th item, alloc & return if (ERROR_SUCCESS != (dwRet = RegEnumKeyExU( hMyKey, dwIndex, szName, // address of buffer for subkey name &cchName, // address for size of subkey buffer NULL, // reserved NULL, // pbclass NULL, // cbclass &ft)) ) goto Ret; *ppszMasterKey = (LPWSTR)SSAlloc(WSZ_BYTECOUNT(szName)); if(*ppszMasterKey == NULL) { dwRet = (DWORD)PST_E_FAIL; goto Ret; } wcscpy(*ppszMasterKey, szName); dwRet = (DWORD)PST_E_OK; Ret: if (hMyKey) RegCloseKey(hMyKey); return dwRet; } DWORD BPGetMasterKeys( LPCWSTR szUser, LPWSTR rgszMasterKeys[], DWORD* pcbMasterKeys, BOOL fUserFilter) { DWORD dwRet; DWORD cKeys=0; for (DWORD cntEnum=0; cntEnum<*pcbMasterKeys; cntEnum++) { if (PST_E_OK != (dwRet = BPEnumMasterKeys( szUser, cntEnum, &rgszMasterKeys[cKeys])) ) break; cKeys++; // filter out non-user keys if (fUserFilter) { if (!FIsUserMasterKey(rgszMasterKeys[cKeys-1])) SSFree(rgszMasterKeys[--cKeys]); } } *pcbMasterKeys = cKeys; return PST_E_OK; } // end MASTER KEYS /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // SECURITY STATE #define SECURITY_STATE_VERSION 0x01 BOOL FBPGetSecurityState( LPCWSTR szUser, LPCWSTR szMK, BYTE rgbSalt[], DWORD cbSalt, BYTE rgbConfirm[], DWORD cbConfirm, PBYTE* ppbMK, DWORD* pcbMK) { DWORD dwRet; HKEY hMKKey = NULL; // Open MK Key // if (PST_E_OK != (dwRet = GetPSTMasterKeyHKEY( szUser, szMK, &hMKKey)) ) goto Ret; dwRet = PST_E_FAIL; if(!FBPGetSecurityStateFromHKEY( hMKKey, rgbSalt, cbSalt, rgbConfirm, cbConfirm, ppbMK, pcbMK)) goto Ret; dwRet = PST_E_OK; Ret: if (hMKKey) RegCloseKey(hMKKey); return (dwRet == PST_E_OK); } BOOL FBPGetSecurityStateFromHKEY( HKEY hMKKey, BYTE rgbSalt[], DWORD cbSalt, BYTE rgbConfirm[], DWORD cbConfirm, PBYTE* ppbMK, DWORD* pcbMK) { DWORD dwRet; PBYTE pbBuf = NULL; DWORD cbBuf; // helpful pointer PBYTE pbCurPtr; DWORD dwMemberSize; DWORD dwCreated; PBYTE pbLocalSalt; PBYTE pbLocalMK; PBYTE pbLocalConfirm; DWORD cbLocalSalt; DWORD cbLocalMK; DWORD cbLocalConfirm; PBYTE pbMaximumPtr; PBYTE pbMinimumPtr; if (ERROR_SUCCESS != (dwRet = RegGetValue( hMKKey, REG_SECURITY_SALT_VALNAME, &pbBuf, &cbBuf)) ) goto Ret; dwRet = PST_E_FAIL; // Security data format // Version | size(MK) | MK | size(Salt) | Salt | size(Confirm) | Confirm if ( cbBuf < (sizeof(DWORD)*4) ) goto Ret; // version check if (SECURITY_STATE_VERSION != *(DWORD*)pbBuf) goto Ret; pbCurPtr = pbBuf + sizeof(DWORD); // fwd past vers pbMinimumPtr = pbCurPtr; pbMaximumPtr = (pbBuf+cbBuf); // // MK // if( pbCurPtr >= pbMaximumPtr || pbCurPtr < pbMinimumPtr ) goto Ret; cbLocalMK = *(DWORD*)pbCurPtr; // size if( cbLocalMK > cbBuf ) goto Ret; pbCurPtr += sizeof(DWORD); // fwd past size pbLocalMK = pbCurPtr; pbCurPtr += cbLocalMK; // fwd past data // // Salt // if( pbCurPtr >= pbMaximumPtr || pbCurPtr < pbMinimumPtr ) goto Ret; cbLocalSalt = *(DWORD*)pbCurPtr; // size if( cbLocalSalt > cbBuf ) goto Ret; pbCurPtr += sizeof(DWORD); // fwd past size pbLocalSalt = pbCurPtr; if (cbLocalSalt != cbSalt) // sizechk goto Ret; pbCurPtr += cbSalt; // fwd past data // // Confirm // if( pbCurPtr >= pbMaximumPtr || pbCurPtr < pbMinimumPtr ) goto Ret; cbLocalConfirm = *(DWORD*)pbCurPtr; // size if( cbLocalConfirm > cbBuf ) goto Ret; pbCurPtr += sizeof(DWORD); // fwd past size pbLocalConfirm = pbCurPtr; if (cbLocalConfirm != cbConfirm) // sizechk goto Ret; pbCurPtr += cbConfirm; // fwd past data // // do a single size sanity check before copying data out. // if( pbCurPtr != (pbBuf + cbBuf) ) goto Ret; MoveMemory(pbBuf, pbLocalMK, cbLocalMK); // move left to front for later realloc CopyMemory(rgbSalt, pbLocalSalt, cbLocalSalt); // data CopyMemory(rgbConfirm, pbLocalConfirm, cbLocalConfirm); // data // // MK fixup // *pcbMK = cbLocalMK; pbCurPtr = (PBYTE)SSReAlloc(pbBuf, *pcbMK); // shorten to MK data if (pbCurPtr == NULL) { dwRet = PST_E_FAIL; if (pbBuf) { SSFree(pbBuf); *ppbMK = NULL; } goto Ret; } *ppbMK = pbCurPtr; dwRet = PST_E_OK; Ret: return (dwRet == PST_E_OK); } BOOL FBPSetSecurityState( LPCWSTR szUser, LPCWSTR szMK, BYTE rgbSalt[], DWORD cbSalt, BYTE rgbConfirm[], DWORD cbConfirm, PBYTE pbMK, DWORD cbMK) { DWORD dwRet; HKEY hMKKey = NULL; // helpful pointer PBYTE pbCurPtr; DWORD cbBuf = cbSalt + cbConfirm + cbMK + 4*sizeof(DWORD); // ver + size + data PBYTE pbBuf = (PBYTE)SSAlloc(cbBuf); if (pbBuf == NULL) { dwRet = PST_E_FAIL; goto Ret; } pbCurPtr = pbBuf; // Security data format // Version | size(MK) | MK | size(Salt) | Salt | size(Confirm) | Confirm *(DWORD*)pbCurPtr = SECURITY_STATE_VERSION; // ver pbCurPtr += sizeof(DWORD); // fwd past ver // MK *(DWORD*)pbCurPtr = cbMK; // size pbCurPtr += sizeof(DWORD); // fwd past size CopyMemory(pbCurPtr, pbMK, cbMK); // data pbCurPtr += cbMK; // fwd past data // Salt *(DWORD*)pbCurPtr = cbSalt; // size pbCurPtr += sizeof(DWORD); // fwd past size CopyMemory(pbCurPtr, rgbSalt, cbSalt); // data pbCurPtr += cbSalt; // fwd past data // Confirm *(DWORD*)pbCurPtr = cbConfirm; // size pbCurPtr += sizeof(DWORD); // fwd past size CopyMemory(pbCurPtr, rgbConfirm, cbConfirm);// data pbCurPtr += cbConfirm; // fwd past data // Open User Key // if (PST_E_OK != (dwRet = GetPSTMasterKeyHKEY( szUser, szMK, &hMKKey)) ) goto Ret; if (ERROR_SUCCESS != (dwRet = RegSetValueExU( hMKKey, REG_SECURITY_SALT_VALNAME, 0, REG_BINARY, pbBuf, cbBuf)) ) goto Ret; dwRet = PST_E_OK; Ret: if (hMKKey) RegCloseKey(hMKKey); if (pbBuf) SSFree(pbBuf); return (dwRet == PST_E_OK); } // end SECURITY STATE /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // begin global MAC Key storage #define INTERNAL_MAC_KEY_VERSION 0x1 BOOL FGetInternalMACKey(LPCWSTR szUser, PBYTE* ppbKey, DWORD* pcbKey) { BOOL fRet = FALSE; HKEY hBaseKey = NULL; HKEY hDataKey = NULL; // Open User Key // if (PST_E_OK != GetPSTUserHKEY( szUser, &hBaseKey, NULL)) goto Ret; // Open Data Key // if (ERROR_SUCCESS != RegOpenKeyExU( hBaseKey, REG_DATA_LOC, 0, KEY_READ | KEY_WRITE, &hDataKey)) goto Ret; if (ERROR_SUCCESS != RegGetValue( hDataKey, REG_USER_INTERNAL_MAC_KEY, ppbKey, pcbKey)) goto Ret; if(*pcbKey < sizeof(DWORD)) goto Ret; // only know about ver 1 keys if (*(DWORD*)*ppbKey != INTERNAL_MAC_KEY_VERSION) goto Ret; // strip version tag, shift left *pcbKey -= sizeof(DWORD); MoveMemory(*ppbKey, *ppbKey + sizeof(DWORD), *pcbKey); fRet = TRUE; Ret: if (hBaseKey) RegCloseKey(hBaseKey); if (hDataKey) RegCloseKey(hDataKey); return fRet; } BOOL FSetInternalMACKey(LPCWSTR szUser, PBYTE pbKey, DWORD cbKey) { BOOL fRet = FALSE; HKEY hBaseKey = NULL; HKEY hDataKey = NULL; DWORD dwCreate; // no need to alloc, we assume we know cbKey size (2 deskeys + blocklen pad + dwVersion) BYTE rgbTmp[(8*3)+sizeof(DWORD)]; // ASSUME: two deskeys, each 8 bytes + blocklen pad if (cbKey != (8*3)) goto Ret; // tack version on front *(DWORD*)rgbTmp = (DWORD)INTERNAL_MAC_KEY_VERSION; CopyMemory(rgbTmp + sizeof(DWORD), pbKey, cbKey); // Open User Key // if (PST_E_OK != GetPSTUserHKEY( szUser, &hBaseKey, NULL)) goto Ret; // Open/Create Data Key // if (ERROR_SUCCESS != RegCreateKeyExU( hBaseKey, REG_DATA_LOC, 0, NULL, // address of class string 0, KEY_READ | KEY_WRITE, NULL, &hDataKey, &dwCreate)) goto Ret; if (ERROR_SUCCESS != RegSetValueExU( hDataKey, REG_USER_INTERNAL_MAC_KEY, 0, REG_BINARY, rgbTmp, sizeof(rgbTmp) )) goto Ret; fRet = TRUE; Ret: if (hBaseKey) RegCloseKey(hBaseKey); if (hDataKey) RegCloseKey(hDataKey); return fRet; } // end global MAC Key storage /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// BOOL DeleteAllUserData( HKEY hKey ) { BOOL fRestorePrivs = FALSE; BOOL fRet = FALSE; // // enable backup and restore privs on NT to circumvent any security // settings. // if(FIsWinNT()) { SetCurrentPrivilege(L"SeRestorePrivilege", TRUE); SetCurrentPrivilege(L"SeBackupPrivilege", TRUE); fRestorePrivs = TRUE; } fRet = DeleteUserData( hKey ); if(fRestorePrivs) { SetCurrentPrivilege(L"SeRestorePrivilege", FALSE); SetCurrentPrivilege(L"SeBackupPrivilege", FALSE); } return fRet; } BOOL DeleteUserData( HKEY hKey ) { LONG rc; WCHAR szSubKey[MAX_PATH]; DWORD cchSubKeyLength; DWORD dwSubKeyMaxIndex; DWORD dwDisposition; cchSubKeyLength = sizeof(szSubKey) / sizeof(WCHAR); // First, get the number of subkeys, so we can decrement the index, // and avoid and re-indexing of the subkeys if (ERROR_SUCCESS != RegQueryInfoKeyA(hKey, NULL, NULL, NULL, &dwSubKeyMaxIndex, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { return FALSE; } if (dwSubKeyMaxIndex) dwSubKeyMaxIndex--; // 0 based index, so index = #keys -1 while((rc=RegEnumKeyExU( hKey, dwSubKeyMaxIndex, szSubKey, &cchSubKeyLength, NULL, NULL, NULL, NULL) ) != ERROR_NO_MORE_ITEMS) { // are we done? if(rc == ERROR_SUCCESS) { HKEY hSubKey; LONG lRet; lRet = RegCreateKeyExU( hKey, szSubKey, 0, NULL, REG_OPTION_BACKUP_RESTORE, // in winnt.h DELETE | KEY_ENUMERATE_SUB_KEYS, NULL, &hSubKey, &dwDisposition ); if(lRet != ERROR_SUCCESS) return FALSE; // // recurse // DeleteUserData(hSubKey); RegDeleteKeyU(hKey, szSubKey); RegCloseKey(hSubKey); // increment index into the key dwSubKeyMaxIndex--; // reset buffer size cchSubKeyLength = sizeof(szSubKey) / sizeof(WCHAR); // Continue the festivities continue; } else { // // note: we need to watch for ERROR_MORE_DATA // this indicates we need a bigger szSubKey buffer // return FALSE; } } return TRUE; }