summaryrefslogtreecommitdiffstats
path: root/core/modules/run-virt
diff options
context:
space:
mode:
authorJonathan Bauer2016-12-23 13:12:09 +0100
committerJonathan Bauer2016-12-23 13:12:09 +0100
commit6806ae4a850fc7785a8c05304237cf53b5b8f951 (patch)
treeb1dd8413d6c7b9a250251da7f0d49bb52b4ddc57 /core/modules/run-virt
parentwrong kernel version variable used (diff)
downloadmltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.tar.gz
mltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.tar.xz
mltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.zip
merge with latest dev version (tm-scripts commit f5a59daf8d70a9027118292cd40b18c221897408)
Diffstat (limited to 'core/modules/run-virt')
-rw-r--r--core/modules/run-virt/data/opt/openslx/scripts/pam_script_auth.d/99-run_virt_credentials41
-rw-r--r--core/modules/run-virt/data/opt/openslx/scripts/pam_script_ses_close.d/runvirt-firewall-clear17
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/scripts/systemd-mount_vm_store13
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/scripts/systemd-run_virt_env63
l---------[-rwxr-xr-x]core/modules/run-virt/data/opt/openslx/scripts/vmchooser-run_virt117
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/config/udhcpd-nat1.conf5
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/LIESMICH24
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/README21
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/00_vars.inc29
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_functions.inc51
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_preliminaries.inc20
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/15_set_trapping.inc14
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/20_get_creds.inc27
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_get_shares.inc22
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_mount_shares.inc66
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/40_check_fallback.inc8
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_postliminaries.inc21
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_umounter.inc12
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/mnt_shares62
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution102
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution_standalone138
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/umnt_shares40
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_installer87
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_runtime97
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exebin15360 -> 53248 bytes
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc32
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc63
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_hardware_variables.inc113
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_variables.inc26
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_firewall.inc12
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc98
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_printer_lpd.inc46
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_sound.inc79
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_virtual_floppy.inc101
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_vm_hypervisor.inc34
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/start_windowmanager.inc27
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/usb_detector.inc77
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc107
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/scripts/set-firewall130
-rwxr-xr-xcore/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt119
-rw-r--r--core/modules/run-virt/fwtool/main.c32
-rw-r--r--core/modules/run-virt/module.build6
-rw-r--r--core/modules/run-virt/module.conf4
-rw-r--r--core/modules/run-virt/module.conf.ubuntu4
-rw-r--r--core/modules/run-virt/pw_daemon.c315
-rwxr-xr-xcore/modules/run-virt/winres/compile13
-rw-r--r--core/modules/run-virt/winres/winres.c1166
-rw-r--r--core/modules/run-virt/winres/winres.manifest34
-rw-r--r--core/modules/run-virt/winres/winres.rc4
49 files changed, 3585 insertions, 154 deletions
diff --git a/core/modules/run-virt/data/opt/openslx/scripts/pam_script_auth.d/99-run_virt_credentials b/core/modules/run-virt/data/opt/openslx/scripts/pam_script_auth.d/99-run_virt_credentials
new file mode 100644
index 00000000..a03d8886
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/scripts/pam_script_auth.d/99-run_virt_credentials
@@ -0,0 +1,41 @@
+#!/bin/ash
+# This is being sourced and running in ash
+
+if [ -n "$TEMP_HOME_DIR" ]; then
+ if [ -z "$PAM_TTY" ] || [ "x$PAM_TTY" = "x:0" ]; then
+ # Pass on network path to home directory
+ if [ -z "$PERSISTENT_NETPATH" ]; then
+ PERSISTENT_NETPATH=$(grep -m1 -F " ${PERSISTENT_HOME_DIR} " "/proc/mounts" | awk '{print $1}')
+ fi
+ if [ -n "$PERSISTENT_NETPATH" ]; then
+ [ "x${PERSISTENT_NETPATH:0:2}" = "x//" ] && PERSISTENT_NETPATH=$(echo "$PERSISTENT_NETPATH" | tr '/' '\')
+ echo "${PERSISTENT_NETPATH}" > "${TEMP_HOME_DIR}/.home"
+ chmod 0644 "${TEMP_HOME_DIR}/.home"
+ fi
+ # pwdaemon
+ # Figure out username
+ XUSER="${REAL_ACCOUNT}"
+ [ -z "$XUSER" ] && XUSER="${PAM_USER}"
+ # Guess domain
+ XDOMAIN=
+ if [ -n "$PERSISTENT_HOME_DIR" ]; then
+ XDOMAIN=$(grep -F " ${PERSISTENT_HOME_DIR} " "/proc/mounts" | grep -m1 -F 'domain=' | sed -r 's/^.*[ ,]domain=([^ ,]+)[ ,].*$/\1/g')
+ fi
+ if [ -z "$XDOMAIN" ]; then
+ XDOMAIN=$(grep -m1 -i '^BASE\s*DC=' "/etc/ldap.conf" | sed -r 's/^BASE\s*DC=([^,;]+).*$/\1/I')
+ fi
+ if [ -z "$XDOMAIN" ]; then
+ XDOMAIN=$(grep -m1 -i '^ldap_search_base\s*=\s*DC=' "/etc/sssd/sssd.conf" | sed -r 's/^ldap_search_base\s*=\s*DC=([^,;]+).*$/\1/I')
+ fi
+ if [ -n "$XDOMAIN" ]; then
+ XDOMAIN=$(echo "$XDOMAIN" | tr '[a-z]' '[A-Z]')
+ else
+ XDOMAIN="WORKGROUP"
+ fi
+ USERNAME="$XDOMAIN\\$XUSER" PASSWORD="$PAM_AUTHTOK" PWSOCKET="${TEMP_HOME_DIR}/.pwsocket" su -c 'pwdaemon --daemon &' "${PAM_USER}" &
+ unset XUSER XDOMAIN
+ fi
+fi
+
+true
+
diff --git a/core/modules/run-virt/data/opt/openslx/scripts/pam_script_ses_close.d/runvirt-firewall-clear b/core/modules/run-virt/data/opt/openslx/scripts/pam_script_ses_close.d/runvirt-firewall-clear
new file mode 100644
index 00000000..dab08190
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/scripts/pam_script_ses_close.d/runvirt-firewall-clear
@@ -0,0 +1,17 @@
+#!/bin/ash
+
+# Sourced by pam_script_ses_close
+
+runvirt_fw_clear () {
+ iptables -w -F runvirt-INPUT
+ ip6tables -w -F runvirt-INPUT
+ iptables -w -F runvirt-OUTPUT
+ ip6tables -w -F runvirt-OUTPUT
+}
+
+if [ "x$PAM_TTY" = "x:0" ]; then
+ runvirt_fw_clear > /dev/null 2>&1
+fi
+
+true
+
diff --git a/core/modules/run-virt/data/opt/openslx/scripts/systemd-mount_vm_store b/core/modules/run-virt/data/opt/openslx/scripts/systemd-mount_vm_store
index 9d478918..235cf4be 100755
--- a/core/modules/run-virt/data/opt/openslx/scripts/systemd-mount_vm_store
+++ b/core/modules/run-virt/data/opt/openslx/scripts/systemd-mount_vm_store
@@ -13,8 +13,12 @@ OUTFILE=$(mktemp)
# no bash, so this is a bit ugly...
if [ "${SLX_VM_NFS#//}" = "${SLX_VM_NFS}" ]; then
# doesn't start with '//' -> assume NFS
- /opt/openslx/bin/timeout -t 10 -s 9 mount -v -t nfs -o ro,async,nolock "$SLX_VM_NFS" /mnt/vmstore
+ /opt/openslx/bin/timeout -t 6 -s 9 mount -v -t nfs -o ro,async,nolock "$SLX_VM_NFS" /mnt/vmstore
RET=$?
+ if [ "$RET" != "0" ]; then
+ /opt/openslx/bin/timeout -t 6 -s 9 mount -v -t nfs -o vers=3,ro,async,nolock "$SLX_VM_NFS" /mnt/vmstore
+ RET=$?
+ fi
else
# starts with '//' -> assume CIFS
export USER="$SLX_VM_NFS_USER"
@@ -25,15 +29,14 @@ else
RET=$?
fi > "$OUTFILE" 2>&1
-if [ $RET -ne 0 ]; then
+if [ "$RET" -ne "0" ]; then
if [ -s "$OUTFILE" ]; then
- slxlog "mount-vmstore-fail" "Mounting '$SLX_VM_NFS' failed. VMs will not boot." "$OUTFILE"
- sleep 1
+ slxlog --delete "mount-vmstore-fail" "Mounting '$SLX_VM_NFS' failed. VMs will not boot." "$OUTFILE"
else
slxlog "mount-vmstore-fail" "Mounting '$SLX_VM_NFS' failed. VMs will not boot."
+ rm -f -- "$OUTFILE"
fi
fi
-rm -f -- "$OUTFILE"
exit $RET
diff --git a/core/modules/run-virt/data/opt/openslx/scripts/systemd-run_virt_env b/core/modules/run-virt/data/opt/openslx/scripts/systemd-run_virt_env
index b8236600..a86b2d0b 100755
--- a/core/modules/run-virt/data/opt/openslx/scripts/systemd-run_virt_env
+++ b/core/modules/run-virt/data/opt/openslx/scripts/systemd-run_virt_env
@@ -28,27 +28,7 @@ export PATH=$PATH:/opt/openslx/bin:/opt/openslx/sbin
# from plugins/vmchooser/XX_vmchooser.sh
VMCHOOSER_DIR="/opt/openslx/vmchooser"
VMCHOOSER_CONF_DIR="$VMCHOOSER_DIR/config"
-
-mkdir -p "${VMCHOOSER_DIR}/data/loopimg"
-mkdir -p "${VMCHOOSER_DIR}/fd-loop" -m 1777
-
-# mount a clean tempfs (bug in UnionFS prevents loopmount to work)
-grep -qE "unionfs |aufs " /proc/mounts && \
- mount -n -o size=1500k -t tmpfs vm-loopimg "${VMCHOOSER_DIR}/data/loopimg"
-
-# create an empty floppy image of 1.44 MByte size
-dd "if=/dev/zero" "of=${VMCHOOSER_DIR}/data/loopimg/fd.img" count=2880 bs=512 2>/dev/null
-chmod 0777 "${VMCHOOSER_DIR}/data/loopimg/fd.img"
-
-# use dos formatter copied into stage3
-mkdosfs "${VMCHOOSER_DIR}/data/loopimg/fd.img"
-mount -n -t msdos -o loop,umask=000 "${VMCHOOSER_DIR}/data/loopimg/fd.img" "${VMCHOOSER_DIR}/fd-loop"
-
-#pvs integration
-#if [ $vmchooser_pvs -ne 0 ]; then
-# sed -i /usr/share/xsessions/default.desktop \
-# -e "s,vmchooser$,vmchooser --pvs,"
-#fi
+DHCP_NAT_CONF="/opt/openslx/vmchooser/config/udhcpd-nat1.conf"
# setup more scratch space for virtual machines, if configured
mkdir -p /tmp/virt /var/log/samba /run/samba
@@ -110,10 +90,20 @@ fi
# write mac
if [ -n "$SLX_PXE_MAC" ]; then
- echo "hostmacaddr=${SLX_PXE_MAC}" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+ hostmacaddr="${SLX_PXE_MAC}"
else ## Fallback:
- echo "hostmacaddr=$(ip a | grep ether | grep -o -E -i '([0-9a-f]{2}:){5}[0-9a-f]{2}' | head -n 1)" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+ hostmacaddr="$(ip a | grep ether | grep -o -E -i '([0-9a-f]{2}:){5}[0-9a-f]{2}' | head -n 1)"
fi
+echo "hostmacaddr='$hostmacaddr'" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+# TODO: We should only generate the suffix here (last 3 octets) as the first 3 are
+# dependant on the virtualizer/emulator. Check if any run-virt.include still relies on
+# $macguestpart/$macaddr. If so, fix it to use its specific first 3 bytes
+# and append $macaddrssuffix
+macaddrprefix='00:50:56'
+macaddrsuffix="$(echo "$hostmacaddr" | awk -F ":" '{print "%VMID%:" $(NF-1) ":" $NF}' | tr '[a-z]' '[A-Z]')"
+echo "macaddrprefix='$macaddrprefix'" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+echo "macaddrsuffix='$macaddrsuffix'" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+
# read in ip address
echo "hostip=${SLX_PXE_CLIENT_IP}" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
# hostname
@@ -132,6 +122,11 @@ for floppy in $(dmesg|grep -i "Floppy drive"|sed "s,.*(s): ,,;s, is .*,,"); do
j=$(expr $j + 1)
done
+# Serial ports
+echo "serial_ports='$(dmesg | grep -Eo 'ttyS[0-9]+' | sed 's,^,/dev/,' | tr '\n' ' ')'" >> "${VMCHOOSER_CONF_DIR}/virtualization.conf"
+# Parallel ports
+modprobe parport_pc
+
################################################################################
### Setup VM networking
################################################################################
@@ -163,19 +158,27 @@ echo "1" >/proc/sys/net/ipv4/conf/br0/forwarding 2>/dev/null
### iptables -t nat -A POSTROUTING -o br0 -s 192.168.0.0/16 -j MASQUERADE
for wait in 1 1 2 2 3 end; do
- grep '^SLX_DNS' "/opt/openslx/config" > /dev/null && break
- [ "$wait" == "end" ] && echo "No DNS config found, using google dns" && break
- echo "Waiting for DNS config.."
+ [ -n "$SLX_DNS" ] && [ -n "$SLX_NET_SEARCH" ] && break
+ if [ "$wait" == "end" ]; then
+ echo "No DNS config found, using google dns"
+ break
+ fi
+ echo "Waiting for DNS & search-domain config.."
sleep "$wait"
+ . /opt/openslx/config
done
# read the DNS configuration and configure the udhcpd
-[ -z "${SLX_DNS}" ] && SLX_DNS="8.8.8.8"
-sed -i "s,DNSSERVER,${SLX_DNS},;s,DOMAIN,${SLX_NET_DOMAIN}," \
- /opt/openslx/vmchooser/config/udhcpd-nat1.conf
+[ -z "${SLX_DNS}" ] && SLX_DNS="8.8.8.8 8.8.4.4"
+[ -z "${SLX_NET_DOMAIN}" ] && SLX_NET_DOMAIN="virtual.site"
+[ -z "${SLX_NET_SEARCH}" ] && SLX_NET_SEARCH="virtual.site"
+sed -i "s#%DNSSERVER%#${SLX_DNS}#;s#%DOMAIN%#${SLX_NET_DOMAIN}#;s#%SEARCH%#${SLX_NET_SEARCH}#" "${DHCP_NAT_CONF}"
+
+# Make sure the primary vm running (we most likely never run more than one at a time anyways) always gets the same ip
+echo "static_lease $(echo "$macaddrprefix:$macaddrsuffix" | sed 's/%VMID%/01/') 192.168.101.20" >> "${DHCP_NAT_CONF}"
mkdir -p /var/lib/udhcpd
-udhcpd -S /opt/openslx/vmchooser/config/udhcpd-nat1.conf
+udhcpd -S "${DHCP_NAT_CONF}"
# creating and configuring vsw2
brctl addbr vsw2
diff --git a/core/modules/run-virt/data/opt/openslx/scripts/vmchooser-run_virt b/core/modules/run-virt/data/opt/openslx/scripts/vmchooser-run_virt
index 1e591389..447f98bc 100755..120000
--- a/core/modules/run-virt/data/opt/openslx/scripts/vmchooser-run_virt
+++ b/core/modules/run-virt/data/opt/openslx/scripts/vmchooser-run_virt
@@ -1,116 +1 @@
-#!/bin/bash
-# Full bash required
-# -----------------------------------------------------------------------------
-# Copyright (c) 2007..2010 - RZ Uni FR
-# Copyright (c) 2007..2013 - OpenSLX GmbH
-#
-# This program is free software distributed under the GPL version 2.
-# See http://openslx.org/COPYING
-#
-# If you have any feedback please consult http://openslx.org/feedback and
-# send your suggestions, praise, or complaints to feedback@openslx.org
-#
-# General information about OpenSLX can be found at http://openslx.org/
-# -----------------------------------------------------------------------------
-# run-virt.sh
-# - This is the generic wrapper for the several virtualization solutions.
-# The idea is to setup a set of variables used by at least two different
-# tools and then include the specific plugin which configures the speci-
-# fied virtualization tool.
-################################################################################
-
-RUNVIRTINCLUDEDIR=/opt/openslx/scripts/includes
-xmlfile="$1"
-
-# Functions needed by vmchooser-run_virt (writelog(), cleanexit(), rv_clean_string())
-source ${RUNVIRTINCLUDEDIR}/vmchooser_runvirt_functions.inc && trap 'trap "" SIGINT SIGTERM; cleanexit' SIGINT SIGTERM
-# Define default dirs / get configs
-source ${RUNVIRTINCLUDEDIR}/set_runvirt_variables.inc
-# Function to detect whether we can use the new way (vmx via http) or the old way (legacy):
-source ${RUNVIRTINCLUDEDIR}/detect_legacy.inc # This yields LEGACY, IMGUUID, IMGVMX
-# For scanning for certain usb classes
-source "${RUNVIRTINCLUDEDIR}/usb_detector.inc"
-
-if [ "$LEGACY" ]; then
- # check for important files used (filecheck()) - vestigial?
- source ${RUNVIRTINCLUDEDIR}/check_runvirt_needed_files.inc
- # Get XML file and dir, legacy (old way)
- source ${RUNVIRTINCLUDEDIR}/get_xml_file_dir_legacy.inc # xmlfile=$1
- # xml file sanity checks, legacy
- source ${RUNVIRTINCLUDEDIR}/check_runvirt_xml_sanity_legacy.inc
- # print console logo
- source ${RUNVIRTINCLUDEDIR}/print_runvirt_console_logo.inc
- # Read needed variables from XML file
- source ${RUNVIRTINCLUDEDIR}/get_xml_file_variables_legacy.inc
- # Declaration of hardware relatedt variables
- source ${RUNVIRTINCLUDEDIR}/set_runvirt_hardware_variables_legacy.inc
- # Sound setup the rest of the environment and run the configured vm
- source ${RUNVIRTINCLUDEDIR}/setup_sound.inc
- # Start printer daemon
- source ${RUNVIRTINCLUDEDIR}/setup_printer_lpd.inc
- # Setup virtual floppy b: for windows guests with config.xml, openslx.exe etc.
- source ${RUNVIRTINCLUDEDIR}/setup_virtual_floppy.inc
- # Try to use dnbd3 to access the image, nfs/cifs fallback
- source ${RUNVIRTINCLUDEDIR}/setup_image_access.inc
- # Get all virtual machine specific stuff from the respective include file
- source ${RUNVIRTINCLUDEDIR}/setup_vm_hypervisor.inc
- # start a windowmanager for easier handling
- source ${RUNVIRTINCLUDEDIR}/start_windowmanager.inc
- # Start poolvideoswitch if DO_PROFILE has been set (WARNING: fixed IP!)
- source ${RUNVIRTINCLUDEDIR}/start_pvs.inc
- # Check if tcpsvd is running. Do not check immediately after spawning,
- # as this could result in success even if it's not really working.
- source ${RUNVIRTINCLUDEDIR}/check_lpd.inc
-else
- # check for important files used (filecheck()) - vestigial?
- # This include does not currently work. TODO.
- # source ${RUNVIRTINCLUDEDIR}/check_runvirt_needed_files.inc && filecheck
-
- # Read needed variables from XML file
- source ${RUNVIRTINCLUDEDIR}/get_xml_file_variables.inc
-
- # Sound setup the rest of the environment and run the configured vm
- source ${RUNVIRTINCLUDEDIR}/setup_sound.inc
-
- # Declaration of hardware relatedt variables
- source ${RUNVIRTINCLUDEDIR}/set_runvirt_hardware_variables.inc
-
- # Start printer daemon
- source ${RUNVIRTINCLUDEDIR}/setup_printer_lpd.inc
-
- # Setup virtual floppy b: for windows guests with config.xml, openslx.exe etc.
- source ${RUNVIRTINCLUDEDIR}/setup_virtual_floppy.inc
-
- # Get all virtual machine specific stuff from the respective include file
- source ${RUNVIRTINCLUDEDIR}/setup_image_access.inc
-
- # start a windowmanager for easier handling
- source ${RUNVIRTINCLUDEDIR}/setup_vm_hypervisor.inc
-
- # Try to use dnbd3 to access the image, nfs/cifs fallback
- source ${RUNVIRTINCLUDEDIR}/start_windowmanager.inc
-
- # Start poolvideoswitch if DO_PROFILE has been set (WARNING: fixed IP!)
- source ${RUNVIRTINCLUDEDIR}/start_pvs.inc
-
- # Check if tcpsvd is running. Do not check immediately after spawning,
- # as this could result in success even if it's not really working.
- source ${RUNVIRTINCLUDEDIR}/check_lpd.inc
-
-fi
-
-# This will start the VM
-writelog "VM command: eval ${VIRTCMD} ${VIRTCMDOPTS}"
-
-# Transported from vmware-runvirt include
-sync
-
-eval ${VIRTCMD} ${VIRTCMDOPTS}
-writelog "Bye."
-
-# Postrun for commands after virtualization finishes
-if [ -n "${POSTRUN}" ]; then
- eval ${POSTRUN} >/dev/null 2>&1
-fi
-
-cleanexit 0
+/opt/openslx/vmchooser/vmchooser-run_virt \ No newline at end of file
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/config/udhcpd-nat1.conf b/core/modules/run-virt/data/opt/openslx/vmchooser/config/udhcpd-nat1.conf
index bca1397c..95d8ebc0 100644
--- a/core/modules/run-virt/data/opt/openslx/vmchooser/config/udhcpd-nat1.conf
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/config/udhcpd-nat1.conf
@@ -31,11 +31,12 @@ lease_file /var/lib/udhcpd/udhcpd-nat1.leases
# location of the pid file
pidfile /var/run/udhcpd-nat1.pid
-option dns DNSSERVER
+option dns %DNSSERVER%
option subnet 255.255.255.0
option router 192.168.101.1
option wins 192.168.101.10
-option domain DOMAIN virtual.site
+option domain %DOMAIN%
+option search %SEARCH%
option lprsrv 192.168.101.1
#option ntpsrv NTPSERVER
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/LIESMICH b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/LIESMICH
new file mode 100644
index 00000000..326af2a4
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/LIESMICH
@@ -0,0 +1,24 @@
+Dieses Paket besteht aus folgenden Skripten:
+
+vm_installer: Dieses Skript einmalig in einer lokalen, permanenten (also
+ nicht innerhalb des Poolsystems) Virtuellen Maschine ausführen.
+ Es schreibt eine systemd-Servicedatei und verlinkt diese, um
+ beim Systemstart per vm_runtime die Skripte zu Auflösungsan-
+ passung und Einhängung eventuell übergebener Netzlaufwerke
+ nach Hochladung der VM in das Poolsystem automatisch zu starten.
+ Das Skript kann von der gemounteten (Pseudo-)Diskette /dev/fd1
+ aus oder einzelstehend gestartet werden.
+ Unterstützung für init-basierte Systeme folgt noch.
+vm_runtime: Dieses Skript wird beim booten der VM aufgerufen und patcht
+ Xsetup, um beim grafischen Start der VM die Skripte shares
+ und resolution aufzurufen.
+mnt_shares: Liest die auf Pseudodiskette gegebene shares.dat aus und hängt
+ ggf. darin angegebene Netzlaufwerke ein.
+resolution: Stellt die Auflösung der VM anhand der übergebenen Auflösung
+ des Grundsystems ein.
+
+resolution_standalone: Einzelstehende Version des resolution-Skriptes, die
+ keine Vorarbeiten seitens systemd bzw. vm_runtime benötigt.
+ Für geeignete Einbindung innerhalb der VM muss daher selbst
+ gesorgt werden.
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/README b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/README
new file mode 100644
index 00000000..12777c67
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/README
@@ -0,0 +1,21 @@
+This package consists of the following scripts:
+
+vm_installer: This script is to be started once in a local, permanent (so
+ not within the pool system environment) virtual machine. It
+ writes a systemd service file and links it, so the scripts
+ for resolution setting and mounting network shares will be
+ started at boot time at boot time via vm_runtime.
+ It may be run from the mounted (pseudo) disk drive /dev/fd1
+ or from elsewhere.
+ init will be supported at later time.
+vm_runtime: Will be started at boot time and patches Xsetup, so the
+ scripts mnt_shares and resolution will be started at graphical
+ login.
+mnt_shares: Reads the config file shares.dat from (pseudo) disk drive and
+ mounts therein given network shares.
+resolution: Sets resolution within the virtual machine according to base
+ system resolution given via config file openslx.ini.
+
+resolution_standalone: Standalone version of resolution sctipt. Needs no
+ preliminary work done by systemd or vm_runtime.
+ One has to embed/start it via adequate means by hand.
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/00_vars.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/00_vars.inc
new file mode 100644
index 00000000..bb7ae3a1
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/00_vars.inc
@@ -0,0 +1,29 @@
+### Variablen #####################################
+LOCALUSER=student
+USERHOME=/home/"$LOCALUSER"
+USERHOMEDIR=/home/"$LOCALUSER"/PERSISTENT
+DISKMOUNTDIR=/mnt/diskmount
+SLXCONFIGFILE="$DISKMOUNTDIR"/openslx.ini
+CONFIGFILE="$DISKMOUNTDIR"/shares.dat
+KEYTEMP=$(mktemp -t XXXXXXXXXX.dat)
+RAWKEYTEMP=$(mktemp -t XXXXXXXXXX.dat)
+BYTES=256
+declare -a ROHSHARES
+
+if [ ! $(mount 2>/dev/null | grep -q "$DISKMOUNTDIR") ]; then
+ [ ! -d "$DISKMOUNTDIR" ] && mkdir -p "$DISKMOUNTDIR"
+ mount /dev/fd1 "$DISKMOUNTDIR" 2>/dev/null 1>&2 # Zu erl.: Fehlerfangen
+fi
+
+NATADDR=$(head -n 1 "$CONFIGFILE" | cut -f 1 -d$'\t')
+PORT=$(head -n 1 "$CONFIGFILE" | cut -f 2 -d$'\t')
+SCHLUESSEL=$(head -n 1 "$CONFIGFILE" | cut -f 4 -d$'\t')
+GLOBALDOMAINUSER=$(head -n 1 "$CONFIGFILE" | cut -f 5 -d$'\t')
+GLOBALUSER=$(echo "$GLOBALDOMAINUSER" | cut -d '\' -f 2)
+
+REMAPMODE=$(grep 'remapMode=' "$SLXCONFIGFILE" | cut -d '=' -f 2)
+CREATEMISSING=$(grep 'createMissingRemap=' "$SLXCONFIGFILE" | cut -d '=' -f 2)
+
+MOUNTOPTSCIFS="-v -t cifs -o uid=$(id --user "$LOCALUSER"),gid=$(id --group "$LOCALUSER"),forceuid,forcegid,file_mode=0700,dir_mode=0700,nobrl,noacl"
+MOUNTOPTSNFS="-v -t nfs4 -o rw,nosuid,nodev,nolock,intr,hard,sloppy"
+### Variablen Ende ################################
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_functions.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_functions.inc
new file mode 100644
index 00000000..97767c51
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_functions.inc
@@ -0,0 +1,51 @@
+### Funktionen ####################################
+
+function xor()
+{ local RES=($(echo "$1" | sed "s/../0x& /g"))
+ shift 1
+ while [[ "$1" ]]; do
+ local ONE=($(echo "$1" | sed "s/../0x& /g"))
+ local COUNT1=${#RES[@]}
+ if [ $COUNT1 -lt ${#ONE[@]} ]; then
+ COUNT1=${#ONE[@]}
+ fi
+ for (( i = 0; i < $COUNT1; i++ )); do
+ RES[$i]=$((${ONE[$i]:-0} ^ ${RES[$i]:-0}))
+ done
+ shift 1
+ done
+ printf "%02x" "${RES[@]}"
+}
+
+function already_mounted()
+{
+ # Ausgabe: gemountet = true = 0, nicht gemountet = false = 1
+ local AUSGANG
+ mount | grep -q " ${1} " && AUSGANG=0 || AUSGANG=1
+ return $AUSGANG
+}
+
+function mounter()
+{
+ # Ausgabe: konnte mounten: 0, konnte nicht mounten: 1, schon gemountet 2
+ already_mounted "$3"
+ ERR=$?
+ if [ "$ERR" -eq 0 ]; then
+ logger "openslx sharemapper: $3 already mounted."
+ AUSGANG=2
+ else
+ mount $1 $2 $3 2>/dev/null 1>&2
+ ERR=$?
+ if [ "$ERR" -gt 0 ]; then
+ logger "openslx sharemapper: could not mount ${2} to ${3}."
+ AUSGANG=1
+ else
+ logger "openslx sharemapper: ${2} mounted to ${3}."
+ AUSGANG=0
+ fi
+ fi
+ return $AUSGANG
+}
+
+### Funktionen Ende ###############################
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_preliminaries.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_preliminaries.inc
new file mode 100644
index 00000000..bcbd6ec1
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/10_preliminaries.inc
@@ -0,0 +1,20 @@
+preliminaries_native()
+{
+ # USERHOMEDIR=~/PERSISTENT, not ~! ################
+ [ -h "$USERHOMEDIR" ] && unlink "$USERHOMEDIR"
+ [ ! -d "$USERHOMEDIR" ] && mkdir -p "$USERHOMEDIR"
+}
+
+preliminaries_vmware()
+{
+ # USERHOMEDIR=~/PERSISTENT, not ~! ################
+ if [ -d "$USERHOMEDIR" ]; then
+ logger "openslx sharemapper: vmware mode: USERHOMEDIR ${USERHOMEDIR} is a directory, moving to ${USERHOMEDIR}_mov."
+ mv "$USERHOMEDIR" "${USERHOMEDIR}"_mov
+ fi
+
+ [ -h "$USERHOMEDIR" ] && unlink "$USERHOMEDIR"
+ logger "openslx sharemapper: vmware mode: linking $USERHOMEDIR to /mnt/hgfs/home."
+ ln -s /mnt/hgfs/home "$USERHOMEDIR" || \
+ logger "openslx sharemapper: vmware mode: Could not link to vmware hgfs mount dir."
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/15_set_trapping.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/15_set_trapping.inc
new file mode 100644
index 00000000..c49b99ff
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/15_set_trapping.inc
@@ -0,0 +1,14 @@
+function ausgang()
+{ rm -f "$KEYTEMP"
+ rm -f "$RAWKEYTEMP"
+ # umount "$DISKMOUNTDIR" # as mounted by systemd now.
+}
+
+function set_trapping()
+{
+ ### Trap ##########################################
+ trap ausgang EXIT SIGHUP SIGINT SIGTERM
+ ###################################################
+}
+
+set_trapping
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/20_get_creds.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/20_get_creds.inc
new file mode 100644
index 00000000..c6f6ffcb
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/20_get_creds.inc
@@ -0,0 +1,27 @@
+function get_creds()
+{
+ # udp-Socket erzeugen Kanal erzeugen::
+ exec 13<>/dev/udp/"$NATADDR"/"$PORT"
+
+ # temp. Datei - wer hat Angst vor Nullbytes? Ich! Ich! Ich!
+ head -n 1 "$CONFIGFILE" |cut -f3 -d$'\t' | while read -n 2 CODE; do [ -n "$CODE" ] && printf "\x$CODE"; done >"$KEYTEMP"
+ # Auf Socket fuer Grundsystem schreiben:
+ cat "$KEYTEMP" >&13
+
+ # Serverantwort pwdaemon in temp. Datei schreiben:
+ timeout 2s dd bs=$BYTES count=1 of="$RAWKEYTEMP" <&13 2>/dev/null
+
+ # Kanal zu Socket schließen:
+ exec 13<&-
+ exec 13>&-
+
+ # Wieviele Zeichen (Bytes 1 und 2 der Paketnutzlast)?
+ ANZAHL=$((16#$(dd if=$RAWKEYTEMP bs=1 count=2 2>/dev/null|hexdump -e '1/1 "%02x"')))
+
+ # Und raus-xor-en:
+ PW=$( xor $(dd if="$RAWKEYTEMP" bs=1 skip=2 2>/dev/null|hexdump -e '1/1 "%02x"') \
+ $(head -n 1 "$CONFIGFILE" | cut -f 4 -d$'\t') | sed 's/../\\x&/g')
+
+ PW=$(echo -e "$PW") # \x...-Ausdrücke zu ASCII
+ PW="${PW:0:${ANZAHL}}" # ...und Rest nach ANZAHL abhacken.
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_get_shares.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_get_shares.inc
new file mode 100644
index 00000000..70b17236
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_get_shares.inc
@@ -0,0 +1,22 @@
+function get_shares()
+{
+ i=0
+ while read -r LINIE; do
+ ROHSHARES[i]="$LINIE"
+ ((i++))
+ done < "$CONFIGFILE"
+
+# echo "${#ROHSHARES[@]} eingelesen:"
+# for (( i = 0; i < ${#ROHSHARES[@]}; i++ )); do
+# echo -n "$i "
+# echo "${ROHSHARES[i]}"
+# done
+
+ let SHAREZAHL=${#ROHSHARES[@]}-1
+ if [ "$SHAREZAHL" -lt 1 ]; then
+ logger "openslx sharemapper: No shares to map/mount found in config file $CONFIGFILE."
+ exit 0
+ else
+ logger "openslx sharemapper: $SHAREZAHL share(s) found."
+ fi
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_mount_shares.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_mount_shares.inc
new file mode 100644
index 00000000..b1320d01
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/30_mount_shares.inc
@@ -0,0 +1,66 @@
+function mount_shares()
+{
+ for (( CONFIGROW = 1; CONFIGROW < ${#ROHSHARES[@]}; CONFIGROW++ )); do
+ SHAREPATH=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 1 -d$'\t') # cifs- oder nfs-Share
+ SHARELETTER=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 2 -d$'\t' | \
+ sed 's/://g') # Laufwerksbuchstabe ohne :
+ SHARENAME=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 3 -d$'\t' | sed 's/ /_/g') # Leerzeichen raus.
+ SHAREUSER=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 4 -d$'\t') # Username, bei Userhome nicht vorhanden
+ SHAREPASS=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 5 -d$'\t') # User-PW, bei Userhome nicht vorhanden
+
+ # Sharetyp bestimmen:
+ if [ "${SHAREPATH:0:2}" == '\\' ]; then
+ USER=$(echo "$SHAREUSER"|cut -d '\' -f 2)
+ MOUNTOPTS="$MOUNTOPTSCIFS"
+ else
+ MOUNTOPTS="$MOUNTOPTSNFS"
+ fi
+
+ # User-Homeverzeichnis?
+ if [ "${SHARENAME:0:5}" == "Home-" ]; then
+ logger "openslx sharemapper: home share \"$SHARENAME\" found (for PERSISTENT)."
+ export USER="${GLOBALUSER}"
+ export PASSWD="${PW}"
+ mounter "${MOUNTOPTS}" ${SHAREPATH} ${USERHOMEDIR} 2>/dev/null 1>&2
+ unset USER
+ unset PASSWD
+ else
+ if [ -z "${SHARELETTER}" ]; then
+ logger "openslx sharemapper: $SHARELETTER not found. Do not know where to mount."
+ continue
+ else
+ USERSHAREDIR="${USERHOME}"/SHARE_"${CONFIGROW}" # ROHSHARES: Zeilennummer; Shares >=1
+ if [ ! -d "$USERSHAREDIR" ]; then
+ mkdir -p "$USERSHAREDIR" 2>/dev/null
+ chown "$LOCALUSER":$(id --group "$LOCALUSER") "$USERSHAREDIR"
+ chmod 700 "$USERSHAREDIR"
+ logger "openslx sharemapper: share mount dir $USERSHAREDIR created."
+ fi
+ fi
+ # Wenn kein Homeverzeichnis, dann share zuerst mit den Credentials aus der share-Konfig
+ # versuchen zu mounten; wenn nicht, dann mit den Hauptcredentials nachversuchen.
+ logger "openslx sharemapper: non-home share \"$SHARENAME\" (${CONFIGROW}) found."
+ export USER="${SHAREUSER}"
+ export PASSWD="${SHAREPASS}"
+ mounter "${MOUNTOPTS}" ${SHAREPATH} ${USERSHAREDIR} 2>/dev/null 1>&2
+ ERR=$?
+ if [ "$ERR" -eq 1 ]; then
+ export USER="${GLOBALUSER}"
+ export PASSWD="${PW}"
+ logger "openslx sharemapper: Could not mount ${USERSHAREDIR}, now trying using user credentials."
+ mounter "${MOUNTOPTS}" ${SHAREPATH} ${USERSHAREDIR} 2>/dev/null 1>&2 \
+ ERR=$? # ERR merken wg. Links aus USERSHAREDIR
+ if [ "$ERR" -eq 1 ]; then
+ logger "openslx sharemapper: Could not mount ${USERSHAREDIR} even using user credentials; giving up."
+ fi
+ unset USER
+ unset PASSWD
+ fi
+ if [ "$ERR" -eq 0 ]; then
+ logger "openslx sharemapper: Linking ${SHARELETTER} and $SHARENAME, if possible."
+ [ -n "${SHARELETTER}" ] && ln -s "$USERSHAREDIR" "${USERHOME}"/"$SHARELETTER"
+ [ -n "${SHARELETTER}" ] && ln -s "$USERSHAREDIR" "${USERHOME}"/"$SHARENAME"
+ fi
+ fi
+ done
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/40_check_fallback.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/40_check_fallback.inc
new file mode 100644
index 00000000..14a13f77
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/40_check_fallback.inc
@@ -0,0 +1,8 @@
+check_fallback() {
+ if [ $(mount | grep -c " $USERHOMEDIR type cifs \| $USERHOMEDIR type nfs") -lt 1 ]; then
+ logger "openslx sharemapper: fallback mode: home share check failed, doing fallback to vmware mode."
+ preliminaries_vmware
+ else
+ logger "openslx sharemapper: fallback mode: home share check passed, no fallback necessary."
+ fi
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_postliminaries.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_postliminaries.inc
new file mode 100644
index 00000000..f6f1cf7d
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_postliminaries.inc
@@ -0,0 +1,21 @@
+postliminaries_native()
+{
+ # USERHOMEDIR=~/PERSISTENT, not ~! ################
+ rmdir "$USERHOMEDIR" && logger "openslx unmounter: home directory entry (PERSISTENT) deleted." \
+ || logger "openslx unmounter: could not delete home directory (PERSISTENT) entry - not empty / unmounted!"
+}
+
+postliminaries_vmware()
+{
+ unlink "$USERHOMEDIR"
+ ERR=$?
+ if [ "$ERR" -ne 0 ]; then
+ logger "openslx unmounter: vmware mode: could not unlink ${USERHOMEDIR}!"
+ logger "openslx unmounter: vmware mode: this is a severe problem; I do not know what to do - exiting!"
+ exit 1
+ else
+ logger "openslx unmounter: vmware mode: ${USERHOMEDIR} unlinked."
+ # checking whether there was a directory moved out earlier:
+ [ -d "${USERHOMEDIR}"_mov ] && mv "${USERHOMEDIR}"_mov "${USERHOMEDIR}"
+ fi
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_umounter.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_umounter.inc
new file mode 100644
index 00000000..e161b961
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/includes/50_umounter.inc
@@ -0,0 +1,12 @@
+umount_home() {
+ umount /home/"${LOCALUSER}"/PERSISTENT && logger "openslx unmounter: umounted home (PERSISTENT)." \
+ || logger "openslx unmounter: could not home (PERSISTENT)!"
+}
+
+umount_shares() {
+ index=0
+ for SHARE in $( mount | grep SHARE | tr -s ' ' | cut -f 3 -d " " ); do
+ umount "${SHARE}" && logger "openslx unmounter: umounted ${SHARE}." \
+ || logger "openslx unmounter: could not umount ${SHARE}!"
+ done
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/mnt_shares b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/mnt_shares
new file mode 100755
index 00000000..0c94f0aa
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/mnt_shares
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# set -x
+
+logger "openslx sharemapper: Started."
+
+OWNDIR=$(dirname $0)
+for i in "$(dirname $0)"/includes/*.inc; do
+ source "$i"
+done
+
+# Wait for network connection to base system
+#!/bin/bash
+
+x=1
+while ! ping -w 1 -c 1 "${NATADDR}" 2>/dev/null 1>&2; do
+ [ "$x" -gt 20 ] && { logger "openslx sharemapper: could not reach base system. Giving up."; exit 1; }
+ let x=x+1
+ sleep 2
+done
+
+logger "openslx sharemapper: base system reaching; commencing."
+
+# REMAPMODE (remapMode): 0: None, 1 Native, 2 Native Fallback, 3 vmware
+# CREATEMISSING (createMissingRemap): 0: Nichts tun, 1 xdg-Verzeichnisse
+
+case "$REMAPMODE" in
+ 0) logger "openslx sharemapper: remapMode 0 (do nothing) detected."
+ exit 0
+ ;;
+ 1) logger "openslx sharemapper: remapMode 1 (native mode) detected."
+ preliminaries_native
+ get_creds # fills global var PW with (currently) decrypted password
+ get_shares # fills array ROHSHARES; row 0 global infos from (shares-)CONFIGFILE,
+ # following rows: column 1 share path, col 2 drive letter, col 3 share name,
+ # column 4 username, col 5 password.
+ mount_shares # mounts shares given in array ROHSHARES.
+ exit 0
+ ;;
+ 2) logger "openslx sharemapper: remapMode 2 (fallback mode) detected."
+ preliminaries_native
+ get_creds # fills global var PW with (currently) decrypted password
+ get_shares # fills array ROHSHARES; row 0 global infos from (shares-)CONFIGFILE,
+ # following rows: column 1 share path, col 2 drive letter, col 3 share name,
+ # column 4 username, col 5 password.
+ mount_shares # mounts shares given in array ROHSHARES.
+ check_fallback # checks for a mounted home and fallbacks to vmware share, if none found.
+ exit 0
+ ;;
+ 3) logger "openslx sharemapper: remapMode 3 (vmware mode) detected."
+ preliminaries_vmware
+ mount_shares # mounts shares given in array ROHSHARES - runvirt checks whether there's
+ # a home share given or not..
+ exit 0
+ ;;
+ *) logger "openslx sharemapper: unknown remapMode in $SLXCONFIGFILE; doing nothing end exiting with error."
+ exit 1.
+ ;;
+esac
+
+exit 0
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution
new file mode 100755
index 00000000..24a0594f
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution
@@ -0,0 +1,102 @@
+#!/bin/bash
+
+# Dieses Skript liest die Auflösungsdate HOSTRES.TXT aus der Diskette 2 (/dev/fd1). In dieser
+# Datei wird die native (maximale) Auflösung des Grundsystems bereitgestellt. fd1 wird vom
+# openslx-Grundsystem geliefert. Es loggt nach SYSLOG (syslog oder messages).
+#
+# Zu erledigen: Jede Menge, zB anständiges Trapping, Fehler abfangen usw...
+# set -x
+
+MOUNTDIR=/mnt/diskmount
+RESFILE="${MOUNTDIR}"/openslx.ini
+DISPLAY=:0.0
+
+check_resolution() {
+ # Now, let's wait even more seconds to see if another process re-changes res.:
+ ACTRES=$(xrandr|grep '*'|tr -s " "|cut -f 2 -d " ")
+ if [ "$ACTRES" != "$RESOLUTION" ]; then
+ logger "openslx resolution utility: resolution changed; re-changing."
+ xrandr --output ${AUSGABE} --mode ${RESOLUTION}
+ else
+ logger "openslx resolution utility: resolution unchanged."
+ fi
+}
+
+logger "openslx resolution utility started."
+
+# Da nun fremdgemountet wird, hier sicherheitshalber zur Kontrolle wg. Gross-/Kleinschreibung:
+RESFILE=$(find "${MOUNTDIR}" -iwholename "${RESFILE}")
+
+if [ -f "$RESFILE" ]; then
+ RESOLUTION=$(grep 'resolution=' "$RESFILE" | cut -d '=' -f 2)
+ if [ -z $RESOLUTION ]; then
+ logger "openslx resolution utility: resolution file $RESFILE seems to be empty!"
+ exit 1
+ fi
+ logger "openslx resolution utility: resolution file $RESFILE yields ${RESOLUTION}."
+else
+ logger "openslx resolution utility: resolution file $RESFILE not found!"
+ exit 1
+fi
+
+# Das ist mitunter ein Problem, da die richtige zu finden - Distroabhängig!
+# Hier ein Beispiel für openSuse 13.2, sollte auch für Debian, Ubuntu, Redhat usw. laufen:.
+XAUTHDATEI=$(ps aux | grep -o "X.* \-auth *[^ ]*" | awk '{print $NF}')
+if [ -n "$XAUTHDATEI" ]; then
+ logger "openslx resolution utility: XAUTHFILE found."
+ XAUTHORITY="${XAUTHDATEI}"
+else
+ logger "openslx resolution utility: XAUTHFILE not found. Exiting."
+ exit 1
+fi
+
+# Zu verbessern: Der Name des Verbundenen ist nicht immer bekannt. Daher nehmen wir das
+# erste 'connected' in der Ausgabe xrandrs:
+AUSGABE=$(xrandr -q|grep -m 1 " connected "|awk '{print $1}')
+if [ -z "$AUSGABE" ]; then
+ logger "openslx resolution utility: Could not detect output device. Exiting."
+ exit 1
+fi
+
+# Pruefen, ob xrand eine passende modeline ausgibt:
+if [ "$(xrandr | grep -c ${RESOLUTION})" -eq 0 ]; then
+ logger "openslx resolution utility: xrandr yields no fitting modeline; adding one."
+ MODELINE=$(cvt ${RESOLUTION//x/ } | grep -v "^#" | sed "s/Modeline //g" | sed 's/"//g')
+ xrandr --newmode $(echo ${MODELINE})
+ xrandr --addmode ${AUSGABE} $(echo ${MODELINE} | cut -d " " -f 1)
+ # Dann einzusteuernde Auflösung natürlich auf die neue ändern:
+ RESOLUTION=$(echo ${MODELINE} | cut -d " " -f 1)
+ logger "openslx resolution utility: (xrandr) modeline ${MODELINE} added (${RESOLUTION})."
+fi
+
+# Auflösung per xrandr setzen:
+xrandr --output ${AUSGABE} --mode ${RESOLUTION}
+ERR=$?
+if [ $ERR -ne 0 ]; then
+ logger "openslx resolution utility: xrandr error code ${ERR}."
+else
+ logger "openslx resolution utility: xrandr ok. Mode $RESOLUTION set."
+fi
+
+# Das hier ist ein wenig problematisch, da nach X-Start die gewünschte Desktopumgebung
+# diese gern zuvor gespeicherte Auflösungen wieder einspielt. Daher warten wir einfach,
+# und prüfen in gewissen Zeitabständen, ob sich die Auflösung geändert hat, und spielen
+# im Änderungsfalle die Grundsystemauflösung wieder ein. Schön ist das nicht.
+
+# Now, let's wait some seconds to see if another process re-changes res.:
+sleep 5
+check_resolution
+
+# Now, let's wait some more seconds to see if another process re-changes res.:
+sleep 15
+check_resolution
+
+# Now, let's wait even more seconds to see if another process re-changes res.:
+sleep 20
+check_resolution
+
+# Now, let's wait even more seconds to see if another process re-changes res.:
+sleep 40
+check_resolution
+
+exit 0
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution_standalone b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution_standalone
new file mode 100755
index 00000000..0dbbcf98
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/resolution_standalone
@@ -0,0 +1,138 @@
+#!/bin/bash
+
+# Dieses Skript liest die Auflösungsdate HOSTRES.TXT aus der Diskette 2 (/dev/fd1). In dieser
+# Datei wird die native (maximale) Auflösung des Grundsystems bereitgestellt. fd1 wird vom
+# openslx-Grundsystem geliefert. Es loggt nach SYSLOG (syslog oder messages).
+#
+# Zu erledigen: Jede Menge, zB anständiges Trapping, Fehler abfangen usw...
+# set -x
+
+MOUNTDIR=/tmp/diskmount
+RESFILE="${MOUNTDIR}"/openslx.ini
+DISPLAY=:0.0
+
+function ausgang() {
+ umount "${MOUNTDIR}"
+ rmdir "${MOUNTDIR}"
+}
+
+check_resolution() {
+ # Now, let's wait even more seconds to see if another process re-changes res.:
+ ACTRES=$(xrandr|grep '*'|tr -s " "|cut -f 2 -d " ")
+ if [ "$ACTRES" != "$RESOLUTION" ]; then
+ logger "openslx resolution utility: resolution changed; re-changing."
+ xrandr --output ${AUSGABE} --mode ${RESOLUTION}
+ else
+ logger "openslx resolution utility: resolution unchanged."
+ fi
+}
+
+trap ausgang EXIT SIGHUP SIGINT SIGTERM
+
+logger "openslx resolution utility started."
+
+# Mountpunkt erzeugen:
+if [ ! -d "$MOUNTDIR" ]; then
+ mkdir "$MOUNTDIR"
+ logger "openslx resolution utility: mkdir'ed diskmount dir $MOUNTDIR."
+fi
+
+# Virtuelles Floppylaufwerk mounten
+mount /dev/fd1 "$MOUNTDIR" 2>/dev/null
+ERR=$?
+if [ $ERR -ne 0 ]; then
+ logger "openslx resolution utility: error code $ERR trying to mount /dev/fd1 to ${MOUNTDIR}. Remounting..."
+ mount -o remount /dev/fd1 "$MOUNTDIR" 2>/dev/null
+ ERR=$?
+ if [ $ERR -ne 0 ]; then
+ logger "openslx resolution utility: error code $ERR trying to remount /dev/fd1 to ${MOUNTDIR}. Giving up."
+ exit 1
+ else
+ logger "openslx resolution utility: remount of /dev/fd1 mounted to diskmount dir ${MOUNTDIR} succeeded."
+ fi
+else
+ logger "openslx resolution utility: /dev/fd1 mounted to diskmount dir ${MOUNTDIR}."
+fi
+
+# Das Mounten mit shortname=WIN95 erwies sich als nicht zuverlässig. Daher hier Kontrolle:
+RESFILE=$(find "${MOUNTDIR}" -iwholename "${RESFILE}")
+
+if [ -f "$RESFILE" ]; then
+ RESOLUTION=$(grep 'resolution=' "$RESFILE" | cut -d '=' -f 2)
+ if [ -z $RESOLUTION ]; then
+ logger "openslx resolution utility: resolution file $RESFILE seems to be empty!"
+ exit 1
+ fi
+ logger "openslx resolution utility: resolution file $RESFILE yields ${RESOLUTION}."
+else
+ logger "openslx resolution utility: resolution file $RESFILE not found!"
+ exit 1
+fi
+
+umount /dev/fd1
+ERR=$?
+if [ "$ERR" -ne 0 ]; then
+ logger "openslx resolution utility: error code $ERR trying to to unmount /dev/fd1. Please unmount by hand."
+fi
+
+# Das ist mitunter ein Problem, da die richtige zu finden - Distroabhängig!
+# Hier ein Beispiel für openSuse 13.2, sollte auch für Debian, Ubuntu, Redhat usw. laufen:.
+XAUTHDATEI=$(ps aux | grep -o "X.* \-auth *[^ ]*" | awk '{print $NF}')
+if [ -n "$XAUTHDATEI" ]; then
+ logger "openslx resolution utility: XAUTHFILE found."
+ XAUTHORITY="${XAUTHDATEI}"
+else
+ logger "openslx resolution utility: XAUTHFILE not found. Exiting."
+ exit 1
+fi
+
+# Zu verbessern: Der Name des Verbundenen ist nicht immer bekannt. Daher nehmen wir das
+# erste 'connected' in der Ausgabe xrandrs:
+AUSGABE=$(xrandr -q|grep -m 1 " connected "|awk '{print $1}')
+if [ -z "$AUSGABE" ]; then
+ logger "openslx resolution utility: Could not detect output device."
+ exit 1
+fi
+
+# Pruefen, ob xrand eine passende modeline ausgibt:
+if [ "$(xrandr | grep -c ${RESOLUTION})" -eq 0 ]; then
+ logger "openslx resolution utility: xrandr yields no fitting modeline; adding one."
+ MODELINE=$(cvt ${RESOLUTION//x/ } | grep -v "^#" | sed "s/Modeline //g" | sed 's/"//g')
+ xrandr --newmode $(echo ${MODELINE})
+ xrandr --addmode ${AUSGABE} $(echo ${MODELINE} | cut -d " " -f 1)
+ # Dann einzusteuernde Auflösung natürlich auf die neue ändern:
+ RESOLUTION=$(echo ${MODELINE} | cut -d " " -f 1)
+ logger "openslx resolution utility: (xrandr) modeline ${MODELINE} added (${RESOLUTION})."
+fi
+
+# Auflösung per xrandr setzen:
+xrandr --output ${AUSGABE} --mode ${RESOLUTION}
+ERR=$?
+if [ $ERR -ne 0 ]; then
+ logger "openslx resolution utility: xrandr error code ${ERR}."
+else
+ logger "openslx resolution utility: xrandr ok. Mode $RESOLUTION set."
+fi
+
+# Das hier ist ein wenig problematisch, da nach X-Start die gewünschte Desktopumgebung
+# diese gern zuvor gespeicherte Auflösungen wieder einspielt. Daher warten wir einfach,
+# und prüfen in gewissen Zeitabständen, ob sich die Auflösung geändert hat, und spielen
+# im Änderungsfalle die Grundsystemauflösung wieder ein. Schön ist das nicht.
+
+# Now, let's wait some seconds to see if another process re-changes res.:
+sleep 5
+check_resolution
+
+# Now, let's wait some more seconds to see if another process re-changes res.:
+sleep 15
+check_resolution
+
+# Now, let's wait even more seconds to see if another process re-changes res.:
+sleep 20
+check_resolution
+
+# Now, let's wait even more seconds to see if another process re-changes res.:
+sleep 40
+check_resolution
+
+exit 0
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/umnt_shares b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/umnt_shares
new file mode 100755
index 00000000..b028cf76
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/umnt_shares
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# set -x
+
+logger "openslx sharemapper: umounter started."
+
+OWNDIR=$(dirname $0)
+for i in "$(dirname $0)"/includes/*.inc; do
+ source "$i"
+done
+
+# REMAPMODE (remapMode): 0: None, 1 Native, 2 Native Fallback, 3 vmware
+# CREATEMISSING (createMissingRemap): 0: Nichts tun, 1 xdg-Verzeichnisse
+
+case "$REMAPMODE" in
+ 0) logger "openslx sharemapper: umounter: remapMode 0 (do nothing) detected."
+ exit 0
+ ;;
+ 1) logger "openslx sharemapper: umounter: remapMode 1 (native mode) detected."
+ umount_shares
+ umount_home
+ postliminaries_native
+ ;;
+ 2) logger "openslx sharemapper: umounter: remapMode 2 (fallback mode) detected."
+ umount_shares
+ umount_home
+ postliminaries_native
+ exit 0
+ ;;
+ 3) logger "openslx sharemapper: umounter: remapMode 3 (vmware mode) detected."
+ postliminaries_vmware
+ exit 0
+ ;;
+ *) logger "openslx sharemapper: umounter: unknown remapMode in $SLXCONFIGFILE; doing nothing end exiting with error."
+ exit 1.
+ ;;
+esac
+
+exit 0
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_installer b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_installer
new file mode 100755
index 00000000..978cee20
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_installer
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+PS=$(which ps)
+GREP=$(which grep)
+LOGGER=$(which logger)
+MKDIR=$(which mkdir)
+MOUNT=$(which mount)
+MOUNTDIR=/mnt/diskmount/
+SERVICEFILE=openslx-scriptinstall.service
+
+# systemd erkennen
+case $(${PS} --pid 1 -o comm h) in
+ systemd) echo "openslx praeinstaller: systemd detected."
+ if [ -d /etc/systemd/system ]; then
+ SERVICEDIR=/etc/systemd/system/
+ else
+ SERVICEDIR=/usr/lib/systemd/system/
+ fi
+ echo "openslx praeinstaller: installing systemd service file to ${SERVICEDIR}/${SERVICEFILE}."
+
+ cat <<-HEREDOC > "$SERVICEDIR"/"$SERVICEFILE"
+ [Unit]
+ Description=openSLX script installer
+ Before=display-manager.service graphical.target
+
+ [Service]
+ Type=oneshot
+ ExecStartPre=${MKDIR} -p /mnt/diskmount
+ ExecStartPre=-${MOUNT} /dev/fd1 /mnt/diskmount
+ ExecStart=${LOGGER} "openslx service file: started."
+ ExecStart=${MOUNTDIR}/linux/vm_runtime
+ ExecStart=${LOGGER} "openslx service file: done."
+ RemainAfterExit=no
+ HEREDOC
+
+ [ ! -d /etc/systemd/system/graphical.target.wants ] && mkdir /etc/systemd/system/graphical.target.wants 2>/dev/null
+ [ ! -d /etc/systemd/system/basic.target.wants ] && mkdir /etc/systemd/system/basic.target.wants 2>/dev/null
+
+ ln -s "${SERVICEDIR}"/"${SERVICEFILE}" /etc/systemd/system/graphical.target.wants/"${SERVICEFILE}"
+ ln -s "${SERVICEDIR}"/"${SERVICEFILE}" /etc/systemd/system/basic.target.wants/"${SERVICEFILE}"
+
+ echo "openslx praeinstaller: doing systemd reload."
+ systemctl daemon-reload
+ ;;
+ init) echo "openslx praeinstaller: init(V) detected."
+ SERVICEDIR=/etc/init.d/
+ [ ! -d "${SERVICEDIR}" ] && { echo "openslx praeinstaller: No init directory $SERVICEDIR found, exiting."; exit 1; }
+ SERVICEFILE=openslx-scriptinstall
+ echo "openslx praeinstaller: installing init service file to ${SERVICEDIR}/${SERVICEFILE}."
+ cat <<-THEREDOC > "${SERVICEDIR}"/"${SERVICEFILE}"
+ #!/bin/sh -e
+ ### BEGIN INIT INFO
+ # Provides: openSLX_scriptinstaller
+ # Required-Start: 2 3 4 5
+ # Required-Stop: 0 1 6
+ # Default-Start: 2 3 4 5
+ # Default-Stop: 0 1 6
+ # X-Interactive: false
+ # Short-Description: openSLX script package starter.
+ ### END INIT INFO
+ #
+ # Starts via Xsetup patching the openSLX script package
+ # to correct screen resolution and mount network shares
+ # when Xsetup is started.
+
+ case "\$1" in
+ start) ${LOGGER} "openslx init file: started."
+ ${MKDIR} -p /mnt/diskmount
+ ${MOUNT} | ${GREP} -q /mnt/diskmount || ${MOUNT} /dev/fd1 /mnt/diskmount
+ ${MOUNTDIR}/linux/vm_runtime
+ ${LOGGER} "openslx init file: done."
+ ;;
+ stop|restart|force-reload) exit 0 ;;
+ *) echo "Usage: $0 {start}" >&2; exit 1 ;;
+ esac
+ THEREDOC
+ chmod +x "${SERVICEDIR}"/"${SERVICEFILE}"
+ echo "openslx praeinstaller: enabling ${SERVICEFILE}."
+ update-rc.d "${SERVICEFILE}" defaults
+ ;;
+ *) echo "openslx praeinstaller: Could not determine mother-of-all-processes (not systemd, not init)."
+ echo "openslx praeinstaller: Giving up, exiting."
+ exit 1
+esac
+
+exit 0
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_runtime b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_runtime
new file mode 100755
index 00000000..0a81c38d
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/linux/vm_runtime
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+# set -x
+
+# logger "openslx vm_runtime: Started."
+
+DISTRIBUTION=$(lsb_release -is | tr '[A-Z]' '[a-z]' | sed -r 's/[^a-z0-9]//g;s/project$//g;s/scientificsl$/scientific/g')
+VERSION=$(lsb_release -rs)
+SCRIPTDIR=/mnt/diskmount/linux/
+RESOLUTIONSCRIPT="${SCRIPTDIR}"/resolution
+SHARESCRIPT="${SCRIPTDIR}"/mnt_shares
+UMOUNTSCRIPT="${SCRIPTDIR}"/umnt_shares
+XSETUP=$(find /etc/X* -name "Xsetup" 2>/dev/null)
+XRESET=$(find /etc/X* -name "Xreset" 2>/dev/null)
+
+[ ! -f "${RESOLUTIONSCRIPT}" -o ! -f "${SHARESCRIPT}" ] && \
+ { logger "openslx vm_runtime: could not find needed scripts on disk. Exiting." ; exit 1 ; }
+
+write_xsetup() {
+ logger "openslx vm_runtime: writing ${XSETUP}..."
+ cat<<-BISHIER > "${XSETUP}"
+ #!/bin/sh
+ ${SHARESCRIPT} &
+ ${RESOLUTIONSCRIPT} &
+ BISHIER
+}
+
+patch_xsetup_shebang() {
+ # Patching after first line, to be exact.
+ logger "openslx vm_runtime: patching ${XSETUP} after shebang line, if necessary."
+ grep -q "${RESOLUTIONSCRIPT}" "${XSETUP}" || sed "1 a ${RESOLUTIONSCRIPT} \&" -i "${XSETUP}"
+ grep -q "${SHARESCRIPT}" "${XSETUP}" || sed "1 a ${SHARESCRIPT} \&" -i "${XSETUP}"
+}
+
+write_xreset() {
+ logger "openslx vm_runtime: writing ${XRESET}..."
+ cat<<-BISHIER > "${XRESET}"
+ #!/bin/sh
+ ${UMOUNTSCRIPT} &
+ BISHIER
+}
+
+patch_xreset_shebang() {
+ # Patching after first line, to be exact.
+ logger "openslx vm_runtime: patching ${XRESET} after shebang line, if necessary."
+ grep -q "${UMOUNTSCRIPT}" "${XRESET}" || sed "1 a ${UMOUNTSCRIPT} \&" -i "${XRESET}"
+}
+
+case "${DISTRIBUTION}" in
+ opensuse) logger "openslx vm_runtime: openSuse detected."
+ if [ ! -e "${XSETUP}" ]; then
+ XSETUP=/etc/X11/xdm/Xsetup
+ write_xsetup
+ else
+ logger "openslx vm_runtime: patching ${XSETUP}."
+ if ! [ grep -c /etc/sysconfig/displaymanager "$XSETUP" 2>/dev/null 1>&2 ]; then
+ logger "openslx vm_runtime: Xsetup: openSuse marker found, patching."
+ sed "s#/etc/sysconfig/displaymanager#/etc/sysconfig/displaymanager\n"${SHARESCRIPT}" \&\n${RESOLUTIONSCRIPT} \&#g" \
+ -i "${XSETUP}"
+ else
+ logger "openslx vm_runtime: Xsetup: openSuse marker not found, patching after shebang line."
+ xsetup_patch_shebang
+ fi
+ logger "openslx vm_runtime: patching ${RESET}."
+ patch_xreset_shebang
+ fi
+ ;;
+ ubuntu) logger "openslx vm_runtime: Ubuntu detected, version ${VERSION}."
+ # Ubuntu has at least in version 14.04 LTS a bug leading to missing Xsetup/Xreset entries:
+ grep -q "session-setup-script=/etc/X11/Xsetup" /etc/lightdm/lightdm.conf.d/50-myconfig.conf \
+ || { sed "$ a session-setup-script=/etc/X11/Xsetup" -i /etc/lightdm/lightdm.conf.d/50-myconfig.conf
+ logger "openslx vm_runtime: session-setup-script patched into /etc/lightdm/lightdm.conf.d/50-myconfig.conf."; }
+ grep -q "session-reset-script=/etc/X11/Xreset" /etc/lightdm/lightdm.conf.d/50-myconfig.conf \
+ || { sed "$ a session-reset-script=/etc/X11/Xreset" -i /etc/lightdm/lightdm.conf.d/50-myconfig.conf
+ logger "openslx vm_runtime: session-reset-script patched into /etc/lightdm/lightdm.conf.d/50-myconfig.conf."; }
+ if [ ! -e "${XSETUP}" ]; then
+ XSETUP=/etc/X11/Xsetup
+ write_xsetup
+ else
+ patch_xsetup_shebang
+ fi
+ if [ ! -e "${XRESET}" ]; then
+ XRESETP=/etc/X11/Xreset
+ write_xreset
+ else
+ patch_xreset_shebang
+ fi
+ ;;
+ debian) logger "openslx vm_runtime: Debian detected."
+ ;;
+ *) logger "openslx vm_runtime: Unknown distribution, exiting."
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe b/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
index 114a0dc0..c0904c92 100755
--- a/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/data/openslx.exe
Binary files differ
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc
new file mode 100644
index 00000000..974a5626
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc
@@ -0,0 +1,32 @@
+########################################################
+# Include: Detect, whether runvirt runs in legacy mode #
+########################################################
+
+# Legacy mode: As runvirt has been before.
+# New mode: uuid in xml _and_ vmx given via http.
+
+writelog "Detecting current/legacy mode ..."
+
+declare -rg TMPCONFIG="$TMPDIR/vmconfig.tmp"
+
+# Assume legacy mode by default, only trigger "current" mode if everything else below worked
+LEGACY=yes
+if [ -z "$IMGUUID" ]; then # Keine uuid: Abbruch, Legacy
+ writelog "Could not extract a uuid param from ${xmlfile}. Triggering legacy mode."
+else
+ # Now getting template file:
+ if ! wget -T 6 -O "$TMPCONFIG" "${SLX_VMCHOOSER_BASE_URL}/lecture/${IMGUUID}" 2>/dev/null >&2; then
+ writelog "wget ${SLX_VMCHOOSER_BASE_URL}/lecture/${IMGUUID}. Triggering legacy mode."
+ else
+ writelog "wget ${SLX_VMCHOOSER_BASE_URL}/lecture/${IMGUUID} successful."
+ if [ ! -s "$TMPCONFIG" ]; then
+ writelog "Server sent zero byte virtual machine description file. Triggering legacy mode."
+ else
+ writelog "Triggering current (non-legacy) mode."
+ LEGACY= # everything worked - clear legacy mode variable (so we use the "current" mode)
+ fi
+ fi
+fi
+
+readonly LEGACY
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc
new file mode 100644
index 00000000..fdacc69c
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc
@@ -0,0 +1,63 @@
+############################################
+# Include: Get needed values from XML file #
+############################################
+
+writelog "Parsing XML..."
+
+declare -rg VMSTORE_PATH=/mnt/vmstore
+
+get_xml () {
+ xmlextract "//settings/eintrag/${1}/@param" "${xmlfile}"
+}
+
+IMGUUID=$(get_xml "uuid")
+
+# # Name of the virt image
+SRC_IMG_ABSOLUTE=$(get_xml "image_path")
+SRC_IMG_RELATIVE=$(get_xml "image_name")
+
+if [ -z "${SRC_IMG_ABSOLUTE}${SRC_IMG_RELATIVE}" ]; then
+ writelog "Neither relative nor absolute path for image found in xml"
+ cleanexit 1
+fi
+
+if [ -n "$SRC_IMG_ABSOLUTE" ] && [ "${SRC_IMG_ABSOLUTE:0:1}" != "/" ]; then
+ writelog "Error parsing XML for absolute image path: given value doesn't start with '/': '$SRC_IMG_ABSOLUTE'"
+ cleanexit 1
+fi
+
+if [ -z "$SRC_IMG_ABSOLUTE" ]; then
+ SRC_IMG_ABSOLUTE="${VMSTORE_PATH}/${SRC_IMG_RELATIVE}"
+fi
+
+IMG_BASENAME=$(basename "$SRC_IMG_ABSOLUTE")
+writelog "Virtual image file name: $IMG_BASENAME"
+
+VM_DISPLAYNAME=$(get_xml "short_description")
+[ -z "$VM_DISPLAYNAME" ] && VM_DISPLAYNAME="${IMG_BASENAME}"
+
+# Define VM_NAME_CLEAN since VM_DISPLAYNAME can be long and contain weird characters
+VM_NAME_CLEAN=$(echo "${VM_DISPLAYNAME:0:32}" | sed -r 's/[^0-9a-zA-Z_-\.]+/_/g')
+
+# image is for the following virtual machine
+PLUGIN_ID=$(grep -o 'virtualmachine param=.*"' "${xmlfile}" \
+ | sed -e "s/&.*;/; /g" | awk -F '"' '{print $2}')
+
+# Extracting OS type (VM_OS_TYPE) from xml file. We don't care here whether VM_OS_TYPE is empty, as then
+# it will yield the default entries later on.
+VM_OS_TYPE=$(get_xml "os")
+
+readonly IMGUUID
+readonly SRC_IMG_ABSOLUTE SRC_IMG_RELATIVE
+readonly IMG_BASENAME
+readonly VM_DISPLAYNAME VM_NAME_CLEAN
+readonly PLUGIN_ID
+readonly VM_OS_TYPE
+
+writelog "VM UUID: $IMGUUID"
+writelog "Virtualization plugin: $PLUGIN_ID"
+writelog "VM name: $VM_DISPLAYNAME"
+writelog "VM short name: $VM_NAME_CLEAN"
+writelog "VM OS: $VM_OS_TYPE"
+writelog "Done parsing XML."
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_hardware_variables.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_hardware_variables.inc
new file mode 100644
index 00000000..508c9efe
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_hardware_variables.inc
@@ -0,0 +1,113 @@
+###########################################
+# Include: Set hardware related variables #
+###########################################
+
+get_vm_id() {
+ local script=${BASH_SOURCE[-1]}
+ [ -z "$script" ] && script="$0"
+ if [ -n "$script" ]; then
+ script=$(readlink -f "$script")
+ if [ -n "$script" ] && [ -s "$script" ]; then
+ #bingo
+ VM_ID=$(ps ax | grep -F "$script" | grep -v 'grep' | grep -o -- "${script}.*\$" | sort -u | wc -l)
+ if [ "$VM_ID" -gt 0 ]; then
+ [ "${#VM_ID}" -eq 1 ] && VM_ID="0${VM_ID}"
+ [ "${#VM_ID}" -gt 2 ] && VM_ID="${VM_ID:0:2}"
+ [ "${#VM_ID}" -eq 2 ] && return
+ fi
+ fi
+ fi
+ # fallback: take last two digits of current pid...
+ VM_ID=$(expr substr $$ $(expr ${#$} - 1) 2)
+ [ "${#VM_ID}" -eq 1 ] && VM_ID="0${VM_ID}"
+}
+
+get_vm_id
+
+# Make sure cpu_cores is not empty
+cpu_cores=${cpu_cores:-"1"}
+
+# Amount of memory for the VM. Be generous if diff is written to HDD
+if mount | grep -q '^/dev/sd.*on.*/tmp'; then
+ reserve=20
+ min=768
+ max=1800
+else
+ reserve=65
+ min=768
+ max=8192
+fi
+
+# Calculate absulute amount of RAM that should stay available to the host
+reserve="$(( ( totalmem * reserve ) / 100 ))"
+# Respect some upper and lower bounds for the host amount
+[ "$reserve" -lt "$min" ] && reserve="$min"
+[ "$reserve" -gt "$max" ] && reserve="$max"
+
+# Get a result which can be divided by 4
+mem="$(( ( ( totalmem - reserve ) / 4 ) * 4 ))"
+if [ -n "$mainvirtmem" ]; then
+ forcemem="$(( mainvirtmem / 4 * 4 ))"
+ mem="$forcemem"
+fi
+hostmem="$(( totalmem - mem ))"
+
+# Fill in VMID
+macaddrsuffix=$(echo "$macaddrsuffix" | sed "s/%VMID%/${VM_ID}/")
+
+if ! echo "$macaddrprefix" | grep -q -E '^[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}$'; then
+ slxlog "virt-mac" "Could not properly generate mac address prefix (got $macaddrprefix)"
+fi
+if ! echo "$macaddrsuffix" | grep -q -E '^[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}$'; then
+ slxlog "virt-mac" "Could not properly generate mac address suffix (got $macaddrsuffix)"
+fi
+macaddr="$macaddrprefix:$macaddrsuffix"
+
+# Virtual fd/cd/dvd and drive devices, floppy b: for configuration
+# if $floppy_0 from virtualization.conf set then fdtest="TRUE"
+fdtest=${floppy_0:+"TRUE"}
+# if $fdtest not set floppy0="FALSE", else "TRUE"
+floppy0=${fdtest:-"FALSE"}
+# if $cdrom_0 from virtualization.conf set then cdtest="TRUE"
+cdtest=${cdrom_0:+"TRUE"}
+# if $cdtest not set cdrom0="FALSE", else "TRUE"
+cdrom0=${cdtest:-"FALSE"}
+# if $cdrom_1 from virtualization.conf set then cdtest="TRUE"
+cdtest=${cdrom_1:+"TRUE"}
+# if $cdtest not set cdrom1="FALSE", else "TRUE"
+cdrom1=${cdtest:-"FALSE"}
+
+# Dynamically detect serial ports here instead of at boot time
+# (virtualization.conf), since USB serial ports get quite common
+# and might not be plugged in at boot time yet
+serial_0=
+#for port in $(awk '{ if ($1 ~ /^[0-9]+:/ && $2 != "uart:unknown") print "/dev/ttyS" sub(/:\$/, "", $1) }' /proc/tty/driver/serial); do
+for port in $serial_ports /dev/ttyUSB*; do
+ [ -c "$port" ] || continue
+ serial_0="$port"
+ break
+done
+
+parallel_0=
+for port in /dev/parport*; do
+ [ -c "$port" ] || continue
+ parallel_0="$port"
+ break
+done
+
+# RDP/VNC port (59001 - 59099)
+remotedesktopport="590${VM_ID}"
+
+# Add rw share for home dir
+homesharepath="${HOME}/PERSISTENT"
+homesharename="home"
+
+# Add common share
+commonsharepath="${HOME}/SHARE"
+commonsharename="share"
+
+# Set hostname: using original hostname and adding string
+hostname="virt-$(hostname)"
+
+writelog "\tVM Hostname:\t\t$hostname"
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_variables.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_variables.inc
new file mode 100644
index 00000000..cd9a573a
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/set_runvirt_variables.inc
@@ -0,0 +1,26 @@
+######################################################
+# Include: Declaration of run-virt default variables #
+######################################################
+
+VMCHOOSER_DIR="/opt/openslx/vmchooser"
+VMCHOOSER_CONF_DIR="$VMCHOOSER_DIR/config"
+USER="$(whoami)"
+LOGFILE="/var/log/openslx/run-virt.${USER}.$$.log"
+TMPDIR="/tmp/virt/${USER}/$$"
+
+readonly VMCHOOSER_DIR VMCHOOSER_CONF_DIR LOGFILE TMPDIR USER
+
+# include general configuration from vmchooser
+[ -f "$VMCHOOSER_CONF_DIR/vmchooser.conf" ] && . "$VMCHOOSER_CONF_DIR/vmchooser.conf"
+# load general virtualization information
+[ -f "$VMCHOOSER_CONF_DIR/virtualization.conf" ] && . "$VMCHOOSER_CONF_DIR/virtualization.conf"
+# Load general openslx config
+[ -f "/opt/openslx/config" ] && . "/opt/openslx/config"
+# Create temp dir
+if ! mkdir -p "$TMPDIR"; then
+ slxlog "virt-tmpdir" "Could not create temporary directory '$TMPDIR' for session"
+ error_user "Konnte kein temporäres Arbeitsverzeichnis für die VM-Sitzung anlegen. Ein Computer-Neustart könnte das Problem lösen."
+ cleanexit 1
+ exit 1
+fi
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_firewall.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_firewall.inc
new file mode 100644
index 00000000..f0820ed7
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_firewall.inc
@@ -0,0 +1,12 @@
+
+setup_firewall () {
+ local LOGF="${TMPDIR}/firewall.log"
+ local RET
+ [ "$DISPLAY" = ":0" ] || return 0 # For now, to avoid conflicts, we only do this on display :0
+ slxfwtool "$IMGUUID" > "$LOGF" 2>&1
+ RET=$?
+ if [ "$RET" != "0" ]; then
+ slxlog "runvirt-firewall" "Error setting up firewall rules for lecture $IMGUUID (Exit code $RET)" "$LOGF"
+ fi
+ return 0
+}
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc
new file mode 100644
index 00000000..4240d9ca
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc
@@ -0,0 +1,98 @@
+###########################################################
+# Include: Setup dnbd for image access, nfs/cifs fallback #
+###########################################################
+
+# This will currently make sure that the variable
+# VM_DISKFILE_RO is set which will contain the
+# absolute path to the disk image to use for the vm
+# session.
+# When using DNBD3 this will differ from SRC_IMG_ABSOLUTE,
+# otherwise it will be identical.
+# In the future DNBD3 (or something else) might provide
+# a CoW layer so we don't need snapshots etc. anymore.
+# This include should set VM_DISKFILE_RW in that case to
+# indicate to the virt plugin that it doesn't need to
+# handle creating a temporary CoW layer itself.
+
+writelog "Setting up disk access for virtualizer/emulator ..."
+
+# Try to use dnbd3 to access the image
+unset VM_DISKFILE_RO
+unset dnbd3_fuse_mount_point
+
+setup_dnbd3 () {
+ # Mount path for images mounted with dnbd3-fuse
+ dnbd3_fuse_mount_point="$TMPDIR/dnbd3fuse.mnt"
+ mkdir -p "${dnbd3_fuse_mount_point}"
+ # start dnbd3-fuse in subshell
+ local dnbd3_tmplog="$TMPDIR/dnbd3fuse.log"
+ local dnbd3_exitflag="$TMPDIR/dnbd3exit$RANDOM"
+ local TIMEOUT vm_revision
+ rm -f -- "$dnbd3_exitflag"
+ (
+ dnbd3-fuse -f -o allow_other,max_readahead=262144 -h "$SLX_DNBD3_SERVERS" -i "${SRC_IMG_RELATIVE}" "${dnbd3_fuse_mount_point}" > "$dnbd3_tmplog" 2>&1
+ RET=$?
+ touch "$dnbd3_exitflag"
+ if [ "$RET" != "0" ]; then
+ writelog "dnbd3-fuse stopped working (Exit code $RET)"
+ slxlog "virt-dnbd3-fuse" "dnbd3-fuse stopped/refused serving '${SRC_IMG_RELATIVE}' from '${SLX_DNBD3_SERVERS}' with error code: $RET" "${dnbd3_tmplog}"
+ fi
+ ) &
+ # give it a bit of time
+ usleep 250000
+ # check if we have the image
+ for TIMEOUT in 0.5 1 1 OUT; do
+ if [ -r "${dnbd3_fuse_mount_point}/img" ]; then
+ vm_revision="$(grep -m 1 "^Revision:" "${dnbd3_fuse_mount_point}/status" | cut -d" " -f2)"
+ VM_DISKFILE_RO="${dnbd3_fuse_mount_point}/img"
+ writelog "DNBD3: $SRC_IMG_RELATIVE on $VM_DISKFILE_RO with rid $vm_revision"
+ break
+ fi
+ [ "$TIMEOUT" = "OUT" -o -e "$dnbd3_exitflag" ] && break
+ sleep "$TIMEOUT"
+ done
+
+ if [ -z "$VM_DISKFILE_RO" ]; then
+ slxlog "virt-dnbd3" "No dnbd3 server for ${SRC_IMG_RELATIVE} found, trying NFS/CIFS..." "$dnbd3_tmplog"
+ writelog "No working dnbd3 server found :-("
+ fi
+}
+
+# See if we should setup dnbd3 image access at all
+if ! which dnbd3-fuse; then
+ writelog "Can't use dnbd3 as dnbd3-fuse binary is not in PATH"
+elif [ -z "$SRC_IMG_RELATIVE" ]; then
+ writelog "Can't use dnbd3 as SRC_IMG_RELATIVE is not set"
+elif [ -z "$SLX_DNBD3_SERVERS" ] || [ "x$SLX_VM_DNBD3" != "xyes" ]; then
+ writelog "Can't use dnbd3 as no servers are given in config, or SLX_VM_DNBD3 is not set to yes"
+else
+ setup_dnbd3
+fi
+
+# VM_DISKFILE_RO will be empty if dnbd3 is not used or failed to connect.
+# Let's try to fall back to NFS/CIFS via file system
+if [ -z "$VM_DISKFILE_RO" ]; then
+ # Maybe we're reading a dnbd3 directory with RIDs encoded into the filename - use latest one
+ rid_suffix=$(ls -1 "${SRC_IMG_ABSOLUTE}.r"* | grep -E -o '\.r[0-9]+$' | grep -o -E '[0-9]+$' | sort -n | tail -n 1)
+ if [ -n "$rid_suffix" ]; then
+ # found
+ VM_DISKFILE_RO="${SRC_IMG_ABSOLUTE}.r${rid_suffix}"
+ elif [ -e "$SRC_IMG_ABSOLUTE" ]; then
+ # try name we got from xml in the first place
+ VM_DISKFILE_RO="$SRC_IMG_ABSOLUTE"
+ fi
+fi
+
+# Check if virtual machine container file exists
+if [ -z "$VM_DISKFILE_RO" ] || ! [ -e "${VM_DISKFILE_RO}" ]; then
+ slxlog "virt-image-missing" "VM image $VM_DISKFILE_RO not found!"
+ writelog "Virtual machine image ${VM_DISKFILE_RO} not found!"
+ error_user "Das Image für die gewählte Virtuelle Maschine konnte nicht gefunden werden.
+Versuchen Sie zunächst, den Computer komplett neu zu starten. Sollte das Problem bestehen bleiben, wenden Sie sich bitte an den Support."
+ cleanexit 1
+fi
+
+readonly VM_DISKFILE_RO
+
+writelog "Disk file to use: $VM_DISKFILE_RO"
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_printer_lpd.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_printer_lpd.inc
new file mode 100644
index 00000000..2fb9310a
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_printer_lpd.inc
@@ -0,0 +1,46 @@
+#####################################
+# Include: Setup printer daemon LPD #
+#####################################
+
+QUEUE="STANDARD" # This has to match the queue you configured in your VM
+SPOOLDIR=
+
+### Disabled: 100megs is not enough, some jobs are HUGE, try to use temp which should be on disk
+## Try using user's tmpfs home first, as it gets wiped on logout
+#if [ -n "${HOME}" ] && [ -w "${HOME}" ]; then
+# SPOOLDIR="${HOME}/.spool"
+# mkdir -p "${SPOOLDIR}/${QUEUE}"
+#fi
+# If failed, try to fall back to /tmp
+
+if [ -z "${SPOOLDIR}" ] || [ ! -w "${SPOOLDIR}/${QUEUE}" ]; then
+ SPOOLDIR="${TMPDIR}/printergui-${RANDOM}"
+ rm -rf -- "${SPOOLDIR}"
+ if ! mkdir -p "${SPOOLDIR}/${QUEUE}"; then
+ slxlog "virt-spooldir" "Could not create spool directory ($SPOOLDIR) for $USER - printing will not work!"
+ # TODO: Warn user
+ fi
+ chmod 0700 "${SPOOLDIR}/${QUEUE}"
+fi
+
+# Start the lpdaemon listening on the given port
+# TODO: externalize with something like runvirt.d (other parts might benefit from that too)
+tcpsvd -E 192.168.101.1 5515 \
+ lpd "$SPOOLDIR" \
+ ash -c "/opt/openslx/scripts/run-virt_print '${USER}' \"${SPOOLDIR}/${QUEUE}/\$DATAFILE\"" &
+
+# PID to kill the process
+PID_LPD="$!"
+
+{
+ sleep 2
+ # Check if tcpsvd is running. Do this a little delayed so we do not check
+ # immediately after trying to spawn it, as this could result in
+ # success even if it's not really working.
+
+ if ! kill -0 "$PID_LPD"; then
+ slxlog "virt-lpd" "Could not start tcpsvd/lpd for virtual machine session"
+ notify_user "Durcksystem" "Das Drucksystem konnte nicht initialisiert werden. Druckfunktion nicht verfügbar."
+ fi
+} &
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_sound.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_sound.inc
new file mode 100644
index 00000000..c6cece3d
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_sound.inc
@@ -0,0 +1,79 @@
+#!/bin/bash
+# ^-- Add shebang even though it's sourced so vim highlights bash specific features properly
+########################
+# Include: Setup sound #
+########################
+
+writelog "Starting sound setup ..."
+
+unset VOL
+if [ -r "/run/hwinfo" ] && source "/run/hwinfo"; then
+ # On startup, the volume of Master, PCM, Speaker, etc. will be set to 100%
+ # Some hardware with builtin speakers might be a bit too loud then, so you can
+ # define an exception table here. Array key is "Manufacturer//Model"
+ declare -A VOLUME_EXCEPTIONS
+ VOLUME_EXCEPTIONS["Hewlett-Packard//HP Compaq 8200 Elite CMT PC"]="85%" # This is bwPC3
+ # Read
+ VOL=${VOLUME_EXCEPTIONS["${HW_MANUF}//${HW_MODEL}"]}
+fi
+
+# Default to maximum volume
+if [ -z "$VOL" ]; then
+ VOL="100%"
+fi
+
+if true; then
+ # detecting which card is to be used
+ writelog --quiet "Detecting which sound card to use ..."
+ PROC="/proc/asound/cards"
+ if [ ! -r "$PROC" ]; then
+ writelog --quiet "'${PROC}' not found or not readable."
+ SOUND_CARD_INDEX=0
+ SOUND_CARD_COUNT=1
+ else
+ # Try to filter HDMI cards first
+ SOUND_CARD_INDEX=$(grep -v -i 'HDMI' "${PROC}" | grep -E -o '^[[:space:]]{0,2}[0-9]+[[:space:]]+' | head -n 1)
+ # If empty, try again with all
+ [ -z "${SOUND_CARD_INDEX}" ] && SOUND_CARD_INDEX=$(cat "${PROC}" | grep -E -o '^[[:space:]]{0,2}[0-9]+[[:space:]]+' | head -n 1)
+ if [ -z "${SOUND_CARD_INDEX}" ]; then
+ writelog --quiet "No sound card found."
+ SOUND_CARD_INDEX=0
+ fi
+ SOUND_CARD_COUNT=$(grep -E '^[[:space:]]{0,2}[0-9]+[[:space:]]+' "${PROC}" | wc -l)
+ fi
+
+ SOUND_CARD_INDEX="$(grep -E -o '[0-9]+' <<<$SOUND_CARD_INDEX)"
+ writelog --quiet "Detected sound card index is: $SOUND_CARD_INDEX"
+ writelog --quiet "Sound card count: $SOUND_CARD_COUNT"
+
+ # Adjust sound volume (playback)... Random mixer names we have encountered during testing
+ writelog --quiet "Setting up volume..."
+ (
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Master' "$VOL" unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'PCM' "100%" unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'CD' "100%" unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Headphone' "100%" unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Front' "100%" unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Speaker' "100%" unmute
+ # Recording. It seems that (most) devices need the volume set to 0, so you
+ # don't hear your own mic input, but should be unmuted. Also on some cards,
+ # you need to set the cap option on the mic you want to use, while other cards
+ # will just ignore that option.
+ # Plus, most cards have a Capture mixer, which needs to be set to cap too, and
+ # have its volume turned up. (There'll probably be some cards that need yet
+ # another setup, but this works for now on 4 tested cards)
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Rear Mic Boost' "50%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Rear Mic' "0%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Front Mic Boost' "50%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Front Mic' "0%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Mic Boost' "50%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Mic' "0%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Capture' "100%" cap unmute
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Input Source' 'Mic'
+ amixer -q -c "$SOUND_CARD_INDEX" sset 'Input Source' 'Front Mic' # Let's hope nobody uses rear mic...
+ # fix random static noise when starting vmplayer when module snd_pcsp (not pcspkr) is loaded
+ amixer -q -c pcsp sset Master "0%" mute 2>/dev/null >&2
+ ) 2>&1 | grep -v 'amixer: Unable to find'
+ writelog --quiet "Done setting up volume."
+fi >> "${LOGFILE}" 2>&1 # Don't pipe here since it would spawn a subshell so all variable modifications would be lost
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_virtual_floppy.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_virtual_floppy.inc
new file mode 100644
index 00000000..d9ae052c
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_virtual_floppy.inc
@@ -0,0 +1,101 @@
+#!/bin/bash
+##############################################
+# Include: Setup virtual floppy for drive b: #
+##############################################
+
+declare -rg FLOPPYIMG="${TMPDIR}/floppy.img"
+declare -rg TMPHOME="${HOME}"
+declare -rg RUNSCRIPT="${TMPDIR}/runscript.tmp"
+
+wget -T 6 -O "${RUNSCRIPT}" "${SLX_VMCHOOSER_BASE_URL}/lecture/${IMGUUID}/runscript" > /dev/null &
+WGET=$!
+
+dd "if=/dev/zero" "of=${FLOPPYIMG}" count=1440 bs=1024
+chmod 0600 "${FLOPPYIMG}"
+mkfs.fat "${FLOPPYIMG}" || mkfs.vfat "${FLOPPYIMG}" || mkdosfs "${FLOPPYIMG}"
+
+# Create file with resolution information etc.
+. "/opt/openslx/inc/shares"
+if [ -z "$SHARE_REMAP_MODE" ]; then
+ SHARE_REMAP_MODE_INI="0"
+ SHARE_REMAP_MODE="3"
+else
+ SHARE_REMAP_MODE_INI="$SHARE_REMAP_MODE"
+fi
+[ -z "$SHARE_CREATE_MISSING_REMAP" ] && SHARE_CREATE_MISSING_REMAP="1"
+declare -rg RESOLUTION=$(xrandr | grep -o -E 'connected\s*(primary)?\s*[0-9]+x[0-9]+\+0\+0' \
+ | grep -o -E -m1 '[0-9]+x[0-9]+')
+
+# Legacy: HOSTRES.TXT
+cat > "${TMPDIR}/HOSTRES.TXT" <<-HIER
+${RESOLUTION}
+HIER
+
+# Create file for network shares to mount
+declare -rg SHARES="${TMPDIR}/shares.dat"
+touch "${SHARES}"
+chmod 0600 "${SHARES}"
+if ! pwdaemon --query "${TMPHOME}/.pwsocket" > "${SHARES}"; then
+ slxlog "virt-pwdaemon" "Could not start pwdaemon"
+else
+ sed -i 's/^/192.168.101.1\t/' "${SHARES}" # TODO: Depending on nettype (in case we have != nat some day)
+ if [ "${SHARE_REMAP_MODE}" = 1 -o "${SHARE_REMAP_MODE}" = 2 ] && [ -e "${TMPHOME}/.home" ]; then
+ NETHOME=$(cat "${TMPHOME}/.home")
+ [ -z "$SHARE_HOME_DRIVE" ] && SHARE_HOME_DRIVE="H:"
+ # Tab between items, so spaces can be used!
+ echo "${NETHOME} ${SHARE_HOME_DRIVE} Home-Verzeichnis" >> "${SHARES}"
+ fi
+ for VAR in ${!SHARE_LINE_*}; do
+ echo "${!VAR}" >> "${SHARES}"
+ done
+fi
+
+wait "$WGET"
+
+# Check downloaded runscript, handle extension marker
+EXT=
+if [ -s "$RUNSCRIPT" ]; then
+ EXT=$(head -n 1 "$RUNSCRIPT" | grep -o -i '^EXT=.*$' | cut -d '=' -f 2-)
+ [ -n "$EXT" ] && [ "x${EXT:0:1}" != "x." ] && EXT=".$EXT"
+fi
+
+# Write info file
+UNAME=
+[ -s "${HOME}/.account" ] && UNAME=$(cat "${HOME}/.account")
+[ -z "${UNAME}" ] && UNAME=$(whoami)
+cat > "${TMPDIR}/openslx.ini" <<-HIER
+[openslx]
+username=${UNAME}
+resolution=${RESOLUTION}
+createMissingRemap=${SHARE_CREATE_MISSING_REMAP}
+remapMode=${SHARE_REMAP_MODE_INI}
+homeDrive=${SHARE_HOME_DRIVE}
+scriptExt=${EXT}
+
+[remap]
+documents=${SHARE_DOCUMENTS}
+downloads=${SHARE_DOWNLOADS}
+desktop=${SHARE_DESKTOP}
+media=${SHARE_MEDIA}
+other=${SHARE_OTHER}
+HIER
+
+# Copy all them there filez into floppy image
+mcopy -i "${FLOPPYIMG}" "${TMPDIR}/openslx.ini" "${TMPDIR}/HOSTRES.TXT" "${SHARES}" "::/"
+mcopy -i "${FLOPPYIMG}" "$VMCHOOSER_DIR/data/openslx.exe" "::/"
+# Copy guest configuration (with added information) config.xml to be accessed
+# via virtual floppy
+mcopy -i "${FLOPPYIMG}" "$xmlfile" "::/config.xml"
+
+# Copying linux directory:
+mcopy -s -i "${FLOPPYIMG}" "$VMCHOOSER_DIR/data/linux" "::/"
+
+# User supplied runscript
+if [ -n "$EXT" ]; then
+ sed -i '1d' "${RUNSCRIPT}"
+ mcopy -i "${FLOPPYIMG}" "${RUNSCRIPT}" "::/runscript${EXT}"
+fi
+
+rm -f -- "${SHARES}" "${TMPDIR}/openslx.ini" "${TMPDIR}/HOSTRES.TXT"
+unset SHARES VAR NETHOME UNAME
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_vm_hypervisor.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_vm_hypervisor.inc
new file mode 100644
index 00000000..7709a85d
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_vm_hypervisor.inc
@@ -0,0 +1,34 @@
+##########################################################################
+# Include: Setup virtual machine hypervisor via vm-specific include file #
+##########################################################################
+
+# Get all virtual machine specific stuff from the respective include file
+if [ ! -e "$VMCHOOSER_DIR/$PLUGIN_ID/run-virt.include" ] ; then
+ slxlog "virt-plugin-missing" "Could not find run-virt.include for $PLUGIN_ID ($VMCHOOSER_DIR/$PLUGIN_ID/run-virt.include)"
+ writelog "Failed because of missing ${PLUGIN_ID} plugin."
+ error_user "Konnte den Virtualisierer '$PLUGIN_ID' nicht finden. Starten der Virtuellen Maschine fehlgeschlagen.
+ Starten Sie den Computer neu und wenden Sie sich an den Support, wenn das Problem weiterhin besteht."
+ cleanexit 1
+fi
+
+self="${PLUGIN_ID}"
+
+if ! bash -n "$VMCHOOSER_DIR/$PLUGIN_ID/run-virt.include"; then
+ slxlog "virt-plugin-syntax" "run-virt.include for $PLUGIN_ID contains syntax errors (bash -n run-virt.include failed)"
+ writelog "Erroneous run-virt.include for $PLUGIN_ID (syntax check)"
+ error_user "Das Start-Script für den Virtualisierer '$PLUGIN_ID' ist fehlerhaft.
+ Starten Sie den Computer neu und wenden Sie sich an den Support, wenn das Problem weiterhin besteht."
+ cleanexit 1
+fi
+
+setup_vm_commandline () {
+ # Now including the hypervisor specific include file:
+ if ! source "$VMCHOOSER_DIR/$PLUGIN_ID/run-virt.include"; then
+ slxlog "virt-plugin-error" "run-virt.include for $PLUGIN_ID could not be sourced properly."
+ writelog "Erroneous run-virt.include for ${PLUGIN_ID}? Source returned != 0"
+ error_user "Das Start-Script für den Virtualisierer '$PLUGIN_ID' hat einen fehlercode zurückgegeben.
+ Starten Sie den Computer neu, falls es beim Ausführen der VM zu Problemen kommt
+ und wenden Sie sich an den Support, wenn das Problem weiterhin besteht."
+ fi
+}
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/start_windowmanager.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/start_windowmanager.inc
new file mode 100644
index 00000000..da43f341
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/start_windowmanager.inc
@@ -0,0 +1,27 @@
+####################################################
+# Include: Start windowmanager for easier handling #
+####################################################
+
+# Some problems may arise with windows opening in background when
+# using eg. vmware without a window manager.
+
+FOUND_WM=
+for dm in openbox kwin xfwm4 metacity blackbox twm fvwm2 ; do
+ if which $dm >/dev/null 2>&1 ; then
+ if [ "$dm" = "fvwm2" ] ; then
+ echo "EdgeScroll 0 0" > ${redodir}/fvwm
+ writelog "Starting fvwm2."
+ fvwm2 -f ${redodir}/fvwm >/dev/null 2>&1 &
+ else
+ writelog "Starting ${dm}."
+ $dm >/dev/null 2>&1 &
+ fi
+ FOUND_WM=1
+ break
+ fi
+done
+
+if [ -z "$FOUND_WM" ]; then
+ slxlog "virt-windowmanager" "Could not find any window manager to use!"
+ notify_user "Konnte keinen Window Manager finden. (Das ist schlecht!)"
+fi
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/usb_detector.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/usb_detector.inc
new file mode 100644
index 00000000..a2d442e4
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/usb_detector.inc
@@ -0,0 +1,77 @@
+# Helper function that will scan /dev/bus/usb for devices matching specific classes
+# and then output the corresponding device ids. This can be used for selective
+# handover of devices to a virtual machine
+
+declare -rg PASSTHROUGH_USB_DEVICES="2 0:5 0:6 0:7 0:14 0:16 0:17 239"
+
+# $1: expression to fill with device information.
+# valid placeholders are:
+# %VENDOR% - device vendor id
+# %PRODUCT% - device product id
+# $2-n: device classes to include in output
+get_usb_devices_int() {
+ [ -z "$TMPDIR" ] && TMPDIR="/tmp"
+ local EXP=$1
+ shift
+ if [ -z "$EXP" ]; then
+ writelog --quiet "No ouput expression template passed to get_usb_devices"
+ cleanexit 1
+ fi
+ if [ $# -eq 0 ]; then
+ writelog --quiet "No device classes given to get_usb_devices"
+ cleanexit 1
+ fi
+ local MATCH=';'
+ while [ $# -gt 0 ]; do
+ MATCH+="$1;"
+ [[ "$1" != *:* ]] && MATCH+="0:$1;"
+ shift
+ done
+ local dev=
+ local key value trailing
+ trailing=
+ local tmp="${TMPDIR}/lsusb.$$.$RANDOM"
+ for dev in /dev/bus/usb/*/*; do
+ if ! lsusb -D "$dev" > "$tmp" 2>/dev/null; then
+ writelog --quiet "Cannot lsusb $dev"
+ continue
+ fi
+ local DC=
+ local OK=
+ local VENDOR=
+ local PRODUCT=
+ while read -r key value trailing || [ -n "$key" ]; do
+ if [[ "$key" == "idVendor" ]]; then
+ [[ "$value" == 0x* ]] && VENDOR="${value:2}"
+ elif [[ "$key" == "idProduct" ]]; then
+ [[ "$value" == 0x* ]] && PRODUCT="${value:2}"
+ elif [ -z "$DC" ]; then
+ # No bDeviceClass seen yet
+ if [[ "$key" == "bDeviceClass" ]]; then
+ DC="$value"
+ [[ "$MATCH" == *";${DC};"* ]] && OK=yo
+ fi
+ else
+ # #DeviceClass is generic, look at sub class
+ if [[ "$key" == "bInterfaceClass" ]]; then
+ [[ "$MATCH" == *";${DC}:${value};"* ]] && OK=yo
+ fi
+ fi
+ if [ -n "$OK" -a -n "$VENDOR" -a -n "$PRODUCT" ]; then
+ echo "$EXP" | sed "s/%VENDOR%/${VENDOR}/g;s/%PRODUCT%/${PRODUCT}/g"
+ break
+ fi
+ done < "$tmp"
+ done
+ rm -f -- "$tmp"
+}
+
+get_usb_devices() {
+ if which lsusb 2>/dev/null >&2 && lsusb --help 2>&1 | grep -q -- '-D' 2>/dev/null; then
+ [ $# -eq 1 ] && set -- "$1" $PASSTHROUGH_USB_DEVICES # no quotes here!
+ get_usb_devices_int "$@" | sort -u
+ else
+ writelog --quiet "Cannot scan usb bus: lsusb not found or doesn't support -D"
+ fi
+}
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
new file mode 100644
index 00000000..ca475da0
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
@@ -0,0 +1,107 @@
+#######################################################
+# Include: Set functions needed by vmchooser-run_virt #
+#######################################################
+
+# function to write to stdout and logfile
+writelog() {
+ local DATE=$(date +%Y-%m-%d-%H-%M-%S)
+ # write to stdout?
+ if [ "x$1" = "x--quiet" ]; then
+ shift
+ else
+ echo -e "$DATE: $@"
+ fi
+ # log into file
+ echo -e "$DATE: $@" >> "${LOGFILE}"
+}
+
+notify_user() {
+ local TOPIC="$1"
+ shift
+ notify-send -u normal "$TOPIC" "$@"
+ writelog "Notify: **${TOPIC}**: $*"
+}
+
+error_user() {
+ local TOPIC="$1"
+ shift
+ local MSG TITLE BODY
+ if [ $# -gt 0 ]; then
+ MSG=" $TOPIC
+$*"
+ TITLE="$TOPIC"
+ BODY="$*"
+ else
+ MSG="$TOPIC"
+ TITLE="ERROR"
+ BODY="$TOPIC"
+ fi
+ # Zenity should yield the nicest result
+ zenity --error --title "$TITLE" --text "$BODY" && return
+ # QnD abuse printergui for error message as it's blocking
+ /opt/openslx/cups/printergui --error "$MSG" && return
+ # printergui might not exist, try fallback here
+ # unfortunately, i can only think of notify+sleep right now
+ notify-send -u critical "$TITLE" "$BODY"
+ sleep 10
+}
+
+# Clean exit will be called at the end of vmchooser-run_virt
+cleanexit() {
+ sleep 1
+ # Ummount dnbd3-fuse
+ if [ -n "$dnbd3_fuse_mount_point" ] && [ -e "$dnbd3_fuse_mount_point/img" ]; then
+ for timeout in 1 1 1 FAIL; do
+ fusermount -u "$dnbd3_fuse_mount_point" && break
+ writelog "dnbd3 still busy...."
+ [ "$timeout" = "FAIL" ] && break
+ sleep "$timeout"
+ done
+ fi
+ # Kill LPD
+ [ -n "${PID_LPD}" ] && kill "${PID_LPD}"
+
+ # If we're not in debug mode, remove all temporary files
+ if [ -n "${TMPDIR}" -a -z "$SLX_DEBUG" ]; then
+ rm -rf -- "${TMPDIR}"
+ fi
+
+ [ $# -gt 0 ] && exit "$1"
+ exit 129 # No exit code was given :/
+}
+
+rv_clean_string() {
+ if [ "$#" -ge 1 ]; then
+ echo "$@" | tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ else
+ tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ fi
+}
+
+# Check if the given variables are set (empty or not)
+isset() {
+ while [ $# -gt 0 ]; do
+ [ -z "${!1+x}" ] && return 1
+ shift
+ done
+ return 0
+}
+
+# Check if the given variables are not empty
+notempty() {
+ while [ $# -gt 0 ]; do
+ [ -z "${!1}" ] && return 1
+ shift
+ done
+ return 0
+}
+
+##
+# Extract given xpath from given xml file
+# e.g.: xmlextract '//node/nestednode/@attribute' "$file"
+# @param
+# @return Plain text, UTF-8
+xmlextract() {
+ xmlstarlet sel -T -E utf-8 -t -v "$1" "$2"
+}
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/scripts/set-firewall b/core/modules/run-virt/data/opt/openslx/vmchooser/scripts/set-firewall
new file mode 100644
index 00000000..2773150c
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/scripts/set-firewall
@@ -0,0 +1,130 @@
+#!/bin/bash
+
+# Do not rename/move this script, or change fwtool.c accordingly
+
+[ "$UID" = "0" ] || exit 1
+
+declare -rg RULES=$(mktemp)
+
+[ -n "$RULES" ] || exit 2
+
+[ -n "$1" ] || exit 3
+
+[ "${#1}" -ge 10 ] || exit 4
+[ "${#1}" -lt 40 ] || exit 5
+
+. /opt/openslx/config
+
+for TOOL in iptables ip6tables; do
+ $TOOL -w -F runvirt-INPUT || $TOOL -w -N runvirt-INPUT
+ $TOOL -w -F runvirt-OUTPUT || $TOOL -w -N runvirt-OUTPUT
+
+ if ! $TOOL -w -C INPUT -i br0 -j runvirt-INPUT; then
+ $TOOL -w -A INPUT -i br0 -j runvirt-INPUT
+ fi
+ if ! $TOOL -w -C OUTPUT -o br0 -j runvirt-OUTPUT; then
+ $TOOL -w -A OUTPUT -o br0 -j runvirt-OUTPUT
+ fi
+ if ! $TOOL -w -C FORWARD -i br0 -j runvirt-INPUT; then
+ $TOOL -w -A FORWARD -i br0 -j runvirt-INPUT
+ fi
+ if ! $TOOL -w -C FORWARD -o br0 -j runvirt-OUTPUT; then
+ $TOOL -w -A FORWARD -o br0 -j runvirt-OUTPUT
+ fi
+ $TOOL -A runvirt-INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
+ $TOOL -A runvirt-OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
+done
+
+declare -rg AUTORULES=$(mktemp)
+
+add_ips () {
+ # add_ips "IN/OUT" "IP1 IP2 IPn" "PORT" "ACCEPT/REJECT"
+ local IP
+ [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ] && return 1
+ for IP in $2; do
+ echo "$1 $IP $3 $4" >> "${AUTORULES}"
+ done
+}
+
+add_ips "IN" "127.0.0.0/8" 0 "ACCEPT"
+add_ips "OUT" "127.0.0.0/8" 0 "ACCEPT"
+add_ips "OUT" "$SLX_DNS" 53 "ACCEPT"
+add_ips "OUT" "$SLX_DNBD3_SERVERS" 5003 "ACCEPT"
+add_ips "OUT" "$SLX_KCL_SERVERS $SLX_SERVER_IP" 0 "ACCEPT"
+
+if [ -n "$SLX_VM_NFS" ]; then
+ IP=
+ if [ "${SLX_VM_NFS:0:2}" = '//' ]; then
+ IP=${SLX_VM_NFS:2}
+ IP=${IP%%/*}
+ else
+ IP=${SLX_VM_NFS%%:*}
+ fi
+ [ -n "$IP" ] && add_ips "OUT" "$IP" 0 "ACCEPT"
+fi
+
+sort -u "${AUTORULES}" > "${RULES}"
+
+wget -T 6 -O - "${SLX_VMCHOOSER_BASE_URL}/lecture/$1/netrules" >> "${RULES}" 2> "${AUTORULES}"
+RET=$?
+
+if [ "$RET" != "0" ]; then
+ echo "wget exit code: $RET :-("
+ grep -q "ERROR 404" "${AUTORULES}" && exit 0
+ exit 6
+fi
+
+declare -rg V4='^[0-9]+(\.[0-9]+)*(/[0-9]+)?$'
+declare -rg V6='^([0-9a-fA-F]+|:)(:+[0-9a-fA-F]*)*(/[0-9]+)?$'
+
+while read -r DIR DEST PORT ACTION GARBAGE || [ -n "$DIR" ]; do
+ if [ -z "$DEST" -o -z "$PORT" -o -z "$ACTION" ]; then
+ echo "Invalid rule: '$DIR $DEST $PORT $ACTION'"
+ continue
+ fi
+ IPLINE1=" -w"
+ IPLINE2=
+ if [ "$DIR" = "IN" ]; then
+ IPLINE1+=" -A runvirt-INPUT"
+ elif [ "$DIR" = "OUT" ]; then
+ IPLINE1+=" -A runvirt-OUTPUT"
+ else
+ continue
+ fi
+ if ! [[ $PORT =~ ^[0-9]+$ ]] || [ "$PORT" -gt 65535 ]; then
+ echo "Invalid port: '$PORT'"
+ continue
+ fi
+ if [ "$DEST" != "*" ]; then
+ if [ "$DIR" = "OUT" ]; then
+ IPLINE1+=" -d $DEST"
+ else
+ IPLINE1+=" -s $DEST"
+ fi
+ fi
+ if [ "$PORT" != 0 ]; then
+ IPLINE2+=" --dport $PORT"
+ fi
+ IPLINE2+=" -j $ACTION"
+ # IPv6?
+ if ! [[ $DEST =~ $V4 ]]; then
+ if [ "$PORT" = 0 ]; then
+ ip6tables $IPLINE1 $IPLINE2
+ else
+ ip6tables $IPLINE1 -p tcp $IPLINE2
+ ip6tables $IPLINE1 -p udp $IPLINE2
+ fi
+ fi
+ # IPv4
+ if ! [[ $DEST =~ $V6 ]]; then
+ if [ "$PORT" = 0 ]; then
+ iptables $IPLINE1 $IPLINE2
+ else
+ iptables $IPLINE1 -p tcp $IPLINE2
+ iptables $IPLINE1 -p udp $IPLINE2
+ fi
+ fi
+done < "$RULES"
+
+exit 0
+
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt b/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt
new file mode 100755
index 00000000..b945cca2
--- /dev/null
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt
@@ -0,0 +1,119 @@
+#!/bin/bash
+# Full bash required
+# -----------------------------------------------------------------------------
+# Copyright (c) 2007..2010 - RZ Uni FR
+# Copyright (c) 2007..2013 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# run-virt.sh
+# - This is the generic wrapper for the several virtualization solutions.
+# The idea is to setup a set of variables used by at least two different
+# tools and then include the specific plugin which configures the speci-
+# fied virtualization tool.
+################################################################################
+
+declare -rg RUNVIRTINCLUDEDIR=/opt/openslx/vmchooser/run-virt-includes
+declare -rg xmlfile="$1"
+
+# Functions needed by vmchooser-run_virt (writelog(), cleanexit(), rv_clean_string())
+if ! source "${RUNVIRTINCLUDEDIR}/vmchooser_runvirt_functions.inc"; then
+ slxlog "run-virt" "Could not source ${RUNVIRTINCLUDEDIR}/vmchooser_runvirt_functions.inc"
+ exit 1
+fi
+
+trap 'trap "" SIGINT SIGTERM; cleanexit' SIGINT SIGTERM
+
+# Define default dirs / get configs
+source "${RUNVIRTINCLUDEDIR}/set_runvirt_variables.inc"
+
+# Read needed variables from XML file
+source "${RUNVIRTINCLUDEDIR}/get_xml_file_variables.inc"
+
+# Download meta data from server (e.g. vmx for vmware)
+source "${RUNVIRTINCLUDEDIR}/download_vm_metadata.inc"
+
+if ! isset IMGUUID TMPCONFIG TMPDIR USER; then
+ slxlog "run-virt" "Internal sanity check failed: One of IMGUUID TMPCONFIG TMPDIR USER is not set."
+ cleanexit 1
+fi
+
+if [ "$LEGACY" ]; then
+
+ # No longer supported - yay
+
+ error_user "Legacy Mode" "
+Die gewählte VM ist eine 'Legacy VM', für die unvollständige
+Metadaten auf dem bwLehrpool-Server hinterlegt sind. Diese
+werden nicht mehr unterstützt. Um diese VM weiterhin nutzen
+zu können, muss sie mittels der bwLehrpool-Suite heruntergeladen,
+einmal gebootet, und wieder hochgeladen werden.
+(Bei der Gelegenheit könnten z.B. auch gleich anfallende Updates
+eingespielt werden.)
+"
+ cleanexit 1
+
+ # End legacy warning
+fi
+
+# Proper meta data received - proceed normally
+
+# Helper that looks for virtualizer-specific include, show error to user if not found
+source "${RUNVIRTINCLUDEDIR}/setup_vm_hypervisor.inc"
+
+# For scanning for certain usb classes
+source "${RUNVIRTINCLUDEDIR}/usb_detector.inc"
+
+# Firewall
+source "${RUNVIRTINCLUDEDIR}/setup_firewall.inc" || writelog "Could not source setup_firewall"
+setup_firewall || writelog "Could not run setup_firewall"
+
+# Sound setup
+source "${RUNVIRTINCLUDEDIR}/setup_sound.inc"
+
+# Declaration of hardware relatedt variables
+source "${RUNVIRTINCLUDEDIR}/set_runvirt_hardware_variables.inc"
+
+# Start printer daemon
+source "${RUNVIRTINCLUDEDIR}/setup_printer_lpd.inc"
+
+# Setup virtual floppy b: for windows guests with config.xml, openslx.exe etc.
+source "${RUNVIRTINCLUDEDIR}/setup_virtual_floppy.inc"
+
+# Try to use dnbd3 to access the image, nfs/cifs fallback
+source "${RUNVIRTINCLUDEDIR}/setup_image_access.inc"
+
+# Window manager required for handling of popups etc.
+source "${RUNVIRTINCLUDEDIR}/start_windowmanager.inc"
+
+# Source run-virt.include of virtualizer
+setup_vm_commandline
+
+# It should have set this variable if all went well
+if [ -z "${VIRTCMD}" ]; then
+ error_user "Fehler beim Starten der VM-Sitzung" "
+Das Start-Script für den Virtualisierer $PLUGIN_ID hat kein Kommando
+zum Starten der Sitzung definiert. Kann Sitzung nicht initialisieren."
+ slxlog "virt-plugin-error" "run-virt.include for $PLUGIN_ID did not set VIRTCMD"
+ cleanexit 1
+fi
+
+writelog "VM command: eval ${VIRTCMD} ${VIRTCMDOPTS}"
+# This will start the VM
+eval ${VIRTCMD} ${VIRTCMDOPTS}
+
+writelog "Virtualizer exited. Bye."
+
+# Postrun for commands after virtualization finishes
+if [ -n "${POSTRUN}" ]; then
+ eval ${POSTRUN} >/dev/null 2>&1
+fi
+
+cleanexit 0
+
diff --git a/core/modules/run-virt/fwtool/main.c b/core/modules/run-virt/fwtool/main.c
new file mode 100644
index 00000000..9e272384
--- /dev/null
+++ b/core/modules/run-virt/fwtool/main.c
@@ -0,0 +1,32 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ puts("Nee\n");
+ return 1;
+ }
+ char * const nargv[] = {
+ "bash",
+ "/opt/openslx/vmchooser/scripts/set-firewall",
+ argv[1],
+ 0
+ };
+ char * const nenv[] = {
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/openslx/sbin:/opt/openslx/bin",
+ "HOME=/root",
+ "LC_ALL=C",
+ "LANG=C",
+ 0
+ };
+
+ setresuid(0, 0, 0);
+ setregid(0, 0);
+
+ execve("/bin/bash", nargv, nenv);
+}
+
diff --git a/core/modules/run-virt/module.build b/core/modules/run-virt/module.build
index 26762bca..56afd839 100644
--- a/core/modules/run-virt/module.build
+++ b/core/modules/run-virt/module.build
@@ -8,9 +8,13 @@ build () {
rm -f -- "$COPYLIST"
list_packet_files > "$COPYLIST"
tarcopy "$(cat "$COPYLIST" | sort -u)" "${MODULE_BUILD_DIR}"
+ # Compile pwdaemon
+ mkdir -p "${MODULE_BUILD_DIR}/opt/openslx/bin"
+ gcc -std=gnu99 -o "${MODULE_BUILD_DIR}/opt/openslx/bin/pwdaemon" -Os "${MODULE_DIR}/pw_daemon.c" || perror "Could not compile the pwdaemon"
+ gcc -std=gnu99 -o "${MODULE_BUILD_DIR}/opt/openslx/bin/slxfwtool" -Os "${MODULE_DIR}/fwtool/main.c" || perror "Could not compile slxfwtool"
}
post_copy() {
- :
+ chmod +s "${TARGET_BUILD_DIR}/opt/openslx/bin/slxfwtool" || perror "Could not set suid bit on slxfwtool"
}
diff --git a/core/modules/run-virt/module.conf b/core/modules/run-virt/module.conf
index bd24ba58..cc1b34a6 100644
--- a/core/modules/run-virt/module.conf
+++ b/core/modules/run-virt/module.conf
@@ -1,4 +1,8 @@
REQUIRED_BINARIES="
lsusb
+ mcopy
+ pwdaemon
+ slxfwtool
+ xmlstarlet
"
diff --git a/core/modules/run-virt/module.conf.ubuntu b/core/modules/run-virt/module.conf.ubuntu
index b285210b..b6008fa0 100644
--- a/core/modules/run-virt/module.conf.ubuntu
+++ b/core/modules/run-virt/module.conf.ubuntu
@@ -1,7 +1,11 @@
REQUIRED_INSTALLED_PACKAGES="
usbutils
+ mtools
+ xmlstarlet
"
REQUIRED_CONTENT_PACKAGES="
usbutils
+ mtools
+ xmlstarlet
"
diff --git a/core/modules/run-virt/pw_daemon.c b/core/modules/run-virt/pw_daemon.c
new file mode 100644
index 00000000..768a5b00
--- /dev/null
+++ b/core/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, (struct sockaddr*)&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';
+ printf("%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, (struct sockaddr*)&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);
+ ret = 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, (struct sockaddr*)&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, (struct sockaddr*)&remote, &remoteLen);
+ if (ret == KEYLEN && memcmp(key1, buffer, KEYLEN) == 0) {
+ if (sendto(fd, passwordEnc, passwordLen, 0, (struct sockaddr*)&remote, sizeof(remote)) == -1) {
+ perror("Could not send password to remote peer");
+ }
+ }
+ }
+}
+
diff --git a/core/modules/run-virt/winres/compile b/core/modules/run-virt/winres/compile
new file mode 100755
index 00000000..da2f59eb
--- /dev/null
+++ b/core/modules/run-virt/winres/compile
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm -- winres.exe
+i686-w64-mingw32-windres -i winres.rc -o resource.res -O coff
+i686-w64-mingw32-gcc -Wall -Wextra -pedantic -Wno-unused-parameter -flto -std=c99 -Os -Wl,--subsystem,windows -o winres.exe winres.c resource.res -lole32 -luuid -lgdi32 -lws2_32 -lshell32 -lmpr -lshlwapi
+rm -- resource.res
+if strip winres.exe; then
+ echo "Successfully created winres.exe"
+ echo "It has NOT been moved to data/.../openslx.exe"
+else
+ echo "FAIL FAIL FAIL no EXE generated!"
+fi
+
diff --git a/core/modules/run-virt/winres/winres.c b/core/modules/run-virt/winres/winres.c
new file mode 100644
index 00000000..44654161
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.c
@@ -0,0 +1,1166 @@
+#define NTDDI_VERSION NTDDI_VISTA
+#define WINVER 0x0602
+#define _WIN32_WINNT 0x0602
+#define WIN32_LEAN_AND_MEAN
+#define _UNICODE
+#define UNICODE
+#define NO_SHLWAPI_STRFCNS
+#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 <shlguid.h>
+#include <strsafe.h>
+#include <tlhelp32.h>
+#include <shlwapi.h>
+#include <shellapi.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 {
+ const char* path;
+ const char* pathIp;
+ 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 BOOL _debug = FALSE;
+
+static HINSTANCE hKernel32, hShell32;
+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;
+
+#define SCRIPTFILELEN (50)
+char _scriptFile[SCRIPTFILELEN];
+
+struct {
+ BOOL documents;
+ BOOL downloads;
+ BOOL desktop;
+ BOOL media;
+ BOOL other;
+} remap;
+static BOOL _createMissingRemap = FALSE;
+
+static void setPowerState();
+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;
+}
+
+typedef HRESULT (*GFPTYPE)(HWND, int, HANDLE, DWORD, wchar_t*);
+typedef HRESULT (*GSFTYPE)(HWND, int, ITEMIDLIST**);
+typedef BOOL (*ID2PTYPE)(const ITEMIDLIST*, wchar_t*);
+
+/**
+ * Load given path (CSIDL). Store in default (must be allocated to hold at least MAX_PATH+1 chars).
+ * If it could not be retrieved by CSIDL and envName is not NULL, it will be read from the
+ * environment if possible.
+ * fallback will be used if everything else fails.
+ * fallback can be NULL, in which case the fallback is empty.
+ */
+static void loadPath(wchar_t *dest, int csidl, wchar_t *envName, wchar_t *fallback)
+{
+ if (hShell32 != NULL) {
+ GFPTYPE aGetFolderPath = (GFPTYPE)GetProcAddress(hShell32, "SHGetFolderPathW");
+ if (aGetFolderPath != NULL) {
+ if ((aGetFolderPath)(HWND_DESKTOP, csidl, NULL, SHGFP_TYPE_CURRENT, dest) == S_OK)
+ return;
+ }
+ // Fallback
+ GSFTYPE aGetSpecialFolder = (GSFTYPE)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
+ ID2PTYPE aPathToId = (ID2PTYPE)GetProcAddress(hShell32, "SHGetPathFromIDListW");
+ if (aGetSpecialFolder != NULL && aPathToId != NULL) {
+ ITEMIDLIST *list = NULL;
+ HRESULT ret1 = (aGetSpecialFolder)(HWND_DESKTOP, csidl, &list);
+ BOOL ret2 = FALSE;
+ if (ret1 == 0) {
+ ret2 = (aPathToId)(list, dest);
+ }
+ if (list != NULL) {
+ CoTaskMemFree(list);
+ }
+ if (ret2)
+ return;
+ }
+ }
+ if (envName != NULL) {
+ // Fallback
+ DWORD ret = GetEnvironmentVariableW(envName, dest, MAX_PATH+1);
+ if (ret > 0 && ret <= MAX_PATH)
+ return;
+ }
+ if (fallback != NULL) {
+ StringCchPrintfW(programsPath, MAX_PATH+1, fallback);
+ return;
+ }
+ *dest = '\0';
+}
+
+static void loadPaths()
+{
+ // Determine a couple of default directories
+ // dest, id, env, fallback
+ loadPath(programsPath, CSIDL_PROGRAM_FILES, L"ProgramFiles", L"C:\\Program Files");
+ loadPath(windowsPath, CSIDL_WINDOWS, L"windir", L"C:\\WINDOWS");
+ loadPath(desktopPath, CSIDL_DESKTOPDIRECTORY, NULL, NULL);
+ if (GetTempPathW(MAX_PATH+1, tempPath) == 0) {
+ DWORD ret = GetEnvironmentVariableW(L"TEMP", tempPath, MAX_PATH+1);
+ if (ret == 0 || ret > MAX_PATH) {
+ tempPath[0] = 0;
+ }
+ }
+ //wlog(L"Programs: %s, Windows: %s, Desktop: %s, Temp: %s", programsPath, windowsPath, desktopPath, tempPath);
+ 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);
+ // Get extension for autorun script
+ GetPrivateProfileStringA("openslx", "scriptExt", "", buffer, sizeof(buffer), SETTINGS_FILE);
+ StringCchPrintfA(_scriptFile, SCRIPTFILELEN, "B:\\runscript%s", buffer);
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ hKernel32 = LoadLibraryW(L"kernel32.dll");
+ if (hKernel32 == NULL) {
+ alog("Cannot load kernel32.dll");
+ }
+ hShell32 = LoadLibraryW(L"shell32.dll");
+ if (hShell32 == NULL) {
+ alog("Cannot load shell32.dll");
+ }
+ winVer.dwOSVersionInfoSize = sizeof(winVer);
+ BOOL retVer = GetVersionEx(&winVer);
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+ _startTime = GetTickCount();
+ loadPaths();
+ if (lpCmdLine != NULL && strstr(lpCmdLine, "debug") != NULL) {
+ _debug = TRUE;
+ 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);
+ // Same with standby
+ setPowerState();
+ // 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());
+ }
+ }
+ // Runscript (if any)
+ if (PathFileExistsA(_scriptFile)) {
+ ShellExecuteA(NULL, "open", _scriptFile, NULL, "B:\\", SW_SHOWNORMAL);
+ }
+ // Message pump
+ MSG Msg;
+ while(GetMessage(&Msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+ FreeLibrary(hKernel32);
+ FreeLibrary(hShell32);
+ 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;
+}
+
+typedef EXECUTION_STATE (WINAPI *TETYPE)(EXECUTION_STATE);
+
+static void setPowerState()
+{
+ // Disable standby and idle-mode (this is a VM!)
+ if (hKernel32 == NULL || winVer.dwMajorVersion < 5 || (winVer.dwMajorVersion == 5 && winVer.dwMinorVersion < 1))
+ return;
+ TETYPE aExecState = (TETYPE)GetProcAddress(hKernel32, "SetThreadExecutionState");
+ if (aExecState == NULL) {
+ alog("Cannot get SetThreadExecutionState from kernel32.dll");
+ return;
+ }
+ if (winVer.dwMajorVersion >= 6) { // Vista+
+ (aExecState)(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_AWAYMODE_REQUIRED);
+ } else { // XP/2003
+ (aExecState)(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
+ }
+}
+
+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;
+}
+
+const char* uncReplaceFqdnByIp(const char* path)
+{
+ if (path == NULL || path[0] != '\\' || path[1] != '\\')
+ return NULL;
+ const char *host = path + 2;
+ const char *rest = strchr(host, '\\');
+ if (rest == NULL || rest - host >= 200)
+ return NULL;
+ char name[201];
+ strncpy(name, host, rest - host);
+ name[rest-host] = '\0';
+ if (_debug) {
+ alog("Trying to resolve '%s'...", name);
+ }
+ struct hostent *remote = gethostbyname(name);
+ if (remote == NULL || remote->h_addrtype != AF_INET || remote->h_addr_list[0] == 0)
+ return NULL;
+ struct in_addr addr;
+ addr.s_addr = *(u_long*)remote->h_addr_list[0];
+ char *ip = inet_ntoa(addr);
+ if (ip == NULL)
+ return NULL;
+ size_t len = 2 /* \\ */ + strlen(ip) /* 1.2.3.4 */ + strlen(rest) /* \path\to\share */ + 1 /* nullchar */;
+ char *retval = malloc(len);
+ snprintf(retval, len, "\\\\%s%s", ip, rest);
+ if (_debug) {
+ alog("Turned '%s' into '%s'", path, retval);
+ }
+ return retval;
+}
+
+#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;
+ // Hack: For unknown reasons, with some servers mounting fails using a fqdn, but using the ip address instead succeeds.
+ d->pathIp = uncReplaceFqdnByIp(d->path);
+ //
+ 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, BOOL useIp)
+{
+ wchar_t path[BUFLEN] = L"", user[BUFLEN] = L"", pass[BUFLEN] = L"", letter[10] = L"", shortcut[BUFLEN] = L"";
+ int ok = -1;
+ if (useIp && d->pathIp[0] == '\0')
+ return FALSE;
+ const char *uncPath = useIp ? d->pathIp : d->path;
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)uncPath, -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')", uncPath);
+ 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], FALSE)) {
+ drives[i].success = TRUE;
+ } else if (mountNetworkShare(&drives[i], TRUE)) {
+ 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, FALSE);
+}
+
+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;
+}
+
+typedef HANDLE (WINAPI *SNTYPE)(DWORD, DWORD);
+typedef BOOL (WINAPI *P32TYPE)(HANDLE, PROCESSENTRY32W*);
+
+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
+ // Late binding
+ if (hKernel32 == NULL || winVer.dwMajorVersion < 5 || (winVer.dwMajorVersion == 5 && winVer.dwMinorVersion < 1)) {
+ return;
+ }
+ SNTYPE aCreateSnapshot;
+ P32TYPE aProcessFirst, aProcessNext;
+ aCreateSnapshot = (SNTYPE)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
+ if (aCreateSnapshot == NULL) {
+ alog("No CreateToolhelp32Snapshot in kernel.dll");
+ return;
+ }
+ aProcessFirst = (P32TYPE)GetProcAddress(hKernel32, "Process32FirstW");
+ if (aProcessFirst == NULL) {
+ alog("No Process32FirstW in kernel.dll");
+ return;
+ }
+ aProcessNext = (P32TYPE)GetProcAddress(hKernel32, "Process32NextW");
+ if (aProcessNext == NULL) {
+ alog("No Process32NextW in kernel.dll");
+ return;
+ }
+ PROCESSENTRY32W entry;
+ entry.dwSize = sizeof(PROCESSENTRY32W);
+ HANDLE snapshot = (aCreateSnapshot)(TH32CS_SNAPPROCESS, 0);
+ if (snapshot != INVALID_HANDLE_VALUE && (aProcessFirst)(snapshot, &entry)) {
+ do {
+ if (_wcsicmp(entry.szExeFile, L"explorer.exe") == 0) {
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
+ if (hProcess == NULL) {
+ alog("Cannot OpenProcess explorer.exe: Remapped paths will not work properly (GetLastError=%d)", (int)GetLastError());
+ } else {
+ if (TerminateProcess(hProcess, 23)) {
+ killOk = TRUE;
+ }
+ CloseHandle(hProcess);
+ }
+ }
+ } while ((aProcessNext)(snapshot, &entry));
+ } else {
+ alog("Could not get process list");
+ }
+ CloseHandle(snapshot);
+ if (patchOk && killOk) {
+ _folderStatus = FS_OK;
+ }
+}
+
diff --git a/core/modules/run-virt/winres/winres.manifest b/core/modules/run-virt/winres/winres.manifest
new file mode 100644
index 00000000..a4ffc98e
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.manifest
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+ <assemblyIdentity type="win32"
+ name="org.openslx.windows.winres"
+ version="4.0.0.0"
+ processorArchitecture="x86"
+ publicKeyToken="0000000000000000"
+ />
+ <description>Sausageface</description>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"
+ />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/core/modules/run-virt/winres/winres.rc b/core/modules/run-virt/winres/winres.rc
new file mode 100644
index 00000000..a9faf9a0
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.rc
@@ -0,0 +1,4 @@
+#include <windows.h>
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "winres.manifest"
+