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.

447 lines
11 KiB

  1. //
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1999
  5. //
  6. // Author: AdamEd
  7. // Date: October 1998
  8. //
  9. // Class Store path query / persistence
  10. //
  11. //
  12. //---------------------------------------------------------------------
  13. #include "cstore.hxx"
  14. #include "cspath.hxx"
  15. HRESULT
  16. GetAppmgmtIniFilePath(
  17. PSID pSid,
  18. LPWSTR* ppwszPath
  19. )
  20. {
  21. UNICODE_STRING SidString;
  22. PTOKEN_USER pTokenUser;
  23. WCHAR wszPath[MAX_PATH];
  24. WCHAR * pwszSystemDir = NULL;
  25. DWORD AllocLength;
  26. DWORD Length;
  27. DWORD Size;
  28. BOOL bStatus;
  29. ULONG ulSize;
  30. *ppwszPath = 0;
  31. pwszSystemDir = wszPath;
  32. AllocLength = sizeof(wszPath) / sizeof(WCHAR);
  33. for (;;)
  34. {
  35. Length = GetSystemDirectory(
  36. pwszSystemDir,
  37. AllocLength );
  38. if ( 0 == Length )
  39. return HRESULT_FROM_WIN32(GetLastError());
  40. if ( Length >= AllocLength )
  41. {
  42. AllocLength = Length + 1;
  43. if (pwszSystemDir != wszPath)
  44. {
  45. LocalFree(pwszSystemDir);
  46. }
  47. pwszSystemDir = (WCHAR *) LocalAlloc( LPTR, AllocLength * sizeof(WCHAR) );
  48. if (NULL == pwszSystemDir)
  49. {
  50. return E_OUTOFMEMORY;
  51. }
  52. continue;
  53. }
  54. break;
  55. }
  56. if ( pSid )
  57. {
  58. NTSTATUS ntStatus;
  59. DWORD dwStatus;
  60. ntStatus = RtlConvertSidToUnicodeString(
  61. &SidString,
  62. pSid,
  63. TRUE );
  64. if (!NT_SUCCESS(ntStatus))
  65. {
  66. if (pwszSystemDir != wszPath)
  67. {
  68. LocalFree(pwszSystemDir);
  69. }
  70. dwStatus = RtlNtStatusToDosError(ntStatus);
  71. return HRESULT_FROM_WIN32(dwStatus);
  72. }
  73. }
  74. else
  75. {
  76. RtlInitUnicodeString( &SidString, L"MACHINE" );
  77. }
  78. HRESULT hr;
  79. // System dir + \appmgmt\ + Sid \ + inifilename \ + null
  80. ulSize = Length + 11 + (SidString.Length / 2) + (sizeof(APPMGMT_INI_FILENAME) / sizeof(WCHAR));
  81. *ppwszPath = new WCHAR[ulSize];
  82. if ( *ppwszPath )
  83. {
  84. hr = StringCchCopy( *ppwszPath, ulSize, pwszSystemDir );
  85. if (SUCCEEDED(hr))
  86. {
  87. if ( pwszSystemDir[lstrlen(pwszSystemDir)-1] != L'\\' )
  88. {
  89. hr = StringCchCat( *ppwszPath, ulSize, L"\\" );
  90. }
  91. if (SUCCEEDED(hr))
  92. {
  93. hr = StringCchCat( *ppwszPath, ulSize, L"appmgmt\\" );
  94. if (SUCCEEDED(hr))
  95. {
  96. hr = StringCchCat( *ppwszPath, ulSize, SidString.Buffer );
  97. if (SUCCEEDED(hr))
  98. {
  99. hr = StringCchCat( *ppwszPath, ulSize, APPMGMT_INI_FILENAME );
  100. }
  101. }
  102. }
  103. }
  104. if (FAILED(hr))
  105. {
  106. if ( pSid )
  107. RtlFreeUnicodeString( &SidString );
  108. if (pwszSystemDir != wszPath)
  109. {
  110. LocalFree(pwszSystemDir);
  111. }
  112. return hr;
  113. }
  114. }
  115. else
  116. {
  117. hr = E_OUTOFMEMORY;
  118. }
  119. if ( pSid )
  120. RtlFreeUnicodeString( &SidString );
  121. if (pwszSystemDir != wszPath)
  122. {
  123. LocalFree(pwszSystemDir);
  124. }
  125. return hr;
  126. }
  127. LONG
  128. GetClassStorePathSize(
  129. HANDLE hFile,
  130. DWORD* pdwSize)
  131. {
  132. BOOL bStatus;
  133. DWORD cbSizeHigh;
  134. //
  135. // Initialize the size to the length of an empty path -- this way
  136. // if no file is passed in we will treat that as a class store path
  137. // of zero length (excluding the terminator). This length must include
  138. // the terminator, so we set our initial size to that of an empty string
  139. //
  140. *pdwSize = sizeof(L'\0');
  141. //
  142. // If we have an open file with data, determine the size of the data
  143. //
  144. if ( hFile )
  145. {
  146. //
  147. // GetFileSize returns the logical size of the file, regardless
  148. // of whether the logical size is the same as the physical
  149. // size due to the vagaries of different file systems or compression
  150. //
  151. *pdwSize = GetFileSize(
  152. hFile,
  153. &cbSizeHigh);
  154. //
  155. // Check for a failure from the api
  156. //
  157. if ( -1 == *pdwSize )
  158. {
  159. return GetLastError();
  160. }
  161. //
  162. // Check the size for validity -- a file of ridiculous
  163. // size will be rejected
  164. //
  165. if ( cbSizeHigh )
  166. {
  167. //
  168. // If the high dword is set, clearly this file
  169. // contains an unreasonable amount of data
  170. //
  171. return ERROR_INSUFFICIENT_BUFFER;
  172. }
  173. else if ( *pdwSize > MAX_CSPATH_SIZE )
  174. {
  175. //
  176. // Again, the size should be within reasonable limits
  177. //
  178. return ERROR_INSUFFICIENT_BUFFER;
  179. }
  180. }
  181. return ERROR_SUCCESS;
  182. }
  183. LONG
  184. ReadClassStorePathFromFile(
  185. HANDLE hFile,
  186. WCHAR* wszDestination,
  187. DWORD cbSize)
  188. {
  189. DWORD cbRead;
  190. BOOL bStatus;
  191. //
  192. // The format of the file is simple -- it is simply the stream of bytes
  193. // that represent a unicode string terminated by a null unicode character --
  194. // we can just read the data directly and copy it to a buffer referenced by
  195. // a WCHAR* -- it will be legitimate unicode string once we read it in -- it includes
  196. // the null unicode char as the last byte read
  197. //
  198. //
  199. // Note that we've read nothing so far
  200. //
  201. cbRead = 0;
  202. //
  203. // If the file has data, read it
  204. //
  205. if ( cbSize )
  206. {
  207. //
  208. // Read the data from the file into the buffer
  209. //
  210. bStatus = ReadFile(
  211. hFile,
  212. wszDestination,
  213. cbSize,
  214. &cbRead,
  215. NULL);
  216. if (!bStatus)
  217. {
  218. return GetLastError();
  219. }
  220. //
  221. // Verify that the last character read was a null unicode character.
  222. // If it wasn't, the file is corrupt -- return an error so we don't
  223. // try to use the corrupt data and cause repeated errors or even crashes
  224. //
  225. if ( wszDestination[ cbRead / sizeof(*wszDestination) - 1 ] != L'\0' )
  226. {
  227. return ERROR_FILE_CORRUPT;
  228. }
  229. }
  230. else
  231. {
  232. //
  233. // For empty files, we simply return an empty unicode string
  234. //
  235. wszDestination[ 0 ] = L'\0';
  236. }
  237. return ERROR_SUCCESS;
  238. }
  239. HRESULT ReadClassStorePath(PSID pSid, LPWSTR* ppwszClassStorePath)
  240. {
  241. HRESULT hr;
  242. LPWSTR wszIniFilePath;
  243. DWORD cbSize;
  244. WCHAR* wszClassStorePath;
  245. LONG Status;
  246. HANDLE hFile;
  247. cbSize = 0;
  248. //
  249. // Notes: The file being read by this function was originally an
  250. // ini file as generated by the WritePrivateProfileSection api.
  251. // Unfortunately, the corresponding GetPrivateProfileString was horribly
  252. // broken in the sense that it had a 32k limit on the size of values. This
  253. // was not acceptable for our design, so we read the file directly
  254. //
  255. hr = GetAppmgmtIniFilePath(
  256. pSid,
  257. &wszIniFilePath);
  258. if (FAILED(hr))
  259. {
  260. return hr;
  261. }
  262. //
  263. // Initialize our reference to conditionally freed data
  264. //
  265. wszClassStorePath = NULL;
  266. //
  267. // First, attempt to open the file, which should already exist. We
  268. // generally do not expect concurrent readers, as there
  269. // are only two processes from which this file is read: services
  270. // and winlogon. Neither should be reading it at the same time, though
  271. // a terminal server case where the same user was logged in to the machine
  272. // twice could cause it
  273. //
  274. hFile = CreateFile(
  275. wszIniFilePath,
  276. GENERIC_READ,
  277. FILE_SHARE_READ,
  278. NULL,
  279. OPEN_EXISTING,
  280. 0,
  281. NULL);
  282. //
  283. // Handle the failure cases
  284. //
  285. if ( INVALID_HANDLE_VALUE == hFile )
  286. {
  287. //
  288. // We want to use NULL to indicate the absence of the file
  289. //
  290. hFile = NULL;
  291. Status = GetLastError();
  292. //
  293. // If the file did not exist, that's ok -- we interpret the
  294. // absence of the file as a blank class store path -- we
  295. // will not exit if the file didn't exist
  296. //
  297. if (ERROR_FILE_NOT_FOUND != Status)
  298. {
  299. goto cleanup_and_exit;
  300. }
  301. }
  302. else
  303. {
  304. //
  305. // If we don't have a file in existence, this means a zero length
  306. // class store path
  307. //
  308. cbSize = 0;
  309. }
  310. //
  311. // Now that we have access to the file or know that the file does
  312. // not exist, we can calculate the size of the class store path
  313. // from the file's size, as they have a 1-1 relationship. Note that if the
  314. // file does not exist, then hFile will be NULL
  315. //
  316. if ( hFile )
  317. {
  318. Status = GetClassStorePathSize(
  319. hFile,
  320. &cbSize);
  321. if ( ERROR_SUCCESS != Status )
  322. {
  323. goto cleanup_and_exit;
  324. }
  325. }
  326. //
  327. // We know the size, so allocate space, treating the size
  328. // as the length (in bytes) of the string including the terminator --
  329. // to handle the case where cbSize is zero because of a nonexistent
  330. // cs path, we will also add a terminating NULL since zero length
  331. // strings are still 1 character in size
  332. //
  333. wszClassStorePath = new WCHAR [ cbSize / sizeof(*wszClassStorePath) + 1 ];
  334. if ( wszClassStorePath )
  335. {
  336. //
  337. // We have a buffer, so read the unicode string into
  338. // the buffer
  339. //
  340. Status = ReadClassStorePathFromFile(
  341. hFile,
  342. wszClassStorePath,
  343. cbSize);
  344. }
  345. else
  346. {
  347. Status = ERROR_NOT_ENOUGH_MEMORY;
  348. }
  349. cleanup_and_exit:
  350. //
  351. // We no longer need the path to the ini file -- free it
  352. //
  353. delete [] wszIniFilePath;
  354. //
  355. // Close the file if it's open
  356. //
  357. if ( hFile )
  358. {
  359. CloseHandle( hFile );
  360. }
  361. //
  362. // On success, set the out param. On failure,
  363. // free any buffer we allocated for the class store path
  364. //
  365. if (ERROR_SUCCESS == Status)
  366. {
  367. *ppwszClassStorePath = wszClassStorePath;
  368. }
  369. else
  370. {
  371. delete [] wszClassStorePath;
  372. }
  373. return HRESULT_FROM_WIN32(Status);
  374. }