windows-nt/Source/XPSP1/NT/com/ole32/oleui/datapkt.cpp
2020-09-26 16:20:57 +08:00

812 lines
20 KiB
C++

//+---------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1997.
//
// File: datapkt.cpp
//
// Contents: Implements the class CDataPacket to manages diverse data
// packets needing to be written to various databases
//
// Classes:
//
// Methods: CDataPacket::CDataPacket (x 7)
// CDataPacket::~CDataPacket
// CDataPacket::ChgSzValue
// CDataPacket::ChgDwordValue
// CDataPacket::ChgACL
// CDataPacket::ChgPassword
// CDataPacket::ChgSrvIdentity
//
// History: 23-Apr-96 BruceMa Created.
// 12-Dec-96 RonanS Added copy constructor to CDataPacket
// to get around bugs when copying CDataPacket.
// Fixed memory leaks in destructor.
// Simplified constructor code.
// 09-Jan-97 SteveBl Modified to support IAccessControl.
//
//----------------------------------------------------------------------
#include "stdafx.h"
#include "assert.h"
#include "datapkt.h"
#if !defined(STANDALONE_BUILD)
extern "C"
{
#include <getuser.h>
}
#endif
#include "util.h"
static TCHAR * TStrDup(const TCHAR *lpszString)
{
TCHAR * lpszTmp = NULL;
int nStrlen = 0;
if (lpszString )
{
lpszTmp = new TCHAR[_tcslen(lpszString) + 1];
ASSERT(lpszTmp);
_tcscpy(lpszTmp, lpszString);
}
return lpszTmp;
}
CDataPacket::CDataPacket(void)
{
m_tagType = Empty;
m_fDelete = FALSE;
m_fDeleteHive = FALSE;
m_hRoot = 0;
SetModified(TRUE);
}
CDataPacket::CDataPacket(HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
DWORD dwValue)
:m_szKeyPath(szKeyPath), m_szValueName(szValueName)
{
m_tagType = NamedValueDword;
m_hRoot = hRoot;
pkt.nvdw.dwValue = dwValue;
SetModified(TRUE);
m_fDelete = FALSE;
m_fDeleteHive = FALSE;
}
CDataPacket::CDataPacket(HKEY hRoot,
TCHAR *szKeyPath,
TCHAR *szValueName,
SECURITY_DESCRIPTOR *pSec,
BOOL fSelfRelative)
:m_szKeyPath(szKeyPath), m_szValueName(szValueName)
{
int err;
ULONG cbLen;
SECURITY_DESCRIPTOR *pSD;
m_tagType = SingleACL;
m_hRoot = hRoot;
// Get the security descriptor into self relative form so we
// can cache it
// Force first call to fail so we can get the real size needed
if (!fSelfRelative)
{
cbLen = 1;
if (!MakeSelfRelativeSD(pSec, NULL, &cbLen))
{
err = GetLastError();
}
// Now really do it
pSD = (SECURITY_DESCRIPTOR *) GlobalAlloc(GMEM_FIXED, cbLen);
if (!pSD)
{
ReportOutOfMemAndTerminate();
// will never get here
return;
}
if (!MakeSelfRelativeSD(pSec, pSD, &cbLen))
{
err = GetLastError();
}
pkt.acl.pSec = pSD;
}
else
{
// The security descriptor is aready in self relative form
// as it was read directly from the registry. However, we still
// have to copy the it.
g_util.CopySD(pSec, &pkt.acl.pSec);
}
SetModified(TRUE);
m_fDelete = FALSE;
m_fDeleteHive = FALSE;
}
CDataPacket::CDataPacket(HKEY hKey,
HKEY *phClsids,
unsigned cClsids,
TCHAR *szTitle,
SECURITY_DESCRIPTOR *pSecOrig,
SECURITY_DESCRIPTOR *pSec,
BOOL fSelfRelative)
{
ULONG cbLen;
SECURITY_DESCRIPTOR *pSD;
m_tagType = RegKeyACL;
m_hRoot = hKey;
pkt.racl.phClsids = phClsids;
pkt.racl.cClsids = cClsids;
pkt.racl.szTitle = TStrDup(szTitle);
// Get the new security descriptor into self relative form so we
// can cache it (if we have to)
if (!fSelfRelative)
{
// Force first call to fail so we can get the real size needed
cbLen = 1;
MakeSelfRelativeSD(pSec, NULL, &cbLen);
// Now really do it
pSD = (SECURITY_DESCRIPTOR *) GlobalAlloc(GMEM_FIXED, cbLen);
if (!pSD)
{
ReportOutOfMemAndTerminate();
// will never get here
return;
}
MakeSelfRelativeSD(pSec, pSD, &cbLen);
pkt.racl.pSec = pSD;
}
else
{
g_util.CopySD(pSec, &pkt.racl.pSec);
}
// The original security descriptor is aready in self relative form
// as it was read directly from the registry. (The edited SD from the
// ACL editor is in absolute form.) However, we still have to copy the
// original SD.
g_util.CopySD(pSecOrig, &pkt.racl.pSecOrig);
SetModified(TRUE);
m_fDelete = FALSE;
m_fDeleteHive = FALSE;
}
CDataPacket::CDataPacket(TCHAR *szPassword,
CLSID appid)
{
m_tagType = Password;
pkt.pw.szPassword = TStrDup(szPassword);
pkt.pw.appid = appid;
SetModified(TRUE);
m_fDelete = FALSE;
m_hRoot = 0;
m_fDeleteHive = FALSE;
}
CDataPacket::CDataPacket(TCHAR *szServiceName,
TCHAR *szIdentity)
{
m_hRoot = 0;
m_tagType = ServiceIdentity;
pkt.si.szServiceName = TStrDup(szServiceName);
pkt.si.szIdentity = TStrDup(szIdentity);
SetModified(TRUE);
m_fDelete = FALSE;
m_fDeleteHive = FALSE;
}
CRegSzNamedValueDp::CRegSzNamedValueDp(const CRegSzNamedValueDp& rDataPacket)
: CDataPacket((const CDataPacket & ) rDataPacket)
{
m_szValue = rDataPacket.m_szValue;
}
CDataPacket::CDataPacket( const CDataPacket & rDataPacket)
:m_szKeyPath (rDataPacket.m_szKeyPath), m_szValueName(rDataPacket.m_szValueName)
{
m_tagType = rDataPacket.m_tagType;
m_fModified = rDataPacket.m_fModified;
m_fDelete = rDataPacket.m_fDelete;
m_hRoot = rDataPacket.m_hRoot;
switch (m_tagType)
{
case NamedValueSz:
// handled by derived class
break;
case NamedValueDword:
pkt.nvdw.dwValue = rDataPacket.pkt.nvdw.dwValue;
break;
case SingleACL:
// Get the security descriptor into self relative form so we
g_util.CopySD(rDataPacket.pkt.acl.pSec, &pkt.acl.pSec);
break;
case RegKeyACL:
pkt.racl.phClsids = rDataPacket.pkt.racl.phClsids;
pkt.racl.cClsids = rDataPacket.pkt.racl.cClsids;
pkt.racl.szTitle = TStrDup(rDataPacket.pkt.racl.szTitle);
g_util.CopySD(rDataPacket.pkt.racl.pSec, &pkt.racl.pSec);
g_util.CopySD(rDataPacket.pkt.racl.pSecOrig, &pkt.racl.pSecOrig);
break;
case Password:
pkt.pw.szPassword = TStrDup(rDataPacket.pkt.pw.szPassword);
pkt.pw.appid = rDataPacket.pkt.pw.appid;
break;
case ServiceIdentity:
pkt.si.szServiceName = TStrDup(rDataPacket.pkt.si.szServiceName);
pkt.si.szIdentity = TStrDup(rDataPacket.pkt.si.szIdentity);
break;
case Empty:
break;
}
}
CDataPacket::~CDataPacket()
{
switch (m_tagType)
{
case NamedValueSz:
// handled by derived class
break;
case NamedValueDword:
break;
case SingleACL:
if (pkt.acl.pSec)
GlobalFree(pkt.acl.pSec);
break;
case RegKeyACL:
if (pkt.racl.szTitle)
delete pkt.racl.szTitle;
if (pkt.racl.pSec)
GlobalFree(pkt.racl.pSec);
if (pkt.racl.pSecOrig)
GlobalFree(pkt.racl.pSecOrig);
break;
case Password:
if (pkt.pw.szPassword)
delete pkt.pw.szPassword;
break;
case ServiceIdentity:
if (pkt.si.szServiceName)
delete pkt.si.szServiceName;
if (pkt.si.szIdentity)
delete pkt.si.szIdentity;
break;
}
}
void CRegSzNamedValueDp::ChgSzValue(TCHAR *szValue)
{
assert(m_tagType == NamedValueSz);
m_szValue = szValue;
SetModified(TRUE);
}
void CDataPacket::ChgDwordValue(DWORD dwValue)
{
assert(m_tagType == NamedValueDword);
pkt.nvdw.dwValue = dwValue;
SetModified(TRUE);
}
void CDataPacket::ChgACL(SECURITY_DESCRIPTOR *pSec, BOOL fSelfRelative)
{
ULONG cbLen;
SECURITY_DESCRIPTOR *pSD;
assert(m_tagType == SingleACL || m_tagType == RegKeyACL);
// Remove the previous security descriptor
if (m_tagType == SingleACL)
{
GlobalFree(pkt.acl.pSec);
pkt.acl.pSec = NULL;
}
else
{
GlobalFree(pkt.racl.pSec);
pkt.racl.pSec = NULL;
}
// Put into self relative form (if necessary)
if (!fSelfRelative)
{
cbLen = 1;
MakeSelfRelativeSD(pSec, NULL, &cbLen);
// Now really do it
pSD = (SECURITY_DESCRIPTOR *) GlobalAlloc(GMEM_FIXED, cbLen);
if (!pSD)
{
ReportOutOfMemAndTerminate();
// will never get here
return;
}
MakeSelfRelativeSD(pSec, pSD, &cbLen);
// Store it
if (m_tagType == SingleACL)
{
pkt.acl.pSec = pSD;
}
else
{
pkt.racl.pSec = pSD;
}
}
else
{
if (m_tagType == SingleACL)
{
g_util.CopySD(pSec, &pkt.acl.pSec);
}
else
{
g_util.CopySD(pSec, &pkt.racl.pSec);
}
}
SetModified(TRUE);
}
void CDataPacket::ChgPassword(TCHAR *szPassword)
{
if (m_tagType != Password)
return;
if (pkt.pw.szPassword)
delete pkt.pw.szPassword;
pkt.pw.szPassword = TStrDup(szPassword);
SetModified(TRUE);
}
void CDataPacket::ChgSrvIdentity(TCHAR *szIdentity)
{
assert(m_tagType == ServiceIdentity);
if (pkt.si.szIdentity)
delete pkt.si.szIdentity;
pkt.si.szIdentity = TStrDup(szIdentity);
SetModified(TRUE);
}
void CDataPacket::MarkForDeletion(BOOL bDelete)
{
m_fDelete = bDelete;
SetModified(TRUE);
}
void CDataPacket::MarkHiveForDeletion(BOOL bDelete)
{
m_fDelete = bDelete;
m_fDeleteHive = bDelete;
SetModified(TRUE);
}
int CDataPacket::Apply()
{
int err = ERROR_SUCCESS;
if (m_fModified)
{
if (m_fDelete)
err = Remove();
else
err = Update();
}
// Cleanup work
if (err == ERROR_SUCCESS)
{
m_fModified = FALSE;
}
else
{
if (err == ERROR_ACCESS_DENIED)
{
g_util.CkForAccessDenied(ERROR_ACCESS_DENIED);
}
else
{
g_util.PostErrorMessage();
}
}
return err;
}
int CDataPacket::Update()
{
int err = ERROR_SUCCESS;
ASSERT(m_fModified);
switch (m_tagType)
{
case Empty:
break;
case NamedValueSz:
ASSERT(FALSE); // we should never reach here
break;
case NamedValueDword:
{
err = g_util.WriteRegDwordNamedValue(m_hRoot,
(LPCTSTR)m_szKeyPath,
(LPCTSTR)m_szValueName,
pkt.nvdw.dwValue);
}
break;
case SingleACL:
{
err = g_util.WriteRegSingleACL(m_hRoot,
(LPCTSTR)m_szKeyPath,
(LPCTSTR)m_szValueName,
pkt.acl.pSec);
}
break;
case RegKeyACL:
err = g_util.WriteRegKeyACL(m_hRoot,
pkt.racl.phClsids,
pkt.racl.cClsids,
pkt.racl.pSec,
pkt.racl.pSecOrig);
break;
case Password:
err = g_util.WriteLsaPassword(pkt.pw.appid,
pkt.pw.szPassword);
break;
case ServiceIdentity:
err = g_util.WriteSrvIdentity(pkt.si.szServiceName,
pkt.si.szIdentity);
break;
}
return err;
}
long CDataPacket::Read(HKEY hKey)
{
return 0;
}
int CDataPacket::Remove()
{
int err = ERROR_SUCCESS;
if (m_fModified && m_fDelete)
{
switch (m_tagType)
{
case Empty:
break;
case SingleACL:
case NamedValueDword:
case NamedValueSz:
case NamedValueMultiSz:
if (m_fDeleteHive)
g_util.DeleteRegKey(m_hRoot,(LPCTSTR)m_szKeyPath);
else
g_util.DeleteRegValue(m_hRoot,
(LPCTSTR)m_szKeyPath,
(LPCTSTR)m_szValueName);
break;
case RegKeyACL:
err = g_util.WriteRegKeyACL(m_hRoot,
pkt.racl.phClsids,
pkt.racl.cClsids,
pkt.racl.pSec,
pkt.racl.pSecOrig);
break;
case Password:
err = g_util.WriteLsaPassword(pkt.pw.appid,
pkt.pw.szPassword);
break;
case ServiceIdentity:
err = g_util.WriteSrvIdentity(pkt.si.szServiceName,
pkt.si.szIdentity);
break;
}
}
return err;
}
//
// ReportOutOfMemAndTerminate
//
// Dcomcnfg was not coded very well to handle out-of-memory
// errors in certain spots. Rather than rip out and replace
// lots of code to fix this properly, I am simply going to report
// an error and terminate the process when this occurs. Dcomnfg
// as of now only ships in the reskit, not in the os.
//
void CDataPacket::ReportOutOfMemAndTerminate()
{
CString sTitle;
CString sMessage;
if (sTitle.LoadString(IDS_FATALOUTOFMEMORYTITLE))
{
if (sMessage.LoadString(IDS_FATALOUTOFMEMORY))
{
MessageBoxW(NULL, sMessage, sTitle, MB_ICONWARNING | MB_OK | MB_TASKMODAL);
}
}
TerminateProcess(GetCurrentProcess(), ERROR_NOT_ENOUGH_MEMORY);
// will never get here
return;
}
//*****************************************************************************
//
// class CRegSzNamedValueDp
//
// data packet for RegSZ named value
//
//*****************************************************************************
int CRegSzNamedValueDp::Update()
{
int err = ERROR_SUCCESS;
ASSERT(m_tagType == NamedValueSz);
ASSERT(m_fModified);
err = g_util.WriteRegSzNamedValue(m_hRoot,
(LPCTSTR)m_szKeyPath,
(LPCTSTR)m_szValueName,
(LPCTSTR)m_szValue,
m_szValue.GetLength() + 1);
return err;
}
long CRegSzNamedValueDp::Read(HKEY hkey)
{
return 0;
}
CString CRegSzNamedValueDp::Value()
{
return m_szValue;
}
CRegSzNamedValueDp::CRegSzNamedValueDp(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName, TCHAR *szValue)
: m_szValue(szValue)
{
m_tagType = NamedValueSz;
m_hRoot = hRoot;
m_szKeyPath = szKeyPath;
m_szValueName = szValueName;
}
BOOL CDataPacket::IsIdentifiedBy(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName)
{
if (((m_tagType == NamedValueSz) &&
(m_hRoot == hRoot) &&
(m_szKeyPath == szKeyPath) &&
(m_szValueName == szValueName)) ||
((m_tagType == NamedValueDword) &&
(m_hRoot == hRoot) &&
(m_szKeyPath == szKeyPath) &&
(m_szValueName == szValueName) ))
return TRUE;
return FALSE;
}
BOOL CRegSzNamedValueDp::IsIdentifiedBy(HKEY hRoot, TCHAR * szKeyPath, TCHAR * szValueName)
{
if (((m_tagType == NamedValueSz) &&
(m_hRoot == hRoot) &&
(m_szKeyPath == szKeyPath) &&
(m_szValueName == szValueName)))
return TRUE;
return FALSE;
}
//////////////////////////////////////////////////////////////////////
// CRegMultiSzNamedValueDp Class
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CRegMultiSzNamedValueDp::CRegMultiSzNamedValueDp(HKEY hRoot, TCHAR *szKeyPath, TCHAR *szValueName)
{
m_tagType = NamedValueMultiSz;
m_hRoot = hRoot;
m_szKeyPath = szKeyPath;
m_szValueName = szValueName;
}
CRegMultiSzNamedValueDp::~CRegMultiSzNamedValueDp()
{
}
BOOL CRegMultiSzNamedValueDp::IsIdentifiedBy(HKEY hRoot, TCHAR * szKeyPath, TCHAR * szValueName)
{
if (((m_tagType == NamedValueMultiSz) &&
(m_hRoot == hRoot) &&
(m_szKeyPath == szKeyPath) &&
(m_szValueName == szValueName)))
return TRUE;
return FALSE;
}
int CRegMultiSzNamedValueDp::Update()
{
int err = ERROR_SUCCESS;
ASSERT(m_tagType == NamedValueMultiSz);
ASSERT(m_fModified);
// build up string to save
// calculate size of string
int nSize=0, nIndex = 0;
for (nIndex = 0; nIndex < m_strValues.GetSize(); nIndex ++)
{
CString sTmp = m_strValues.GetAt(nIndex);
nSize += sTmp.GetLength()+1;
}
nSize += 2;
// build up string to save
TCHAR* lpszTmp = new TCHAR[nSize];
if (lpszTmp)
{
int nOffset = 0;
for (nIndex = 0; nIndex < m_strValues.GetSize(); nIndex ++)
{
CString sTmp = m_strValues.GetAt(nIndex);
_tcscpy((TCHAR*)(&lpszTmp[nOffset]), (LPCTSTR) sTmp);
nOffset += sTmp.GetLength()+1;
}
// finish with two nulls
lpszTmp[nOffset++] = TEXT('\0');
lpszTmp[nOffset++] = TEXT('\0');
err = g_util.WriteRegMultiSzNamedValue(m_hRoot,
(LPCTSTR)m_szKeyPath,
(LPCTSTR)m_szValueName,
lpszTmp,
nOffset);
delete lpszTmp;
}
return err;
}
void CRegMultiSzNamedValueDp::Clear()
{
m_strValues.RemoveAll();
}
long CRegMultiSzNamedValueDp::Read(HKEY hKey)
{
ASSERT(hKey != NULL);
HKEY hkEndpoints = NULL;
DWORD dwType = REG_MULTI_SZ;
DWORD dwcbBuffer = 1024;
TCHAR* pszBuffer = new TCHAR[1024];
ASSERT(pszBuffer != NULL);
// try to read values into default sized buffer
LONG lErr = RegQueryValueEx(hKey,
(LPCTSTR)m_szValueName,
0,
&dwType,
(LPBYTE)pszBuffer,
&dwcbBuffer);
// if buffer is not big enough, extend it and reread
if (lErr == ERROR_MORE_DATA)
{
delete pszBuffer;
DWORD dwNewSize = (dwcbBuffer + 1 / sizeof(TCHAR));
pszBuffer = new TCHAR[dwNewSize];
if (pszBuffer)
dwcbBuffer = dwNewSize;
lErr = RegQueryValueEx(m_hRoot,
(LPCTSTR)m_szValueName,
0,
&dwType,
(LPBYTE)pszBuffer,
&dwcbBuffer);
}
if ((lErr == ERROR_SUCCESS) &&
(dwcbBuffer > 0) &&
(dwType == REG_MULTI_SZ))
{
// parse each string
TCHAR * lpszRegEntry = pszBuffer;
while(lpszRegEntry && *lpszRegEntry)
{
// caclulate length of entry
CString sTmp(lpszRegEntry);
int nLenEntry = sTmp.GetLength();
m_strValues.Add(sTmp);
lpszRegEntry += nLenEntry+1;
}
}
else if ((lErr != ERROR_SUCCESS) && (lErr != ERROR_FILE_NOT_FOUND))
g_util.PostErrorMessage();
delete pszBuffer;
SetModified(FALSE);
return lErr;
}