Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

673 lines
16 KiB

  1. //
  2. // Author: DebiM
  3. // Date: September 1996
  4. //
  5. // File: csuser.cxx
  6. //
  7. // Maintains a list of class containers per User SID.
  8. // Looks up this list for every IClassAccess call from OLE32/SCM.
  9. //
  10. //
  11. //---------------------------------------------------------------------
  12. #include "cstore.hxx"
  13. //
  14. // Link list pointer for Class Containers Seen
  15. //
  16. extern CLASSCONTAINER *gpContainerHead;
  17. //
  18. // Link list pointer for User Profiles Seen
  19. //
  20. extern USERPROFILE *gpUserHead;
  21. // Initialzed in InitializeClassStore at startup
  22. extern CRITICAL_SECTION ClassStoreBindList;
  23. //-------------------------------------------------------------------------
  24. //
  25. // OpenUserRegKey
  26. //
  27. // Opens a key under a user's HKEY_CLASSES_ROOT registry key. On NT5
  28. // HKCR is equivalent to HKEY_USERS\{sid string}\Software\Classes.
  29. //
  30. // A SID string is used to create
  31. // the proper registry key name to open.
  32. //
  33. //-------------------------------------------------------------------------
  34. DWORD
  35. OpenUserRegKey(
  36. IN PSID pSid,
  37. IN WCHAR * pwszSubKey,
  38. OUT HKEY * phKey
  39. )
  40. {
  41. UNICODE_STRING UnicodeString;
  42. WCHAR * pwszKey;
  43. DWORD AllocSize;
  44. NTSTATUS Status;
  45. UnicodeString.Length = UnicodeString.MaximumLength = 0;
  46. UnicodeString.Buffer = 0;
  47. Status = RtlConvertSidToUnicodeString(
  48. &UnicodeString,
  49. pSid,
  50. (BOOLEAN)TRUE // Allocate
  51. );
  52. //
  53. // Don't return a raw NT status code. This is the only possible error
  54. // condition presuming our sid is valid.
  55. //
  56. if ( Status != STATUS_SUCCESS )
  57. return ERROR_OUTOFMEMORY;
  58. //
  59. // Your friendly reminder, unicode string length is in bytes and doesn't include
  60. // null terminator, if any.
  61. // Add byte for '\\' and end null.
  62. //
  63. AllocSize = UnicodeString.Length + ((1 + lstrlen(pwszSubKey) + 1) * sizeof(WCHAR));
  64. pwszKey = (WCHAR *) alloca( AllocSize );
  65. if ( pwszKey )
  66. {
  67. memcpy( pwszKey, UnicodeString.Buffer, UnicodeString.Length );
  68. pwszKey[UnicodeString.Length / 2] = L'\\';
  69. lstrcpyW( &pwszKey[(UnicodeString.Length / 2) + 1], pwszSubKey );
  70. }
  71. RtlFreeUnicodeString( &UnicodeString );
  72. if ( ! pwszKey )
  73. return ERROR_OUTOFMEMORY;
  74. Status = RegOpenKeyEx(
  75. HKEY_USERS,
  76. pwszKey,
  77. 0,
  78. KEY_READ,
  79. phKey );
  80. return Status;
  81. }
  82. //
  83. // GetUserSid
  84. // ----------
  85. //
  86. // Synopsis: return the user SID of the caller.
  87. //
  88. // Arguments: &PSID - Where to store the caller's PSID
  89. //
  90. // Returns: HRESULT - S_OK if successful
  91. // E_FAIL otherwise
  92. //
  93. SID LocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
  94. HRESULT GetUserSid(PSID *ppUserSid, UINT *pCallType)
  95. {
  96. BYTE achBuffer[100];
  97. PTOKEN_USER pUser = (PTOKEN_USER) &achBuffer;
  98. PSID pSid;
  99. DWORD dwBytesRequired;
  100. BOOL fAllocatedBuffer = FALSE;
  101. HRESULT hr = S_OK;
  102. HANDLE hUserToken = NULL;
  103. BOOL fImpersonated = TRUE;
  104. *pCallType = CS_CALL_USERPROCESS;
  105. // Initialize
  106. *ppUserSid = NULL;
  107. // Get caller's token while impersonating
  108. if (!OpenThreadToken(GetCurrentThread(),
  109. TOKEN_DUPLICATE | TOKEN_QUERY,
  110. TRUE,
  111. &hUserToken))
  112. {
  113. fImpersonated = FALSE;
  114. if (ERROR_NO_TOKEN != GetLastError())
  115. return HRESULT_FROM_WIN32(GetLastError());
  116. if (!OpenProcessToken(GetCurrentProcess(),
  117. TOKEN_DUPLICATE | TOKEN_QUERY,
  118. &hUserToken))
  119. {
  120. return HRESULT_FROM_WIN32(GetLastError());
  121. }
  122. }
  123. if (SUCCEEDED(hr))
  124. {
  125. if (!GetTokenInformation(
  126. hUserToken, // Handle
  127. TokenUser, // TokenInformationClass
  128. pUser, // TokenInformation
  129. sizeof(achBuffer), // TokenInformationLength
  130. &dwBytesRequired // ReturnLength
  131. ))
  132. {
  133. //
  134. // Need to handle the case of insufficient buffer size.
  135. //
  136. if (sizeof(achBuffer) >= dwBytesRequired)
  137. {
  138. hr = HRESULT_FROM_WIN32(GetLastError());
  139. }
  140. if (SUCCEEDED(hr))
  141. {
  142. //
  143. // Allocate space for the user info
  144. //
  145. pUser = (PTOKEN_USER) CoTaskMemAlloc(dwBytesRequired);
  146. if (pUser == NULL)
  147. {
  148. hr = E_OUTOFMEMORY;
  149. }
  150. }
  151. if (SUCCEEDED(hr))
  152. {
  153. fAllocatedBuffer = TRUE;
  154. //
  155. // Read in the UserInfo
  156. //
  157. if (!GetTokenInformation(
  158. hUserToken, // Handle
  159. TokenUser, // TokenInformationClass
  160. pUser, // TokenInformation
  161. dwBytesRequired, // TokenInformationLength
  162. &dwBytesRequired // ReturnLength
  163. ))
  164. {
  165. hr = HRESULT_FROM_WIN32(GetLastError());
  166. }
  167. }
  168. }
  169. }
  170. if (hUserToken)
  171. {
  172. CloseHandle( hUserToken );
  173. hUserToken = NULL;
  174. }
  175. if (SUCCEEDED(hr))
  176. {
  177. //
  178. // Distinguish between
  179. // a) LOCAL_SYSTEM,
  180. // b) Impersonated Call from a LOCAL_SYSTEM
  181. // and c) In_proc call from a user process
  182. //
  183. // For case (c) make the SID null.
  184. //
  185. if (EqualSid(pUser->User.Sid, &LocalSystemSid))
  186. {
  187. *pCallType = CS_CALL_LOCALSYSTEM;
  188. }
  189. else
  190. {
  191. if (fImpersonated)
  192. {
  193. *pCallType = CS_CALL_IMPERSONATED;
  194. }
  195. else
  196. {
  197. *pCallType = CS_CALL_USERPROCESS;
  198. }
  199. }
  200. // Alloc buffer for copy of SID
  201. dwBytesRequired = GetLengthSid(pUser->User.Sid);
  202. *ppUserSid = CoTaskMemAlloc(dwBytesRequired);
  203. if (*ppUserSid == NULL)
  204. {
  205. hr = E_OUTOFMEMORY;
  206. }
  207. else
  208. {
  209. // Copy SID
  210. if (!CopySid(dwBytesRequired, *ppUserSid, pUser->User.Sid))
  211. {
  212. hr = HRESULT_FROM_WIN32(GetLastError());
  213. CoTaskMemFree(*ppUserSid);
  214. *ppUserSid = NULL;
  215. }
  216. }
  217. }
  218. if (fAllocatedBuffer == TRUE)
  219. {
  220. CoTaskMemFree(pUser);
  221. }
  222. return hr;
  223. }
  224. #if 0
  225. //
  226. // GetDomainClassStore
  227. // -------------------
  228. //
  229. // This will go away.
  230. //
  231. // Currently this is used to get the Class Store Path
  232. // for the domain.
  233. //
  234. #define DEFAULTSTORENAME L"CN=ClassStore"
  235. HRESULT
  236. GetDomainClassStore(
  237. LPOLESTR * pszDefaultContainer,
  238. LPOLESTR * pszDefaultStore)
  239. //
  240. // Finds the Root Path for the DC for this machine
  241. // Then gets the Default Known CLass Store for the DC
  242. //
  243. {
  244. HRESULT hr;
  245. LPOLESTR PathNames[2];
  246. VARIANT * pVarFilter = NULL;
  247. IEnumVARIANT * pEnum;
  248. IADs * pADs;
  249. VARIANT VariantArray[2];
  250. IDispatch * pDispatch = NULL;
  251. ULONG cFetched;
  252. IADsContainer * pContainer = NULL;
  253. //
  254. // Do a bind to the DC by a GetObject for the Path LDAP:
  255. //
  256. hr = ADsGetObject(
  257. L"LDAP:",
  258. IID_IADsContainer,
  259. (void **)&pContainer
  260. );
  261. RETURN_ON_FAILURE(hr);
  262. hr = ADsBuildEnumerator(
  263. pContainer,
  264. &pEnum
  265. );
  266. hr = ADsEnumerateNext(
  267. pEnum,
  268. 1,
  269. VariantArray,
  270. &cFetched
  271. );
  272. pEnum->Release();
  273. if ((hr == S_FALSE) || (cFetched == 0))
  274. {
  275. return E_FAIL;
  276. }
  277. pDispatch = VariantArray[0].pdispVal;
  278. memset(VariantArray, 0, sizeof(VARIANT)*2);
  279. hr = pDispatch->QueryInterface(IID_IADs, (void **) &pADs) ;
  280. pDispatch->Release();
  281. pADs->get_ADsPath(pszDefaultContainer);
  282. pADs->Release();
  283. pContainer->Release();
  284. *pszDefaultStore = DEFAULTSTORENAME;
  285. return S_OK;
  286. }
  287. #endif
  288. PCLASSCONTAINER
  289. GetClassStore (LPOLESTR pszPath)
  290. {
  291. PCLASSCONTAINER pCS = NULL;
  292. pCS = (CLASSCONTAINER *) CoTaskMemAlloc (sizeof(CLASSCONTAINER));
  293. if (!pCS)
  294. return NULL;
  295. pCS->gpClassStore = NULL;
  296. pCS->cBindFailures = 0;
  297. pCS->cAccess = 0;
  298. pCS->cNotFound = 0;
  299. pCS->pszClassStorePath = (LPOLESTR)CoTaskMemAlloc
  300. (sizeof(WCHAR) * (wcslen(pszPath)+1));
  301. if (!(pCS->pszClassStorePath))
  302. {
  303. CoTaskMemFree(pCS);
  304. return NULL;
  305. }
  306. wcscpy (pCS->pszClassStorePath, pszPath);
  307. //++cStores;
  308. return pCS;
  309. }
  310. extern WCHAR pwszDebugPath [];
  311. extern BOOL fDebugPath;
  312. //
  313. // GetPerUserClassStore
  314. // ---------------------
  315. //
  316. // Synopsis: Gets the ADT Class Store List from the
  317. // per-user Registry.
  318. // Returns error if none defined,
  319. //
  320. // Arguments:
  321. // [out] ppStoreList : where to store list of class container
  322. // serial numbers
  323. // [out] pcStores : where to store number of class containers
  324. //
  325. // Returns: S_OK,
  326. //
  327. // History: Changed by (DebiM)
  328. // 2/24/97
  329. // return a NULL list of Class Stores when none defined.
  330. //
  331. HRESULT GetPerUserClassStore(
  332. PSID pSid,
  333. UINT CallType,
  334. LPOLESTR **ppStoreList,
  335. DWORD *pcStores)
  336. {
  337. LONG lErrorCode;
  338. DWORD dwDataLen = 0;
  339. DWORD dwType;
  340. HKEY hKey = NULL;
  341. HRESULT hr = S_OK;
  342. LPOLESTR pszPath, pszStart;
  343. LPOLESTR *ppszPath;
  344. LPWSTR pszPathList=NULL;
  345. *pcStores = 0;
  346. *ppStoreList = NULL;
  347. if (!fDebugPath)
  348. {
  349. switch (CallType)
  350. {
  351. case CS_CALL_LOCALSYSTEM :
  352. CSDBGPrint((L"Reading HKLM for class store path"));
  353. break;
  354. case CS_CALL_IMPERSONATED :
  355. CSDBGPrint((L"Reading as an impersonated user for class store path"));
  356. break;
  357. case CS_CALL_USERPROCESS :
  358. CSDBGPrint((L"Reading HKCU for class store path"));
  359. break;
  360. default:
  361. return E_FAIL;
  362. }
  363. HRESULT hrCSPath;
  364. hrCSPath = ReadClassStorePath(
  365. CallType != CS_CALL_LOCALSYSTEM ? pSid : NULL,
  366. &pszPathList);
  367. if (FAILED(hrCSPath))
  368. {
  369. // treat as NULL list of Class Stores
  370. delete [] pszPathList;
  371. return S_OK;
  372. }
  373. }
  374. else // Test Mode - Privately Set Path - Only for testing
  375. {
  376. wcscpy (&pszPathList[0], &pwszDebugPath[0]);
  377. }
  378. // counting the number of ';'s and the number of class stores.
  379. // assuming that it ends with a ;
  380. DWORD cTentativeStores = 0;
  381. for (pszPath = pszPathList, cTentativeStores = 0;
  382. (pszPath = wcschr(pszPath, L';'));)
  383. {
  384. ++(cTentativeStores); pszPath++;
  385. }
  386. ++(cTentativeStores);
  387. pszPath = pszPathList;
  388. ppszPath = *ppStoreList = (LPOLESTR *) CoTaskMemAlloc
  389. (sizeof(LPOLESTR) * (cTentativeStores));
  390. if (*ppStoreList == NULL)
  391. {
  392. return E_OUTOFMEMORY;
  393. }
  394. memset (*ppStoreList, 0, sizeof(LPOLESTR) * (cTentativeStores));
  395. //
  396. // Parse the list to separate different class containers
  397. //
  398. while (*pszPath)
  399. {
  400. while (*pszPath == L' ')
  401. ++pszPath;
  402. pszStart = pszPath;
  403. if (!*pszPath)
  404. break;
  405. if (*pszPath == L';')
  406. {
  407. ++pszPath;
  408. continue;
  409. }
  410. while (*pszPath && (*pszPath != L';'))
  411. ++pszPath;
  412. //
  413. // got one. save it.
  414. //
  415. *ppszPath = (LPOLESTR) CoTaskMemAlloc (sizeof(WCHAR) * (ULONG) (pszPath - pszStart + 1));
  416. if (!(*ppszPath))
  417. ERROR_ON_FAILURE(hr=E_OUTOFMEMORY);
  418. memcpy (*ppszPath, pszStart, sizeof (WCHAR) * (ULONG) (pszPath - pszStart));
  419. *((*ppszPath)+(pszPath - pszStart)) = NULL;
  420. (ppszPath)++;
  421. if (*pszPath == L';')
  422. {
  423. ++pszPath;
  424. }
  425. (*pcStores)++;
  426. if ((*pcStores) == cTentativeStores)
  427. break;
  428. }
  429. delete [] pszPathList;
  430. return S_OK;
  431. Error_Cleanup:
  432. DWORD i;
  433. for (i = 0; i < (*pcStores); i++)
  434. {
  435. if (ppszPath[i])
  436. CoTaskMemFree(ppszPath[i]);
  437. }
  438. CoTaskMemFree(ppszPath);
  439. ppStoreList = NULL;
  440. (*pcStores) = 0;
  441. if (pszPathList)
  442. CoTaskMemFree(pszPathList);
  443. return hr;
  444. }
  445. //
  446. // GetUserClassStores
  447. // ------------------
  448. //
  449. // Synopsis: This routine reads the Class Store list and parses it.
  450. // If it has prior knowledge it reurns the parsed list.
  451. // Arguments:
  452. // [out] pcStores: Number of Class Stores
  453. // [out] ppStoreIdList: Class Store Id List,
  454. //
  455. // Returns: S_OK
  456. // May return a NULL list of Class Stores.
  457. //
  458. //
  459. HRESULT GetUserClassStores(
  460. PCLASSCONTAINER **ppStoreList,
  461. DWORD *pcStores,
  462. BOOL *pfCache,
  463. PSID *ppUserSid)
  464. {
  465. HRESULT hr = S_OK;
  466. UINT CallType;
  467. PCLASSCONTAINER *pList = NULL;
  468. DWORD i;
  469. //
  470. // Get the SID of the calling process
  471. //
  472. hr = GetUserSid(ppUserSid, &CallType);
  473. if (FAILED(hr))
  474. {
  475. *ppUserSid = NULL;
  476. hr = S_OK;
  477. }
  478. *pfCache = (CallType == CS_CALL_IMPERSONATED);
  479. if (gDebug)
  480. {
  481. if (*pfCache)
  482. CSDBGPrint((L"Cache the class store"));
  483. }
  484. EnterCriticalSection (&ClassStoreBindList);
  485. //
  486. // Get the Class Store List
  487. //
  488. LPOLESTR *ppStoreNameList = NULL;
  489. hr = GetPerUserClassStore(
  490. *ppUserSid, CallType, &ppStoreNameList, pcStores);
  491. //
  492. // Note that the above may return a NULL list of Class Stores
  493. //
  494. CSDBGPrint((L"Found %d ClassStores", (*pcStores)));
  495. if (SUCCEEDED(hr))
  496. {
  497. *ppStoreList = pList = (PCLASSCONTAINER *)
  498. CoTaskMemAlloc (sizeof(PCLASSCONTAINER) * (*pcStores));
  499. if (!(*ppStoreList))
  500. hr = E_OUTOFMEMORY;
  501. else
  502. memset(pList, 0, sizeof(PCLASSCONTAINER) * (*pcStores));
  503. }
  504. if (SUCCEEDED(hr))
  505. {
  506. for (i=0; i < (*pcStores); i++)
  507. {
  508. *pList = GetClassStore (ppStoreNameList[i]);
  509. if (!(*pList))
  510. {
  511. // free all the ones that have been allocated.
  512. DWORD j;
  513. for (j = 0; j < (*pcStores); j++)
  514. if (*pList)
  515. {
  516. if ((*pList)->pszClassStorePath)
  517. CoTaskMemFree((*pList)->pszClassStorePath);
  518. CoTaskMemFree(*pList);
  519. }
  520. hr = E_OUTOFMEMORY;
  521. (*pcStores) = 0;
  522. break;
  523. }
  524. pList++;
  525. }
  526. }
  527. if (ppStoreNameList)
  528. {
  529. for (i=0; i < (*pcStores); ++i)
  530. {
  531. if (ppStoreNameList[i])
  532. CoTaskMemFree (ppStoreNameList[i]);
  533. }
  534. }
  535. if (ppStoreNameList)
  536. CoTaskMemFree (ppStoreNameList);
  537. LeaveCriticalSection (&ClassStoreBindList);
  538. return hr;
  539. }