Skip to content

Instantly share code, notes, and snippets.

@justsh
Forked from samhocevar/gist:00eec26d9e9988d080ac
Last active January 23, 2017 22:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justsh/311ae744c73c76be24b4d88b588c72a5 to your computer and use it in GitHub Desktop.
Save justsh/311ae744c73c76be24b4d88b588c72a5 to your computer and use it in GitHub Desktop.
Configure sshd on MSYS2 and run it as a Windows service
#!/bin/sh
#
# msys2-sshd-setup.sh — configure sshd on MSYS2 and run it as a Windows service
#
# Please report issues and/or improvements to Sam Hocevar <sam@hocevar.net>
#
# Prerequisites:
# — MSYS2 itself: http://sourceforge.net/projects/msys2/
# — admin tools: pacman -S openssh cygrunsrv mingw-w64-x86_64-editrights
#
# This script is a cleaned up and improved version of the procedure initially
# found at https://ghc.haskell.org/trac/ghc/wiki/Building/Windows/SSHD
#
# Changelog:
# 24 Aug 2015 — run server with -e to redirect logs to /var/log/sshd.log
#
set -e
# Configuration
PRIV_USER=sshdsrv
PRIV_NAME="Privileged user for sshd"
UNPRIV_USER=sshd # DO NOT CHANGE; this username is hardcoded in the openssh code
UNPRIV_NAME="Privilege separation user for sshd"
EMPTY_DIR=/var/empty
to_install=""
# Check installation sanity
if ! /mingw64/bin/editrights -h 1>/dev/null 2>&1; then
echo "Missing 'editrights'. Marking 'mingw-w64-x86_64-editrights' for install..."
to_install="$to_install mingw-w64-x86_64-editrights"
fi
if ! cygrunsrv -v 1>/dev/null 2>&1; then
echo "Missing 'cygrunsrv'. Marking 'cygrunsrv' for install..."
to_install="$to_install cygrunsrv"
fi
if ! ssh-keygen -A 1>/dev/null 2>&1; then
echo "Missing 'ssh-keygen'. Marking 'openssh' for install..."
to_install="$to_install openssh"
fi
# In the general case, DO NOT use `yes` or --no-confirm
# with pacman.
# shellcheck disable=2086
yes | pacman -Sy $to_install
if [ $? -ne 0 ]; then
exit $?
fi
if cygrunsrv -Q sshd >/dev/null 2>&1; then
echo "The sshd service is already installed"
exit 1
fi
# Create privileged cyg_server user
# Some random password; this is only needed internally by cygrunsrv and
# is limited to 14 characters by Windows (lol)
tmp_pass="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | dd count=14 bs=1 2>/dev/null)"
# Create user
if ! net user "${PRIV_USER}" >/dev/null 2>&1; then
echo "Creating user ${PRIV_USER}"
net user "${PRIV_USER}" "${tmp_pass}" //add //fullname:"${PRIV_NAME}" //homedir:"$(cygpath -w ${EMPTY_DIR})" //yes
if [ $? -ne 0 ]; then
echo "ERROR: Unable to create Windows user ${PRIV_USER}" 1>&2
exit 1
fi
else
echo "User ${PRIV_USER} already exists"
fi
# Add user to the Administrators group if necessary
admingroup="$(mkgroup -l | awk -F: '{if ($2 == "S-1-5-32-544") print $1;}')"
if ! net localgroup "${admingroup}" | grep -q '^'"${PRIV_USER}"'$'; then
echo "Adding user to admin group \"$admingroup\""
net localgroup "${admingroup}" "${PRIV_USER}" //add
if [ $? -ne 0 ]; then
echo "ERROR: Unable to add user ${PRIV_USER} to group ${admingroup}" 1>&2
exit 1
fi
else
echo "User ${PRIV_USER} is already a member of the admin group"
fi
# Infinite passwd expiry
passwd -e "${PRIV_USER}"
# set required privileges
for flag in SeAssignPrimaryTokenPrivilege SeCreateTokenPrivilege \
SeTcbPrivilege SeDenyRemoteInteractiveLogonRight \
SeServiceLogonRight; do
echo "Adding right \"${flag}\" to ${PRIV_USER}"
/mingw64/bin/editrights -a "${flag}" -u "${PRIV_USER}"
if [ $? -ne 0 ]; then
echo "ERROR: Unable to give ${flag} rights to user ${PRIV_USER}"
exit 1
fi
done
# The unprivileged sshd user (for privilege separation)
if ! net user "${UNPRIV_USER}" >/dev/null 2>&1; then
echo "Creating unprivileged user ${UNPRIV_USER}"
net user "${UNPRIV_USER}" //add //fullname:"${UNPRIV_NAME}" //homedir:"$(cygpath -w ${EMPTY_DIR})" //active:no //yes
if [ $? -ne 0 ]; then
echo "ERROR: Unable to create Windows user ${UNPRIV_USER}" 1>&2
exit 1
fi
else
echo "User ${UNPRIV_USER} already exists"
fi
# Add or update /etc/passwd entries
touch /etc/passwd
for u in "${PRIV_USER}" "${UNPRIV_USER}"; do
sed -i -e '/^'"${u}"':/d' /etc/passwd
SED='/^'"${u}"':/s?^\(\([^:]*:\)\{5\}\).*?\1'"${EMPTY_DIR}"':/bin/false?p'
mkpasswd -l -u "${u}" | sed -e 's/^[^:]*+//' | sed -ne "${SED}" \
>> /etc/passwd
done
# Finally, register service with cygrunsrv and start it
#
echo "Remove sshd service from cygrunsrv"
cygrunsrv -R sshd >/dev/null 2>&1 || true
echo "Install the sshd service to cygrunsrv"
cygrunsrv -I sshd -d "MSYS2 sshd" -p \
/usr/bin/sshd.exe -a "-D -e" -y tcpip -u "${PRIV_USER}" -w "${tmp_pass}"
# The SSH service should start automatically when Windows is rebooted. You can
# manually restart the service by running `net stop sshd` + `net start sshd`
if ! net start sshd; then
echo "ERROR: Unable to start sshd service" 1>&2
echo "ERROR: You may need to reboot for the service to start" 1>&2
exit 1
fi
# Avoid errors pertaining to the last login service
touch /var/log/lastlog
chmod 664 /var/log/lastlog
echo "
Remember to check the following Windows settings:
- The listening port (e.g. 22) is open inbound via Windows Firewall
- The Network Discovery Service is turned on (recommended for Private
connections only)
"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment