Skip to content

Instantly share code, notes, and snippets.

@bashenk
Last active August 8, 2023 09:03
Show Gist options
  • Save bashenk/dcfe262f48a00638ee27e01136b5a7e7 to your computer and use it in GitHub Desktop.
Save bashenk/dcfe262f48a00638ee27e01136b5a7e7 to your computer and use it in GitHub Desktop.
Auto setup of X11 on WSL without disabling access control
#!/usr/bin/env sh
say() { if ! ${quiet:-false}; then printf '%s\n' "$@"; fi; }
err() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2; }
# File name of the Windows xserver program
win_xserver='vcxsrv.exe'
# Full path to the Windows xauth program for the running xserver
# PROGRA~1 is the short name for "Program Files", which solves spaces issues
win_xauth_exe='/mnt/c/PROGRA~1/VcXsrv/xauth.exe'
# Screen to use for the DISPLAY (can be either an integer or a decimal)
screen='0.0'
# Normally xauth defaults to ~/.Xauthority, but a different file will allow automatically removing outdated entries
xauthority_file="$HOME/.Xauthority"
# Whether or not to force recreation of the .Xauthority file
force=false
while getopts ":a:e:fhqs:x:" OPT; do
case "$OPT" in
a) win_xauth_exe="${OPTARG}" ;;
e) screen="${OPTARG}" ;;
f) force=true ;;
h)
cat << EOL
Configure X11 from WSL to the Windows host X Window server
wsl_x11_setup.sh [-a PATH] [-e NUM] [-f] [-q] [-s FILENAME] [-x PATH]
-a Specify the xauth.exe path to use
-e Specify the screen to use for the DISPLAY
Can be either an integer or a decimal
-f Force recreation of .Xauthority file
-h Display this help text
-q Prevent all output
-s Specify the file name of the Windows xserver program
This will be used to verify the server is running
-x Specify the .Xauthority file to use
EOL
exit 0
;;
q) quiet=true ;;
s) win_xserver="${OPTARG}" ;;
x) xauthority_file="${OPTARG}" ;;
\?)
err "Argument '-${OPTARG}' not recognized"
exit 3
;;
esac
done
shift $((OPTIND - 1))
# Get the adapter address on WSL2
_remote_ip="$(awk '/nameserver/ { print $2; exit 0 }' < /etc/resolv.conf)"
# An alternative way to retrieve the real adapter address on WSL2, which would be different than /etc/resolv.conf if you
# happened to make changes to that file.
if [ -z "$_remote_ip" ]; then
_remote_ip="$(/mnt/c/Windows/System32/ipconfig.exe \
| awk 'BEGIN{RS="\r\n"} NR==1,/vEthernet \(WSL\):/ {next}; $1=="IPv4" {print $NF; exit}')"
fi
export DISPLAY="${_remote_ip}:${screen}"
# Tests whether the currently defined DISPLAY is already configured in xauth
check_xauth() {
touch "$xauthority_file"
say "Checking for existence of current DISPLAY ($DISPLAY) in $xauthority_file file"
[ -n "$(xauth -f "$xauthority_file" -n list "$DISPLAY")" ]
}
# Validates that the configured X11 forwarding is working
validate_x11_forwarding() {
say "Validating X11 forwarding is working"
xset q 1> /dev/null 2>&1
}
# Simple check for a running existence of the win_xserver process. This is faster, though less reliable, than check_processes
check_tasklist() {
say "Checking task list for existence of $win_xserver"
/mnt/c/Windows/System32/tasklist.exe /V /FI "IMAGENAME eq $win_xserver" /FI "STATUS eq running" /NH 2> /dev/null \
| grep -qs "^$win_xserver"
}
# Checks whether the process list contains an entry with the win_xserver process running on the same display to which we
# intend to connect. This is slower, though more reliable, than check_tasklist
check_processes() {
say "Checking process list for existence of $win_xserver"
_processes="$(/mnt/c/Windows/System32/Wbem/wmic.exe path win32_process get commandline /format:list \
| sed -e 's/ \{2,\}//' \
| grep -o "${win_xserver%.*}.*:[0-9]\.\?[0-9]\?")"
echo "$_processes" | grep -qs "${win_xserver%.*}" && echo "$_processes" | grep -qs "\s:${screen%.*}"
}
# Creates a temporary xauth token on the Windows side that'll allow an authorized connection
add_cookie_to_remote() {
if [ ! -f "$win_xauth_exe" ]; then
err "Windows xauth.exe program not found at '$win_xauth_exe'"
return 3
fi
_key="$(printf '%s\n' "generate localhost:${screen%.*} . trusted timeout 604800" 'list' 'quit' \
| "$win_xauth_exe" -i -n -q 2> /dev/null)"
touch "$xauthority_file"
xauth -f "$xauthority_file" -q remove "$DISPLAY"
say "Adding DISPLAY to xauth"
[ -n "$_key" ] && xauth -f "$xauthority_file" -q add "$DISPLAY" . "${_key##* }"
}
# Use check_tasklist for slightly quicker, less reliable check, or check_processes for a more reliable, slighly slower check
if ! check_tasklist; then
err "$win_xserver is not running on display $DISPLAY"
exit 1
fi
if ! $force && check_xauth && validate_x11_forwarding; then
say 'xauth is already set up'
exit 0
fi
if ! add_cookie_to_remote; then
err "Unable to create MIT-MAGIC-COOKIE-1 for display $DISPLAY"
exit 2
else
say "Successfully set up X11 for $DISPLAY"
exit 0
fi
@mikaello
Copy link

Thanks a lot for this Gist! Everything except line 111 works perfect:

| "$win_xauth_exe" -i -n -q 2> /dev/null)"

This step I have to do manually because the xauth.exe fails with:

/mnt/c/Users/.../vcxsrv_v1.20/xauth.exe: Permission denied

... when I try to run it from WSL. Did you do anything to be able to run xauth.exe from WSL?

@mikaello
Copy link

mikaello commented Oct 28, 2022

It helps to ask! I found a fix, I just added the following to /etc/wsl.conf (source):

[automount]
enabled = true
options = "metadata,umask=0077,fmask=0077"

(read about automount in Microsoft article "Automatically Configuring WSL")

And chmod the xauth.exe so I got permission to run it, i.e.:

chmod +x /mnt/c/Users/.../vcxsrv_v1.20/xauth.exe

Then it worked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment