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.

1127 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ipc.c
  5. Abstract:
  6. The routines in this source file implement an interprocess communication
  7. mechanism to allow migration DLLs to be isolated into a separate process
  8. ("sandboxing"). This is done so that no DLL can affect the results of
  9. any other DLL or Setup.
  10. The IPC mechanism used here is memory mapped files. Writes to the
  11. memory mapped file are synchronized by two events, one for the receiver
  12. and one by the host.
  13. Author:
  14. Jim Schmidt (jimschm) 22-Mar-1997
  15. Revision History:
  16. jimschm 19-Mar-2001 Removed DVD check (now in migration dll)
  17. jimschm 02-Jun-1999 Added IPC-based DVD check
  18. jimschm 21-Sep-1998 Converted from mailslots to memory mapped files.
  19. (There are bugs in both Win9x and NT mailslots
  20. that broke the original design.)
  21. jimschm 19-Jan-1998 Added beginings of WinVerifyTrust calls
  22. jimschm 15-Jul-1997 Added many workarounds for Win95 bugs.
  23. --*/
  24. #include "pch.h"
  25. #include "migutilp.h"
  26. #include <softpub.h>
  27. #ifdef UNICODE
  28. #error Build must be ANSI
  29. #endif
  30. #define DBG_IPC "Ipc"
  31. typedef struct {
  32. HANDLE Mapping;
  33. HANDLE DoCommand;
  34. HANDLE GetResults;
  35. } IPCDATA, *PIPCDATA;
  36. static PCTSTR g_Mode;
  37. static HANDLE g_ProcessHandle;
  38. static BOOL g_Host;
  39. static IPCDATA g_IpcData;
  40. VOID
  41. pCloseIpcData (
  42. VOID
  43. );
  44. BOOL
  45. pOpenIpcData (
  46. VOID
  47. );
  48. BOOL
  49. pCreateIpcData (
  50. IN PSECURITY_ATTRIBUTES psa
  51. );
  52. typedef struct {
  53. DWORD Command;
  54. DWORD Result;
  55. DWORD TechnicalLogId;
  56. DWORD GuiLogId;
  57. DWORD DataSize;
  58. BYTE Data[];
  59. } MAPDATA, *PMAPDATA;
  60. BOOL
  61. OpenIpcA (
  62. IN BOOL Win95Side,
  63. IN PCSTR ExePath, OPTIONAL
  64. IN PCSTR RemoteArg, OPTIONAL
  65. IN PCSTR WorkingDir OPTIONAL
  66. )
  67. /*++
  68. Routine Description:
  69. OpenIpc has two modes of operation, depending on who the caller is. If the
  70. caller is w95upg.dll or w95upgnt.dll, then the IPC mode is called "host mode."
  71. If the caller is migisol.exe, then the IPC mode is called "remote mode."
  72. In host mode, OpenIpc creates all of the objects necessary to implement
  73. the IPC. This includes two events, DoCommand and GetResults, and a
  74. file mapping. After creating the objects, the remote process is launched.
  75. In remote mode, OpenIpc opens the existing objects that have already
  76. been created.
  77. Arguments:
  78. Win95Side - Used in host mode only. Specifies that w95upg.dll is running
  79. when TRUE, or that w95upgnt.dll is running when FALSE.
  80. ExePath - Specifies the command line for migisol.exe. Specifies NULL
  81. to indicate remote mode.
  82. RemoteArg - Used in host mode only. Specifies the migration DLL
  83. path. Ignored in remote mode.
  84. WorkingDir - Used in host mode only. Specifies the working directory path
  85. for the migration DLL. Ignored in remote mode.
  86. Return value:
  87. TRUE if the IPC channel was opened. If host mode, TRUE indicates that
  88. migisol.exe is up and running. If remote mode, TRUE indicates that
  89. migisol is ready for commands.
  90. --*/
  91. {
  92. CHAR CmdLine[MAX_CMDLINE];
  93. STARTUPINFOA si;
  94. PROCESS_INFORMATION pi;
  95. BOOL ProcessResult;
  96. HANDLE SyncEvent = NULL;
  97. HANDLE ObjectArray[2];
  98. DWORD rc;
  99. PSECURITY_DESCRIPTOR psd = NULL;
  100. SECURITY_ATTRIBUTES sa, *psa;
  101. BOOL Result = FALSE;
  102. #ifdef DEBUG
  103. g_Mode = ExePath ? TEXT("host") : TEXT("remote");
  104. #endif
  105. __try {
  106. g_ProcessHandle = NULL;
  107. g_Host = (ExePath != NULL);
  108. if (ISNT()) {
  109. //
  110. // Create nul DACL for NT
  111. //
  112. ZeroMemory (&sa, sizeof (sa));
  113. psd = (PSECURITY_DESCRIPTOR) MemAlloc (g_hHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
  114. if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION)) {
  115. __leave;
  116. }
  117. if (!SetSecurityDescriptorDacl (psd, TRUE, (PACL) NULL, FALSE)) {
  118. __leave;
  119. }
  120. sa.nLength = sizeof (sa);
  121. sa.lpSecurityDescriptor = psd;
  122. psa = &sa;
  123. } else {
  124. psa = NULL;
  125. }
  126. if (g_Host) {
  127. //
  128. // Create the IPC objects
  129. //
  130. if (!pCreateIpcData (psa)) {
  131. DEBUGMSG ((DBG_ERROR, "Cannot create IPC channel"));
  132. __leave;
  133. }
  134. MYASSERT (RemoteArg);
  135. SyncEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("win9xupg"));
  136. MYASSERT (SyncEvent);
  137. //
  138. // Create the child process
  139. //
  140. wsprintfA (
  141. CmdLine,
  142. "\"%s\" %s \"%s\"",
  143. ExePath,
  144. Win95Side ? "-r" : "-m",
  145. RemoteArg
  146. );
  147. ZeroMemory (&si, sizeof (si));
  148. si.cb = sizeof (si);
  149. si.dwFlags = STARTF_FORCEOFFFEEDBACK;
  150. ProcessResult = CreateProcessA (
  151. NULL,
  152. CmdLine,
  153. NULL,
  154. NULL,
  155. FALSE,
  156. CREATE_DEFAULT_ERROR_MODE,
  157. NULL,
  158. WorkingDir,
  159. &si,
  160. &pi
  161. );
  162. if (ProcessResult) {
  163. CloseHandle (pi.hThread);
  164. } else {
  165. LOG ((LOG_ERROR, "Cannot start %s", CmdLine));
  166. __leave;
  167. }
  168. //
  169. // Wait for process to fail or wait for it to set the win95upg event
  170. //
  171. ObjectArray[0] = SyncEvent;
  172. ObjectArray[1] = pi.hProcess;
  173. rc = WaitForMultipleObjects (2, ObjectArray, FALSE, 60000);
  174. g_ProcessHandle = pi.hProcess;
  175. if (rc != WAIT_OBJECT_0) {
  176. DEBUGMSG ((
  177. DBG_WARNING,
  178. "Process %x did not signal 'ready'. Wait timed out. (%s)",
  179. g_ProcessHandle,
  180. g_Mode
  181. ));
  182. LOG ((LOG_ERROR, "Upgrade pack failed during process creation."));
  183. __leave;
  184. }
  185. DEBUGMSG ((DBG_IPC, "Process %s is running (%s)", CmdLine, g_Mode));
  186. } else { // !g_Host
  187. //
  188. // Open the IPC objects
  189. //
  190. if (!pOpenIpcData()) {
  191. DEBUGMSG ((DBG_ERROR, "Cannot open IPC channel"));
  192. __leave;
  193. }
  194. //
  195. // Set event notifying setup that we've created our mailslot
  196. //
  197. SyncEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("win9xupg"));
  198. if (!SyncEvent) {
  199. __leave;
  200. }
  201. SetEvent (SyncEvent);
  202. }
  203. Result = TRUE;
  204. }
  205. __finally {
  206. //
  207. // Cleanup code
  208. //
  209. PushError();
  210. if (!Result) {
  211. CloseIpc();
  212. }
  213. if (SyncEvent) {
  214. CloseHandle (SyncEvent);
  215. }
  216. if (psd) {
  217. MemFree (g_hHeap, 0, psd);
  218. }
  219. PopError();
  220. }
  221. return Result;
  222. }
  223. BOOL
  224. OpenIpcW (
  225. IN BOOL Win95Side,
  226. IN PCWSTR ExePath, OPTIONAL
  227. IN PCWSTR RemoteArg, OPTIONAL
  228. IN PCWSTR WorkingDir OPTIONAL
  229. )
  230. {
  231. PCSTR AnsiExePath, AnsiRemoteArg, AnsiWorkingDir;
  232. BOOL b;
  233. if (ExePath) {
  234. AnsiExePath = ConvertWtoA (ExePath);
  235. } else {
  236. AnsiExePath = NULL;
  237. }
  238. if (RemoteArg) {
  239. AnsiRemoteArg = ConvertWtoA (RemoteArg);
  240. } else {
  241. AnsiRemoteArg = NULL;
  242. }
  243. if (WorkingDir) {
  244. AnsiWorkingDir = ConvertWtoA (WorkingDir);
  245. } else {
  246. AnsiWorkingDir = NULL;
  247. }
  248. b = OpenIpcA (Win95Side, AnsiExePath, AnsiRemoteArg, AnsiWorkingDir);
  249. FreeConvertedStr (AnsiExePath);
  250. FreeConvertedStr (AnsiRemoteArg);
  251. FreeConvertedStr (AnsiWorkingDir);
  252. return b;
  253. }
  254. VOID
  255. CloseIpc (
  256. VOID
  257. )
  258. /*++
  259. Routine Description:
  260. Tells migisol.exe process to terminate, and then cleans up all resources
  261. opened by OpenIpc.
  262. Arguments:
  263. none
  264. Return Value:
  265. none
  266. --*/
  267. {
  268. if (g_Host) {
  269. //
  270. // Tell migisol.exe to terminate
  271. // if the communications channel is up
  272. //
  273. if (g_IpcData.Mapping && !SendIpcCommand (IPC_TERMINATE, NULL, 0)) {
  274. KillIpcProcess();
  275. }
  276. if (g_ProcessHandle) {
  277. WaitForSingleObject (g_ProcessHandle, 10000);
  278. }
  279. }
  280. pCloseIpcData();
  281. if (g_ProcessHandle) {
  282. CloseHandle (g_ProcessHandle);
  283. g_ProcessHandle = NULL;
  284. }
  285. }
  286. VOID
  287. pCloseIpcData (
  288. VOID
  289. )
  290. {
  291. if (g_IpcData.DoCommand) {
  292. CloseHandle (g_IpcData.DoCommand);
  293. g_IpcData.DoCommand = NULL;
  294. }
  295. if (g_IpcData.GetResults) {
  296. CloseHandle (g_IpcData.GetResults);
  297. g_IpcData.GetResults = NULL;
  298. }
  299. if (g_IpcData.Mapping) {
  300. CloseHandle (g_IpcData.Mapping);
  301. g_IpcData.Mapping = NULL;
  302. }
  303. }
  304. BOOL
  305. pCreateIpcData (
  306. IN PSECURITY_ATTRIBUTES psa
  307. )
  308. /*++
  309. Routine Description:
  310. pCreateIpcData creates the objects necessary to transfer data between
  311. migisol.exe and w95upg*.dll. This function is called in host mode (i.e.,
  312. from w95upg.dll or w95upgnt.dll).
  313. Arguments:
  314. psa - Specifies NT nul DACL, or NULL on Win9x
  315. Return Value:
  316. TRUE if the objects were created properly, or FALSE if not.
  317. --*/
  318. {
  319. ZeroMemory (&g_IpcData, sizeof (g_IpcData));
  320. g_IpcData.DoCommand = CreateEvent (psa, FALSE, FALSE, TEXT("Setup.DoCommand"));
  321. g_IpcData.GetResults = CreateEvent (psa, FALSE, FALSE, TEXT("Setup.GetResults"));
  322. g_IpcData.Mapping = CreateFileMapping (
  323. INVALID_HANDLE_VALUE,
  324. psa,
  325. PAGE_READWRITE,
  326. 0,
  327. 0x10000,
  328. TEXT("Setup.IpcData")
  329. );
  330. if (!g_IpcData.DoCommand ||
  331. !g_IpcData.GetResults ||
  332. !g_IpcData.Mapping
  333. ) {
  334. pCloseIpcData();
  335. return FALSE;
  336. }
  337. return TRUE;
  338. }
  339. BOOL
  340. pOpenIpcData (
  341. VOID
  342. )
  343. /*++
  344. Routine Description:
  345. pOpenIpcData opens objects necessary to transfer data between migisol.exe
  346. and w95upg*.dll. This funciton is called in remote mode (i.e., by
  347. migisol.exe). This function must be called after the host has created the
  348. objects with pCreateIpcData.
  349. Arguments:
  350. None.
  351. Return Value:
  352. TRUE of the objects were opened successfully, FALSE otherwise.
  353. --*/
  354. {
  355. ZeroMemory (&g_IpcData, sizeof (g_IpcData));
  356. g_IpcData.DoCommand = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("Setup.DoCommand"));
  357. g_IpcData.GetResults = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("Setup.GetResults"));
  358. g_IpcData.Mapping = OpenFileMapping (
  359. FILE_MAP_READ|FILE_MAP_WRITE,
  360. FALSE,
  361. TEXT("Setup.IpcData")
  362. );
  363. if (!g_IpcData.DoCommand ||
  364. !g_IpcData.GetResults ||
  365. !g_IpcData.Mapping
  366. ) {
  367. pCloseIpcData();
  368. return FALSE;
  369. }
  370. return TRUE;
  371. }
  372. BOOL
  373. IsIpcProcessAlive (
  374. VOID
  375. )
  376. /*++
  377. Routine Description:
  378. IsIpcProcessAlive checks for the presense of migisol.exe. This function is
  379. intended only for host mode.
  380. Arguments:
  381. None.
  382. Return Value:
  383. TRUE if migisol.exe is still running, FALSE otherwise.
  384. --*/
  385. {
  386. if (!g_ProcessHandle) {
  387. return FALSE;
  388. }
  389. if (WaitForSingleObject (g_ProcessHandle, 0) == WAIT_OBJECT_0) {
  390. return FALSE;
  391. }
  392. return TRUE;
  393. }
  394. VOID
  395. KillIpcProcess (
  396. VOID
  397. )
  398. /*++
  399. Routine Description:
  400. KillIpcProcess forcefully terminates an open migisol.exe process. This is
  401. used in GUI mode when the DLL refuses to die.
  402. Arguments:
  403. None.
  404. Return Value:
  405. None.
  406. --*/
  407. {
  408. PushError();
  409. if (IsIpcProcessAlive()) {
  410. TerminateProcess (g_ProcessHandle, 0);
  411. }
  412. PopError();
  413. }
  414. DWORD
  415. CheckForWaitingData (
  416. IN HANDLE Slot,
  417. IN DWORD MinimumSize,
  418. IN DWORD Timeout
  419. )
  420. /*++
  421. Routine Description:
  422. CheckForWaitingData waits for data to be received by a mailslot.
  423. If the data does not arrive within the specified timeout, then zero is
  424. returned, and ERROR_SEM_TIMEOUT is set as the last error.
  425. If the data arrives within the specified timeout, then the number of
  426. waiting bytes are returned to the caller.
  427. This routine works around a Win95 bug with GetMailslotInfo. Please
  428. change with caution.
  429. Arguments:
  430. Slot - Specifies handle to inbound mailslot
  431. MinimumSize - Specifies the number of bytes that must be available before
  432. the routine considers the data to be available. NOTE: If
  433. a message smaller than MinimumSize is waiting, this
  434. routine will be blocked until the timeout expires.
  435. This parameter must be greater than zero.
  436. Timeout - Specifies the number of milliseconds to wait for the message.
  437. Return value:
  438. The number of bytes waiting in the mailslot, or 0 if the timeout was
  439. reached.
  440. --*/
  441. {
  442. DWORD WaitingSize;
  443. DWORD UnreliableTimeout;
  444. DWORD End;
  445. MYASSERT (MinimumSize > 0);
  446. End = GetTickCount() + Timeout;
  447. //
  448. // The wrap case -- this is really rare (once every 27 days),
  449. // so just let the tick count go back to zero
  450. //
  451. if (End < GetTickCount()) {
  452. while (End < GetTickCount()) {
  453. Sleep (100);
  454. }
  455. End = GetTickCount() + Timeout;
  456. }
  457. do {
  458. if (!GetMailslotInfo (Slot, NULL, &WaitingSize, NULL, &UnreliableTimeout)) {
  459. DEBUGMSG ((DBG_ERROR, "CheckForWaitingData: GetMailslotInfo failed (%s)", g_Mode));
  460. return 0;
  461. }
  462. //
  463. // WARNING: Win95 doesn't always return 0xffffffff when there is no data
  464. // available. On some machines, Win9x has returned 0xc0ffffff.
  465. //
  466. WaitingSize = LOWORD(WaitingSize);
  467. if (WaitingSize < 0xffff && WaitingSize >= MinimumSize) {
  468. return WaitingSize;
  469. }
  470. } while (GetTickCount() < End);
  471. SetLastError (ERROR_SEM_TIMEOUT);
  472. return 0;
  473. }
  474. BOOL
  475. pWriteIpcData (
  476. IN HANDLE Mapping,
  477. IN PBYTE Data, OPTIONAL
  478. IN DWORD DataSize,
  479. IN DWORD Command,
  480. IN DWORD ResultCode,
  481. IN DWORD TechnicalLogId,
  482. IN DWORD GuiLogId
  483. )
  484. /*++
  485. Routine Description:
  486. pWriteIpcData puts data in the memory mapped block that migisol.exe and
  487. w95upg*.dll share. The OS takes care of the synchronization for us.
  488. Arguments:
  489. Mapping - Specifies the open mapping object
  490. Data - Specifies binary data to write
  491. DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
  492. Command - Specifies a command DWORD, or 0 if not required
  493. ResultCode - Specifies the result code of the last command, or 0 if not
  494. applicable
  495. TechnicalLogId - Specifies the message constant ID (MSG_*) to be added to
  496. setupact.log, or 0 if not applicable
  497. GuiLogId - Specifies the message constant (MSG_*) of the message to
  498. be presented via a popup, or 0 if not applicable
  499. Return Value:
  500. TRUE if the data was written, FALSE if a sharing violation or other error
  501. occurs
  502. --*/
  503. {
  504. PMAPDATA MapData;
  505. MYASSERT (Mapping);
  506. MapData = (PMAPDATA) MapViewOfFile (Mapping, FILE_MAP_WRITE, 0, 0, 0);
  507. if (!MapData) {
  508. return FALSE;
  509. }
  510. if (!Data) {
  511. DataSize = 0;
  512. }
  513. MapData->Command = Command;
  514. MapData->Result = ResultCode;
  515. MapData->TechnicalLogId = TechnicalLogId;
  516. MapData->GuiLogId = GuiLogId;
  517. MapData->DataSize = DataSize;
  518. if (DataSize) {
  519. CopyMemory (MapData->Data, Data, DataSize);
  520. }
  521. UnmapViewOfFile (MapData);
  522. return TRUE;
  523. }
  524. BOOL
  525. pReadIpcData (
  526. IN HANDLE Mapping,
  527. OUT PBYTE *Data, OPTIONAL
  528. OUT PDWORD DataSize, OPTIONAL
  529. OUT PDWORD Command, OPTIONAL
  530. OUT PDWORD ResultCode, OPTIONAL
  531. OUT PDWORD TechnicalLogId, OPTIONAL
  532. OUT PDWORD GuiLogId OPTIONAL
  533. )
  534. /*++
  535. Routine Description:
  536. pReadIpcData retrieves data put in the shared memory block. The OS takes
  537. care of synchronization for us.
  538. Arguments:
  539. Mapping - Specifies the memory mapping object
  540. Data - Receives the inbound binary data, if any is available, or
  541. NULL if no data is available. The caller must free this
  542. data with MemFree.
  543. DataSize - Receives the number of bytes in Data
  544. Command - Receives the inbound command, or 0 if no command was
  545. specified
  546. ResultCode - Receives the command result code, or 0 if not applicable
  547. TechnicalLogId - Receives the message constant (MSG_*) of the message to be
  548. logged to setupact.log, or 0 if no message is to be logged
  549. GuiLogId - Receives the message constant (MSG_*) of the message to be
  550. presented in a popup, or 0 if no message is to be presented
  551. Return Value:
  552. TRUE if data was read, or FALSE if a sharing violation or other error occurs
  553. --*/
  554. {
  555. PMAPDATA MapData;
  556. MapData = (PMAPDATA) MapViewOfFile (Mapping, FILE_MAP_READ, 0, 0, 0);
  557. if (!MapData) {
  558. return FALSE;
  559. }
  560. if (Data) {
  561. if (MapData->DataSize) {
  562. *Data = MemAlloc (g_hHeap, 0, MapData->DataSize);
  563. MYASSERT (*Data);
  564. CopyMemory (*Data, MapData->Data, MapData->DataSize);
  565. } else {
  566. *Data = NULL;
  567. }
  568. }
  569. if (DataSize) {
  570. *DataSize = MapData->DataSize;
  571. }
  572. if (Command) {
  573. *Command = MapData->Command;
  574. }
  575. if (ResultCode) {
  576. *ResultCode = MapData->Result;
  577. }
  578. if (TechnicalLogId) {
  579. *TechnicalLogId = MapData->TechnicalLogId;
  580. }
  581. if (GuiLogId) {
  582. *GuiLogId = MapData->GuiLogId;
  583. }
  584. UnmapViewOfFile (MapData);
  585. return TRUE;
  586. }
  587. BOOL
  588. SendIpcCommand (
  589. IN DWORD Command,
  590. IN PBYTE Data, OPTIONAL
  591. IN DWORD DataSize
  592. )
  593. /*++
  594. Routine Description:
  595. SendIpcCommand puts a command and optional binary data in the shared memory
  596. block. It then sets the DoCommand event, triggering the other process to
  597. read the shared memory. It is required that a command result is sent
  598. before the next SendIpcCommand. See SendIpcCommandResult.
  599. Arguments:
  600. Command - Specifies the command to be executed by migisol.exe
  601. Data - Specifies the data associated with the command
  602. DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
  603. Return Value:
  604. TRUE if the command was placed in the shared memory block, FALSE otherwise
  605. --*/
  606. {
  607. if (!pWriteIpcData (
  608. g_IpcData.Mapping,
  609. Data,
  610. DataSize,
  611. Command,
  612. 0,
  613. 0,
  614. 0
  615. )) {
  616. DEBUGMSG ((DBG_ERROR, "SendIpcCommand: Can't send the command to the remote process"));
  617. return FALSE;
  618. }
  619. SetEvent (g_IpcData.DoCommand);
  620. return TRUE;
  621. }
  622. BOOL
  623. GetIpcCommandResults (
  624. IN DWORD Timeout,
  625. OUT PBYTE *ReturnData, OPTIONAL
  626. OUT PDWORD ReturnDataSize, OPTIONAL
  627. OUT PDWORD ResultCode, OPTIONAL
  628. OUT PDWORD TechnicalLogId, OPTIONAL
  629. OUT PDWORD GuiLogId OPTIONAL
  630. )
  631. /*++
  632. Routine Description:
  633. GetIpcCommandResults reads the shared memory block and returns the
  634. available data.
  635. Arguments:
  636. Timeout - Specifies the amount of time to wait for a command result
  637. (in ms), or INFINITE to wait forever.
  638. ReturnData - Receives the binary data associated with the command
  639. result, or NULL if no data is associated with the result.
  640. The caller must free this data with MemFree.
  641. ReturnDataSize - Receives the number of bytes in ReturnData, or 0 if
  642. ReturnData is NULL.
  643. ResultCode - Receives the command result code
  644. TechnicalLogId - Receives the message constant (MSG_*) to be logged in
  645. setupact.log, or 0 if no message is specified
  646. GuiLogId - Receives the message constant (MSG_*) of the message to be
  647. presented in a popup, or 0 if no message is to be presented
  648. Return Value:
  649. TRUE if command results were obtained, or FALSE if the wait timed out or
  650. the IPC connection crashed
  651. --*/
  652. {
  653. DWORD rc;
  654. BOOL b;
  655. rc = WaitForSingleObject (g_IpcData.GetResults, Timeout);
  656. if (rc != WAIT_OBJECT_0) {
  657. SetLastError (ERROR_NO_DATA);
  658. return FALSE;
  659. }
  660. b = pReadIpcData (
  661. g_IpcData.Mapping,
  662. ReturnData,
  663. ReturnDataSize,
  664. NULL,
  665. ResultCode,
  666. TechnicalLogId,
  667. GuiLogId
  668. );
  669. return b;
  670. }
  671. BOOL
  672. GetIpcCommand (
  673. IN DWORD Timeout,
  674. IN PDWORD Command, OPTIONAL
  675. IN PBYTE *Data, OPTIONAL
  676. IN PDWORD DataSize OPTIONAL
  677. )
  678. /*++
  679. Routine Description:
  680. GetIpcCommand obtains the command that needs to be processed. This routine
  681. is called by migisol.exe (the remote process).
  682. Arguments:
  683. Timeout - Specifies the amount of time (in ms) to wait for a command, or
  684. INFINITE to wait forever
  685. Command - Receives the command that needs to be executed
  686. Data - Receives the data associated with the command. The caller must
  687. free this block with MemFree.
  688. DataSize - Receives the number of bytes in Data, or 0 if Data is NULL.
  689. Return Value:
  690. TRUE if a command was received, FALSE otherwise.
  691. --*/
  692. {
  693. DWORD rc;
  694. BOOL b;
  695. rc = WaitForSingleObject (g_IpcData.DoCommand, Timeout);
  696. if (rc != WAIT_OBJECT_0) {
  697. SetLastError (ERROR_NO_DATA);
  698. return FALSE;
  699. }
  700. b = pReadIpcData (
  701. g_IpcData.Mapping,
  702. Data,
  703. DataSize,
  704. Command,
  705. NULL,
  706. NULL,
  707. NULL
  708. );
  709. return b;
  710. }
  711. BOOL
  712. SendIpcCommandResults (
  713. IN DWORD ResultCode,
  714. IN DWORD TechnicalLogId,
  715. IN DWORD GuiLogId,
  716. IN PBYTE Data, OPTIONAL
  717. IN DWORD DataSize
  718. )
  719. /*++
  720. Routine Description:
  721. SendIpcCommandResults puts the command results in the shared memory block.
  722. This routine is called by migisol.exe (the remote process).
  723. Arguments:
  724. ResultCode - Specifies the result code of the command.
  725. TechnicalLogId - Specifies the message constant (MSG_*) of the message to
  726. be logged in setupact.log, or 0 if no message is to be
  727. logged
  728. GuiLogId - Specifies the message constant (MSG_*) of the message to
  729. be presented in a popup to the user, or 0 if no message
  730. needs to be presented
  731. Data - Specifies the binary data to pass as command results, or
  732. NULL of no binary data is required
  733. DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
  734. Return Value:
  735. TRUE if the command results were placed in shared memory, FALSE otherwise.
  736. --*/
  737. {
  738. BOOL b;
  739. b = pWriteIpcData (
  740. g_IpcData.Mapping,
  741. Data,
  742. DataSize,
  743. 0,
  744. ResultCode,
  745. TechnicalLogId,
  746. GuiLogId
  747. );
  748. if (!b) {
  749. DEBUGMSG ((DBG_ERROR, "Can't write command results to IPC buffer"));
  750. return FALSE;
  751. }
  752. SetEvent (g_IpcData.GetResults);
  753. return TRUE;
  754. }
  755. BOOL
  756. IsDllSignedA (
  757. IN WINVERIFYTRUST WinVerifyTrustApi,
  758. IN PCSTR DllSpec
  759. )
  760. {
  761. PCWSTR UnicodeStr;
  762. BOOL b;
  763. UnicodeStr = CreateUnicode (DllSpec);
  764. if (!UnicodeStr) {
  765. return FALSE;
  766. }
  767. b = IsDllSignedW (WinVerifyTrustApi, UnicodeStr);
  768. DestroyUnicode (UnicodeStr);
  769. return b;
  770. }
  771. BOOL
  772. IsDllSignedW (
  773. IN WINVERIFYTRUST WinVerifyTrustApi,
  774. IN PCWSTR DllSpec
  775. )
  776. {
  777. GUID VerifyGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  778. WINTRUST_DATA WinTrustData;
  779. WINTRUST_FILE_INFO WinTrustFileInfo;
  780. LONG rc;
  781. if (!WinVerifyTrustApi) {
  782. return TRUE;
  783. }
  784. ZeroMemory (&WinTrustData, sizeof (WinTrustData));
  785. ZeroMemory (&WinTrustFileInfo, sizeof (WinTrustFileInfo));
  786. WinTrustData.cbStruct = sizeof(WINTRUST_DATA);
  787. WinTrustData.dwUIChoice = WTD_UI_NONE;
  788. WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
  789. WinTrustData.pFile = &WinTrustFileInfo;
  790. WinTrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  791. WinTrustFileInfo.hFile = INVALID_HANDLE_VALUE;
  792. WinTrustFileInfo.pcwszFilePath = DllSpec;
  793. rc = WinVerifyTrustApi (
  794. INVALID_HANDLE_VALUE,
  795. &VerifyGuid,
  796. &WinTrustData
  797. );
  798. return rc == ERROR_SUCCESS;
  799. }