//+--------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1993 - 1997. // // File: virtreg.cpp // // Contents: Implements the class CVirtualRegistry which manages a // virtual registry // // Classes: // // Methods: CVirtualRegistry::CVirtualRegistry // CVirtualRegistry::~CVirtualRegistry // CVirtualRegistry::ReadRegSzNamedValue // CVirtualRegistry::NewRegSzNamedValue // CVirtualRegistry::ChgRegSzNamedValue // CVirtualRegistry::ReadRegDwordNamedValue // CVirtualRegistry::NewRegDwordNamedValue // CVirtualRegistry::ChgRegDwordNamedValue // CVirtualRegistry::NewRegSingleACL // CVirtualRegistry::ChgRegACL // CVirtualRegistry::NewRegKeyACL // CVirtualRegistry::ReadLsaPassword // CVirtualRegistry::NewLsaPassword // CVirtualRegistry::ChgLsaPassword // CVirtualRegistry::ReadSrvIdentity // CVirtualRegistry::NewSrvIdentity // CVirtualRegistry::ChgSrvIdentity // CVirtualRegistry::MarkForDeletion // CVirtualRegistry::GetAt // CVirtualRegistry::Remove // CVirtualRegistry::Cancel // CVirtualRegistry::Apply // CVirtualRegistry::ApplyAll // CVirtualRegistry::Ok // CVirtualRegistry::SearchForRegEntry // CVirtualRegistry::SearchForLsaEntry // CVirtualRegistry::SearchForSrvEntry // // History: 23-Apr-96 BruceMa Created. // 15-Dec-96 RonanS Tidied up to remove memory leaks // Use array of pointers to avoid bitwise copy // //---------------------------------------------------------------------- #include "stdafx.h" #include "afxtempl.h" #include "assert.h" #if !defined(STANDALONE_BUILD) extern "C" { #include "ntlsa.h" } #endif #include "winsvc.h" #include "types.h" #include "datapkt.h" #if !defined(STANDALONE_BUILD) extern "C" { #include } #endif #include "util.h" #include "virtreg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif CVirtualRegistry::CVirtualRegistry(void) { m_pkts.SetSize(0, 8); } CVirtualRegistry::~CVirtualRegistry(void) { // ronans - remove any remaining items RemoveAll(); } // Read a named string value from the registry and cache it int CVirtualRegistry::ReadRegSzNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, int *pIndex) { int err; HKEY hKey; ULONG lSize; DWORD dwType; TCHAR szVal[MAX_PATH]; // Check if we already have an entry for this *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { CDataPacket * pCdp = GetAt(*pIndex); ASSERT(pCdp); // should always be non null if (pCdp->IsDeleted()) { *pIndex = -1; return ERROR_FILE_NOT_FOUND; } else return ERROR_SUCCESS; } // Open the referenced key if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey)) != ERROR_SUCCESS) { g_util.CkForAccessDenied(err); return err; } // Attempt to read the named value lSize = MAX_PATH * sizeof(TCHAR); if ((err = RegQueryValueEx(hKey, szValueName, NULL, &dwType, (BYTE *) szVal, &lSize)) != ERROR_SUCCESS) { g_util.CkForAccessDenied(err); if (hKey != hRoot) RegCloseKey(hKey); return err; } // Build a data packet if (dwType == REG_SZ) { CDataPacket * pNewPacket = new CRegSzNamedValueDp(hRoot, szKeyPath, szValueName, szVal); ASSERT(pNewPacket); if (!pNewPacket) { return ERROR_NOT_ENOUGH_MEMORY; } *pIndex = (int)m_pkts.Add(pNewPacket); pNewPacket->SetModified( FALSE); return ERROR_SUCCESS; } else return ERROR_BAD_TOKEN_TYPE; } // Read a named string value from the registry and cache it int CVirtualRegistry::ReadRegMultiSzNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, int *pIndex) { int err = ERROR_SUCCESS; HKEY hKey; // Check if we already have an entry for this *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { CDataPacket * pCdp = GetAt(*pIndex); ASSERT(pCdp); // should always be non null if (pCdp->IsDeleted()) { *pIndex = -1; return ERROR_FILE_NOT_FOUND; } else return err; } // Open the referenced key if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey)) == ERROR_SUCCESS) { // Build a data packet CRegMultiSzNamedValueDp * pNewPacket = new CRegMultiSzNamedValueDp(hRoot, szKeyPath, szValueName); ASSERT(pNewPacket); if (pNewPacket) { // read the key if ((err = pNewPacket -> Read(hKey)) == ERROR_SUCCESS) { *pIndex = (int)m_pkts.Add(pNewPacket); pNewPacket->SetModified( FALSE); } else { g_util.CkForAccessDenied(err); delete pNewPacket; if (hKey != hRoot) RegCloseKey(hKey); } } else err = ERROR_NOT_ENOUGH_MEMORY; if (err != ERROR_SUCCESS) g_util.CkForAccessDenied(err); } return err; } int CVirtualRegistry::NewRegSzNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, TCHAR *szVal, int *pIndex) { // It may be in the virtual registry but marked for deletion *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { CRegSzNamedValueDp * pCdp = (CRegSzNamedValueDp *)GetAt(*pIndex); pCdp->MarkForDeletion(FALSE); pCdp->ChgSzValue(szVal); return ERROR_SUCCESS; } // Build a data packet and add it CRegSzNamedValueDp * pNewPacket = new CRegSzNamedValueDp (hRoot, szKeyPath, szValueName, szVal); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } int CVirtualRegistry::NewRegMultiSzNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, int *pIndex) { // It may be in the virtual registry but marked for deletion *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { CRegMultiSzNamedValueDp * pCdp = (CRegMultiSzNamedValueDp *)GetAt(*pIndex); pCdp->MarkForDeletion(FALSE); pCdp->Clear(); pCdp -> SetModified(TRUE); return ERROR_SUCCESS; } // Build a data packet and add it CRegMultiSzNamedValueDp * pNewPacket = new CRegMultiSzNamedValueDp (hRoot, szKeyPath, szValueName); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; pNewPacket -> SetModified(TRUE); *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } void CVirtualRegistry::ChgRegSzNamedValue(int nIndex, TCHAR *szVal) { CRegSzNamedValueDp* pCdp = (CRegSzNamedValueDp*)m_pkts.ElementAt(nIndex); pCdp->ChgSzValue(szVal); } // Read a named DWORD value from the registry int CVirtualRegistry::ReadRegDwordNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, int *pIndex) { int err; HKEY hKey; ULONG lSize; DWORD dwType; DWORD dwVal; // Check if we already have an entry for this *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { return ERROR_SUCCESS; } // Open the referenced key if ((err = RegOpenKeyEx(hRoot, szKeyPath, 0, KEY_ALL_ACCESS, &hKey)) != ERROR_SUCCESS) { g_util.CkForAccessDenied(err); return err; } // Attempt to read the named value lSize = sizeof(DWORD); if ((err = RegQueryValueEx(hKey, szValueName, NULL, &dwType, (BYTE *) &dwVal, &lSize)) != ERROR_SUCCESS) { g_util.CkForAccessDenied(err); if (hKey != hRoot) { RegCloseKey(hKey); } return err; } // Close the registry key if (hKey != hRoot) { RegCloseKey(hKey); } // Build a data packet if (dwType == REG_DWORD) { CDataPacket * pNewPacket = new CDataPacket(hRoot, szKeyPath, szValueName, dwVal); ASSERT(pNewPacket); if (!pNewPacket) { return ERROR_NOT_ENOUGH_MEMORY; } *pIndex = (int)m_pkts.Add(pNewPacket); pNewPacket-> SetModified(FALSE); return ERROR_SUCCESS; } else { return ERROR_BAD_TOKEN_TYPE; } } int CVirtualRegistry::NewRegDwordNamedValue(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, DWORD dwVal, int *pIndex) { // It may be in the virtual registry but marked for deletion *pIndex = SearchForRegEntry(hRoot, szKeyPath, szValueName); if (*pIndex >= 0) { CDataPacket * pCdp = GetAt(*pIndex); pCdp->MarkForDeletion(FALSE); pCdp->pkt.nvdw.dwValue = dwVal; pCdp->SetModified(TRUE); return ERROR_SUCCESS; } // Build a data packet and add it CDataPacket * pNewPacket = new CDataPacket(hRoot, szKeyPath, szValueName, dwVal); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); pNewPacket->SetModified(TRUE); return ERROR_SUCCESS; } void CVirtualRegistry::ChgRegDwordNamedValue(int nIndex, DWORD dwVal) { CDataPacket * pCdp = m_pkts.ElementAt(nIndex); pCdp->pkt.nvdw.dwValue = dwVal; pCdp->SetModified( TRUE); } int CVirtualRegistry::NewRegSingleACL(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, SECURITY_DESCRIPTOR *pacl, BOOL fSelfRelative, int *pIndex) { // Build a data packet and add it CDataPacket * pNewPacket = new CDataPacket(hRoot, szKeyPath, szValueName, pacl, fSelfRelative); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } void CVirtualRegistry::ChgRegACL(int nIndex, SECURITY_DESCRIPTOR *pacl, BOOL fSelfRelative) { CDataPacket * pCdp = m_pkts.ElementAt(nIndex); pCdp->ChgACL(pacl, fSelfRelative); pCdp->SetModified(TRUE); } int CVirtualRegistry::NewRegKeyACL(HKEY hKey, HKEY *phClsids, unsigned cClsids, TCHAR *szTitle, SECURITY_DESCRIPTOR *paclOrig, SECURITY_DESCRIPTOR *pacl, BOOL fSelfRelative, int *pIndex) { // Build a data packet and add it CDataPacket * pNewPacket = new CDataPacket(hKey, phClsids, cClsids, szTitle, paclOrig, pacl, fSelfRelative); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } int CVirtualRegistry::ReadLsaPassword(CLSID &clsid, int *pIndex) { #if !defined(STANDALONE_BUILD) LSA_OBJECT_ATTRIBUTES sObjAttributes; HANDLE hPolicy = NULL; LSA_UNICODE_STRING sKey; TCHAR szKey[GUIDSTR_MAX + 5]; PLSA_UNICODE_STRING psPassword; // Check if we already have an entry fo this *pIndex = SearchForLsaEntry(clsid); if (*pIndex >= 0) { return ERROR_SUCCESS; } // Formulate the access key lstrcpyW(szKey, L"SCM:"); g_util.StringFromGUID(clsid, &szKey[4], GUIDSTR_MAX); szKey[GUIDSTR_MAX + 4] = L'\0'; // UNICODE_STRING length fields are in bytes and include the NULL // terminator sKey.Length = (USHORT)((lstrlenW(szKey) + 1) * sizeof(WCHAR)); sKey.MaximumLength = (GUIDSTR_MAX + 5) * sizeof(WCHAR); sKey.Buffer = szKey; // Open the local security policy InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL); if (!NT_SUCCESS(LsaOpenPolicy(NULL, &sObjAttributes, POLICY_GET_PRIVATE_INFORMATION, &hPolicy))) { return GetLastError(); } // Read the user's password if (!NT_SUCCESS(LsaRetrievePrivateData(hPolicy, &sKey, &psPassword))) { LsaClose(hPolicy); return GetLastError(); } // Close the policy handle, we're done with it now. LsaClose(hPolicy); // Build a data packet CDataPacket * pNewPacket = new CDataPacket(psPassword->Buffer, clsid); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; pNewPacket->SetModified( FALSE ); *pIndex = (int)m_pkts.Add(pNewPacket); #endif return ERROR_SUCCESS; } int CVirtualRegistry::NewLsaPassword(CLSID &clsid, TCHAR *szPassword, int *pIndex) { // Build a data packet and add it CDataPacket * pNewPacket = new CDataPacket(szPassword, clsid); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } void CVirtualRegistry::ChgLsaPassword(int nIndex, TCHAR *szPassword) { CDataPacket * pCdp = m_pkts.ElementAt(nIndex); pCdp -> ChgPassword(szPassword); pCdp -> SetModified(TRUE); } int CVirtualRegistry::ReadSrvIdentity(TCHAR *szService, int *pIndex) { SC_HANDLE hSCManager; SC_HANDLE hService; QUERY_SERVICE_CONFIG sServiceQueryConfig; DWORD dwSize; // Check if we already have an entry fo this *pIndex = SearchForSrvEntry(szService); if (*pIndex >= 0) { return ERROR_SUCCESS; } // Open the service control manager if (hSCManager = OpenSCManager(NULL, NULL, GENERIC_READ)) { // Open a handle to the requested service if (hService = OpenService(hSCManager, szService, GENERIC_READ)) { // Close the service manager's database CloseServiceHandle(hSCManager); // Query the service if (QueryServiceConfig(hService, &sServiceQueryConfig, sizeof(QUERY_SERVICE_CONFIG), &dwSize)) { // Build a data packet CDataPacket * pNewPacket = new CDataPacket(szService, sServiceQueryConfig.lpServiceStartName); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; pNewPacket->SetModified(FALSE); *pIndex = (int)m_pkts.Add(pNewPacket); // Return success CloseServiceHandle(hSCManager); CloseServiceHandle(hService); return ERROR_SUCCESS; } } CloseServiceHandle(hSCManager); } return GetLastError(); } int CVirtualRegistry::NewSrvIdentity(TCHAR *szService, TCHAR *szIdentity, int *pIndex) { // Build a data packet and add it CDataPacket * pNewPacket = new CDataPacket(szService, szIdentity); ASSERT(pNewPacket); if (!pNewPacket) return ERROR_NOT_ENOUGH_MEMORY; *pIndex = (int)m_pkts.Add(pNewPacket); return ERROR_SUCCESS; } void CVirtualRegistry::ChgSrvIdentity(int nIndex, TCHAR *szIdentity) { CDataPacket *pCdp = m_pkts.ElementAt(nIndex); pCdp -> ChgSrvIdentity(szIdentity); pCdp -> SetModified( TRUE); } void CVirtualRegistry::MarkForDeletion(int nIndex) { CDataPacket * pCdp = GetAt(nIndex); pCdp->MarkForDeletion(TRUE); pCdp->SetModified(TRUE); } void CVirtualRegistry::MarkHiveForDeletion(int nIndex) { CDataPacket * pCdp = GetAt(nIndex); pCdp->MarkHiveForDeletion(TRUE); pCdp->SetModified(TRUE); } CDataPacket * CVirtualRegistry::GetAt(int nIndex) { return m_pkts.ElementAt(nIndex); } void CVirtualRegistry::Remove(int nIndex) { CDataPacket * pCdp = GetAt(nIndex); // ronans - must always destroy even if packet has not been marked dirty if (pCdp) delete pCdp; // overwrite with empty data packet m_pkts.SetAt(nIndex, new CDataPacket); } void CVirtualRegistry::RemoveAll(void) { int nSize = (int)m_pkts.GetSize(); for (int k = 0; k < nSize; k++) { Remove(k); CDataPacket * pCdp = GetAt(k); // remove empty packet if (pCdp) delete pCdp; } m_pkts.RemoveAll(); } void CVirtualRegistry::Cancel(int nIndex) { int nSize = (int)m_pkts.GetSize(); for (int k = nIndex; k < nSize; k++) { m_pkts.SetAt(nIndex, new CDataPacket); } } int CVirtualRegistry::Apply(int nIndex) { int err = ERROR_SUCCESS; int nSize = (int)m_pkts.GetSize(); CDataPacket *pCdp = m_pkts.ElementAt(nIndex); if (pCdp->IsModified()) err = pCdp -> Apply(); return err;; } int CVirtualRegistry::ApplyAll(void) { int nSize = (int)m_pkts.GetSize(); // Persist all non-empty data packets for (int k = 0; k < nSize; k++) { Apply(k); } return ERROR_SUCCESS; } int CVirtualRegistry::Ok(int nIndex) { return 0; } int CVirtualRegistry::SearchForRegEntry(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName) { int nSize = (int)m_pkts.GetSize(); for (int k = 0; k < nSize; k++) { CDataPacket * pCdp = GetAt(k); if (pCdp -> IsIdentifiedBy(hRoot, szKeyPath, szValueName)) return k; } return -1; } int CVirtualRegistry::SearchForLsaEntry(CLSID appid) { int nSize = (int)m_pkts.GetSize(); for (int k = 0; k < nSize; k++) { CDataPacket * pCdp = GetAt(k); if (pCdp->m_tagType == Password && g_util.IsEqualGuid(pCdp->pkt.pw.appid, appid)) { return k; } } return -1; } int CVirtualRegistry::SearchForSrvEntry(TCHAR *szServiceName) { int nSize = (int)m_pkts.GetSize(); for (int k = 0; k < nSize; k++) { CDataPacket * pCdp = GetAt(k); if (pCdp->m_tagType == ServiceIdentity && (_tcscmp(pCdp->pkt.si.szServiceName, szServiceName))) { return k; } } return -1; }