windows-nt/Source/XPSP1/NT/com/ole32/cs/backend/csuser.cxx
2020-09-26 16:20:57 +08:00

674 lines
16 KiB
C++

//
// Author: DebiM
// Date: September 1996
//
// File: csuser.cxx
//
// Maintains a list of class containers per User SID.
// Looks up this list for every IClassAccess call from OLE32/SCM.
//
//
//---------------------------------------------------------------------
#include "cstore.hxx"
//
// Link list pointer for Class Containers Seen
//
extern CLASSCONTAINER *gpContainerHead;
//
// Link list pointer for User Profiles Seen
//
extern USERPROFILE *gpUserHead;
// Initialzed in InitializeClassStore at startup
extern CRITICAL_SECTION ClassStoreBindList;
//-------------------------------------------------------------------------
//
// OpenUserRegKey
//
// Opens a key under a user's HKEY_CLASSES_ROOT registry key. On NT5
// HKCR is equivalent to HKEY_USERS\{sid string}\Software\Classes.
//
// A SID string is used to create
// the proper registry key name to open.
//
//-------------------------------------------------------------------------
DWORD
OpenUserRegKey(
IN PSID pSid,
IN WCHAR * pwszSubKey,
OUT HKEY * phKey
)
{
UNICODE_STRING UnicodeString;
WCHAR * pwszKey;
DWORD AllocSize;
NTSTATUS Status;
UnicodeString.Length = UnicodeString.MaximumLength = 0;
UnicodeString.Buffer = 0;
Status = RtlConvertSidToUnicodeString(
&UnicodeString,
pSid,
(BOOLEAN)TRUE // Allocate
);
//
// Don't return a raw NT status code. This is the only possible error
// condition presuming our sid is valid.
//
if ( Status != STATUS_SUCCESS )
return ERROR_OUTOFMEMORY;
//
// Your friendly reminder, unicode string length is in bytes and doesn't include
// null terminator, if any.
// Add byte for '\\' and end null.
//
AllocSize = UnicodeString.Length + ((1 + lstrlen(pwszSubKey) + 1) * sizeof(WCHAR));
pwszKey = (WCHAR *) alloca( AllocSize );
if ( pwszKey )
{
memcpy( pwszKey, UnicodeString.Buffer, UnicodeString.Length );
pwszKey[UnicodeString.Length / 2] = L'\\';
lstrcpyW( &pwszKey[(UnicodeString.Length / 2) + 1], pwszSubKey );
}
RtlFreeUnicodeString( &UnicodeString );
if ( ! pwszKey )
return ERROR_OUTOFMEMORY;
Status = RegOpenKeyEx(
HKEY_USERS,
pwszKey,
0,
KEY_READ,
phKey );
return Status;
}
//
// GetUserSid
// ----------
//
// Synopsis: return the user SID of the caller.
//
// Arguments: &PSID - Where to store the caller's PSID
//
// Returns: HRESULT - S_OK if successful
// E_FAIL otherwise
//
SID LocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
HRESULT GetUserSid(PSID *ppUserSid, UINT *pCallType)
{
BYTE achBuffer[100];
PTOKEN_USER pUser = (PTOKEN_USER) &achBuffer;
PSID pSid;
DWORD dwBytesRequired;
BOOL fAllocatedBuffer = FALSE;
HRESULT hr = S_OK;
HANDLE hUserToken = NULL;
BOOL fImpersonated = TRUE;
*pCallType = CS_CALL_USERPROCESS;
// Initialize
*ppUserSid = NULL;
// Get caller's token while impersonating
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY,
TRUE,
&hUserToken))
{
fImpersonated = FALSE;
if (ERROR_NO_TOKEN != GetLastError())
return HRESULT_FROM_WIN32(GetLastError());
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE | TOKEN_QUERY,
&hUserToken))
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
if (SUCCEEDED(hr))
{
if (!GetTokenInformation(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
sizeof(achBuffer), // TokenInformationLength
&dwBytesRequired // ReturnLength
))
{
//
// Need to handle the case of insufficient buffer size.
//
if (sizeof(achBuffer) >= dwBytesRequired)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
if (SUCCEEDED(hr))
{
//
// Allocate space for the user info
//
pUser = (PTOKEN_USER) CoTaskMemAlloc(dwBytesRequired);
if (pUser == NULL)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
fAllocatedBuffer = TRUE;
//
// Read in the UserInfo
//
if (!GetTokenInformation(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
dwBytesRequired, // TokenInformationLength
&dwBytesRequired // ReturnLength
))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
}
if (hUserToken)
{
CloseHandle( hUserToken );
hUserToken = NULL;
}
if (SUCCEEDED(hr))
{
//
// Distinguish between
// a) LOCAL_SYSTEM,
// b) Impersonated Call from a LOCAL_SYSTEM
// and c) In_proc call from a user process
//
// For case (c) make the SID null.
//
if (EqualSid(pUser->User.Sid, &LocalSystemSid))
{
*pCallType = CS_CALL_LOCALSYSTEM;
}
else
{
if (fImpersonated)
{
*pCallType = CS_CALL_IMPERSONATED;
}
else
{
*pCallType = CS_CALL_USERPROCESS;
}
}
// Alloc buffer for copy of SID
dwBytesRequired = GetLengthSid(pUser->User.Sid);
*ppUserSid = CoTaskMemAlloc(dwBytesRequired);
if (*ppUserSid == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
// Copy SID
if (!CopySid(dwBytesRequired, *ppUserSid, pUser->User.Sid))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CoTaskMemFree(*ppUserSid);
*ppUserSid = NULL;
}
}
}
if (fAllocatedBuffer == TRUE)
{
CoTaskMemFree(pUser);
}
return hr;
}
#if 0
//
// GetDomainClassStore
// -------------------
//
// This will go away.
//
// Currently this is used to get the Class Store Path
// for the domain.
//
#define DEFAULTSTORENAME L"CN=ClassStore"
HRESULT
GetDomainClassStore(
LPOLESTR * pszDefaultContainer,
LPOLESTR * pszDefaultStore)
//
// Finds the Root Path for the DC for this machine
// Then gets the Default Known CLass Store for the DC
//
{
HRESULT hr;
LPOLESTR PathNames[2];
VARIANT * pVarFilter = NULL;
IEnumVARIANT * pEnum;
IADs * pADs;
VARIANT VariantArray[2];
IDispatch * pDispatch = NULL;
ULONG cFetched;
IADsContainer * pContainer = NULL;
//
// Do a bind to the DC by a GetObject for the Path LDAP:
//
hr = ADsGetObject(
L"LDAP:",
IID_IADsContainer,
(void **)&pContainer
);
RETURN_ON_FAILURE(hr);
hr = ADsBuildEnumerator(
pContainer,
&pEnum
);
hr = ADsEnumerateNext(
pEnum,
1,
VariantArray,
&cFetched
);
pEnum->Release();
if ((hr == S_FALSE) || (cFetched == 0))
{
return E_FAIL;
}
pDispatch = VariantArray[0].pdispVal;
memset(VariantArray, 0, sizeof(VARIANT)*2);
hr = pDispatch->QueryInterface(IID_IADs, (void **) &pADs) ;
pDispatch->Release();
pADs->get_ADsPath(pszDefaultContainer);
pADs->Release();
pContainer->Release();
*pszDefaultStore = DEFAULTSTORENAME;
return S_OK;
}
#endif
PCLASSCONTAINER
GetClassStore (LPOLESTR pszPath)
{
PCLASSCONTAINER pCS = NULL;
pCS = (CLASSCONTAINER *) CoTaskMemAlloc (sizeof(CLASSCONTAINER));
if (!pCS)
return NULL;
pCS->gpClassStore = NULL;
pCS->cBindFailures = 0;
pCS->cAccess = 0;
pCS->cNotFound = 0;
pCS->pszClassStorePath = (LPOLESTR)CoTaskMemAlloc
(sizeof(WCHAR) * (wcslen(pszPath)+1));
if (!(pCS->pszClassStorePath))
{
CoTaskMemFree(pCS);
return NULL;
}
wcscpy (pCS->pszClassStorePath, pszPath);
//++cStores;
return pCS;
}
extern WCHAR pwszDebugPath [];
extern BOOL fDebugPath;
//
// GetPerUserClassStore
// ---------------------
//
// Synopsis: Gets the ADT Class Store List from the
// per-user Registry.
// Returns error if none defined,
//
// Arguments:
// [out] ppStoreList : where to store list of class container
// serial numbers
// [out] pcStores : where to store number of class containers
//
// Returns: S_OK,
//
// History: Changed by (DebiM)
// 2/24/97
// return a NULL list of Class Stores when none defined.
//
HRESULT GetPerUserClassStore(
PSID pSid,
UINT CallType,
LPOLESTR **ppStoreList,
DWORD *pcStores)
{
LONG lErrorCode;
DWORD dwDataLen = 0;
DWORD dwType;
HKEY hKey = NULL;
HRESULT hr = S_OK;
LPOLESTR pszPath, pszStart;
LPOLESTR *ppszPath;
LPWSTR pszPathList=NULL;
*pcStores = 0;
*ppStoreList = NULL;
if (!fDebugPath)
{
switch (CallType)
{
case CS_CALL_LOCALSYSTEM :
CSDBGPrint((L"Reading HKLM for class store path"));
break;
case CS_CALL_IMPERSONATED :
CSDBGPrint((L"Reading as an impersonated user for class store path"));
break;
case CS_CALL_USERPROCESS :
CSDBGPrint((L"Reading HKCU for class store path"));
break;
default:
return E_FAIL;
}
HRESULT hrCSPath;
hrCSPath = ReadClassStorePath(
CallType != CS_CALL_LOCALSYSTEM ? pSid : NULL,
&pszPathList);
if (FAILED(hrCSPath))
{
// treat as NULL list of Class Stores
delete [] pszPathList;
return S_OK;
}
}
else // Test Mode - Privately Set Path - Only for testing
{
wcscpy (&pszPathList[0], &pwszDebugPath[0]);
}
// counting the number of ';'s and the number of class stores.
// assuming that it ends with a ;
DWORD cTentativeStores = 0;
for (pszPath = pszPathList, cTentativeStores = 0;
(pszPath = wcschr(pszPath, L';'));)
{
++(cTentativeStores); pszPath++;
}
++(cTentativeStores);
pszPath = pszPathList;
ppszPath = *ppStoreList = (LPOLESTR *) CoTaskMemAlloc
(sizeof(LPOLESTR) * (cTentativeStores));
if (*ppStoreList == NULL)
{
return E_OUTOFMEMORY;
}
memset (*ppStoreList, 0, sizeof(LPOLESTR) * (cTentativeStores));
//
// Parse the list to separate different class containers
//
while (*pszPath)
{
while (*pszPath == L' ')
++pszPath;
pszStart = pszPath;
if (!*pszPath)
break;
if (*pszPath == L';')
{
++pszPath;
continue;
}
while (*pszPath && (*pszPath != L';'))
++pszPath;
//
// got one. save it.
//
*ppszPath = (LPOLESTR) CoTaskMemAlloc (sizeof(WCHAR) * (ULONG) (pszPath - pszStart + 1));
if (!(*ppszPath))
ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
memcpy (*ppszPath, pszStart, sizeof (WCHAR) * (ULONG) (pszPath - pszStart));
*((*ppszPath)+(pszPath - pszStart)) = NULL;
(ppszPath)++;
if (*pszPath == L';')
{
++pszPath;
}
(*pcStores)++;
if ((*pcStores) == cTentativeStores)
break;
}
delete [] pszPathList;
return S_OK;
Error_Cleanup:
DWORD i;
for (i = 0; i < (*pcStores); i++)
{
if (ppszPath[i])
CoTaskMemFree(ppszPath[i]);
}
CoTaskMemFree(ppszPath);
ppStoreList = NULL;
(*pcStores) = 0;
if (pszPathList)
CoTaskMemFree(pszPathList);
return hr;
}
//
// GetUserClassStores
// ------------------
//
// Synopsis: This routine reads the Class Store list and parses it.
// If it has prior knowledge it reurns the parsed list.
// Arguments:
// [out] pcStores: Number of Class Stores
// [out] ppStoreIdList: Class Store Id List,
//
// Returns: S_OK
// May return a NULL list of Class Stores.
//
//
HRESULT GetUserClassStores(
PCLASSCONTAINER **ppStoreList,
DWORD *pcStores,
BOOL *pfCache,
PSID *ppUserSid)
{
HRESULT hr = S_OK;
UINT CallType;
PCLASSCONTAINER *pList = NULL;
DWORD i;
//
// Get the SID of the calling process
//
hr = GetUserSid(ppUserSid, &CallType);
if (FAILED(hr))
{
*ppUserSid = NULL;
hr = S_OK;
}
*pfCache = (CallType == CS_CALL_IMPERSONATED);
if (gDebug)
{
if (*pfCache)
CSDBGPrint((L"Cache the class store"));
}
EnterCriticalSection (&ClassStoreBindList);
//
// Get the Class Store List
//
LPOLESTR *ppStoreNameList = NULL;
hr = GetPerUserClassStore(
*ppUserSid, CallType, &ppStoreNameList, pcStores);
//
// Note that the above may return a NULL list of Class Stores
//
CSDBGPrint((L"Found %d ClassStores", (*pcStores)));
if (SUCCEEDED(hr))
{
*ppStoreList = pList = (PCLASSCONTAINER *)
CoTaskMemAlloc (sizeof(PCLASSCONTAINER) * (*pcStores));
if (!(*ppStoreList))
hr = E_OUTOFMEMORY;
else
memset(pList, 0, sizeof(PCLASSCONTAINER) * (*pcStores));
}
if (SUCCEEDED(hr))
{
for (i=0; i < (*pcStores); i++)
{
*pList = GetClassStore (ppStoreNameList[i]);
if (!(*pList))
{
// free all the ones that have been allocated.
DWORD j;
for (j = 0; j < (*pcStores); j++)
if (*pList)
{
if ((*pList)->pszClassStorePath)
CoTaskMemFree((*pList)->pszClassStorePath);
CoTaskMemFree(*pList);
}
hr = E_OUTOFMEMORY;
(*pcStores) = 0;
break;
}
pList++;
}
}
if (ppStoreNameList)
{
for (i=0; i < (*pcStores); ++i)
{
if (ppStoreNameList[i])
CoTaskMemFree (ppStoreNameList[i]);
}
}
if (ppStoreNameList)
CoTaskMemFree (ppStoreNameList);
LeaveCriticalSection (&ClassStoreBindList);
return hr;
}