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.
667 lines
18 KiB
667 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dest.c
|
|
|
|
Abstract:
|
|
|
|
Implements the destination side of the home networking transport
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 01-Jul-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include <winsock.h>
|
|
#include <wsipx.h>
|
|
#include <wsnwlink.h>
|
|
#include <wsnetbs.h>
|
|
#include "homenetp.h"
|
|
|
|
#define DBG_HOMENET "HomeNet"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
#define S_DETAILS_PREFIX TEXT("details-")
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct {
|
|
TCHAR TempFile [MAX_PATH];
|
|
PCVOID AllocPtr;
|
|
PCVOID DetailsPtr;
|
|
HANDLE FileHandle;
|
|
HANDLE MapHandle;
|
|
} ALLOCSTATE, *PALLOCSTATE;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
BOOL g_ConnectionRequested;
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
BOOL
|
|
pHomeNetReadAllImages (
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR imageFile = NULL;
|
|
UINT imageIdx = 1;
|
|
OCABHANDLE cabHandle;
|
|
BOOL result = TRUE;
|
|
|
|
do {
|
|
|
|
imageFile = BuildImageFileName (imageIdx);
|
|
if (!DoesFileExist (imageFile)) {
|
|
FreeImageFileName (imageFile);
|
|
break;
|
|
}
|
|
|
|
cabHandle = CabOpenCabinet (imageFile);
|
|
if (cabHandle) {
|
|
if (!CabExtractAllFiles (cabHandle, g_TransportTempDir)) {
|
|
result = FALSE;
|
|
}
|
|
CabCloseCabinet (cabHandle);
|
|
DeleteFile (imageFile);
|
|
} else {
|
|
result = FALSE;
|
|
}
|
|
|
|
FreeImageFileName (imageFile);
|
|
imageIdx ++;
|
|
|
|
} while (result);
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
pGeneratePassword (
|
|
OUT PSTR Key,
|
|
IN UINT KeySize
|
|
)
|
|
{
|
|
// no ILOilo0 characters
|
|
CHAR validChars[] = "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz123456789";
|
|
DWORD validCharsNr = TcharCountA (validChars);
|
|
HCRYPTPROV hProv = 0;
|
|
UINT i;
|
|
|
|
if (!CryptAcquireContext (&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
CryptGenRandom (hProv, KeySize, (LPBYTE)Key);
|
|
for (i=0; i<KeySize; i++) {
|
|
Key[i] = validChars[Key[i] % validCharsNr];
|
|
}
|
|
|
|
if (hProv) {
|
|
CryptReleaseContext (hProv, 0);
|
|
hProv = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD WINAPI
|
|
DisplayPasswordProc (
|
|
LPVOID lpParameter // thread data
|
|
)
|
|
{
|
|
PPASSWORD_DATA passwordData;
|
|
|
|
passwordData = (PPASSWORD_DATA) lpParameter;
|
|
|
|
IsmSendMessageToApp (TRANSPORTMESSAGE_NET_DISPLAY_PASSWORD, (ULONG_PTR)passwordData);
|
|
|
|
if (passwordData) {
|
|
IsmReleaseMemory (passwordData);
|
|
}
|
|
|
|
ExitThread (0);
|
|
}
|
|
|
|
HANDLE
|
|
pDisplayPassword (
|
|
IN PCSTR Key,
|
|
IN HANDLE Event
|
|
)
|
|
{
|
|
PPASSWORD_DATA passwordData;
|
|
DWORD threadId;
|
|
|
|
passwordData = IsmGetMemory (sizeof (PASSWORD_DATA));
|
|
if (!passwordData) {
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMemory (passwordData, sizeof (PASSWORD_DATA));
|
|
passwordData->Key = (PSTR)Key;
|
|
passwordData->KeySize = 0;
|
|
passwordData->Event = Event;
|
|
|
|
return CreateThread (
|
|
NULL,
|
|
0,
|
|
DisplayPasswordProc,
|
|
(LPVOID)(passwordData),
|
|
0,
|
|
&threadId
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportBeginApply (
|
|
VOID
|
|
)
|
|
{
|
|
ERRUSER_EXTRADATA extraData;
|
|
DWORD status = 0;
|
|
PCTSTR memDbFile;
|
|
BOOL b = FALSE;
|
|
DWORD msg;
|
|
UINT fileNumber = 0;
|
|
LONGLONG numerator;
|
|
LONGLONG divisor;
|
|
LONGLONG tick;
|
|
UINT delta;
|
|
HANDLE event = NULL;
|
|
HANDLE thread = NULL;
|
|
DWORD waitResult;
|
|
PBYTE buffer;
|
|
|
|
g_Platform = PLATFORM_DESTINATION;
|
|
|
|
ZeroMemory (&extraData, sizeof (ERRUSER_EXTRADATA));
|
|
extraData.Error = ERRUSER_ERROR_UNKNOWN;
|
|
|
|
__try {
|
|
//
|
|
// Download the image
|
|
//
|
|
|
|
if (g_BackgroundThread) {
|
|
WaitForSingleObject (g_BackgroundThread, INFINITE);
|
|
} else {
|
|
g_ConnectionRequested = ConnectToSource (&g_Connection, &g_Metrics);
|
|
}
|
|
|
|
if (!g_ConnectionRequested) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_CONNECT_TO_SOURCE));
|
|
extraData.Error = ERRUSER_ERROR_CANTFINDSOURCE;
|
|
__leave;
|
|
}
|
|
|
|
// now we connected to the source. Let's pop up a dialog showing a randomly generated
|
|
// password and ask the user to type the password on the source machine.
|
|
if (!pGeneratePassword (g_GlobalKey, GLOBALKEY_SIZE)) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
|
|
extraData.Error = ERRUSER_ERROR_NOENCRYPTION;
|
|
__leave;
|
|
}
|
|
|
|
event = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
|
|
thread = pDisplayPassword (g_GlobalKey, event);
|
|
|
|
// Let's wait for the first message (should be MESSAGE_PASSWORD);
|
|
do {
|
|
msg = ReceiveFromSource (&g_Connection, NULL, &buffer, 1000);
|
|
|
|
if (msg == MESSAGE_DATA) {
|
|
if (buffer && StringMatchA (g_GlobalKey, buffer)) {
|
|
// This is it, the key is correct
|
|
SetEvent (event);
|
|
SendMessageToDestination (&g_Connection, MESSAGE_PASSWORDOK);
|
|
} else {
|
|
msg = 0;
|
|
SendMessageToDestination (&g_Connection, MESSAGE_PASSWORDWRONG);
|
|
}
|
|
if (buffer) {
|
|
HeapFree (g_hHeap, 0, buffer);
|
|
}
|
|
}
|
|
|
|
if (msg == MESSAGE_CANCEL) {
|
|
// The source computer cancelled
|
|
SetEvent (event);
|
|
}
|
|
|
|
waitResult = WaitForSingleObject (thread, 0);
|
|
|
|
} while ((waitResult == WAIT_TIMEOUT) && (msg != MESSAGE_DATA) && (msg != MESSAGE_CANCEL));
|
|
|
|
if (thread) {
|
|
waitResult = WaitForSingleObject (thread, 5000);
|
|
if (waitResult == WAIT_TIMEOUT) {
|
|
TerminateThread (thread, 0);
|
|
}
|
|
CloseHandle (thread);
|
|
thread = NULL;
|
|
}
|
|
|
|
if (event) {
|
|
CloseHandle (event);
|
|
event = NULL;
|
|
}
|
|
|
|
if (msg != MESSAGE_DATA) {
|
|
// the user cancelled
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_CONNECT_TO_SOURCE));
|
|
extraData.Error = ERRUSER_ERROR_CANTFINDSOURCE;
|
|
__leave;
|
|
}
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Receiving from source"));
|
|
|
|
do {
|
|
msg = ReceiveFromSource (&g_Connection, g_TransportTempDir, NULL, 0);
|
|
|
|
if (msg == MESSAGE_FILE) {
|
|
//
|
|
// Tick the progress bar
|
|
//
|
|
|
|
fileNumber++;
|
|
|
|
numerator = (LONGLONG) fileNumber * (LONGLONG) g_DownloadSliceSize;
|
|
divisor = (LONGLONG) g_Metrics.FileCount;
|
|
if (divisor) {
|
|
tick = numerator / divisor;
|
|
} else {
|
|
tick = 0;
|
|
}
|
|
|
|
delta = (UINT) tick - g_DownloadTicks;
|
|
|
|
if (delta) {
|
|
IsmTickProgressBar (g_DownloadSlice, delta);
|
|
}
|
|
}
|
|
|
|
} while (msg && msg != MESSAGE_DONE);
|
|
|
|
if (msg != MESSAGE_DONE) {
|
|
if (GetLastError () == ERROR_DISK_FULL) {
|
|
// we just failed because we don't have enough space on the destination
|
|
// path. Let's tell that to the user
|
|
extraData.Error = ERRUSER_ERROR_CANTCREATECABFILE;
|
|
} else {
|
|
extraData.Error = ERRUSER_ERROR_CANTRECEIVEFROMSOURCE;
|
|
}
|
|
PushError ();
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_TRANSFER_INCOMPLETE));
|
|
CloseConnection (&g_Connection);
|
|
PopError ();
|
|
__leave;
|
|
}
|
|
|
|
SendMessageToDestination (&g_Connection, MESSAGE_DONE);
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Image transfer finished"));
|
|
|
|
//
|
|
// Now process the image
|
|
//
|
|
|
|
status = GetTransportStatus (g_StatusFile, &g_CompressData);
|
|
|
|
if (status != TRSTATUS_READY) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INVALID_DOWNLOAD));
|
|
extraData.Error = ERRUSER_ERROR_INVALIDDATARECEIVED;
|
|
__leave;
|
|
}
|
|
|
|
g_StatusFileHandle = BfOpenFile (g_StatusFile);
|
|
if (g_StatusFileHandle == INVALID_HANDLE_VALUE) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_OPEN_STATUS_FILE, g_StatusFile));
|
|
extraData.Error = ERRUSER_ERROR_INVALIDDATARECEIVED;
|
|
__leave;
|
|
}
|
|
|
|
if (g_CompressData) {
|
|
b = pHomeNetReadAllImages ();
|
|
} else {
|
|
b = TRUE;
|
|
}
|
|
|
|
if (b) {
|
|
memDbFile = AllocStorageFileName (S_TRANSPORT_DAT_FILE);
|
|
b = MemDbLoad (memDbFile);
|
|
FreeStorageFileName (memDbFile);
|
|
}
|
|
|
|
if (!b) {
|
|
extraData.Error = ERRUSER_ERROR_CANTREADIMAGE;
|
|
}
|
|
}
|
|
__finally {
|
|
}
|
|
|
|
if (!b) {
|
|
PushError ();
|
|
extraData.ErrorArea = ERRUSER_AREA_LOAD;
|
|
IsmSendMessageToApp (MODULEMESSAGE_DISPLAYERROR, (ULONG_PTR)(&extraData));
|
|
PopError ();
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
HomeNetTransportEndApply (
|
|
VOID
|
|
)
|
|
{
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
|
|
CloseConnection (&g_Connection);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportAcquireObject (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN MIG_OBJECTSTRINGHANDLE ObjectName,
|
|
OUT PMIG_CONTENT ObjectContent, CALLER_INITIALIZED
|
|
IN MIG_CONTENTTYPE ContentType,
|
|
IN UINT MemoryContentLimit
|
|
)
|
|
{
|
|
UINT value;
|
|
PCBYTE memValue;
|
|
UINT memValueSize;
|
|
PCTSTR fileValue = NULL;
|
|
BOOL valueInFile;
|
|
KEYHANDLE keyHandle;
|
|
PALLOCSTATE allocState;
|
|
PCTSTR detailsKey = NULL;
|
|
PBYTE details;
|
|
UINT detailsSize;
|
|
PCTSTR sourceFile;
|
|
PCTSTR decoratedObject = NULL;
|
|
HANDLE fileHandle;
|
|
BOOL result = FALSE;
|
|
|
|
if (!ObjectContent) {
|
|
return FALSE;
|
|
}
|
|
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
MYASSERT ((ObjectTypeId & PLATFORM_MASK) == PLATFORM_SOURCE);
|
|
|
|
decoratedObject = BuildDecoratedObject (ObjectTypeId, ObjectName);
|
|
|
|
allocState = (PALLOCSTATE) MemAllocZeroed (sizeof (ALLOCSTATE));
|
|
|
|
if (MemDbGetValue (decoratedObject, &value)) {
|
|
if (value == TRFLAG_FILE) {
|
|
valueInFile = TRUE;
|
|
keyHandle = MemDbGetSingleLinkage (decoratedObject, 0, 0);
|
|
if (keyHandle) {
|
|
fileValue = MemDbGetKeyFromHandle (keyHandle, 0);
|
|
result = fileValue != NULL;
|
|
} else {
|
|
fileValue = NULL;
|
|
result = TRUE;
|
|
}
|
|
} else if (value == TRFLAG_MEMORY) {
|
|
valueInFile = FALSE;
|
|
memValueSize = 0;
|
|
memValue = MemDbGetUnorderedBlob (decoratedObject, 0, &memValueSize);
|
|
result = TRUE;
|
|
} else {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_UNSUPPORTED_DATA, value));
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
}
|
|
if (result) {
|
|
result = FALSE;
|
|
|
|
if (valueInFile) {
|
|
if ((ContentType == CONTENTTYPE_ANY) ||
|
|
(ContentType == CONTENTTYPE_FILE) ||
|
|
(ContentType == CONTENTTYPE_DETAILS_ONLY)
|
|
) {
|
|
// this is stored as a file and it's wanted as a file
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
if (fileValue) {
|
|
ObjectContent->FileContent.ContentPath = AllocStorageFileName (fileValue);
|
|
ObjectContent->FileContent.ContentSize = BfGetFileSize (ObjectContent->FileContent.ContentPath);
|
|
} else {
|
|
ObjectContent->FileContent.ContentSize = 0;
|
|
ObjectContent->FileContent.ContentPath = NULL;
|
|
}
|
|
result = TRUE;
|
|
} else {
|
|
// this is stored as a file and it's wanted as memory
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = FALSE;
|
|
if (fileValue) {
|
|
sourceFile = AllocStorageFileName (fileValue);
|
|
ObjectContent->MemoryContent.ContentSize = (UINT) BfGetFileSize (sourceFile);
|
|
ObjectContent->MemoryContent.ContentBytes = MapFileIntoMemory (
|
|
sourceFile,
|
|
&allocState->FileHandle,
|
|
&allocState->MapHandle
|
|
);
|
|
FreeStorageFileName (sourceFile);
|
|
result = (ObjectContent->MemoryContent.ContentBytes != NULL);
|
|
} else {
|
|
ObjectContent->MemoryContent.ContentSize = 0;
|
|
ObjectContent->MemoryContent.ContentBytes = NULL;
|
|
result = TRUE;
|
|
}
|
|
}
|
|
MemDbReleaseMemory (fileValue);
|
|
} else {
|
|
if ((ContentType == CONTENTTYPE_ANY) ||
|
|
(ContentType == CONTENTTYPE_MEMORY) ||
|
|
(ContentType == CONTENTTYPE_DETAILS_ONLY)
|
|
) {
|
|
// this is stored as memory and it's wanted as memory
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = FALSE;
|
|
ObjectContent->MemoryContent.ContentSize = memValueSize;
|
|
ObjectContent->MemoryContent.ContentBytes = memValue;
|
|
result = TRUE;
|
|
} else {
|
|
// this is stored as memory and it's wanted as a file
|
|
if (memValue) {
|
|
if (IsmGetTempFile (allocState->TempFile, ARRAYSIZE(allocState->TempFile))) {
|
|
fileHandle = BfCreateFile (allocState->TempFile);
|
|
if (fileHandle) {
|
|
if (BfWriteFile (fileHandle, memValue, memValueSize)) {
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
ObjectContent->FileContent.ContentSize = memValueSize;
|
|
ObjectContent->FileContent.ContentPath = DuplicatePathString (allocState->TempFile, 0);
|
|
result = TRUE;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
}
|
|
}
|
|
MemDbReleaseMemory (memValue);
|
|
} else {
|
|
ObjectContent->ObjectTypeId = ObjectTypeId;
|
|
ObjectContent->ContentInFile = TRUE;
|
|
ObjectContent->FileContent.ContentSize = 0;
|
|
ObjectContent->FileContent.ContentPath = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
}
|
|
|
|
if (result) {
|
|
//
|
|
// Fill the details
|
|
//
|
|
|
|
detailsKey = JoinText (S_DETAILS_PREFIX, decoratedObject);
|
|
|
|
details = MemDbGetUnorderedBlob (detailsKey, 0, &detailsSize);
|
|
|
|
if (!details) {
|
|
detailsSize = 0;
|
|
}
|
|
|
|
allocState->DetailsPtr = details;
|
|
|
|
ObjectContent->Details.DetailsSize = detailsSize;
|
|
ObjectContent->Details.DetailsData = details;
|
|
|
|
FreeText (detailsKey);
|
|
|
|
ObjectContent->TransHandle = allocState;
|
|
}
|
|
|
|
if (!result) {
|
|
FreeAlloc (allocState);
|
|
}
|
|
|
|
DestroyDecoratedObject (decoratedObject);
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportReleaseObject (
|
|
IN OUT PMIG_CONTENT ObjectContent
|
|
)
|
|
{
|
|
PALLOCSTATE allocState;
|
|
|
|
MYASSERT (g_Platform == PLATFORM_DESTINATION);
|
|
|
|
allocState = (PALLOCSTATE) ObjectContent->TransHandle;
|
|
|
|
if (ObjectContent->ContentInFile) {
|
|
FreeStorageFileName (ObjectContent->FileContent.ContentPath);
|
|
if (allocState && allocState->TempFile[0]) {
|
|
DeleteFile (allocState->TempFile);
|
|
}
|
|
} else {
|
|
if (allocState && allocState->FileHandle && allocState->MapHandle) {
|
|
UnmapFile (
|
|
ObjectContent->MemoryContent.ContentBytes,
|
|
allocState->MapHandle,
|
|
allocState->FileHandle
|
|
);
|
|
} else {
|
|
MemDbReleaseMemory (ObjectContent->MemoryContent.ContentBytes);
|
|
}
|
|
}
|
|
|
|
if (allocState && allocState->DetailsPtr) {
|
|
MemDbReleaseMemory (allocState->DetailsPtr);
|
|
}
|
|
|
|
FreeAlloc (allocState);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
DestinationBackgroundThread (
|
|
PVOID DontCare
|
|
)
|
|
{
|
|
BOOL connect;
|
|
ULONG_PTR result;
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Destination background thread is running"));
|
|
|
|
for (;;) {
|
|
connect = ConnectToSource (&g_Connection, &g_Metrics);
|
|
|
|
if (connect) {
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Asking app if connection is acceptable"));
|
|
|
|
result = IsmSendMessageToApp (TRANSPORTMESSAGE_READY_TO_CONNECT, (ULONG_PTR) g_Metrics.SourceName);
|
|
|
|
if (result == APPRESPONSE_FAIL) {
|
|
DEBUGMSG ((DBG_HOMENET, "App says NO!"));
|
|
CloseConnection (&g_Connection);
|
|
continue;
|
|
}
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "App says YES!"));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
g_ConnectionRequested = connect;
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Destination background thread is complete"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|