#define NTDDI_VERSION NTDDI_VISTA #define WINVER 0x0602 #define _WIN32_WINNT 0x0602 #define WIN32_LEAN_AND_MEAN #define _UNICODE #define UNICODE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_GUID(ID_IAudioEndpointVolume, 0x5CDF2C82, 0x841E, 0x4546, 0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A); DEFINE_GUID(ID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); DEFINE_GUID(ID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E); #define WM_SOCKDATA (WM_APP+1) typedef struct { const char* path; const char* letter; const char* shortcut; const char* user; const char* pass; BOOL success; } netdrive_t; static const ssize_t KEYLEN = 16; #define DRIVEMAX (100) #define LOGFILELEN (300) #define SETTINGS_FILE "B:\\OPENSLX.INI" #define SETTINGS_FILE_W L"B:\\OPENSLX.INI" static OSVERSIONINFO winVer; static BOOL bGetShares = FALSE; static netdrive_t drives[DRIVEMAX]; static wchar_t desktopPath[MAX_PATH+1], tempPath[MAX_PATH+1], programsPath[MAX_PATH+1], windowsPath[MAX_PATH+1]; static wchar_t logFile[LOGFILELEN]; static DWORD _startTime; #define FS_UNKNOWN (-1) #define FS_ERROR (0) #define FS_OK (1) static int _folderStatus = FS_UNKNOWN; // -1 = Not handled yet, 0 = patching failed, 1 = remapped ok #define RM_NONE (0) #define RM_NATIVE (1) #define RM_NATIVE_FALLBACK (2) #define RM_VMWARE (3) static int _remapMode = RM_NONE; static const char* _remapHomeDrive = NULL; struct { BOOL documents; BOOL downloads; BOOL desktop; BOOL media; BOOL other; } remap; static BOOL _createMissingRemap = FALSE; static int setResolution(); static int muteSound(); static int setShutdownText(); static void readShareFile(); static BOOL mountNetworkShares(); static int queryPasswordDaemon(); static BOOL fileExists(wchar_t* szPath); static BOOL folderExists(wchar_t* szPath); static void patchUserPaths(wchar_t *letter); static void remapViaSharedFolder(); static HRESULT createFolderShortcut(wchar_t* sTargetfile, wchar_t* sLinkfile, wchar_t* comment); static void alog(const char *fmt, ...) { FILE *f = _wfopen(logFile, L"a+"); if (f == NULL) return; time_t raw = time(NULL); struct tm *tinf; char buffer[80]; tinf = localtime(&raw); strftime(buffer, 80, "%I:%M:%S ", tinf); fputs(buffer, f); va_list args; va_start(args, fmt); vfprintf(f, fmt, args); va_end(args); fputc('\n', f); fclose(f); } static void wlog(const wchar_t *fmt, ...) { wchar_t wbuffer[1000]; char abuffer[1000]; va_list args; FILE *f = _wfopen(logFile, L"a+"); if (f == NULL) return; time_t raw = time(NULL); struct tm *tinf; tinf = localtime(&raw); strftime(abuffer, 1000, "%I:%M:%S ", tinf); fputs(abuffer, f); va_start(args, fmt); StringCchVPrintfW(wbuffer, 1000, fmt, args); va_end(args); if (WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, abuffer, 1000, NULL, NULL) == 0) { snprintf(abuffer, 1000, "Cannot wlog: widechar to utf8 failed."); } fputs(abuffer, f); fputc('\n', f); fclose(f); } static void CALLBACK resetShutdown(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { static BOOL bInProc = FALSE; if (!bInProc) { bInProc = TRUE; setShutdownText(); bInProc = FALSE; } } static void CALLBACK tmrResolution(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { static BOOL bInProc = FALSE; if (!bInProc) { bInProc = TRUE; if (setResolution() == 0) { KillTimer(hWnd, idEvent); } bInProc = FALSE; } } static void CALLBACK setupNetworkDrives(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { static BOOL bInProc = FALSE; static int fails = 0; if (bInProc) return; bInProc = TRUE; if (!bGetShares && (_remapMode == RM_NATIVE_FALLBACK || _remapMode == RM_VMWARE)) { remapViaSharedFolder(); } else { int ret = queryPasswordDaemon(); if (ret != 0) { if (++fails < 10) goto exit_func; alog("queryPasswordDaemon returned %d", ret); } else { if (!mountNetworkShares()) { if (GetTickCount() - _startTime < 30000 && ++fails < 15) goto exit_func; } } // Finished successfully or failed completely if (_folderStatus != FS_OK && (_remapMode == RM_NATIVE_FALLBACK || _remapMode == RM_VMWARE)) { remapViaSharedFolder(); } } KillTimer(hWnd, idEvent); if (_remapMode != RM_NONE) { if (_folderStatus == FS_ERROR) { MessageBoxA(NULL, "Fehler beim Einbinden des Home-Verzeichnisses. Bitte nichts Wichtiges in der VM speichern, sondern z.B. einen USB-Stick verwenden.", "Warnung", MB_ICONERROR); } else if (_folderStatus == FS_UNKNOWN) { MessageBoxA(NULL, "Kein Home-Verzeichnis gefunden. Bitte nichts Wichtiges in der VM speichern, sondern z.B. einen USB-Stick verwenden.", "Warnung", MB_ICONERROR); } } return; exit_func: bInProc = FALSE; } static void loadPaths() { // Determine a couple of default directories if (SHGetFolderPathW(HWND_DESKTOP, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, programsPath) != S_OK) { DWORD ret = GetEnvironmentVariableW(L"ProgramFiles", programsPath, MAX_PATH+1); if (ret == 0 || ret > MAX_PATH) { StringCchPrintfW(programsPath, MAX_PATH+1, L"C:\\Program Files"); } } if (SHGetFolderPathW(HWND_DESKTOP, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, windowsPath) != S_OK) { DWORD ret = GetEnvironmentVariableW(L"windir", windowsPath, MAX_PATH+1); if (ret == 0 || ret > MAX_PATH) { StringCchPrintfW(windowsPath, MAX_PATH+1, L"C:\\WINDOWS"); } } if (SHGetFolderPathW(HWND_DESKTOP, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, desktopPath) != S_OK) { desktopPath[0] = 0; } if (GetTempPathW(MAX_PATH+1, tempPath) == 0) { tempPath[0] = 0; } StringCchPrintfW(logFile, LOGFILELEN, L"%s\\%s", desktopPath, L"openslx.log"); FILE *tfh = _wfopen(logFile, L"a+"); if (tfh == NULL) { StringCchPrintfW(logFile, LOGFILELEN, L"%s\\%s", tempPath, L"openslx.log"); tfh = _wfopen(logFile, L"a+"); } if (tfh != NULL) { fseek(tfh, 0, SEEK_END); long pos = ftell(tfh); fclose(tfh); if (pos < 3) { _wremove(logFile); } } // Read settings from ini file remap.documents = GetPrivateProfileIntA("remap", "documents", 1, SETTINGS_FILE) != 0; remap.downloads = GetPrivateProfileIntA("remap", "downloads", 1, SETTINGS_FILE) != 0; remap.desktop = GetPrivateProfileIntA("remap", "desktop", 0, SETTINGS_FILE) != 0; remap.media = GetPrivateProfileIntA("remap", "media", 1, SETTINGS_FILE) != 0; remap.other = GetPrivateProfileIntA("remap", "other", 0, SETTINGS_FILE) != 0; _createMissingRemap = GetPrivateProfileIntA("openslx", "createMissingRemap", 1, SETTINGS_FILE) != 0; _remapMode = GetPrivateProfileIntA("openslx", "remapMode", RM_NATIVE_FALLBACK, SETTINGS_FILE); if (_remapMode == RM_NONE) { _folderStatus = FS_OK; } char buffer[10]; GetPrivateProfileStringA("openslx", "homeDrive", "H:", buffer, sizeof(buffer), SETTINGS_FILE); buffer[0] = toupper(buffer[0]); buffer[1] = ':'; buffer[2] = '\0'; _remapHomeDrive = strdup(buffer); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { winVer.dwOSVersionInfoSize = sizeof(winVer); BOOL retVer = GetVersionEx(&winVer); CoInitialize(NULL); _startTime = GetTickCount(); loadPaths(); if (lpCmdLine != NULL && strstr(lpCmdLine, "debug") != NULL) { alog("Windows Version %d.%d", (int)winVer.dwMajorVersion, (int)winVer.dwMinorVersion); } // Mute sound by default if (retVer && winVer.dwMajorVersion >= 6) muteSound(); // Disable screen saver as it might give the false impression that the session is securely locked SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); // Disable standby and idle-mode (this is a VM!) if (winVer.dwMajorVersion >= 6) { // Vista+ SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_AWAYMODE_REQUIRED); } else { // XP/2003 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); } // Any network shares to mount? readShareFile(); if (bGetShares || _remapMode != RM_NONE) { UINT_PTR tRet = SetTimer(NULL, 0, 1550, (TIMERPROC)&setupNetworkDrives); if (tRet == 0) { alog("Could not create timer for mounting network shares: %d", (int)GetLastError()); } } // Shutdown button label if (retVer && winVer.dwMajorVersion == 6 && winVer.dwMinorVersion == 1) { // Only on Windows 7 // Repeatedly set caption UINT_PTR tRet = SetTimer(NULL, 0, 5230, (TIMERPROC)&resetShutdown); if (tRet == 0) { alog("Could not create timer for shutdown button: %d", (int)GetLastError()); } } // Resolution if (fileExists(SETTINGS_FILE_W) && setResolution() != 0) { UINT_PTR tRet = SetTimer(NULL, 0, 3111, (TIMERPROC)&tmrResolution); if (tRet == 0) { alog("Could not create timer for resolution setting: %d", (int)GetLastError()); } } // Message pump MSG Msg; while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return 0; } static BOOL fileExists(wchar_t* szPath) { DWORD dwAttrib = GetFileAttributesW(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0); } static BOOL folderExists(wchar_t* szPath) { DWORD dwAttrib = GetFileAttributesW(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } static int execute(wchar_t *path, wchar_t *arguments) { STARTUPINFOW si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); si.cb = sizeof(si); if (!CreateProcessW(path, arguments, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { return -1; } while (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_SENDMESSAGE) == WAIT_OBJECT_0+1) { MSG Msg; while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } } DWORD exitCode; BOOL ret = GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (!ret) { return -2; } return (int)exitCode; } static int setResolution() { int ret; static int width = 0, height = 0; if (width == 0 && height == 0) { // use config file in floppy char data[200] = ""; GetPrivateProfileStringA("openslx", "resolution", "", data, sizeof(data), SETTINGS_FILE); char *x = strchr(data, 'x'); if (x == NULL) { alog("Malformed resolution in " SETTINGS_FILE ": '%s'", data); return 0; } *x++ = '\0'; width = atoi(data); height = atoi(x); if (width < 320 || height < 240) { alog("Invalid resolution in " SETTINGS_FILE ": '%s' (parsed width=%d, height=%d)", data, width, height); return 0; } } // Try vmware tools static wchar_t path[MAX_PATH] = L""; if (path[0] == 0) { StringCchPrintfW(path, MAX_PATH, L"%s\\VMware\\VMware Tools\\VMwareResolutionSet.exe", programsPath); if (!fileExists(path)) { // Strip (x86) if found and try again wchar_t *x86 = wcsstr(path, L" (x86)"); if (x86 != NULL) { while ((*x86 = *(x86 + 6)) != 0) ++x86; } } if (!fileExists(path)) { char buffer[300]; WideCharToMultiByte(CP_UTF8, 0, path, -1, buffer, 300, NULL, NULL); alog("vmware tools not found, using winapi to set resolution (path: %s)", buffer); } } if (path[0] != 0 && fileExists(path)) { wchar_t cmdline[MAX_PATH]; StringCchPrintfW(cmdline, MAX_PATH, L"VMwareResolutionSet.exe 0 1 , 0 0 %d %d", width, height); int ret = execute(path, cmdline); if (ret == -1) { alog("VmwareRes: CreateProcess failed (%d)", (int)GetLastError()); } else if (ret == -2) { alog("VmwareRes: GetExitCode failed (%d)", (int)GetLastError()); } } // Use WinAPI as fallback DEVMODE mode; int query = 1337; memset(&mode, 0, sizeof(mode)); mode.dmSize = sizeof(mode); // MSDN recommends to fill the struct first by querying.... query = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode); // Then set our own desired mode mode.dmPelsWidth = width; mode.dmPelsHeight = height; mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; ret = ChangeDisplaySettings(&mode, CDS_GLOBAL | CDS_UPDATEREGISTRY); if (ret != DISP_CHANGE_SUCCESSFUL) { ret = ChangeDisplaySettings(&mode, CDS_GLOBAL); } if (ret != DISP_CHANGE_SUCCESSFUL) { ret = ChangeDisplaySettings(&mode, CDS_UPDATEREGISTRY); } if (ret != DISP_CHANGE_SUCCESSFUL) { ret = ChangeDisplaySettings(&mode, 0); } if (ret != DISP_CHANGE_SUCCESSFUL) { static int fails = 0; if (++fails == 5) { alog("Fehler beim Setzen der Auflösung: %d (soll: 0) / %d ( soll: !0) - Zielaufloesung: %d * %d", ret, query, width, height); } return 1; } return 0; } static int muteSound() { IMMDeviceEnumerator *deviceEnumerator = NULL; HRESULT hr = CoCreateInstance(&ID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &ID_IMMDeviceEnumerator, (LPVOID *)&deviceEnumerator); if (hr != S_OK) { alog("CoCreateInstance failed. Cannot mute."); return 1; } //deviceEnumerator->lpVtbl->AddRef(deviceEnumerator); IMMDevice *defaultDevice = NULL; hr = deviceEnumerator->lpVtbl->GetDefaultAudioEndpoint(deviceEnumerator, eRender, eConsole, &defaultDevice); if (hr != S_OK) { alog("GetDefaultAudioEndpoint failed. Cannot mute."); return 2; } //defaultDevice->lpVtbl->AddRef(defaultDevice); //deviceEnumerator->lpVtbl->Release(deviceEnumerator); IAudioEndpointVolume *endpointVolume = NULL; hr = defaultDevice->lpVtbl->Activate(defaultDevice, &ID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume); if (hr != S_OK) { alog("IMMDevice::Activate() failed. Cannot mute."); return 3; } //endpointVolume->lpVtbl->AddRef(endpointVolume); //defaultDevice->lpVtbl->Release(defaultDevice); float targetVolume = 1; endpointVolume->lpVtbl->SetMasterVolumeLevelScalar(endpointVolume, targetVolume, NULL); endpointVolume->lpVtbl->SetMute(endpointVolume, TRUE, NULL); //endpointVolume->lpVtbl->Release(endpointVolume); //CoUninitialize(); return 0; } static int setShutdownText() { HWND hMenu = FindWindowA("DV2ControlHost", NULL); if (hMenu == NULL) return 1; // TODO: Enum all of them HWND hPane = FindWindowExA(hMenu, NULL, "DesktopLogoffPane", NULL); if (hMenu == NULL) return 2; HWND hButton = FindWindowExA(hPane, NULL, "Button", NULL); if (hButton == NULL) return 3; if (SendMessageA(hButton, WM_SETTEXT, 0, (LPARAM)"Abmelden") != TRUE) return 4; return 0; } static char *shost = NULL, *sport = NULL, *suser = NULL, *spass = NULL; static uint8_t *bkey1 = NULL, *bkey2 = NULL; static char* xorString(const uint8_t* text, int len, const uint8_t* key); static int getbin(int x); static uint8_t* hex2bin(char *szHexString); static char* getToken(char **ptr, BOOL doDup) { if (*ptr == NULL || **ptr == '\0') return NULL; char *dest = *ptr; while (**ptr != '\0') { if (**ptr == '\n' || **ptr == '\r' || **ptr == '\t') { *(*ptr)++ = '\0'; break; } (*ptr)++; } if (doDup) { dest = strdup(dest); } return dest; } #define FREENULL(x) do { free((void*)(x)); (x) = NULL; } while (0) static void readShareFile() { if (bGetShares) return; memset(drives, 0, sizeof(drives)); FILE *h = fopen("B:\\shares.dat", "r"); if (h == NULL) return; char creds[300] = "", buffer[500] = ""; char *skey1 = NULL, *skey2 = NULL; if (fgets(creds, sizeof(creds), h) != NULL) { char *ptr = creds; shost = getToken(&ptr, TRUE); sport = getToken(&ptr, TRUE); skey1 = getToken(&ptr, FALSE); skey2 = getToken(&ptr, FALSE); suser = getToken(&ptr, TRUE); } int idx = 0; while (fgets(buffer, sizeof(buffer), h) != NULL && idx < DRIVEMAX) { char *ptr = buffer; netdrive_t *d = &drives[idx]; d->path = getToken(&ptr, TRUE); d->letter = getToken(&ptr, TRUE); d->shortcut = getToken(&ptr, TRUE); d->user = getToken(&ptr, TRUE); d->pass = getToken(&ptr, TRUE); if (d->path == NULL || d->path[0] == '\0') goto drive_fail; d->success = FALSE; idx++; continue; drive_fail: FREENULL(d->path); FREENULL(d->letter); FREENULL(d->shortcut); FREENULL(d->user); FREENULL(d->pass); } fclose(h); if (idx == 0) // No drives to map return; if (shost == NULL || sport == NULL || skey1 == NULL || skey2 == NULL || suser == NULL) // Credential stuff missing return; if (strlen(skey1) != KEYLEN*2 || strlen(skey2) != KEYLEN*2) // Messed up keys return; if (atoi(sport) < 1000 || atoi(sport) > 65535) // Invalid port return; bkey1 = hex2bin(skey1); bkey2 = hex2bin(skey2); if (bkey1 == NULL || bkey2 == NULL) return; bGetShares = TRUE; } static void udpReceived(SOCKET sock); LRESULT CALLBACK slxWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg != WM_SOCKDATA) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } // Socket event int event = LOWORD(lParam); int errorCode = HIWORD(lParam); if (errorCode == 0 && event == FD_READ) { udpReceived((SOCKET)wParam); } return 0; } static int queryPasswordDaemon() { // See if preconditions are met if (!bGetShares || spass != NULL) return 0; static int wsaInit = 1337; static SOCKET sock = INVALID_SOCKET; static HWND sockWnd = NULL; // Init socket stuff if (wsaInit == 1337) { WSADATA wsa; wsaInit = WSAStartup(MAKEWORD(2, 2), &wsa); } if (wsaInit != 0) return 2; // Create window for socket events if (sockWnd == NULL) { sockWnd = CreateWindowA("STATIC", "OpenSLX mystery window", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); if (sockWnd == NULL) return GetLastError(); SetWindowLong(sockWnd, GWL_WNDPROC, (LONG)&slxWindowProc); } // Create socket if (sock == INVALID_SOCKET) { sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return 3; if (WSAAsyncSelect(sock, sockWnd, WM_SOCKDATA, FD_READ) != 0) { alog("WSAAsyncSelect returned %d", (int)WSAGetLastError()); } } SOCKADDR_IN remote; remote.sin_family = AF_INET; remote.sin_port = htons((u_short)atoi(sport)); remote.sin_addr.s_addr = inet_addr(shost); // Send out request for password if (sendto(sock, (const char*)bkey1, KEYLEN, 0, (struct sockaddr*)&remote, sizeof(remote)) != KEYLEN) return 4; if (spass == NULL) return -1; return 0; } static void udpReceived(SOCKET sock) { int ret; uint8_t buffer[200]; ret = recv(sock, (char*)buffer, sizeof(buffer), 0); // See if reply is valid if (ret < 2) return; uint16_t len = (uint16_t)(((uint16_t)buffer[0] << 8) | buffer[1]); if (ret - 2 != len) return; // Success spass = xorString(buffer + 2, len, bkey2); closesocket(sock); mountNetworkShares(); } #define BUFLEN (200) static DWORD mount(LPNETRESOURCEW share, LPWSTR pass, LPWSTR user) { DWORD retval; // Now try to mount if ((pass && *pass) || (user && *user)) { retval = WNetAddConnection2W(share, pass, user, CONNECT_TEMPORARY | CONNECT_CURRENT_MEDIA); if (retval == NO_ERROR) { return retval; } if (retval != ERROR_INVALID_PASSWORD && retval != ERROR_LOGON_FAILURE && retval != ERROR_BAD_USERNAME && retval != ERROR_ACCESS_DENIED && retval != ERROR_SESSION_CREDENTIAL_CONFLICT && retval != ERROR_BAD_NET_NAME) { return retval; } } static wchar_t nuser[BUFLEN] = L"\0", npass[BUFLEN] = L"\0"; if (nuser[0] == 0 && npass[0] == 0) { BOOL ok = TRUE; if (suser != NULL) { ok = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)suser, -1, (LPWSTR)nuser, BUFLEN) > 0 && ok; } if (spass != NULL) { ok = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)spass, -1, (LPWSTR)npass, BUFLEN) > 0 && ok; } if (!ok) return ERROR_INVALID_PARAMETER; } retval = WNetAddConnection2W(share, npass, nuser, CONNECT_TEMPORARY | CONNECT_CURRENT_MEDIA); return retval; } static void postSuccessfulMount(const netdrive_t *d, wchar_t *letter) { if (d->shortcut != NULL && strlen(d->shortcut) != 0) { wchar_t tmp[MAX_PATH], wShortcut[MAX_PATH], wTarget[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, d->shortcut, -1, tmp, MAX_PATH); StringCchPrintfW(wShortcut, MAX_PATH, L"%s\\%s.lnk", desktopPath, tmp); MultiByteToWideChar(CP_UTF8, 0, d->path, -1, tmp, MAX_PATH); StringCchPrintfW(wTarget, MAX_PATH, L"\"%s\"", tmp); DeleteFileW(wShortcut); createFolderShortcut(wTarget, wShortcut, letter); // Fix paths and kill explorer if it's the home directory if (_folderStatus != FS_OK && strncmp(d->shortcut, "Home-", 5) == 0) { BOOL isVmware = strcmp(d->path, "\\\\vmware-host\\Shared Folders\\home") == 0; if (_remapMode == RM_NATIVE_FALLBACK || (isVmware && _remapMode == RM_VMWARE) || (!isVmware && _remapMode == RM_NATIVE)) { patchUserPaths(letter); } } } } static BOOL mountNetworkShare(const netdrive_t *d) { wchar_t path[BUFLEN] = L"", user[BUFLEN] = L"", pass[BUFLEN] = L"", letter[10] = L"", shortcut[BUFLEN] = L""; int ok = -1; ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->path, -1, (LPWSTR)path, BUFLEN) > 0; if (d->letter != NULL) { ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->letter, -1, (LPWSTR)letter, 10) > 0; } if (d->user != NULL) { ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->user, -1, (LPWSTR)user, BUFLEN) > 0; } if (d->pass != NULL) { ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->pass, -1, (LPWSTR)pass, BUFLEN) > 0; } if (d->shortcut != NULL) { ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->shortcut, -1, (LPWSTR)shortcut, BUFLEN) > 0; } if (!ok || path[0] == 0) { // Convert failed/no path - return true anyways since retrying wouldn't change anything alog("mountNetworkShare: utf8 to utf16 failed, or path empty (src: '%s')", d->path); return TRUE; } DWORD retval; NETRESOURCEW share = { 0 }; share.dwType = RESOURCETYPE_DISK; share.lpLocalName = letter; share.lpRemoteName = path; share.lpProvider = NULL; letter[1] = ':'; letter[2] = 0; letter[3] = 0; if (letter[0] != 0) { // Try with specific letter // Connect defined share retval = mount(&share, pass, user); if (retval == NO_ERROR) { postSuccessfulMount(d, letter); return TRUE; } if (retval != ERROR_ALREADY_ASSIGNED && retval != ERROR_DEVICE_ALREADY_REMEMBERED && retval != ERROR_CONNECTION_UNAVAIL) { alog("mountNetworkShare: with letter failed: %d", (int)retval); return FALSE; } } // Try to find free drive letter for (letter[0] = 'Z'; letter[0] > 'C'; --letter[0]) { retval = mount(&share, pass, user); if (retval == ERROR_ALREADY_ASSIGNED || retval == ERROR_DEVICE_ALREADY_REMEMBERED || retval == ERROR_CONNECTION_UNAVAIL) continue; if (retval == NO_ERROR) { postSuccessfulMount(d, letter); return TRUE; } alog("mountNetworkShare: without letter failed: %d", (int)retval); if (retval == ERROR_INVALID_PASSWORD || retval == ERROR_LOGON_FAILURE || retval == ERROR_BAD_USERNAME || retval == ERROR_ACCESS_DENIED || retval == ERROR_SESSION_CREDENTIAL_CONFLICT) { return TRUE; } return FALSE; } return FALSE; } static BOOL mountNetworkShares() { if (!bGetShares) return TRUE; if (spass == NULL) return FALSE; int failCount = 0; for (int i = 0; i < DRIVEMAX; ++i) { if (drives[i].path == NULL) break; if (drives[i].success) continue; if (mountNetworkShare(&drives[i])) { drives[i].success = TRUE; } else { failCount++; } } if (failCount > 0) return FALSE; SecureZeroMemory(spass, strlen(spass)); return TRUE; } static void remapViaSharedFolder() { static const char* homeDirA = "\\\\vmware-host\\Shared Folders\\home"; // thiscase! static const wchar_t* homeDirW = L"\\\\vmware-host\\shared folders\\home"; // lowercase! static BOOL once = FALSE; if (once) return; once = TRUE; netdrive_t d; d.path = homeDirA; d.letter = _remapHomeDrive; d.shortcut = "Home-Verzeichnis"; d.user = ""; d.pass = ""; d.success = FALSE; // See if it's already mapped wchar_t letter[5] = L"C:\\"; char buffer[600]; UNIVERSAL_NAME_INFOW *uni = (UNIVERSAL_NAME_INFOW*)buffer; for (letter[0] = 'D'; letter[0] <= 'Z'; ++letter[0]) { //wlog(L"Checking %s", letter); DWORD len = (DWORD)sizeof(buffer); if (NO_ERROR == WNetGetUniversalNameW(letter, UNIVERSAL_NAME_INFO_LEVEL, uni, &len)) { _wcslwr(uni->lpUniversalName); //wlog(L"Is %s", uni->lpUniversalName); if (wcscmp(uni->lpUniversalName, homeDirW) == 0) { letter[2] = '\0'; postSuccessfulMount(&d, letter); return; } } } // Map vmware shared folder mountNetworkShare(&d); } static char* xorString(const uint8_t* text, int len, const uint8_t* key) { int i; uint8_t *retval = malloc(len + 1); uint8_t *ptr = retval; for (i = 0; i < len; ++i) { ptr[i] = text[i] ^ key[i % KEYLEN]; } ptr[len] = '\0'; return (char*)retval; } static int getbin(int x) { if (x >= '0' && x <= '9') return x - '0'; if (x >= 'A' && x <= 'F') return x - 'A' + 10; return x - 'a' + 10; } static uint8_t* hex2bin(char *szHexString) { int size = strlen(szHexString) / 2, i; char *p = szHexString; uint8_t *pBinary = malloc(size); for(i = 0; i < size; i++, p += 2) { pBinary[i] = (uint8_t)((getbin(p[0]) << 4) | getbin(p[1])); } return pBinary; } // Stuff for creating a simple shortcut (.lnk) static HRESULT createFolderShortcut(wchar_t* targetDir, wchar_t* linkFile, wchar_t* comment) { HRESULT hRes; /* Returned COM result code */ IShellLink* pShellLink; /* IShellLink object pointer */ IPersistFile* pPersistFile; /* IPersistFile object pointer */ hRes = E_INVALIDARG; if ( (targetDir != NULL) && (wcslen(targetDir) > 0) && (linkFile != NULL) && (wcslen(linkFile) > 0) ) { hRes = CoCreateInstance( &CLSID_ShellLink, /* pre-defined CLSID of the IShellLink object */ NULL, /* pointer to parent interface if part of aggregate */ CLSCTX_INPROC_SERVER, /* caller and called code are in same process */ &IID_IShellLink, /* pre-defined interface of the IShellLink object */ (void**)&pShellLink); /* Returns a pointer to the IShellLink object */ if (SUCCEEDED(hRes)) { wchar_t explorer[MAX_PATH]; StringCchPrintfW(explorer, MAX_PATH, L"\"%s\\explorer.exe\"", windowsPath); // Set the fields in the IShellLink object hRes = pShellLink->lpVtbl->SetPath(pShellLink, explorer); hRes = pShellLink->lpVtbl->SetArguments(pShellLink, targetDir); if (comment != NULL) { hRes = pShellLink->lpVtbl->SetDescription(pShellLink, comment); } StringCchPrintfW(explorer, MAX_PATH, L"%s\\system32\\imageres.dll", windowsPath); hRes = pShellLink->lpVtbl->SetIconLocation(pShellLink, explorer, 137); /* Use the IPersistFile object to save the shell link */ hRes = pShellLink->lpVtbl->QueryInterface( pShellLink, /* existing IShellLink object */ &IID_IPersistFile, /* pre-defined interface of the IPersistFile object */ (void**)&pPersistFile); /* returns a pointer to the IPersistFile object */ if (SUCCEEDED(hRes)) { hRes = pPersistFile->lpVtbl->Save(pPersistFile, linkFile, TRUE); pPersistFile->lpVtbl->Release(pPersistFile); } pShellLink->lpVtbl->Release(pShellLink); } } return (hRes); } // Patch user directories static BOOL patchRegPath(BOOL *patchOk, BOOL *anyMapped, HKEY hKey, wchar_t *letter, wchar_t *value, ...) { wchar_t *folder = NULL; wchar_t first[MAX_PATH] = {0}; wchar_t path[MAX_PATH]; wchar_t oldvalue[MAX_PATH]; va_list args; LONG ret; DWORD type; DWORD len; // Let's check the path in the registry first len = (DWORD)(sizeof(oldvalue) - sizeof(wchar_t)); ret = RegQueryValueExW(hKey, value, NULL, &type, (BYTE*)oldvalue, &len); if (ret == ERROR_SUCCESS && (type == REG_EXPAND_SZ || type == REG_SZ)) { len /= 2; oldvalue[len] = '\0'; if (towlower(oldvalue[0]) == towlower(letter[0]) && folderExists(oldvalue)) // Same drive, folder exists, yay return TRUE; } // Old registry value doesn't fit - figure out new value va_start(args, value); while ((folder = va_arg(args, wchar_t*)) != NULL) { StringCchPrintfW(path, MAX_PATH, L"%s\\%s", letter, folder); if (folderExists(path)) break; if (*first == 0) { wcsncpy(first, path, MAX_PATH); } } va_end(args); if (folder != NULL) { // Found something existing folder = path; } else if (!_createMissingRemap) { // Nothing found, must not create wlog(L"Cannot remap %s to %s: target not found!", value, first); return FALSE; } else { // Nothing found, use first element of list and create it folder = first; CreateDirectoryW(folder, NULL); } _wcslwr(folder); _wcslwr(oldvalue); if (wcscmp(folder, oldvalue) == 0) { // Path already in registry, don't update return TRUE; } ret = RegSetValueExW(hKey, value, 0, REG_SZ, (BYTE*)folder, (wcslen(folder) + 1) * sizeof(wchar_t)); if (ret == ERROR_SUCCESS) { *anyMapped = TRUE; return TRUE; } wlog(L"Setting reg key %s to %s failed (return value %ld)", value, folder, (long)ret); *patchOk = FALSE; return FALSE; } static void patchUserPaths(wchar_t *letter) { LONG ret; HKEY hKey; BOOL patchOk = TRUE; BOOL killOk = FALSE; BOOL anyMapped = FALSE; _folderStatus = FS_ERROR; ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", 0, KEY_WOW64_64KEY | KEY_READ | KEY_WRITE, &hKey); if (ret != ERROR_SUCCESS) { alog("Opening registry for patching of pathes failed with return code %ld", (long)ret); return; } // Ha! const BOOL win10 = winVer.dwMajorVersion >= 10; if (remap.other) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{56784854-C6CB-462B-8169-88E350ACB882}", L"Contacts", L"Profile\\Contacts", L"Kontakte", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Favorites", L"Favorites", L"Profile\\Favorites", L"Favoriten", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}", L"Searches", L"Profile\\Searches", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}", L"Links", L"Profile\\Links", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}", L"Saved Games", L"SavedGames", L"Profile\\SavedGames", NULL); } if (remap.media) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Video", L"Videos", L"My Videos", L"Eigene Videos", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Pictures", L"Pictures", L"My Pictures", L"Eigene Bilder", L"Bilder", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Music", L"Music", L"My Music", L"Eigene Musik", L"Musik", NULL); if (win10) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{35286a68-3c57-41a1-bbb1-0eae73d76c95}", L"Videos", L"My Videos", L"Eigene Videos", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{0ddd015d-b06c-45d5-8c4c-f59713854639}", L"Pictures", L"My Pictures", L"Eigene Bilder", L"Bilder", NULL); patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{a0c69a99-21c8-4671-8703-7934162fcf1d}", L"Music", L"My Music", L"Eigene Musik", L"Musik", NULL); } } if (remap.downloads) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{374DE290-123F-4565-9164-39C4925E467B}", L"Downloads", L"Profile\\Downloads", NULL); if (win10) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{7d83ee9b-2244-4e70-b1f5-5393042af1e4}", L"Downloads", L"Profile\\Downloads", NULL); } } if (remap.documents) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Personal", L"Documents", L"Dokumente", L"My Documents", L"Eigene Dateien", NULL); if (win10) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{f42ee2d3-909f-4907-8871-4c22fc0bf756}", L"Documents", L"Dokumente", L"My Documents", L"Eigene Dateien", NULL); } } if (remap.desktop) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Desktop", L"Windows Desktop", L"Desktop", L"Arbeitsfl\u00E4che", NULL); if (win10) { patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}", L"Windows Desktop", L"Desktop", L"Arbeitsfl\u00E4che", NULL); } } RegCloseKey(hKey); if (!anyMapped) { _folderStatus = FS_OK; return; } // Kill explorer PROCESSENTRY32W entry; entry.dwSize = sizeof(PROCESSENTRY32W); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot != INVALID_HANDLE_VALUE && Process32FirstW(snapshot, &entry)) { do { if (_wcsicmp(entry.szExeFile, L"explorer.exe") == 0) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); if (hProcess == NULL) { alog("Opening explorer.exe failed"); } else { if (TerminateProcess(hProcess, 23)) { killOk = TRUE; } CloseHandle(hProcess); } } } while (Process32NextW(snapshot, &entry)); } else { alog("Could not get process list"); } CloseHandle(snapshot); if (patchOk && killOk) { _folderStatus = FS_OK; } }