/*++ 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: --*/ // // Includes // #include "pch.h" #include #include #include #include #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; iKey = (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; }