968 lines
23 KiB
C++
968 lines
23 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"
|
|
void GetCurrentUsn(LPOLESTR pStoreUsn);
|
|
|
|
//
|
|
// 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 *) PrivMemAlloc( 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 );
|
|
|
|
PrivMemFree( pwszKey );
|
|
|
|
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 };
|
|
|
|
#define CS_CALL_LOCALSYSTEM 1
|
|
#define CS_CALL_USERPROCESS 2
|
|
#define CS_CALL_IMPERSONATED 3
|
|
|
|
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 (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);
|
|
}
|
|
|
|
if (hUserToken)
|
|
CloseHandle( hUserToken );
|
|
|
|
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
|
|
|
|
// GetKnownClassStore
|
|
// -------------------
|
|
//
|
|
//
|
|
// Synopsis: Gets a class container path.
|
|
// Looks up list of containers seen
|
|
// and returns the pointer for this container.
|
|
// If a new class container is seen,
|
|
// it is added to this list and its pointer is returned.
|
|
//
|
|
// Arguments: [in] pszPath - Class container Path
|
|
// Returns: pClassStoreNode : Class Container Node
|
|
//
|
|
//
|
|
|
|
|
|
PCLASSCONTAINER
|
|
GetKnownClassStore (LPOLESTR pszPath)
|
|
{
|
|
PCLASSCONTAINER pCS = gpContainerHead;
|
|
|
|
//
|
|
// Chain thru the link list of containers ...
|
|
//
|
|
while (pCS != NULL)
|
|
{
|
|
if (!wcscmp (pszPath, pCS->pszClassStorePath))
|
|
{
|
|
break;
|
|
}
|
|
pCS = pCS->pNextClassStore;
|
|
}
|
|
|
|
//
|
|
// If not matched ..
|
|
// Add it to the beginning of the list.
|
|
//
|
|
|
|
if (pCS == NULL)
|
|
{
|
|
pCS = (CLASSCONTAINER *) CoTaskMemAlloc (sizeof(CLASSCONTAINER));
|
|
pCS->pNextClassStore = gpContainerHead;
|
|
gpContainerHead = pCS;
|
|
pCS->gpClassStore = NULL;
|
|
pCS->cBindFailures = 0;
|
|
pCS->cAccess = 0;
|
|
pCS->cNotFound = 0;
|
|
pCS->pszClassStorePath = (LPOLESTR)CoTaskMemAlloc
|
|
(sizeof(WCHAR) * (wcslen(pszPath)+1));
|
|
wcscpy (pCS->pszClassStorePath, pszPath);
|
|
//++cStores;
|
|
}
|
|
|
|
return pCS;
|
|
|
|
}
|
|
|
|
/*
|
|
//
|
|
// GetUserSyncPoint
|
|
// ----------------
|
|
//
|
|
// Synopsis: Receives and Stores the Next Sync Point.
|
|
// Reads and returns the current sync point.
|
|
// When Advance is called the current becomes the lastsyncpoint.
|
|
// No error returned,
|
|
//
|
|
// BUGBUG. This is NOT thread-safe now. Fix it!
|
|
//
|
|
HRESULT GetUserSyncPoint(LPWSTR pszContainer, CSUSN *pPrevUsn)
|
|
{
|
|
LONG lErrorCode;
|
|
DWORD dwDataLen = _MAX_PATH;
|
|
DWORD dwType;
|
|
HKEY hKey = NULL;
|
|
HRESULT hr = S_OK;
|
|
WCHAR wszSync[_MAX_PATH + 1];
|
|
PSID pUserSid;
|
|
CSUSN CurrUsn;
|
|
|
|
//
|
|
// Get the current USN
|
|
//
|
|
|
|
GetCurrentUsn(&CurrUsn);
|
|
|
|
//
|
|
// Get the SID of the calling process
|
|
//
|
|
|
|
hr = GetUserSid(&pUserSid);
|
|
RETURN_ON_FAILURE(hr);
|
|
|
|
//
|
|
// This should be outside of impersonation
|
|
// So revert to LOCAL SYSTEM.
|
|
|
|
RpcRevertToSelf();
|
|
|
|
lErrorCode = OpenUserRegKey(
|
|
pUserSid,
|
|
L"Software\\Microsoft\\ClassStore",
|
|
&hKey);
|
|
|
|
|
|
if (lErrorCode != ERROR_SUCCESS)
|
|
{
|
|
DWORD dwDisp;
|
|
|
|
lErrorCode = RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
L"Software\\Microsoft\\ClassStore",
|
|
NULL,
|
|
L"REG_SZ",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisp);
|
|
}
|
|
|
|
|
|
lErrorCode = RegQueryValueEx(hKey,
|
|
pszContainer,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)wszSync,
|
|
&dwDataLen);
|
|
|
|
|
|
if (lErrorCode != ERROR_SUCCESS)
|
|
{
|
|
pPrevUsn->dwLowDateTime = CurrUsn.dwLowDateTime;
|
|
pPrevUsn->dwHighDateTime = CurrUsn.dwHighDateTime;
|
|
|
|
wsprintf (wszSync, L"%lu %lu %lu %lu",
|
|
pPrevUsn->dwHighDateTime,
|
|
pPrevUsn->dwLowDateTime,
|
|
pPrevUsn->dwHighDateTime,
|
|
pPrevUsn->dwLowDateTime);
|
|
|
|
lErrorCode = RegSetValueEx(
|
|
hKey,
|
|
pszContainer, //L"LastSync",
|
|
NULL,
|
|
REG_SZ,
|
|
(LPBYTE)wszSync,
|
|
(2 * wcslen(wszSync)) + 2);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
{
|
|
swscanf (wszSync, L"%lu %lu",
|
|
&pPrevUsn->dwHighDateTime,
|
|
&pPrevUsn->dwLowDateTime);
|
|
|
|
wsprintf (wszSync, L"%lu %lu %lu %lu",
|
|
pPrevUsn->dwHighDateTime,
|
|
pPrevUsn->dwLowDateTime,
|
|
CurrUsn.dwHighDateTime,
|
|
CurrUsn.dwLowDateTime);
|
|
|
|
lErrorCode = RegSetValueEx(
|
|
hKey,
|
|
pszContainer, //L"LastSync",
|
|
NULL,
|
|
REG_SZ,
|
|
(LPBYTE)wszSync,
|
|
(2 * wcslen(wszSync)) + 2);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// Impersonate again
|
|
|
|
RpcImpersonateClient((RPC_BINDING_HANDLE)0);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// AdvanceUserSyncPoint
|
|
// --------------------
|
|
//
|
|
// Synopsis: Makes the Next Sync Point as Last Sync Point.
|
|
// No error returned,
|
|
//
|
|
//
|
|
HRESULT AdvanceUserSyncPoint(LPWSTR pszContainer)
|
|
{
|
|
LONG lErrorCode;
|
|
DWORD dwDataLen = _MAX_PATH;
|
|
DWORD dwType;
|
|
HKEY hKey = NULL;
|
|
HRESULT hr = S_OK;
|
|
WCHAR wszSync[_MAX_PATH + 1];
|
|
CSUSN PrevUsn, NextUsn;
|
|
PSID pUserSid;
|
|
|
|
//
|
|
// Get the SID of the calling process
|
|
// Already assumed to be under impersonation
|
|
//
|
|
hr = GetUserSid(&pUserSid);
|
|
RETURN_ON_FAILURE(hr);
|
|
|
|
//
|
|
// This should be outside of impersonation
|
|
// So revert to LOCAL SYSTEM.
|
|
|
|
RpcRevertToSelf();
|
|
|
|
lErrorCode = OpenUserRegKey(
|
|
pUserSid,
|
|
L"Software\\Microsoft\\ClassStore",
|
|
&hKey);
|
|
|
|
if ( lErrorCode == ERROR_SUCCESS)
|
|
{
|
|
lErrorCode = RegQueryValueEx(hKey,
|
|
pszContainer,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)wszSync,
|
|
&dwDataLen);
|
|
|
|
if (lErrorCode != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
if (lErrorCode == ERROR_SUCCESS)
|
|
{
|
|
swscanf (wszSync, L"%lu %lu %lu %lu",
|
|
&PrevUsn.dwHighDateTime,
|
|
&PrevUsn.dwLowDateTime,
|
|
&NextUsn.dwHighDateTime,
|
|
&NextUsn.dwLowDateTime);
|
|
|
|
wsprintf (wszSync, L"%lu %lu %lu %lu",
|
|
NextUsn.dwHighDateTime,
|
|
NextUsn.dwLowDateTime,
|
|
NextUsn.dwHighDateTime,
|
|
NextUsn.dwLowDateTime);
|
|
|
|
lErrorCode = RegSetValueEx(
|
|
hKey,
|
|
pszContainer, //L"LastSync",
|
|
NULL,
|
|
REG_SZ,
|
|
(LPBYTE)wszSync,
|
|
(2 * wcslen(wszSync)) + 2);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// Impersonate again
|
|
|
|
RpcImpersonateClient((RPC_BINDING_HANDLE)0);
|
|
|
|
return S_OK;
|
|
}
|
|
*/
|
|
|
|
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.
|
|
//
|
|
#define MAXCLASSSTORES 10
|
|
|
|
HRESULT GetPerUserClassStore(
|
|
PSID pSid,
|
|
UINT CallType,
|
|
LPOLESTR **ppStoreList,
|
|
DWORD *pcStores)
|
|
|
|
{
|
|
LONG lErrorCode;
|
|
DWORD dwDataLen = 2000;
|
|
DWORD dwType;
|
|
HKEY hKey = NULL;
|
|
HRESULT hr = S_OK;
|
|
LPOLESTR pszPath, pszStart;
|
|
LPOLESTR *ppszPath;
|
|
WCHAR pszPathList [2000 + 1];
|
|
|
|
*pcStores = 0;
|
|
*ppStoreList = NULL;
|
|
|
|
if (!fDebugPath)
|
|
{
|
|
switch (CallType)
|
|
{
|
|
case CS_CALL_LOCALSYSTEM :
|
|
|
|
lErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy",
|
|
NULL,
|
|
KEY_READ,
|
|
&hKey);
|
|
break;
|
|
|
|
case CS_CALL_IMPERSONATED :
|
|
|
|
lErrorCode = OpenUserRegKey(
|
|
pSid,
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy",
|
|
&hKey);
|
|
break;
|
|
|
|
case CS_CALL_USERPROCESS :
|
|
|
|
lErrorCode = RegOpenKeyEx(HKEY_CURRENT_USER,
|
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy",
|
|
NULL,
|
|
KEY_ALL_ACCESS,
|
|
&hKey);
|
|
break;
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ( lErrorCode != ERROR_SUCCESS)
|
|
{
|
|
// treat as NULL list of Class Stores
|
|
return S_OK;
|
|
}
|
|
|
|
lErrorCode = RegQueryValueEx(hKey,
|
|
L"ClassStorePath",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pszPathList,
|
|
&dwDataLen);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (lErrorCode != ERROR_SUCCESS)
|
|
{
|
|
// treat as NULL list of Class Stores
|
|
return S_OK;
|
|
}
|
|
}
|
|
else // Test Mode - Privately Set Path - Only for testing
|
|
{
|
|
wcscpy (&pszPathList[0], &pwszDebugPath[0]);
|
|
}
|
|
|
|
|
|
pszPath = pszPathList;
|
|
|
|
ppszPath = *ppStoreList = (LPOLESTR *) CoTaskMemAlloc
|
|
(sizeof(LPOLESTR) * MAXCLASSSTORES);
|
|
|
|
if (*ppStoreList == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// 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) * (pszPath - pszStart + 1));
|
|
|
|
memcpy (*ppszPath, pszStart, sizeof (WCHAR) * (pszPath - pszStart));
|
|
*((*ppszPath)+(pszPath - pszStart)) = NULL;
|
|
|
|
(ppszPath)++;
|
|
++(*pcStores);
|
|
|
|
if (*pszPath == L';')
|
|
{
|
|
++pszPath;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// CacheSid
|
|
// ---------
|
|
//
|
|
// Synopsis: Gets a SID.
|
|
// Gets a list of class container paths for this SID.
|
|
// Looks up known class containers to map these to
|
|
// ClassStore Node pointers.
|
|
// Caches the SID and associated class store list.
|
|
//
|
|
// Arguments:
|
|
// [in] pUserSid: SID
|
|
// [in] ppStoreList: Class Store Path List,
|
|
// [in] cStores: Number of Class Stores
|
|
//
|
|
//
|
|
// Returns: ppStoreList: Class Store Node List
|
|
//
|
|
|
|
PCLASSCONTAINER * CacheSid (PSID pUserSid,
|
|
LPOLESTR *ppStoreList,
|
|
DWORD cStores)
|
|
{
|
|
ULONG i;
|
|
PCLASSCONTAINER *pStoreList, *pList;
|
|
USERPROFILE *pUser;
|
|
|
|
//
|
|
// Allocate a User structure
|
|
// and store the user specific values in it
|
|
//
|
|
pUser = (USERPROFILE *) CoTaskMemAlloc (sizeof(USERPROFILE));
|
|
if (pUserSid)
|
|
{
|
|
pUser->pCachedSid = (PSID) CoTaskMemAlloc (GetLengthSid(pUserSid));
|
|
|
|
|
|
CopySid(GetLengthSid(pUserSid),
|
|
pUser->pCachedSid,
|
|
pUserSid);
|
|
}
|
|
else
|
|
pUser->pCachedSid = NULL;
|
|
|
|
|
|
//
|
|
// Link it to the beginning of the User Linklist
|
|
//
|
|
pUser->pNextUser = gpUserHead;
|
|
gpUserHead = pUser;
|
|
|
|
//
|
|
// Find its ClassStore Path and setup the class store node chain
|
|
//
|
|
if (cStores == 0)
|
|
{
|
|
// NULL list of Class Stores
|
|
|
|
pStoreList = pUser->pUserStoreList = NULL;
|
|
}
|
|
else
|
|
{
|
|
pStoreList = pList =
|
|
pUser->pUserStoreList = (PCLASSCONTAINER *)
|
|
CoTaskMemAlloc (sizeof(PCLASSCONTAINER) * cStores);
|
|
|
|
for (i=0; i < cStores; i++)
|
|
{
|
|
*pList = GetKnownClassStore (*ppStoreList);
|
|
ppStoreList++;
|
|
pList++;
|
|
}
|
|
}
|
|
|
|
pUser->cUserStoreCount = cStores;
|
|
|
|
return pStoreList;
|
|
}
|
|
|
|
|
|
//
|
|
// GetUserClassStores
|
|
// ------------------
|
|
//
|
|
// Synopsis: This routine finds out the SID of the user.
|
|
// It then looks up a global cache of SIDs to see if it
|
|
// has accessed the list of Class Stores for this user.
|
|
//
|
|
// If not, it 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
|
|
// See change note for GetPerUserClassStore().
|
|
// May return a NULL list of Class Stores.
|
|
//
|
|
//
|
|
|
|
HRESULT GetUserClassStores(
|
|
PCLASSCONTAINER **ppStoreList,
|
|
DWORD *pcStores)
|
|
|
|
{
|
|
int l;
|
|
PSID pUserSid;
|
|
HRESULT hr = S_OK;
|
|
UINT CallType;
|
|
|
|
// Impersonate before accessing SID
|
|
|
|
//RpcImpersonateClient((RPC_BINDING_HANDLE)0);
|
|
|
|
//
|
|
// Get the SID of the calling process
|
|
//
|
|
|
|
hr = GetUserSid(&pUserSid, &CallType);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
pUserSid = NULL;
|
|
hr = S_OK;
|
|
}
|
|
|
|
//RpcRevertToSelf();
|
|
|
|
EnterCriticalSection (&ClassStoreBindList);
|
|
|
|
//
|
|
// Look this up in the global list of SIDs
|
|
//
|
|
USERPROFILE *pUser = gpUserHead;
|
|
|
|
while (pUser != NULL)
|
|
{
|
|
if ((pUserSid == pUser->pCachedSid) || // Null UserSid
|
|
(EqualSid(pUserSid, pUser->pCachedSid)))
|
|
//
|
|
// Found the match
|
|
//
|
|
{
|
|
*ppStoreList = pUser->pUserStoreList;
|
|
*pcStores = pUser->cUserStoreCount;
|
|
break;
|
|
}
|
|
pUser = pUser->pNextUser;
|
|
}
|
|
|
|
|
|
if (pUser == NULL)
|
|
{
|
|
//
|
|
// Didnt find this User's Sid
|
|
// Get the Class Store List and cache it along with this SID
|
|
//
|
|
LPOLESTR *ppStoreNameList = NULL;
|
|
UINT i;
|
|
|
|
hr = GetPerUserClassStore(
|
|
pUserSid, CallType, &ppStoreNameList, pcStores);
|
|
|
|
//
|
|
// Note that the above may return a NULL list of Class Stores
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppStoreList = CacheSid (pUserSid, ppStoreNameList, *pcStores);
|
|
//
|
|
// release memory allocated in GetPerUserClassStore()
|
|
//
|
|
for (i=0; i < *pcStores; ++i)
|
|
{
|
|
CoTaskMemFree (ppStoreNameList[i]);
|
|
}
|
|
|
|
if (ppStoreNameList)
|
|
CoTaskMemFree (ppStoreNameList);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection (&ClassStoreBindList);
|
|
//
|
|
// Free the Sid
|
|
//
|
|
if (pUserSid)
|
|
CoTaskMemFree (pUserSid);
|
|
|
|
return hr;
|
|
}
|
|
|