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
1204 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ipc.c
|
|
|
|
Abstract:
|
|
|
|
The routines in this source file implement an interprocess communication
|
|
mechanism to allow migration DLLs to be isolated into a separate process
|
|
("sandboxing"). This is done so that no DLL can affect the results of
|
|
any other DLL or Setup.
|
|
|
|
The IPC mechanism used here is memory mapped files. Writes to the
|
|
memory mapped file are synchronized by two events, one for the receiver
|
|
and one by the host.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 22-Mar-1997
|
|
|
|
Revision History:
|
|
|
|
jimschm 19-Mar-2001 Removed DVD check (now in migration dll)
|
|
jimschm 02-Jun-1999 Added IPC-based DVD check
|
|
jimschm 21-Sep-1998 Converted from mailslots to memory mapped files.
|
|
(There are bugs in both Win9x and NT mailslots
|
|
that broke the original design.)
|
|
jimschm 19-Jan-1998 Added beginings of WinVerifyTrust calls
|
|
|
|
jimschm 15-Jul-1997 Added many workarounds for Win95 bugs.
|
|
|
|
--*/
|
|
|
|
|
|
#include "pch.h"
|
|
#include "migutilp.h"
|
|
|
|
#include <softpub.h>
|
|
|
|
#ifdef UNICODE
|
|
#error Build must be ANSI
|
|
#endif
|
|
|
|
#define DBG_IPC "Ipc"
|
|
#define SHARED_MEMORY_SIZE 0x10000
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
HANDLE Mapping;
|
|
HANDLE DoCommand;
|
|
HANDLE GetResults;
|
|
} IPCDATA, *PIPCDATA;
|
|
|
|
static PCTSTR g_Mode;
|
|
static HANDLE g_ProcessHandle;
|
|
static BOOL g_Host;
|
|
static IPCDATA g_IpcData;
|
|
|
|
VOID
|
|
pCloseIpcData (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pOpenIpcData (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pCreateIpcData (
|
|
IN PSECURITY_ATTRIBUTES psa
|
|
);
|
|
|
|
typedef struct {
|
|
DWORD Command;
|
|
DWORD Result;
|
|
DWORD TechnicalLogId;
|
|
DWORD GuiLogId;
|
|
DWORD DataSize;
|
|
BYTE Data[];
|
|
} MAPDATA, *PMAPDATA;
|
|
|
|
BOOL
|
|
OpenIpcA (
|
|
IN BOOL Win95Side,
|
|
IN PCSTR ExePath, OPTIONAL
|
|
IN PCSTR RemoteArg, OPTIONAL
|
|
IN PCSTR WorkingDir OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
OpenIpc has two modes of operation, depending on who the caller is. If the
|
|
caller is w95upg.dll or w95upgnt.dll, then the IPC mode is called "host mode."
|
|
If the caller is migisol.exe, then the IPC mode is called "remote mode."
|
|
|
|
In host mode, OpenIpc creates all of the objects necessary to implement
|
|
the IPC. This includes two events, DoCommand and GetResults, and a
|
|
file mapping. After creating the objects, the remote process is launched.
|
|
|
|
In remote mode, OpenIpc opens the existing objects that have already
|
|
been created.
|
|
|
|
Arguments:
|
|
|
|
Win95Side - Used in host mode only. Specifies that w95upg.dll is running
|
|
when TRUE, or that w95upgnt.dll is running when FALSE.
|
|
|
|
ExePath - Specifies the command line for migisol.exe. Specifies NULL
|
|
to indicate remote mode.
|
|
|
|
RemoteArg - Used in host mode only. Specifies the migration DLL
|
|
path. Ignored in remote mode.
|
|
|
|
WorkingDir - Used in host mode only. Specifies the working directory path
|
|
for the migration DLL. Ignored in remote mode.
|
|
|
|
Return value:
|
|
|
|
TRUE if the IPC channel was opened. If host mode, TRUE indicates that
|
|
migisol.exe is up and running. If remote mode, TRUE indicates that
|
|
migisol is ready for commands.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR CmdLine[MAX_CMDLINE];
|
|
STARTUPINFOA si;
|
|
PROCESS_INFORMATION pi;
|
|
BOOL ProcessResult;
|
|
HANDLE SyncEvent = NULL;
|
|
HANDLE ObjectArray[2];
|
|
DWORD rc;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
SECURITY_ATTRIBUTES sa, *psa;
|
|
BOOL Result = FALSE;
|
|
HANDLE hToken = NULL;
|
|
ULONG cbBuffer;
|
|
PTOKEN_USER pUserToken = NULL;
|
|
DWORD dwACLSize;
|
|
PACL pACL = NULL;
|
|
|
|
#ifdef DEBUG
|
|
g_Mode = ExePath ? TEXT("host") : TEXT("remote");
|
|
#endif
|
|
|
|
__try {
|
|
|
|
g_ProcessHandle = NULL;
|
|
|
|
g_Host = (ExePath != NULL);
|
|
|
|
if (ISNT()) {
|
|
//
|
|
// Create all access non-null DACL for NT
|
|
//
|
|
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)){
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:OpenProcessToken failed."));
|
|
__leave;
|
|
}
|
|
cbBuffer = 0;
|
|
if(GetTokenInformation(hToken, TokenUser, NULL, 0, &cbBuffer) ||
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER){
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:GetTokenInformation or GetLastError() != ERROR_INSUFFICIENT_BUFFER failed."));
|
|
__leave;
|
|
|
|
}
|
|
pUserToken = (PTOKEN_USER)MemAlloc(g_hHeap, 0, cbBuffer);
|
|
if(!pUserToken){
|
|
__leave;
|
|
}
|
|
|
|
if(!GetTokenInformation(hToken, TokenUser, pUserToken, cbBuffer, &cbBuffer)){
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:GetTokenInformation failed."));
|
|
__leave;
|
|
}
|
|
|
|
dwACLSize = sizeof(ACCESS_ALLOWED_ACE) + 8 + GetLengthSid(pUserToken->User.Sid) - sizeof(DWORD);
|
|
pACL = (PACL)MemAlloc(g_hHeap, 0, dwACLSize);
|
|
|
|
if(!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)){
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:InitializeAcl failed."));
|
|
__leave;
|
|
}
|
|
|
|
if(!AddAccessAllowedAce(pACL,
|
|
ACL_REVISION,
|
|
GENERIC_ALL | STANDARD_RIGHTS_ALL,
|
|
pUserToken->User.Sid)){
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:AddAccessAllowedAce failed."));
|
|
__leave;
|
|
}
|
|
|
|
ZeroMemory(&sa, sizeof(sa));
|
|
|
|
psd = (PSECURITY_DESCRIPTOR)MemAlloc(g_hHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
if(!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) {
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:InitializeSecurityDescriptor failed."));
|
|
__leave;
|
|
}
|
|
|
|
if(!SetSecurityDescriptorDacl(psd, TRUE, pACL, FALSE)) {
|
|
DEBUGMSG((DBG_ERROR, "OpenIpcA:SetSecurityDescriptorDacl failed."));
|
|
__leave;
|
|
}
|
|
|
|
sa.nLength = sizeof (sa);
|
|
sa.lpSecurityDescriptor = psd;
|
|
|
|
psa = &sa;
|
|
|
|
} else {
|
|
psa = NULL;
|
|
}
|
|
|
|
if (g_Host) {
|
|
//
|
|
// Create the IPC objects
|
|
//
|
|
|
|
if (!pCreateIpcData (psa)) {
|
|
DEBUGMSG ((DBG_ERROR, "Cannot create IPC channel"));
|
|
__leave;
|
|
}
|
|
|
|
MYASSERT (RemoteArg);
|
|
|
|
SyncEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("win9xupg"));
|
|
MYASSERT (SyncEvent);
|
|
|
|
//
|
|
// Create the child process
|
|
//
|
|
|
|
if(FAILED(StringCchPrintfA(
|
|
CmdLine,
|
|
ARRAYSIZE(CmdLine),
|
|
"\"%s\" %s \"%s\"",
|
|
ExePath,
|
|
Win95Side ? "-r" : "-m",
|
|
RemoteArg))
|
|
)
|
|
{
|
|
LOG ((LOG_ERROR, "OpenIpcA: _snprintf cuts cmdline"));
|
|
__leave;
|
|
}
|
|
|
|
ZeroMemory (&si, sizeof (si));
|
|
si.cb = sizeof (si);
|
|
si.dwFlags = STARTF_FORCEOFFFEEDBACK;
|
|
|
|
ProcessResult = CreateProcessA (
|
|
NULL,
|
|
CmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_DEFAULT_ERROR_MODE,
|
|
NULL,
|
|
WorkingDir,
|
|
&si,
|
|
&pi
|
|
);
|
|
|
|
if (ProcessResult) {
|
|
CloseHandle (pi.hThread);
|
|
} else {
|
|
LOG ((LOG_ERROR, "Cannot start %s", CmdLine));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Wait for process to fail or wait for it to set the win95upg event
|
|
//
|
|
|
|
ObjectArray[0] = SyncEvent;
|
|
ObjectArray[1] = pi.hProcess;
|
|
rc = WaitForMultipleObjects (2, ObjectArray, FALSE, 60000);
|
|
g_ProcessHandle = pi.hProcess;
|
|
|
|
if (rc != WAIT_OBJECT_0) {
|
|
DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"Process %x did not signal 'ready'. Wait timed out. (%s)",
|
|
g_ProcessHandle,
|
|
g_Mode
|
|
));
|
|
|
|
LOG ((LOG_ERROR, "Upgrade pack failed during process creation."));
|
|
|
|
__leave;
|
|
}
|
|
|
|
DEBUGMSG ((DBG_IPC, "Process %s is running (%s)", CmdLine, g_Mode));
|
|
|
|
} else { // !g_Host
|
|
//
|
|
// Open the IPC objects
|
|
//
|
|
|
|
if (!pOpenIpcData()) {
|
|
DEBUGMSG ((DBG_ERROR, "Cannot open IPC channel"));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Set event notifying setup that we've created our mailslot
|
|
//
|
|
|
|
SyncEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("win9xupg"));
|
|
if (!SyncEvent) {
|
|
__leave;
|
|
}
|
|
SetEvent (SyncEvent);
|
|
}
|
|
|
|
Result = TRUE;
|
|
}
|
|
|
|
__finally {
|
|
//
|
|
// Cleanup code
|
|
//
|
|
|
|
PushError();
|
|
|
|
if (!Result) {
|
|
CloseIpc();
|
|
}
|
|
|
|
if (SyncEvent) {
|
|
CloseHandle (SyncEvent);
|
|
}
|
|
|
|
if (psd) {
|
|
MemFree (g_hHeap, 0, psd);
|
|
}
|
|
if(hToken){
|
|
CloseHandle(hToken);
|
|
}
|
|
if(pUserToken){
|
|
MemFree(g_hHeap, 0, pUserToken);
|
|
}
|
|
if(pACL){
|
|
MemFree(g_hHeap, 0, pACL);
|
|
}
|
|
|
|
PopError();
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
OpenIpcW (
|
|
IN BOOL Win95Side,
|
|
IN PCWSTR ExePath, OPTIONAL
|
|
IN PCWSTR RemoteArg, OPTIONAL
|
|
IN PCWSTR WorkingDir OPTIONAL
|
|
)
|
|
{
|
|
PCSTR AnsiExePath, AnsiRemoteArg, AnsiWorkingDir;
|
|
BOOL b;
|
|
|
|
if (ExePath) {
|
|
AnsiExePath = ConvertWtoA (ExePath);
|
|
} else {
|
|
AnsiExePath = NULL;
|
|
}
|
|
|
|
if (RemoteArg) {
|
|
AnsiRemoteArg = ConvertWtoA (RemoteArg);
|
|
} else {
|
|
AnsiRemoteArg = NULL;
|
|
}
|
|
|
|
if (WorkingDir) {
|
|
AnsiWorkingDir = ConvertWtoA (WorkingDir);
|
|
} else {
|
|
AnsiWorkingDir = NULL;
|
|
}
|
|
|
|
b = OpenIpcA (Win95Side, AnsiExePath, AnsiRemoteArg, AnsiWorkingDir);
|
|
|
|
if(AnsiExePath){
|
|
FreeConvertedStr (AnsiExePath);
|
|
}
|
|
|
|
if(AnsiRemoteArg){
|
|
FreeConvertedStr (AnsiRemoteArg);
|
|
}
|
|
|
|
if(AnsiWorkingDir){
|
|
FreeConvertedStr (AnsiWorkingDir);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
CloseIpc (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tells migisol.exe process to terminate, and then cleans up all resources
|
|
opened by OpenIpc.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
if (g_Host) {
|
|
//
|
|
// Tell migisol.exe to terminate
|
|
// if the communications channel is up
|
|
//
|
|
if (g_IpcData.Mapping && !SendIpcCommand (IPC_TERMINATE, NULL, 0)) {
|
|
KillIpcProcess();
|
|
}
|
|
|
|
if (g_ProcessHandle) {
|
|
WaitForSingleObject (g_ProcessHandle, 10000);
|
|
}
|
|
}
|
|
|
|
pCloseIpcData();
|
|
|
|
if (g_ProcessHandle) {
|
|
CloseHandle (g_ProcessHandle);
|
|
g_ProcessHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
pCloseIpcData (
|
|
VOID
|
|
)
|
|
{
|
|
if (g_IpcData.DoCommand) {
|
|
CloseHandle (g_IpcData.DoCommand);
|
|
g_IpcData.DoCommand = NULL;
|
|
}
|
|
|
|
if (g_IpcData.GetResults) {
|
|
CloseHandle (g_IpcData.GetResults);
|
|
g_IpcData.GetResults = NULL;
|
|
}
|
|
|
|
if (g_IpcData.Mapping) {
|
|
CloseHandle (g_IpcData.Mapping);
|
|
g_IpcData.Mapping = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCreateIpcData (
|
|
IN PSECURITY_ATTRIBUTES psa
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pCreateIpcData creates the objects necessary to transfer data between
|
|
migisol.exe and w95upg*.dll. This function is called in host mode (i.e.,
|
|
from w95upg.dll or w95upgnt.dll).
|
|
|
|
Arguments:
|
|
|
|
psa - Specifies NT nul DACL, or NULL on Win9x
|
|
|
|
Return Value:
|
|
|
|
TRUE if the objects were created properly, or FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
ZeroMemory (&g_IpcData, sizeof (g_IpcData));
|
|
|
|
g_IpcData.DoCommand = CreateEvent (psa, FALSE, FALSE, TEXT("Setup.DoCommand"));
|
|
g_IpcData.GetResults = CreateEvent (psa, FALSE, FALSE, TEXT("Setup.GetResults"));
|
|
|
|
g_IpcData.Mapping = CreateFileMapping (
|
|
INVALID_HANDLE_VALUE,
|
|
psa,
|
|
PAGE_READWRITE,
|
|
0,
|
|
SHARED_MEMORY_SIZE,
|
|
TEXT("Setup.IpcData")
|
|
);
|
|
|
|
if (!g_IpcData.DoCommand ||
|
|
!g_IpcData.GetResults ||
|
|
!g_IpcData.Mapping
|
|
) {
|
|
pCloseIpcData();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pOpenIpcData (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pOpenIpcData opens objects necessary to transfer data between migisol.exe
|
|
and w95upg*.dll. This funciton is called in remote mode (i.e., by
|
|
migisol.exe). This function must be called after the host has created the
|
|
objects with pCreateIpcData.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE of the objects were opened successfully, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
ZeroMemory (&g_IpcData, sizeof (g_IpcData));
|
|
|
|
g_IpcData.DoCommand = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("Setup.DoCommand"));
|
|
g_IpcData.GetResults = OpenEvent (EVENT_ALL_ACCESS, FALSE, TEXT("Setup.GetResults"));
|
|
|
|
g_IpcData.Mapping = OpenFileMapping (
|
|
FILE_MAP_READ|FILE_MAP_WRITE,
|
|
FALSE,
|
|
TEXT("Setup.IpcData")
|
|
);
|
|
|
|
if (!g_IpcData.DoCommand ||
|
|
!g_IpcData.GetResults ||
|
|
!g_IpcData.Mapping
|
|
) {
|
|
pCloseIpcData();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsIpcProcessAlive (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IsIpcProcessAlive checks for the presense of migisol.exe. This function is
|
|
intended only for host mode.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if migisol.exe is still running, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (!g_ProcessHandle) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (WaitForSingleObject (g_ProcessHandle, 0) == WAIT_OBJECT_0) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
KillIpcProcess (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
KillIpcProcess forcefully terminates an open migisol.exe process. This is
|
|
used in GUI mode when the DLL refuses to die.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PushError();
|
|
|
|
if (IsIpcProcessAlive()) {
|
|
TerminateProcess (g_ProcessHandle, 0);
|
|
}
|
|
|
|
PopError();
|
|
}
|
|
|
|
|
|
DWORD
|
|
CheckForWaitingData (
|
|
IN HANDLE Slot,
|
|
IN DWORD MinimumSize,
|
|
IN DWORD Timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
CheckForWaitingData waits for data to be received by a mailslot.
|
|
|
|
If the data does not arrive within the specified timeout, then zero is
|
|
returned, and ERROR_SEM_TIMEOUT is set as the last error.
|
|
|
|
If the data arrives within the specified timeout, then the number of
|
|
waiting bytes are returned to the caller.
|
|
|
|
This routine works around a Win95 bug with GetMailslotInfo. Please
|
|
change with caution.
|
|
|
|
Arguments:
|
|
|
|
Slot - Specifies handle to inbound mailslot
|
|
|
|
MinimumSize - Specifies the number of bytes that must be available before
|
|
the routine considers the data to be available. NOTE: If
|
|
a message smaller than MinimumSize is waiting, this
|
|
routine will be blocked until the timeout expires.
|
|
This parameter must be greater than zero.
|
|
|
|
Timeout - Specifies the number of milliseconds to wait for the message.
|
|
|
|
Return value:
|
|
|
|
The number of bytes waiting in the mailslot, or 0 if the timeout was
|
|
reached.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD WaitingSize;
|
|
DWORD UnreliableTimeout;
|
|
DWORD End;
|
|
|
|
MYASSERT (MinimumSize > 0);
|
|
|
|
End = GetTickCount() + Timeout;
|
|
|
|
//
|
|
// The wrap case -- this is really rare (once every 27 days),
|
|
// so just let the tick count go back to zero
|
|
//
|
|
|
|
if (End < GetTickCount()) {
|
|
while (End < GetTickCount()) {
|
|
Sleep (100);
|
|
}
|
|
End = GetTickCount() + Timeout;
|
|
}
|
|
|
|
do {
|
|
if (!GetMailslotInfo (Slot, NULL, &WaitingSize, NULL, &UnreliableTimeout)) {
|
|
DEBUGMSG ((DBG_ERROR, "CheckForWaitingData: GetMailslotInfo failed (%s)", g_Mode));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// WARNING: Win95 doesn't always return 0xffffffff when there is no data
|
|
// available. On some machines, Win9x has returned 0xc0ffffff.
|
|
//
|
|
|
|
WaitingSize = LOWORD(WaitingSize);
|
|
|
|
if (WaitingSize < 0xffff && WaitingSize >= MinimumSize) {
|
|
return WaitingSize;
|
|
}
|
|
} while (GetTickCount() < End);
|
|
|
|
SetLastError (ERROR_SEM_TIMEOUT);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pWriteIpcData (
|
|
IN HANDLE Mapping,
|
|
IN PBYTE Data, OPTIONAL
|
|
IN DWORD DataSize,
|
|
IN DWORD Command,
|
|
IN DWORD ResultCode,
|
|
IN DWORD TechnicalLogId,
|
|
IN DWORD GuiLogId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pWriteIpcData puts data in the memory mapped block that migisol.exe and
|
|
w95upg*.dll share. The OS takes care of the synchronization for us.
|
|
|
|
Arguments:
|
|
|
|
Mapping - Specifies the open mapping object
|
|
|
|
Data - Specifies binary data to write
|
|
|
|
DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
|
|
|
|
Command - Specifies a command DWORD, or 0 if not required
|
|
|
|
ResultCode - Specifies the result code of the last command, or 0 if not
|
|
applicable
|
|
|
|
TechnicalLogId - Specifies the message constant ID (MSG_*) to be added to
|
|
setupact.log, or 0 if not applicable
|
|
|
|
GuiLogId - Specifies the message constant (MSG_*) of the message to
|
|
be presented via a popup, or 0 if not applicable
|
|
|
|
Return Value:
|
|
|
|
TRUE if the data was written, FALSE if a sharing violation or other error
|
|
occurs
|
|
|
|
--*/
|
|
|
|
{
|
|
PMAPDATA MapData;
|
|
|
|
if (!Data) {
|
|
MYASSERT(!DataSize);
|
|
DataSize = 0;
|
|
}
|
|
|
|
if((DataSize + sizeof(MAPDATA)) >= SHARED_MEMORY_SIZE){
|
|
return FALSE;
|
|
}
|
|
|
|
MYASSERT (Mapping);
|
|
MapData = (PMAPDATA) MapViewOfFile (Mapping, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (!MapData) {
|
|
return FALSE;
|
|
}
|
|
|
|
MapData->Command = Command;
|
|
MapData->Result = ResultCode;
|
|
MapData->TechnicalLogId = TechnicalLogId;
|
|
MapData->GuiLogId = GuiLogId;
|
|
MapData->DataSize = DataSize;
|
|
|
|
if (DataSize) {
|
|
CopyMemory (MapData->Data, Data, DataSize);
|
|
}
|
|
|
|
UnmapViewOfFile (MapData);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pReadIpcData (
|
|
IN HANDLE Mapping,
|
|
OUT PBYTE *Data, OPTIONAL
|
|
OUT PDWORD DataSize, OPTIONAL
|
|
OUT PDWORD Command, OPTIONAL
|
|
OUT PDWORD ResultCode, OPTIONAL
|
|
OUT PDWORD TechnicalLogId, OPTIONAL
|
|
OUT PDWORD GuiLogId OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pReadIpcData retrieves data put in the shared memory block. The OS takes
|
|
care of synchronization for us.
|
|
|
|
Arguments:
|
|
|
|
Mapping - Specifies the memory mapping object
|
|
|
|
Data - Receives the inbound binary data, if any is available, or
|
|
NULL if no data is available. The caller must free this
|
|
data with MemFree.
|
|
|
|
DataSize - Receives the number of bytes in Data
|
|
|
|
Command - Receives the inbound command, or 0 if no command was
|
|
specified
|
|
|
|
ResultCode - Receives the command result code, or 0 if not applicable
|
|
|
|
TechnicalLogId - Receives the message constant (MSG_*) of the message to be
|
|
logged to setupact.log, or 0 if no message is to be logged
|
|
|
|
GuiLogId - Receives the message constant (MSG_*) of the message to be
|
|
presented in a popup, or 0 if no message is to be presented
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was read, or FALSE if a sharing violation or other error occurs
|
|
|
|
--*/
|
|
|
|
{
|
|
PMAPDATA MapData;
|
|
|
|
MapData = (PMAPDATA) MapViewOfFile (Mapping, FILE_MAP_READ, 0, 0, 0);
|
|
if (!MapData) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Data) {
|
|
if (MapData->DataSize) {
|
|
*Data = MemAlloc (g_hHeap, 0, MapData->DataSize);
|
|
MYASSERT (*Data);
|
|
CopyMemory (*Data, MapData->Data, MapData->DataSize);
|
|
} else {
|
|
*Data = NULL;
|
|
}
|
|
}
|
|
|
|
if (DataSize) {
|
|
*DataSize = MapData->DataSize;
|
|
}
|
|
|
|
if (Command) {
|
|
*Command = MapData->Command;
|
|
}
|
|
|
|
if (ResultCode) {
|
|
*ResultCode = MapData->Result;
|
|
}
|
|
|
|
if (TechnicalLogId) {
|
|
*TechnicalLogId = MapData->TechnicalLogId;
|
|
}
|
|
|
|
if (GuiLogId) {
|
|
*GuiLogId = MapData->GuiLogId;
|
|
}
|
|
|
|
UnmapViewOfFile (MapData);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SendIpcCommand (
|
|
IN DWORD Command,
|
|
IN PBYTE Data, OPTIONAL
|
|
IN DWORD DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
SendIpcCommand puts a command and optional binary data in the shared memory
|
|
block. It then sets the DoCommand event, triggering the other process to
|
|
read the shared memory. It is required that a command result is sent
|
|
before the next SendIpcCommand. See SendIpcCommandResult.
|
|
|
|
Arguments:
|
|
|
|
Command - Specifies the command to be executed by migisol.exe
|
|
|
|
Data - Specifies the data associated with the command
|
|
|
|
DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
|
|
|
|
Return Value:
|
|
|
|
TRUE if the command was placed in the shared memory block, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
if (!pWriteIpcData (
|
|
g_IpcData.Mapping,
|
|
Data,
|
|
DataSize,
|
|
Command,
|
|
0,
|
|
0,
|
|
0
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR, "SendIpcCommand: Can't send the command to the remote process"));
|
|
return FALSE;
|
|
}
|
|
|
|
SetEvent (g_IpcData.DoCommand);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetIpcCommandResults (
|
|
IN DWORD Timeout,
|
|
OUT PBYTE *ReturnData, OPTIONAL
|
|
OUT PDWORD ReturnDataSize, OPTIONAL
|
|
OUT PDWORD ResultCode, OPTIONAL
|
|
OUT PDWORD TechnicalLogId, OPTIONAL
|
|
OUT PDWORD GuiLogId OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetIpcCommandResults reads the shared memory block and returns the
|
|
available data.
|
|
|
|
Arguments:
|
|
|
|
Timeout - Specifies the amount of time to wait for a command result
|
|
(in ms), or INFINITE to wait forever.
|
|
|
|
ReturnData - Receives the binary data associated with the command
|
|
result, or NULL if no data is associated with the result.
|
|
The caller must free this data with MemFree.
|
|
|
|
ReturnDataSize - Receives the number of bytes in ReturnData, or 0 if
|
|
ReturnData is NULL.
|
|
|
|
ResultCode - Receives the command result code
|
|
|
|
TechnicalLogId - Receives the message constant (MSG_*) to be logged in
|
|
setupact.log, or 0 if no message is specified
|
|
|
|
GuiLogId - Receives the message constant (MSG_*) of the message to be
|
|
presented in a popup, or 0 if no message is to be presented
|
|
|
|
Return Value:
|
|
|
|
TRUE if command results were obtained, or FALSE if the wait timed out or
|
|
the IPC connection crashed
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
rc = WaitForSingleObject (g_IpcData.GetResults, Timeout);
|
|
|
|
if (rc != WAIT_OBJECT_0) {
|
|
SetLastError (ERROR_NO_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
b = pReadIpcData (
|
|
g_IpcData.Mapping,
|
|
ReturnData,
|
|
ReturnDataSize,
|
|
NULL,
|
|
ResultCode,
|
|
TechnicalLogId,
|
|
GuiLogId
|
|
);
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetIpcCommand (
|
|
IN DWORD Timeout,
|
|
IN PDWORD Command, OPTIONAL
|
|
IN PBYTE *Data, OPTIONAL
|
|
IN PDWORD DataSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetIpcCommand obtains the command that needs to be processed. This routine
|
|
is called by migisol.exe (the remote process).
|
|
|
|
Arguments:
|
|
|
|
Timeout - Specifies the amount of time (in ms) to wait for a command, or
|
|
INFINITE to wait forever
|
|
|
|
Command - Receives the command that needs to be executed
|
|
|
|
Data - Receives the data associated with the command. The caller must
|
|
free this block with MemFree.
|
|
|
|
DataSize - Receives the number of bytes in Data, or 0 if Data is NULL.
|
|
|
|
Return Value:
|
|
|
|
TRUE if a command was received, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
rc = WaitForSingleObject (g_IpcData.DoCommand, Timeout);
|
|
|
|
if (rc != WAIT_OBJECT_0) {
|
|
SetLastError (ERROR_NO_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
b = pReadIpcData (
|
|
g_IpcData.Mapping,
|
|
Data,
|
|
DataSize,
|
|
Command,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SendIpcCommandResults (
|
|
IN DWORD ResultCode,
|
|
IN DWORD TechnicalLogId,
|
|
IN DWORD GuiLogId,
|
|
IN PBYTE Data, OPTIONAL
|
|
IN DWORD DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
SendIpcCommandResults puts the command results in the shared memory block.
|
|
This routine is called by migisol.exe (the remote process).
|
|
|
|
Arguments:
|
|
|
|
ResultCode - Specifies the result code of the command.
|
|
|
|
TechnicalLogId - Specifies the message constant (MSG_*) of the message to
|
|
be logged in setupact.log, or 0 if no message is to be
|
|
logged
|
|
|
|
GuiLogId - Specifies the message constant (MSG_*) of the message to
|
|
be presented in a popup to the user, or 0 if no message
|
|
needs to be presented
|
|
|
|
Data - Specifies the binary data to pass as command results, or
|
|
NULL of no binary data is required
|
|
|
|
DataSize - Specifies the number of bytes in Data, or 0 if Data is NULL
|
|
|
|
Return Value:
|
|
|
|
TRUE if the command results were placed in shared memory, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
b = pWriteIpcData (
|
|
g_IpcData.Mapping,
|
|
Data,
|
|
DataSize,
|
|
0,
|
|
ResultCode,
|
|
TechnicalLogId,
|
|
GuiLogId
|
|
);
|
|
|
|
if (!b) {
|
|
DEBUGMSG ((DBG_ERROR, "Can't write command results to IPC buffer"));
|
|
return FALSE;
|
|
}
|
|
|
|
SetEvent (g_IpcData.GetResults);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDllSignedA (
|
|
IN WINVERIFYTRUST WinVerifyTrustApi,
|
|
IN PCSTR DllSpec
|
|
)
|
|
{
|
|
PCWSTR UnicodeStr;
|
|
BOOL b;
|
|
|
|
if(!DllSpec){
|
|
MYASSERT(DllSpec);
|
|
return FALSE;
|
|
}
|
|
|
|
UnicodeStr = CreateUnicode (DllSpec);
|
|
if (!UnicodeStr) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = IsDllSignedW (WinVerifyTrustApi, UnicodeStr);
|
|
|
|
DestroyUnicode (UnicodeStr);
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDllSignedW (
|
|
IN WINVERIFYTRUST WinVerifyTrustApi,
|
|
IN PCWSTR DllSpec
|
|
)
|
|
{
|
|
GUID VerifyGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
WINTRUST_DATA WinTrustData;
|
|
WINTRUST_FILE_INFO WinTrustFileInfo;
|
|
LONG rc;
|
|
|
|
if(!DllSpec){
|
|
MYASSERT(DllSpec);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WinVerifyTrustApi) {
|
|
return TRUE;
|
|
}
|
|
|
|
ZeroMemory (&WinTrustData, sizeof (WinTrustData));
|
|
ZeroMemory (&WinTrustFileInfo, sizeof (WinTrustFileInfo));
|
|
|
|
WinTrustData.cbStruct = sizeof(WINTRUST_DATA);
|
|
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
|
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
WinTrustData.pFile = &WinTrustFileInfo;
|
|
|
|
WinTrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
|
WinTrustFileInfo.hFile = INVALID_HANDLE_VALUE;
|
|
WinTrustFileInfo.pcwszFilePath = DllSpec;
|
|
|
|
rc = WinVerifyTrustApi (
|
|
INVALID_HANDLE_VALUE,
|
|
&VerifyGuid,
|
|
&WinTrustData
|
|
);
|
|
|
|
return rc == ERROR_SUCCESS;
|
|
}
|