Forked from samhocevar/gist:00eec26d9e9988d080ac
Last active
January 23, 2017 22:29
-
-
Save justsh/311ae744c73c76be24b4d88b588c72a5 to your computer and use it in GitHub Desktop.
Configure sshd on MSYS2 and run it as a Windows service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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