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.

510 lines
14 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. uRet = FILEOP_DOIT;
  153. } else
  154. uRet = FILEOP_SKIP;
  155. }
  156. break;
  157. case SPFILENOTIFY_FILEEXTRACTED:
  158. {
  159. PFILEPATHS_A pInfo = (PFILEPATHS_A) Param1;
  160. uRet = pInfo->Win32Error;
  161. if (NO_ERROR == uRet &&
  162. 0 == _stricmp(pCabFileContext->pszTempTargetFileName,
  163. pInfo->Target))
  164. pCabFileContext->fDidExtract = TRUE;
  165. }
  166. break;
  167. default:
  168. uRet = NO_ERROR;
  169. }
  170. return uRet;
  171. }
  172. typedef BOOL (WINAPI *PFN_SETUP_ITERATE_CABINET_A)(
  173. IN PCSTR CabinetFile,
  174. IN DWORD Reserved,
  175. IN PSP_FILE_CALLBACK_A MsgHandler,
  176. IN PVOID Context
  177. );
  178. //+-------------------------------------------------------------------------
  179. // Load setupapi.dll and call SetupIterateCabinetA to extract and
  180. // expand the specified file in the cab.
  181. //--------------------------------------------------------------------------
  182. BOOL WINAPI
  183. ExtractFileFromCabFileA(
  184. IN LPCSTR pszFileInCab,
  185. IN const CHAR szTempCabFileName[MAX_PATH],
  186. IN const CHAR szTempTargetFileName[MAX_PATH]
  187. )
  188. {
  189. BOOL fResult;
  190. HMODULE hDll = NULL;
  191. PFN_SETUP_ITERATE_CABINET_A pfnSetupIterateCabinetA;
  192. EXTRACT_CAB_FILE_CONTEXT_A CabFileContext;
  193. if (NULL == (hDll = LoadLibraryA("setupapi.dll")))
  194. goto LoadSetupApiDllError;
  195. if (NULL == (pfnSetupIterateCabinetA =
  196. (PFN_SETUP_ITERATE_CABINET_A) GetProcAddress(
  197. hDll, "SetupIterateCabinetA")))
  198. goto SetupIterateCabinetAProcAddressError;
  199. memset(&CabFileContext, 0, sizeof(CabFileContext));
  200. CabFileContext.pszFileInCab = pszFileInCab;
  201. CabFileContext.pszTempTargetFileName = szTempTargetFileName;
  202. if (!pfnSetupIterateCabinetA(
  203. szTempCabFileName,
  204. 0, // Reserved
  205. ExtractCabFileCallbackA,
  206. &CabFileContext
  207. ))
  208. goto SetupIterateCabinetError;
  209. if (!CabFileContext.fDidExtract)
  210. goto NoCabFileExtracted;
  211. fResult = TRUE;
  212. CommonReturn:
  213. if (hDll) {
  214. DWORD dwLastErr = GetLastError();
  215. FreeLibrary(hDll);
  216. SetLastError(dwLastErr);
  217. }
  218. return fResult;
  219. ErrorReturn:
  220. fResult = FALSE;
  221. goto CommonReturn;
  222. TRACE_ERROR(LoadSetupApiDllError)
  223. TRACE_ERROR(SetupIterateCabinetAProcAddressError)
  224. TRACE_ERROR(SetupIterateCabinetError)
  225. SET_ERROR(NoCabFileExtracted, ERROR_FILE_NOT_FOUND)
  226. }
  227. typedef BOOL (WINAPI *PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A)(
  228. IN HANDLE hToken,
  229. IN LPCSTR lpSrc,
  230. OUT LPSTR lpDest,
  231. IN DWORD dwSize
  232. );
  233. //+-------------------------------------------------------------------------
  234. // Get the thread's temp directory. We may be doing thread impersonation.
  235. //
  236. // Returns 0 if unable to get a thread temp path
  237. //--------------------------------------------------------------------------
  238. DWORD WINAPI
  239. I_GetThreadTempPathA(
  240. OUT CHAR szTempPath[MAX_PATH]
  241. )
  242. {
  243. DWORD cch;
  244. HANDLE hToken = NULL;
  245. HMODULE hDll = NULL;
  246. PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A
  247. pfnExpandEnvironmentStringsForUserA;
  248. if (!FIsWinNT5())
  249. return 0;
  250. if (!OpenThreadToken(
  251. GetCurrentThread(),
  252. TOKEN_QUERY | TOKEN_IMPERSONATE,
  253. TRUE,
  254. &hToken
  255. ))
  256. // We aren't impersonating. Default to the system environment
  257. // variables.
  258. hToken = NULL;
  259. if (NULL == (hDll = LoadLibraryA("userenv.dll")))
  260. goto LoadUserenvDllError;
  261. if (NULL == (pfnExpandEnvironmentStringsForUserA =
  262. (PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A) GetProcAddress(hDll,
  263. "ExpandEnvironmentStringsForUserA")))
  264. goto ExpandEnvironmentStringsForUserAProcAddressError;
  265. szTempPath[0] = L'\0';
  266. if (!pfnExpandEnvironmentStringsForUserA(
  267. hToken,
  268. "%Temp%\\",
  269. szTempPath,
  270. MAX_PATH - 1
  271. ) || '\0' == szTempPath[0])
  272. goto ExpandTempError;
  273. szTempPath[MAX_PATH - 1] = '\0';
  274. cch = strlen(szTempPath);
  275. CommonReturn:
  276. if (hToken)
  277. CloseHandle(hToken);
  278. if (hDll)
  279. FreeLibrary(hDll);
  280. return cch;
  281. ErrorReturn:
  282. cch = 0;
  283. goto CommonReturn;
  284. TRACE_ERROR(LoadUserenvDllError)
  285. TRACE_ERROR(ExpandEnvironmentStringsForUserAProcAddressError)
  286. TRACE_ERROR(ExpandTempError)
  287. }
  288. //+-------------------------------------------------------------------------
  289. // Extract, expand and allocate an in-memory blob for the specified
  290. // file from the in-memory cab.
  291. //
  292. // The allocated bytes must be freed by calling PkiFree().
  293. //--------------------------------------------------------------------------
  294. BOOL WINAPI
  295. ExtractBlobFromCabA(
  296. IN const BYTE *pbCab,
  297. IN DWORD cbCab,
  298. IN LPCSTR pszFileInCab,
  299. OUT BYTE **ppb,
  300. OUT DWORD *pcb
  301. )
  302. {
  303. BOOL fResult;
  304. DWORD dwLastErr = 0;
  305. BYTE *pb = NULL;
  306. DWORD cb;
  307. CHAR szTempPath[MAX_PATH];
  308. CHAR szTempCabFileName[MAX_PATH]; szTempCabFileName[0] = '\0';
  309. CHAR szTempTargetFileName[MAX_PATH]; szTempTargetFileName[0] = '\0';
  310. DWORD cch;
  311. // Get temp filenames for the cabinet and extracted target
  312. cch = GetTempPathA(CHAIN_CHAR_LEN(szTempPath), szTempPath);
  313. if (0 == cch || (CHAIN_CHAR_LEN(szTempPath) - 1) < cch)
  314. goto GetTempPathError;
  315. if (0 == GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName)) {
  316. dwLastErr = GetLastError();
  317. // If we are doing thread impersonation, we may not have access to the
  318. // process's temp directory. Try to get the impersonated thread's
  319. // temp directory.
  320. cch = I_GetThreadTempPathA(szTempPath);
  321. if (0 != cch)
  322. cch = GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName);
  323. if (0 == cch) {
  324. SetLastError(dwLastErr);
  325. szTempCabFileName[0] = '\0';
  326. goto GetTempCabFileNameError;
  327. }
  328. }
  329. szTempCabFileName[CHAIN_CHAR_LEN(szTempCabFileName) - 1] = '\0';
  330. if (0 == GetTempFileNameA(szTempPath, "Tar", 0, szTempTargetFileName)) {
  331. szTempTargetFileName[0] = '\0';
  332. goto GetTempTargetFileNameError;
  333. }
  334. szTempTargetFileName[CHAIN_CHAR_LEN(szTempTargetFileName) - 1] = '\0';
  335. // Write the cab bytes to the temporary cab file
  336. if (!WriteBlobToFileA(szTempCabFileName, pbCab, cbCab))
  337. goto WriteCabFileError;
  338. // Extract the specified file from the temporary cab file
  339. if (!ExtractFileFromCabFileA(
  340. pszFileInCab, szTempCabFileName, szTempTargetFileName))
  341. goto ExtractFileFromCabFileError;
  342. // Read and allocate the bytes from the temporary target file
  343. if (!ReadBlobFromFileA(szTempTargetFileName, &pb, &cb))
  344. goto ReadTargetFileError;
  345. fResult = TRUE;
  346. CommonReturn:
  347. // Delete the temp files
  348. if ('\0' != szTempCabFileName)
  349. DeleteFileA(szTempCabFileName);
  350. if ('\0' != szTempTargetFileName)
  351. DeleteFileA(szTempTargetFileName);
  352. *ppb = pb;
  353. *pcb = cb;
  354. SetLastError(dwLastErr);
  355. return fResult;
  356. ErrorReturn:
  357. dwLastErr = GetLastError();
  358. if (pb) {
  359. PkiFree(pb);
  360. pb = NULL;
  361. }
  362. cb = 0;
  363. fResult = FALSE;
  364. goto CommonReturn;
  365. TRACE_ERROR(GetTempPathError)
  366. TRACE_ERROR(GetTempCabFileNameError)
  367. TRACE_ERROR(GetTempTargetFileNameError)
  368. TRACE_ERROR(WriteCabFileError)
  369. TRACE_ERROR(ExtractFileFromCabFileError)
  370. TRACE_ERROR(ReadTargetFileError)
  371. }
  372. //+---------------------------------------------------------------------------
  373. //
  374. // Function: ExtractAuthRootAutoUpdateCtlFromCab
  375. //
  376. // Synopsis: Extract the authroot.stl file from the cabinet blob
  377. // and create the AuthRoot Auto Update CTL.
  378. //
  379. // Assumption: Chain engine isn't locked in the calling thread.
  380. //
  381. //----------------------------------------------------------------------------
  382. PCCTL_CONTEXT WINAPI
  383. ExtractAuthRootAutoUpdateCtlFromCab (
  384. IN PCRYPT_BLOB_ARRAY pcbaCab
  385. )
  386. {
  387. PCRYPT_DATA_BLOB pCabBlob;
  388. PCCTL_CONTEXT pCtl = NULL;
  389. BYTE *pbEncodedCtl = NULL;
  390. DWORD cbEncodedCtl;
  391. CERT_CREATE_CONTEXT_PARA CreateContextPara;
  392. // Get the cab blob
  393. pCabBlob = pcbaCab->rgBlob;
  394. if (0 == pcbaCab->cBlob || 0 == pCabBlob->cbData)
  395. goto InvalidCabBlob;
  396. // Extract, expand and create an in-memory blob for the stl file in the
  397. // in-memory cab
  398. if (!ExtractBlobFromCabA(
  399. pCabBlob->pbData,
  400. pCabBlob->cbData,
  401. CERT_AUTH_ROOT_CTL_FILENAME_A,
  402. &pbEncodedCtl,
  403. &cbEncodedCtl
  404. ))
  405. goto ExtractStlFromCabError;
  406. // Create the Ctl from the extracted bytes
  407. memset(&CreateContextPara, 0, sizeof(CreateContextPara));
  408. CreateContextPara.cbSize = sizeof(CreateContextPara);
  409. CreateContextPara.pfnFree = PkiFree;
  410. pCtl = (PCCTL_CONTEXT) CertCreateContext(
  411. CERT_STORE_CTL_CONTEXT,
  412. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  413. pbEncodedCtl,
  414. cbEncodedCtl,
  415. CERT_CREATE_CONTEXT_NOCOPY_FLAG,
  416. &CreateContextPara
  417. );
  418. // For NO_COPY_FLAG, pbEncodedCtl is always freed, even for an error
  419. pbEncodedCtl = NULL;
  420. if (NULL == pCtl)
  421. goto CreateCtlError;
  422. CommonReturn:
  423. return pCtl;
  424. ErrorReturn:
  425. assert(NULL == pCtl);
  426. if (pbEncodedCtl)
  427. PkiFree(pbEncodedCtl);
  428. goto CommonReturn;
  429. SET_ERROR(InvalidCabBlob, ERROR_INVALID_DATA)
  430. TRACE_ERROR(ExtractStlFromCabError)
  431. TRACE_ERROR(CreateCtlError)
  432. }