Leaked source code of windows server 2003
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.

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