Skip to content

Instantly share code, notes, and snippets.

@abakum
Forked from samhocevar/gist:00eec26d9e9988d080ac
Last active December 7, 2017 11:43
Show Gist options
  • Save abakum/5be504bc7920a5f6dbd48e797c31715d to your computer and use it in GitHub Desktop.
Save abakum/5be504bc7920a5f6dbd48e797c31715d 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
# 06 Dec 2017 - add pacman, MSYSTEM_CARCH, MSYSTEM_PREFIX, mkpasswd -c, AcceptEnv MSYSTEM
#
# Installation
#
pacman -Sy
pacman -S --needed openssh
pacman -S --needed cygrunsrv
pacman -S --needed mingw-w64-${MSYSTEM_CARCH}-editrights
pacman -S --needed mingw-w64-${MSYSTEM_CARCH}-iconv
set -e
#
# Configuration
#
PRIV_USER=sshd_server
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
if [ "${LANG:0:3}" == "en_" ]; then
log="cat /var/log/sshd.log"
else
log="iconv -f $(cmd /c chcp|tr -dc [:digit:]) -t $(echo $LANG|sed -e 's/^[^.]*.//') /var/log/sshd.log"
fi
#
# Check installation sanity
#
if ! ${MSYSTEM_PREFIX}/bin/editrights -h >/dev/null; then
echo "ERROR: Missing 'editrights'. Try: pacman -S mingw-w64-${MSYSTEM_CARCH}-editrights."
exit 1
fi
if ! cygrunsrv -v >/dev/null; then
echo "ERROR: Missing 'cygrunsrv'. Try: pacman -S cygrunsrv."
exit 1
fi
if ! ssh-keygen -A; then
echo "ERROR: Missing 'ssh-keygen'. Try: pacman -S openssh."
exit 1
fi
#
# The 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)"
echo "Add or update user ${PRIV_USER}"|tee /var/log/sshd.log
add="$(if ! net user "${PRIV_USER}" >/dev/null; then echo "//add"; fi)"
if ! net user "${PRIV_USER}" "${tmp_pass}" ${add} //fullname:"${PRIV_NAME}" \
//homedir:"$(cygpath -w ${EMPTY_DIR})" //yes >>/var/log/sshd.log 2>&1; then
${log}
echo "ERROR: Unable to create Windows user ${PRIV_USER}"|tee -a /var/log/sshd.log
exit 1
fi
echo "Add user ${PRIV_USER} to the Administrators group if necessary"|tee -a /var/log/sshd.log
admingroup="$(mkgroup -l | awk -F: '{if ($2 == "S-1-5-32-544") print $1;}')"
if ! (net localgroup "${admingroup}" | grep -q '^'"${PRIV_USER}"'$'); then
if ! net localgroup "${admingroup}" "${PRIV_USER}" //add >>/var/log/sshd.log 2>&1; then
${log}
echo "ERROR: Unable to add user ${PRIV_USER} to group ${admingroup}"|tee -a /var/log/sshd.log
exit 1
fi
fi
# Infinite passwd expiry
passwd -e "${PRIV_USER}"
echo "Set required privileges fo user ${PRIV_USER}"|tee -a /var/log/sshd.log
for flag in SeAssignPrimaryTokenPrivilege SeCreateTokenPrivilege \
SeTcbPrivilege SeDenyRemoteInteractiveLogonRight SeServiceLogonRight; do
if ! ${MSYSTEM_PREFIX}/bin/editrights -a "${flag}" -u "${PRIV_USER}"; then
echo "ERROR: Unable to give ${flag} rights to user ${PRIV_USER}"|tee -a /var/log/sshd.log
exit 1
fi
done
net user "${PRIV_USER}" >>/var/log/sshd.log 2>&1
#
# The unprivileged sshd user (for privilege separation)
#
echo "Add or update user ${UNPRIV_USER}"|tee -a /var/log/sshd.log
add="$(if ! net user "${UNPRIV_USER}" >/dev/null; then echo "//add"; fi)"
if ! net user "${UNPRIV_USER}" ${add} //fullname:"${UNPRIV_NAME}" \
//homedir:"$(cygpath -w ${EMPTY_DIR})" //active:no >>/var/log/sshd.log 2>&1; then
${log}
echo "ERROR: Unable to create Windows user ${PRIV_USER}"|tee -a /var/log/sshd.log
exit 1
fi
net user "${UNPRIV_USER}" >>/var/log/sshd.log 2>&1
#
# Add or update /etc/passwd entries
#
#touch /etc/passwd
if [ ! /etc/passwd ]; then
# First run. Add current user to passwd
mkpasswd -c > /etc/passwd
# Avoid errors pertaining to the last login service
touch /var/log/lastlog
echo AcceptEnv MSYSTEM >> /etc/ssh/sshd_config
echo "To start shell as ${MSYSTEM} use:"|tee -a /var/log/sshd.log
echo "MSYSTEM=${MSYSTEM} ssh ..."|tee -a /var/log/sshd.log
fi
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
#
cygrunsrv -R sshd || true
cygrunsrv -I sshd -d "MSYS2 sshd" -p \
/usr/bin/sshd.exe -a "-D -e" -y tcpip -u "${PRIV_USER}" -w "${tmp_pass}"
echo "The SSH service should start automatically when Windows is rebooted. You can"|tee -a /var/log/sshd.log
echo "manually restart the service by running 'net stop sshd&net start sshd'"|tee -a /var/log/sshd.log
if ! net start sshd >>/var/log/sshd.log 2>&1; then
${log}
echo "ERROR: Unable to start sshd service"|tee -a /var/log/sshd.log
exit 1
fi
${log}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment