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.

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