summaryrefslogtreecommitdiffstats
path: root/remote/modules
diff options
context:
space:
mode:
authorSimon Rettberg2016-03-01 18:39:00 +0100
committerSimon Rettberg2016-03-01 18:39:00 +0100
commit53761f30bc231bbac9a84bb300e9c11454d72b25 (patch)
treed071fc7da6b449eefa48e2182c3d3fbd3dcb6ee4 /remote/modules
parent[run-virt] Don't writelog to stdout if usb device listing fails (diff)
downloadtm-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/modules')
-rwxr-xr-xremote/modules/run-virt/compile2
-rw-r--r--remote/modules/run-virt/pw_daemon.c315
-rw-r--r--remote/modules/run-virt/winres.c608
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;
+}
+