diff options
| author | Simon Rettberg | 2016-03-01 18:39:00 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2016-03-01 18:39:00 +0100 |
| commit | 53761f30bc231bbac9a84bb300e9c11454d72b25 (patch) | |
| tree | d071fc7da6b449eefa48e2182c3d3fbd3dcb6ee4 /remote | |
| parent | [run-virt] Don't writelog to stdout if usb device listing fails (diff) | |
| download | tm-scripts-53761f30bc231bbac9a84bb300e9c11454d72b25.tar.gz tm-scripts-53761f30bc231bbac9a84bb300e9c11454d72b25.tar.xz tm-scripts-53761f30bc231bbac9a84bb300e9c11454d72b25.zip | |
[run-virt] Add pw passing and share mounting mechanism for win vms
This is work in progress, mechanisms in run-virt are missing.
The commit contains only the required features for passing the
credentials and mounting network shares inside a windows vm.
Diffstat (limited to 'remote')
| -rwxr-xr-x | remote/modules/run-virt/compile | 2 | ||||
| -rw-r--r-- | remote/modules/run-virt/pw_daemon.c | 315 | ||||
| -rw-r--r-- | remote/modules/run-virt/winres.c | 608 |
3 files changed, 856 insertions, 69 deletions
diff --git a/remote/modules/run-virt/compile b/remote/modules/run-virt/compile index 4db15686..0e388e46 100755 --- a/remote/modules/run-virt/compile +++ b/remote/modules/run-virt/compile @@ -1,5 +1,5 @@ #!/bin/sh rm -- winres.exe -i686-w64-mingw32-gcc -std=c99 -Os -Wl,--subsystem,windows -o winres.exe winres.c -lole32 -luuid -lgdi32 #-lws2_32 +i686-w64-mingw32-gcc -Wall -Wextra -pedantic -Wno-unused-parameter -std=c99 -Os -Wl,--subsystem,windows -o winres.exe winres.c -lole32 -luuid -lgdi32 -lws2_32 -lshell32 -lmpr strip winres.exe && echo "Successfully created winres.exe" diff --git a/remote/modules/run-virt/pw_daemon.c b/remote/modules/run-virt/pw_daemon.c new file mode 100644 index 00000000..3316a0e3 --- /dev/null +++ b/remote/modules/run-virt/pw_daemon.c @@ -0,0 +1,315 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <linux/random.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/prctl.h> +#include <sys/un.h> + +static const ssize_t KEYLEN = 16; + +static pid_t udpPid = -1; +static char *username = NULL; +static uint8_t *passwordEnc = NULL; +static size_t passwordLen = 0; +static uint8_t *key1 = NULL, *key2 = NULL; +static char *key1s = NULL, *key2s = NULL; + +static int mode_daemon(); +static int mode_query(const char *socketPath); +static void sig_handler(int sig); +static int setup_vars(const char *envuser, const char *envpass); +static uint8_t* keygen(); +static char* bin2hex(uint8_t* bin, size_t len); +static uint8_t* xorString(const char* inputText, const uint8_t* key); +static int init_udp(); + +int main(int argc, char **argv) +{ + if (argc > 1 && strcmp(argv[1], "--daemon") == 0) { + return mode_daemon(); + } else if (argc > 2 && strcmp(argv[1], "--query") == 0) { + return mode_query(argv[2]); + } + fprintf(stderr, "Invalid call. Use --daemon or --query\n"); + return 1; +} + +static int mode_query(const char *socketPath) +{ + int fd; + struct sockaddr_un remote; + struct timeval tv; + char buffer[200]; + ssize_t ret; + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + perror("Cannot create unix socket for connecting"); + return 1; + } + memset(&remote, 0, sizeof(remote)); + remote.sun_family = AF_UNIX; + strncpy(remote.sun_path, socketPath, sizeof(remote.sun_path)-1); + tv.tv_sec = 2; + tv.tv_usec = 0; + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + if (connect(fd, &remote, sizeof(remote)) == -1) { + perror("Cannot connect to pw daemon"); + return 1; + } + if (write(fd, "GET", 3) == -1) { + perror("Writing to pw daemon failed"); + return 1; + } + ret = read(fd, buffer, sizeof(buffer)-1); + if (ret == -1) { + perror("Reading from pw daemon failed"); + return 1; + } + if (ret < 1 || (size_t)ret > sizeof(buffer)-1) { + fprintf(stderr, "Reply from pw daemon has invalid length\n"); + return 1; + } + if (buffer[ret-1] != '\n') { + fprintf(stderr, "Corrupted reply received from pw daemon\n"); + return 1; + } + buffer[ret] = '\0'; + fprintf(stderr, "%s", buffer); + return 0; +} + +static int mode_daemon() +{ + int listenFd, udpPort = -1; + struct sockaddr_un addr; + struct sigaction sig; + const char *envuser = getenv("USERNAME"); + const char *envpass = getenv("PASSWORD"); + const char *pwsocket = getenv("PWSOCKET"); + memset(&addr, 0, sizeof(addr)); + memset(&sig, 0, sizeof(sig)); + if (envuser == NULL) { + fprintf(stderr, "USERNAME not set\n"); + return 1; + } + if (envpass == NULL) { + fprintf(stderr, "PASSWORD not set\n"); + return 1; + } + if (pwsocket == NULL) { + fprintf(stderr, "PWSOCKET not set\n"); + return 1; + } + if (setup_vars(envuser, envpass) == -1) { + fprintf(stderr, "Error setting up variables\n"); + return 1; + } + listenFd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (listenFd == -1) { + perror("Could not create unix socket"); + return 1; + } + // Change permissions before bind, so it will be created with + // the right ones right away + if (fchmod(listenFd, S_IRUSR | S_IWUSR) == -1) { + perror("Cannot set permissions on socket fd prior to binding"); + return 1; + } + remove(pwsocket); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, pwsocket, sizeof(addr.sun_path)-1); + if (bind(listenFd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + perror("Could not bind unix socket"); + return 1; + } + if (listen(listenFd, 10) == -1) { + perror("Cannot listen on unix socket"); + return 1; + } + // Mainloop + sig.sa_handler = &sig_handler; + sigaction(SIGCHLD, &sig, NULL); + for (;;) { + struct sockaddr_un remote; + socklen_t len = sizeof(remote); + int fd = accept(listenFd, &remote, &len); + if (fd != -1) { + if (udpPort == -1) { + udpPort = init_udp(); + } + // Success, handle client + pid_t child = fork(); + if (child == 0) { + // This is the child + ssize_t ret; + char buffer[200]; + ret = read(fd, buffer, sizeof(buffer)); + if (ret >= 3 && strncmp(buffer, "GET", 3) == 0) { + snprintf(buffer, sizeof(buffer), "%d\t%s\t%s\t%s\n", udpPort, key1s, key2s, username); + write(fd, buffer, strlen(buffer)); + } + close(fd); + return 0; + } else { + // Parent, close child fd + close(fd); + } + } else { + // Error? + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR || errno == ECONNABORTED) + continue; + perror("Fatal accept error, bailing out"); + return 1; + } + } + return 0; +} + +static void sig_handler(int sig) +{ + pid_t p; + int status = sig; // Mute unused warning + while ((p = waitpid(-1, &status, WNOHANG)) > 0) { + if (p == udpPid) { + fprintf(stderr, "UDP listener died!\n"); + exit(1); + } + } +} + +static int setup_vars(const char *envuser, const char *envpass) +{ + srand((unsigned int)getpid() ^ (unsigned int)time(NULL)); + key1 = keygen(); + key2 = keygen(); + key1s = bin2hex(key1, (size_t)KEYLEN); + key2s = bin2hex(key2, (size_t)KEYLEN); + username = strdup(envuser); + passwordEnc = xorString(envpass, key2); + passwordLen = strlen(envpass) + 2; // +2 for 2byte length prefix + if (key1s == NULL || key2s == NULL || username == NULL || passwordEnc == NULL) { + return -1; + } + return 0; +} + +static uint8_t* keygen() +{ + ssize_t done = 0, ret; + uint8_t *key = malloc(KEYLEN); + int entropy; + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd != -1) { + if (ioctl(fd, RNDGETENTCNT, &entropy) == 0 && entropy > 0) { //Make sure we opened a random device + while (done < KEYLEN) { + ret = read(fd, key + done, (size_t)(KEYLEN - done)); + if (ret == -1) { + if (errno == EINTR) + continue; + break; + } + if (ret == 0) + break; + done += ret; + } + } + close(fd); + fprintf(stderr, "Got %d bytes from urandom\n", (int)done); + } + while (done < KEYLEN) { + key[done++] = (char)(rand() & 0xff); + } + return key; +} + +static uint8_t* xorString(const char* inputText, const uint8_t* key) +{ + uint8_t *text = (uint8_t*)inputText; + size_t len = strlen(inputText); + size_t i; + uint8_t *retval = malloc(len + 2); + uint8_t *ptr = retval + 2; + retval[0] = (uint8_t)(len & 0xff00) >> 8; + retval[1] = (uint8_t)(len & 0xff); + for (i = 0; i < len; ++i) { + ptr[i] = text[i] ^ key[i % KEYLEN]; + } + return retval; +} + +static char* bin2hex(uint8_t* bin, size_t len) +{ + static const char hexconvtab[] = "0123456789abcdef"; + char *retval = malloc(len * 2 + 1); + size_t i; + for (i = 0; i < len; ++i) { + retval[i*2] = hexconvtab[bin[i] >> 4]; + retval[i*2+1] = hexconvtab[bin[i] & 0xf]; + } + retval[i*2] = '\0'; + return retval; +} + +static int init_udp() +{ + uint16_t port = 0; + int fd; + int tries = 0; + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + perror("Cannot create udp socket"); + return -1; + } + for (;;) { + port = (uint16_t)(40000 + rand() % 20000); + struct sockaddr_in local; + local.sin_family = AF_INET; + local.sin_port = htons((uint16_t)port); + local.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, &local, sizeof(local)) == -1) { + if (++tries > 100) { + perror("Cannot bind udp socket"); + close(fd); + return -1; + } + continue; + } + break; + } + udpPid = fork(); + if (udpPid == -1) { + perror("Forking udp listener failed"); + close(fd); + return -1; + } + if (udpPid != 0) { + close(fd); + return port; + } + // Child + prctl(PR_SET_PDEATHSIG, SIGTERM); + for (;;) { + struct sockaddr_in remote; + socklen_t remoteLen = sizeof(remote); + uint8_t buffer[KEYLEN]; + ssize_t ret = recvfrom(fd, buffer, KEYLEN, 0, &remote, &remoteLen); + if (ret == KEYLEN && memcmp(key1, buffer, KEYLEN) == 0) { + if (sendto(fd, passwordEnc, passwordLen, 0, &remote, sizeof(remote)) == -1) { + perror("Could not send password to remote peer"); + } + } + } +} + diff --git a/remote/modules/run-virt/winres.c b/remote/modules/run-virt/winres.c index c9065c03..1a6c6a6b 100644 --- a/remote/modules/run-virt/winres.c +++ b/remote/modules/run-virt/winres.c @@ -1,53 +1,164 @@ #define NTDDI_VERSION NTDDI_VISTA #define WINVER 0x0602 #define _WIN32_WINNT 0x0602 -//#include <winsock2.h> +#define WIN32_LEAN_AND_MEAN #include <windows.h> +#include <winsock2.h> +#include <winnetwk.h> #include <mmdeviceapi.h> #include <endpointvolume.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <initguid.h> +#include <stdint.h> +#include <stdarg.h> +#include <wchar.h> +#include <time.h> +#include <shlobj.h> +#include <strsafe.h> 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 { + char* path; + char* letter; + char* shortcut; + char* user; + char* pass; + BOOL success; +} netdrive_t; + +static const ssize_t KEYLEN = 16; +#define DRIVEMAX (100) +#define LOGFILELEN (300) + +static BOOL bGetShares = FALSE; +static netdrive_t drives[DRIVEMAX]; +static wchar_t desktopPath[MAX_PATH+1], tempPath[MAX_PATH+1], programsPath[MAX_PATH+1]; +static wchar_t logFile[LOGFILELEN]; + 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 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, ...) +{ + char buffer[1000]; + if (MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)suser, -1, (LPWSTR)nuser, BUFLEN) == 0) + return; +} +*/ + + +// TODO: Figure out if no timers are running anymore so we can quit static void CALLBACK resetShutdown(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { - setShutdownText(); + 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; + int ret = queryPasswordDaemon(); + if (ret != 0) { + if (++fails < 10) + goto exit_func; + alog("queryPasswordDaemon returned %d", ret); + } else { + if (!mountNetworkShares() && ++fails < 15) + goto exit_func; + } + KillTimer(hWnd, idEvent); +exit_func: + bInProc = FALSE; +} + +static void loadPaths() +{ + 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_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); + } + } } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { - int ret; - /* - // Part 1: Auf UDP Paket vom Host warten, mit Anweisungen zur Auflösung - WSADATA wsa; - WSAStartup(MAKEWORD(2, 0), &wsa); - if (ret != 0) return 1; - SOCKET s = socket(PF_INET, SOCK_DGRAM, 0); - if (s == INVALID_SOCKET) return 2; - SOCKADDR_IN local, remote; - local.sin_family = AF_INET; - local.sin_port = htons(2013); - local.sin_addr.s_addr = ADDR_ANY; - ret = bind(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)); - if (ret == SOCKET_ERROR) return 3; - for (;;) { - recvfrom(s, - } - */ OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); BOOL retVer = GetVersionEx(&version); - // Set resolution to what HOSTRES.TXT says - setResolution(); + loadPaths(); // Mute sound by default if (retVer && version.dwMajorVersion >= 6) muteSound(); @@ -59,64 +170,140 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } else { // XP/2003 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); } + // Any network shares to mount? + readShareFile(); + if (bGetShares) { + UINT_PTR tRet = SetTimer(NULL, 0, 2550, (TIMERPROC)&setupNetworkDrives); + if (tRet == 0) { + alog("Could not create timer for mounting network shares: %d", (int)GetLastError()); + } + } // Shutdown button label if (retVer && version.dwMajorVersion == 6 && version.dwMinorVersion == 1) { // Only on Windows 7 - char buffer[100]; // Repeatedly set caption - UINT_PTR tRet = SetTimer(NULL, 0, 5000, (TIMERPROC)&resetShutdown); + UINT_PTR tRet = SetTimer(NULL, 0, 5030, (TIMERPROC)&resetShutdown); if (tRet == 0) { - snprintf(buffer, 100, "Could not create timer: %d", (int)tRet); - MessageBoxA(0, buffer, "SetTimer", 0); - return 0; + alog("Could not create timer for shutdown button: %d", (int)GetLastError()); } - // Message pump - MSG Msg; - while(GetMessage(&Msg, NULL, 0, 0) > 0) { - TranslateMessage(&Msg); - DispatchMessage(&Msg); + } + // Resolution + if (fileExists(L"B:\\hostres.txt") && 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)); +} + static int setResolution() { - int ret, i; - int width, height; - // Quicker way: use config file in floppy - FILE *h = fopen("B:\\hostres.txt", "rb"); - if (h == NULL) return 4; - char data[200] = ""; - fread(data, 200, 1, h); - char *x = strchr(data, 'x'); - if (x == NULL) return 5; - *x++ = '\0'; - width = atoi(data); - height = atoi(x); - fclose(h); - // Part 2: Auflösung setzen und verabschieden + int ret; + static int width = 0, height = 0; + if (width == 0 && height == 0) { + // use config file in floppy + FILE *h = fopen("B:\\hostres.txt", "rb"); + if (h == NULL) { + alog("b:\\hostres.txt not found"); + return 0; + } + char data[200] = ""; + fread(data, 200, 1, h); + fclose(h); + char *x = strchr(data, 'x'); + if (x == NULL) { + alog("Malformed resolution in hostres.txt: '%s'", data); + return 0; + } + *x++ = '\0'; + width = atoi(data); + height = atoi(x); + if (width < 320 || height < 240) { + alog("Invalid resolution in hostres.txt: '%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)) { + STARTUPINFOW si; + PROCESS_INFORMATION pi; + wchar_t cmdline[MAX_PATH]; + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); + si.cb = sizeof(si); + StringCchPrintfW(cmdline, MAX_PATH, L"VMwareResolutionSet.exe 0 1 , 0 0 %d %d", width, height); + if (CreateProcessW(path, cmdline, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + DWORD exitCode; + BOOL ret = GetExitCodeProcess(pi.hProcess, &exitCode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + if (ret && exitCode == 0) { + return 0; + } + alog("vmware res set executed but failed (ret %d, code %d, lasterror %d)", + (int)ret, (int)exitCode, (int)GetLastError()); + } else { + alog("createprocess for vmware res set failed with code %d", (int)GetLastError()); + } + } + // Use WinAPI as fallback DEVMODE mode; int query = 1337; - for (i = 0; i < 6; ++i) { - 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 , (i < 3 ? CDS_GLOBAL : 0) | (i < 2 ? CDS_UPDATEREGISTRY : 0)); - if (ret == DISP_CHANGE_SUCCESSFUL) break; - Sleep(1000); + 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) { - char err[200]; - snprintf(err, 200, - "Fehler beim Setzen der Aufloesung: %d (soll: 0) / %d ( soll: !0)\r\n" - "Zielaufloesung: %d * %d", ret, query, width, height); - MessageBoxA(0, err, "OpenSLX", 0); + 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; } @@ -127,14 +314,14 @@ static int muteSound() IMMDeviceEnumerator *deviceEnumerator = NULL; HRESULT hr = CoCreateInstance(&ID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &ID_IMMDeviceEnumerator, (LPVOID *)&deviceEnumerator); if (hr != S_OK) { - MessageBoxA(0, "CoCreateInstance failed. Cannot mute.", "OpenSLX", 0); + 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) { - MessageBoxA(0, "GetDefaultAudioEndpoint failed. Cannot mute.", "OpenSLX", 0); + alog("GetDefaultAudioEndpoint failed. Cannot mute."); return 2; } //defaultDevice->lpVtbl->AddRef(defaultDevice); @@ -142,7 +329,7 @@ static int muteSound() IAudioEndpointVolume *endpointVolume = NULL; hr = defaultDevice->lpVtbl->Activate(defaultDevice, &ID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume); if (hr != S_OK) { - MessageBoxA(0, "IMMDevice::Activate() failed. Cannot mute.", "OpenSLX", 0); + alog("IMMDevice::Activate() failed. Cannot mute."); return 3; } //endpointVolume->lpVtbl->AddRef(endpointVolume); @@ -158,12 +345,297 @@ static int muteSound() static int setShutdownText() { HWND hMenu = FindWindowA("DV2ControlHost", NULL); - if (hMenu == NULL) return 1; + 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 (SendMessage(hButton, WM_SETTEXT, 0, (LPARAM)"Abmelden") != TRUE) return 4; + 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(x); (x) = NULL; } while (0) + +static void readShareFile() +{ + if (bGetShares) + return; + memset(drives, 0, sizeof(drives)); + FILE *h = fopen(".\\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, FALSE); + sport = getToken(&ptr, FALSE); + skey1 = getToken(&ptr, FALSE); + skey2 = getToken(&ptr, FALSE); + suser = getToken(&ptr, FALSE); + } + 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; + shost = strdup(shost); + sport = strdup(sport); + 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); +} + +#define BUFLEN (200) + +static DWORD mount(LPNETRESOURCEW share, LPWSTR pass, LPWSTR user) +{ + DWORD retval; + 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 && ERROR_ACCESS_DENIED) { + return retval; + } + static wchar_t nuser[BUFLEN] = L"", npass[BUFLEN] = L""; + if (nuser[0] == 0 && npass[0] == 0) { + int ok = -1; + ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)suser, -1, (LPWSTR)nuser, BUFLEN) > 0; + ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)spass, -1, (LPWSTR)npass, BUFLEN) > 0; + if (!ok) + return ERROR_INVALID_PARAMETER; + } + retval = WNetAddConnection2W(share, npass, nuser, CONNECT_TEMPORARY | CONNECT_CURRENT_MEDIA); + return retval; +} + +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; + share.dwType = RESOURCETYPE_DISK; + share.lpLocalName = letter; + share.lpRemoteName = path; + share.lpProvider = NULL; + letter[1] = ':'; + letter[2] = 0; // TODO d->shortcut + if (letter[0] != 0) { + // Try with specific letter + retval = mount(&share, pass, user); + if (retval == NO_ERROR) + return TRUE; + if (retval != ERROR_ALREADY_ASSIGNED) { + alog("mountNetworkShare: with letter failed: %d", (int)retval); + return FALSE; + } + } + // Let Window assign a letter + share.lpLocalName = NULL; + retval = mount(&share, pass, user); + if (retval != NO_ERROR) { + alog("mountNetworkShare: without letter failed: %d", (int)retval); + } + return retval == NO_ERROR; +} + +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 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; +} + |
