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.

513 lines
15 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000
  5. //
  6. // File: extract.cpp
  7. //
  8. // Contents: Chain Cabinet Extraction
  9. //
  10. // Functions: ExtractAuthRootAutoUpdateCtlFromCab
  11. //
  12. // History: 11-Nov-00 philh Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <global.hxx>
  16. #include <setupapi.h>
  17. #include <dbgdef.h>
  18. #include <userenv.h>
  19. #define CHAIN_CHAR_LEN(sz) (sizeof(sz) / sizeof(sz[0]))
  20. //+===========================================================================
  21. // Extract helper functions
  22. //============================================================================
  23. //+-------------------------------------------------------------------------
  24. // Allocate and read a blob from a file.
  25. //
  26. // The allocated bytes must be freed by calling PkiFree().
  27. //--------------------------------------------------------------------------
  28. BOOL WINAPI
  29. ReadBlobFromFileA(
  30. IN LPCSTR pszFileName,
  31. OUT BYTE **ppb,
  32. OUT DWORD *pcb
  33. )
  34. {
  35. BOOL fResult;
  36. HANDLE hFile;
  37. BYTE *pb = NULL;
  38. DWORD cb = 0;
  39. DWORD cbRead = 0;
  40. hFile = CreateFileA(
  41. pszFileName,
  42. GENERIC_READ,
  43. FILE_SHARE_READ | FILE_SHARE_WRITE,
  44. NULL, // lpsa
  45. OPEN_EXISTING,
  46. 0, // fdwAttrsAndFlags
  47. NULL // TemplateFile
  48. );
  49. if (INVALID_HANDLE_VALUE == hFile)
  50. goto CreateFileError;
  51. cb = GetFileSize(hFile, NULL);
  52. if (0 == cb)
  53. goto EmptyFile;
  54. if (NULL == (pb = (BYTE *) PkiNonzeroAlloc(cb)))
  55. goto OutOfMemory;
  56. if (!ReadFile(hFile, pb, cb, &cbRead, NULL))
  57. goto ReadFileError;
  58. if (cbRead != cb)
  59. goto InvalidFileLengthError;
  60. fResult = TRUE;
  61. CommonReturn:
  62. if (INVALID_HANDLE_VALUE != hFile) {
  63. DWORD dwLastErr = GetLastError();
  64. CloseHandle(hFile);
  65. SetLastError(dwLastErr);
  66. }
  67. *ppb = pb;
  68. *pcb = cb;
  69. return fResult;
  70. ErrorReturn:
  71. if (pb) {
  72. PkiFree(pb);
  73. pb = NULL;
  74. }
  75. cb = 0;
  76. fResult = FALSE;
  77. goto CommonReturn;
  78. TRACE_ERROR(CreateFileError)
  79. SET_ERROR(EmptyFile, ERROR_INVALID_DATA)
  80. TRACE_ERROR(OutOfMemory)
  81. TRACE_ERROR(ReadFileError)
  82. SET_ERROR(InvalidFileLengthError, ERROR_INVALID_DATA)
  83. }
  84. //+-------------------------------------------------------------------------
  85. // Write the blob to the specified file
  86. //--------------------------------------------------------------------------
  87. BOOL WINAPI
  88. WriteBlobToFileA(
  89. IN LPCSTR pszFileName,
  90. IN const BYTE *pb,
  91. IN DWORD cb
  92. )
  93. {
  94. BOOL fResult;
  95. HANDLE hFile;
  96. DWORD cbWritten;
  97. hFile = CreateFileA(
  98. pszFileName,
  99. GENERIC_WRITE,
  100. 0, // fdwShareMode
  101. NULL, // lpsa
  102. CREATE_ALWAYS,
  103. 0, // fdwAttrsAndFlags
  104. 0); // TemplateFile
  105. if (INVALID_HANDLE_VALUE == hFile)
  106. goto CreateFileError;
  107. if (!WriteFile(hFile, pb, cb, &cbWritten, NULL))
  108. goto WriteFileError;
  109. fResult = TRUE;
  110. CommonReturn:
  111. if (INVALID_HANDLE_VALUE != hFile) {
  112. DWORD dwLastErr = GetLastError();
  113. CloseHandle(hFile);
  114. SetLastError(dwLastErr);
  115. }
  116. return fResult;
  117. ErrorReturn:
  118. fResult = FALSE;
  119. goto CommonReturn;
  120. TRACE_ERROR(CreateFileError)
  121. TRACE_ERROR(WriteFileError)
  122. }
  123. typedef struct _EXTRACT_CAB_FILE_CONTEXT_A {
  124. LPCSTR pszFileInCab;
  125. LPCSTR pszTempTargetFileName; // MAX_PATH array
  126. BOOL fDidExtract;
  127. } EXTRACT_CAB_FILE_CONTEXT_A, *PEXTRACT_CAB_FILE_CONTEXT_A;
  128. //+-------------------------------------------------------------------------
  129. // Callback called by SetupIterateCabinetA to extract the file.
  130. //--------------------------------------------------------------------------
  131. UINT CALLBACK
  132. ExtractCabFileCallbackA(
  133. IN PVOID Context,
  134. IN UINT Notification,
  135. IN UINT_PTR Param1,
  136. IN UINT_PTR Param2
  137. )
  138. {
  139. UINT uRet;
  140. PEXTRACT_CAB_FILE_CONTEXT_A pCabFileContext =
  141. (PEXTRACT_CAB_FILE_CONTEXT_A) Context;
  142. switch (Notification) {
  143. case SPFILENOTIFY_FILEINCABINET:
  144. {
  145. PFILE_IN_CABINET_INFO_A pInfo =
  146. (PFILE_IN_CABINET_INFO_A) Param1;
  147. if (0 == _stricmp(pCabFileContext->pszFileInCab,
  148. pInfo->NameInCabinet)) {
  149. strncpy(pInfo->FullTargetName,
  150. pCabFileContext->pszTempTargetFileName,
  151. CHAIN_CHAR_LEN(pInfo->FullTargetName));
  152. pInfo->FullTargetName[
  153. CHAIN_CHAR_LEN(pInfo->FullTargetName) - 1] = '\0';
  154. uRet = FILEOP_DOIT;
  155. } else
  156. uRet = FILEOP_SKIP;
  157. }
  158. break;
  159. case SPFILENOTIFY_FILEEXTRACTED:
  160. {
  161. PFILEPATHS_A pInfo = (PFILEPATHS_A) Param1;
  162. uRet = pInfo->Win32Error;
  163. if (NO_ERROR == uRet &&
  164. 0 == _stricmp(pCabFileContext->pszTempTargetFileName,
  165. pInfo->Target))
  166. pCabFileContext->fDidExtract = TRUE;
  167. }
  168. break;
  169. default:
  170. uRet = NO_ERROR;
  171. }
  172. return uRet;
  173. }
  174. typedef BOOL (WINAPI *PFN_SETUP_ITERATE_CABINET_A)(
  175. IN PCSTR CabinetFile,
  176. IN DWORD Reserved,
  177. IN PSP_FILE_CALLBACK_A MsgHandler,
  178. IN PVOID Context
  179. );
  180. //+-------------------------------------------------------------------------
  181. // Load setupapi.dll and call SetupIterateCabinetA to extract and
  182. // expand the specified file in the cab.
  183. //--------------------------------------------------------------------------
  184. BOOL WINAPI
  185. ExtractFileFromCabFileA(
  186. IN LPCSTR pszFileInCab,
  187. IN const CHAR szTempCabFileName[MAX_PATH],
  188. IN const CHAR szTempTargetFileName[MAX_PATH]
  189. )
  190. {
  191. BOOL fResult;
  192. HMODULE hDll = NULL;
  193. PFN_SETUP_ITERATE_CABINET_A pfnSetupIterateCabinetA;
  194. EXTRACT_CAB_FILE_CONTEXT_A CabFileContext;
  195. if (NULL == (hDll = LoadLibraryA("setupapi.dll")))
  196. goto LoadSetupApiDllError;
  197. if (NULL == (pfnSetupIterateCabinetA =
  198. (PFN_SETUP_ITERATE_CABINET_A) GetProcAddress(
  199. hDll, "SetupIterateCabinetA")))
  200. goto SetupIterateCabinetAProcAddressError;
  201. memset(&CabFileContext, 0, sizeof(CabFileContext));
  202. CabFileContext.pszFileInCab = pszFileInCab;
  203. CabFileContext.pszTempTargetFileName = szTempTargetFileName;
  204. if (!pfnSetupIterateCabinetA(
  205. szTempCabFileName,
  206. 0, // Reserved
  207. ExtractCabFileCallbackA,
  208. &CabFileContext
  209. ))
  210. goto SetupIterateCabinetError;
  211. if (!CabFileContext.fDidExtract)
  212. goto NoCabFileExtracted;
  213. fResult = TRUE;
  214. CommonReturn:
  215. if (hDll) {
  216. DWORD dwLastErr = GetLastError();
  217. FreeLibrary(hDll);
  218. SetLastError(dwLastErr);
  219. }
  220. return fResult;
  221. ErrorReturn:
  222. fResult = FALSE;
  223. goto CommonReturn;
  224. TRACE_ERROR(LoadSetupApiDllError)
  225. TRACE_ERROR(SetupIterateCabinetAProcAddressError)
  226. TRACE_ERROR(SetupIterateCabinetError)
  227. SET_ERROR(NoCabFileExtracted, ERROR_FILE_NOT_FOUND)
  228. }
  229. typedef BOOL (WINAPI *PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A)(
  230. IN HANDLE hToken,
  231. IN LPCSTR lpSrc,
  232. OUT LPSTR lpDest,
  233. IN DWORD dwSize
  234. );
  235. //+-------------------------------------------------------------------------
  236. // Get the thread's temp directory. We may be doing thread impersonation.
  237. //
  238. // Returns 0 if unable to get a thread temp path
  239. //--------------------------------------------------------------------------
  240. DWORD WINAPI
  241. I_GetThreadTempPathA(
  242. OUT CHAR szTempPath[MAX_PATH]
  243. )
  244. {
  245. DWORD cch;
  246. HANDLE hToken = NULL;
  247. HMODULE hDll = NULL;
  248. PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A
  249. pfnExpandEnvironmentStringsForUserA;
  250. if (!FIsWinNT5())
  251. return 0;
  252. if (!OpenThreadToken(
  253. GetCurrentThread(),
  254. TOKEN_QUERY | TOKEN_IMPERSONATE,
  255. TRUE,
  256. &hToken
  257. ))
  258. // We aren't impersonating. Default to the system environment
  259. // variables.
  260. hToken = NULL;
  261. if (NULL == (hDll = LoadLibraryA("userenv.dll")))
  262. goto LoadUserenvDllError;
  263. if (NULL == (pfnExpandEnvironmentStringsForUserA =
  264. (PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A) GetProcAddress(hDll,
  265. "ExpandEnvironmentStringsForUserA")))
  266. goto ExpandEnvironmentStringsForUserAProcAddressError;
  267. szTempPath[0] = L'\0';
  268. if (!pfnExpandEnvironmentStringsForUserA(
  269. hToken,
  270. "%Temp%\\",
  271. szTempPath,
  272. MAX_PATH - 1
  273. ) || '\0' == szTempPath[0])
  274. goto ExpandTempError;
  275. szTempPath[MAX_PATH - 1] = '\0';
  276. cch = strlen(szTempPath);
  277. CommonReturn:
  278. if (hToken)
  279. CloseHandle(hToken);
  280. if (hDll)
  281. FreeLibrary(hDll);
  282. return cch;
  283. ErrorReturn:
  284. cch = 0;
  285. goto CommonReturn;
  286. TRACE_ERROR(LoadUserenvDllError)
  287. TRACE_ERROR(ExpandEnvironmentStringsForUserAProcAddressError)
  288. TRACE_ERROR(ExpandTempError)
  289. }
  290. //+-------------------------------------------------------------------------
  291. // Extract, expand and allocate an in-memory blob for the specified
  292. // file from the in-memory cab.
  293. //
  294. // The allocated bytes must be freed by calling PkiFree().
  295. //--------------------------------------------------------------------------
  296. BOOL WINAPI
  297. ExtractBlobFromCabA(
  298. IN const BYTE *pbCab,
  299. IN DWORD cbCab,
  300. IN LPCSTR pszFileInCab,
  301. OUT BYTE **ppb,
  302. OUT DWORD *pcb
  303. )
  304. {
  305. BOOL fResult;
  306. DWORD dwLastErr = 0;
  307. BYTE *pb = NULL;
  308. DWORD cb;
  309. CHAR szTempPath[MAX_PATH];
  310. CHAR szTempCabFileName[MAX_PATH]; szTempCabFileName[0] = '\0';
  311. CHAR szTempTargetFileName[MAX_PATH]; szTempTargetFileName[0] = '\0';
  312. DWORD cch;
  313. // Get temp filenames for the cabinet and extracted target
  314. cch = GetTempPathA(CHAIN_CHAR_LEN(szTempPath), szTempPath);
  315. if (0 == cch || (CHAIN_CHAR_LEN(szTempPath) - 1) < cch)
  316. goto GetTempPathError;
  317. if (0 == GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName)) {
  318. dwLastErr = GetLastError();
  319. // If we are doing thread impersonation, we may not have access to the
  320. // process's temp directory. Try to get the impersonated thread's
  321. // temp directory.
  322. cch = I_GetThreadTempPathA(szTempPath);
  323. if (0 != cch)
  324. cch = GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName);
  325. if (0 == cch) {
  326. SetLastError(dwLastErr);
  327. szTempCabFileName[0] = '\0';
  328. goto GetTempCabFileNameError;
  329. }
  330. }
  331. szTempCabFileName[CHAIN_CHAR_LEN(szTempCabFileName) - 1] = '\0';
  332. if (0 == GetTempFileNameA(szTempPath, "Tar", 0, szTempTargetFileName)) {
  333. szTempTargetFileName[0] = '\0';
  334. goto GetTempTargetFileNameError;
  335. }
  336. szTempTargetFileName[CHAIN_CHAR_LEN(szTempTargetFileName) - 1] = '\0';
  337. // Write the cab bytes to the temporary cab file
  338. if (!WriteBlobToFileA(szTempCabFileName, pbCab, cbCab))
  339. goto WriteCabFileError;
  340. // Extract the specified file from the temporary cab file
  341. if (!ExtractFileFromCabFileA(
  342. pszFileInCab, szTempCabFileName, szTempTargetFileName))
  343. goto ExtractFileFromCabFileError;
  344. // Read and allocate the bytes from the temporary target file
  345. if (!ReadBlobFromFileA(szTempTargetFileName, &pb, &cb))
  346. goto ReadTargetFileError;
  347. fResult = TRUE;
  348. CommonReturn:
  349. // Delete the temp files
  350. if ('\0' != szTempCabFileName)
  351. DeleteFileA(szTempCabFileName);
  352. if ('\0' != szTempTargetFileName)
  353. DeleteFileA(szTempTargetFileName);
  354. *ppb = pb;
  355. *pcb = cb;
  356. SetLastError(dwLastErr);
  357. return fResult;
  358. ErrorReturn:
  359. dwLastErr = GetLastError();
  360. if (pb) {
  361. PkiFree(pb);
  362. pb = NULL;
  363. }
  364. cb = 0;
  365. fResult = FALSE;
  366. goto CommonReturn;
  367. TRACE_ERROR(GetTempPathError)
  368. TRACE_ERROR(GetTempCabFileNameError)
  369. TRACE_ERROR(GetTempTargetFileNameError)
  370. TRACE_ERROR(WriteCabFileError)
  371. TRACE_ERROR(ExtractFileFromCabFileError)
  372. TRACE_ERROR(ReadTargetFileError)
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Function: ExtractAuthRootAutoUpdateCtlFromCab
  377. //
  378. // Synopsis: Extract the authroot.stl file from the cabinet blob
  379. // and create the AuthRoot Auto Update CTL.
  380. //
  381. // Assumption: Chain engine isn't locked in the calling thread.
  382. //
  383. //----------------------------------------------------------------------------
  384. PCCTL_CONTEXT WINAPI
  385. ExtractAuthRootAutoUpdateCtlFromCab (
  386. IN PCRYPT_BLOB_ARRAY pcbaCab
  387. )
  388. {
  389. PCRYPT_DATA_BLOB pCabBlob;
  390. PCCTL_CONTEXT pCtl = NULL;
  391. BYTE *pbEncodedCtl = NULL;
  392. DWORD cbEncodedCtl;
  393. CERT_CREATE_CONTEXT_PARA CreateContextPara;
  394. // Get the cab blob
  395. pCabBlob = pcbaCab->rgBlob;
  396. if (0 == pcbaCab->cBlob || 0 == pCabBlob->cbData)
  397. goto InvalidCabBlob;
  398. // Extract, expand and create an in-memory blob for the stl file in the
  399. // in-memory cab
  400. if (!ExtractBlobFromCabA(
  401. pCabBlob->pbData,
  402. pCabBlob->cbData,
  403. CERT_AUTH_ROOT_CTL_FILENAME_A,
  404. &pbEncodedCtl,
  405. &cbEncodedCtl
  406. ))
  407. goto ExtractStlFromCabError;
  408. // Create the Ctl from the extracted bytes
  409. memset(&CreateContextPara, 0, sizeof(CreateContextPara));
  410. CreateContextPara.cbSize = sizeof(CreateContextPara);
  411. CreateContextPara.pfnFree = PkiFree;
  412. pCtl = (PCCTL_CONTEXT) CertCreateContext(
  413. CERT_STORE_CTL_CONTEXT,
  414. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  415. pbEncodedCtl,
  416. cbEncodedCtl,
  417. CERT_CREATE_CONTEXT_NOCOPY_FLAG,
  418. &CreateContextPara
  419. );
  420. // For NO_COPY_FLAG, pbEncodedCtl is always freed, even for an error
  421. pbEncodedCtl = NULL;
  422. if (NULL == pCtl)
  423. goto CreateCtlError;
  424. CommonReturn:
  425. return pCtl;
  426. ErrorReturn:
  427. assert(NULL == pCtl);
  428. if (pbEncodedCtl)
  429. PkiFree(pbEncodedCtl);
  430. goto CommonReturn;
  431. SET_ERROR(InvalidCabBlob, ERROR_INVALID_DATA)
  432. TRACE_ERROR(ExtractStlFromCabError)
  433. TRACE_ERROR(CreateCtlError)
  434. }