| #!/bin/bash |
| # |
| # ssh-host-config, Copyright 2000, 2001, 2002, 2003 Red Hat Inc. |
| # |
| # This file is part of the Cygwin port of OpenSSH. |
| |
| # Subdirectory where the new package is being installed |
| PREFIX=/usr |
| |
| # Directory where the config files are stored |
| SYSCONFDIR=/etc |
| LOCALSTATEDIR=/var |
| |
| progname=$0 |
| auto_answer="" |
| port_number=22 |
| |
| privsep_configured=no |
| privsep_used=yes |
| sshd_in_passwd=no |
| sshd_in_sam=no |
| |
| request() |
| { |
| if [ "${auto_answer}" = "yes" ] |
| then |
| echo "$1 (yes/no) yes" |
| return 0 |
| elif [ "${auto_answer}" = "no" ] |
| then |
| echo "$1 (yes/no) no" |
| return 1 |
| fi |
| |
| answer="" |
| while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ] |
| do |
| echo -n "$1 (yes/no) " |
| read -e answer |
| done |
| if [ "X${answer}" = "Xyes" ] |
| then |
| return 0 |
| else |
| return 1 |
| fi |
| } |
| |
| # Check options |
| |
| while : |
| do |
| case $# in |
| 0) |
| break |
| ;; |
| esac |
| |
| option=$1 |
| shift |
| |
| case "${option}" in |
| -d | --debug ) |
| set -x |
| ;; |
| |
| -y | --yes ) |
| auto_answer=yes |
| ;; |
| |
| -n | --no ) |
| auto_answer=no |
| ;; |
| |
| -c | --cygwin ) |
| cygwin_value="$1" |
| shift |
| ;; |
| |
| -p | --port ) |
| port_number=$1 |
| shift |
| ;; |
| |
| -w | --pwd ) |
| password_value="$1" |
| shift |
| ;; |
| |
| *) |
| echo "usage: ${progname} [OPTION]..." |
| echo |
| echo "This script creates an OpenSSH host configuration." |
| echo |
| echo "Options:" |
| echo " --debug -d Enable shell's debug output." |
| echo " --yes -y Answer all questions with \"yes\" automatically." |
| echo " --no -n Answer all questions with \"no\" automatically." |
| echo " --cygwin -c <options> Use \"options\" as value for CYGWIN environment var." |
| echo " --port -p <n> sshd listens on port n." |
| echo " --pwd -w <passwd> Use \"pwd\" as password for user 'sshd_server'." |
| echo |
| exit 1 |
| ;; |
| |
| esac |
| done |
| |
| # Check if running on NT |
| _sys="`uname`" |
| _nt=`expr "${_sys}" : "CYGWIN_NT"` |
| # If running on NT, check if running under 2003 Server or later |
| if [ ${_nt} -gt 0 ] |
| then |
| _nt2003=`uname | awk -F- '{print ( $2 >= 5.2 ) ? 1 : 0;}'` |
| fi |
| |
| # Check for running ssh/sshd processes first. Refuse to do anything while |
| # some ssh processes are still running |
| |
| if ps -ef | grep -v grep | grep -q ssh |
| then |
| echo |
| echo "There are still ssh processes running. Please shut them down first." |
| echo |
| exit 1 |
| fi |
| |
| # Check for ${SYSCONFDIR} directory |
| |
| if [ -e "${SYSCONFDIR}" -a ! -d "${SYSCONFDIR}" ] |
| then |
| echo |
| echo "${SYSCONFDIR} is existant but not a directory." |
| echo "Cannot create global configuration files." |
| echo |
| exit 1 |
| fi |
| |
| # Create it if necessary |
| |
| if [ ! -e "${SYSCONFDIR}" ] |
| then |
| mkdir "${SYSCONFDIR}" |
| if [ ! -e "${SYSCONFDIR}" ] |
| then |
| echo |
| echo "Creating ${SYSCONFDIR} directory failed" |
| echo |
| exit 1 |
| fi |
| fi |
| |
| # Create /var/log and /var/log/lastlog if not already existing |
| |
| if [ -f ${LOCALSTATEDIR}/log ] |
| then |
| echo "Creating ${LOCALSTATEDIR}/log failed!" |
| else |
| if [ ! -d ${LOCALSTATEDIR}/log ] |
| then |
| mkdir -p ${LOCALSTATEDIR}/log |
| fi |
| if [ -d ${LOCALSTATEDIR}/log/lastlog ] |
| then |
| chmod 777 ${LOCALSTATEDIR}/log/lastlog |
| elif [ ! -f ${LOCALSTATEDIR}/log/lastlog ] |
| then |
| cat /dev/null > ${LOCALSTATEDIR}/log/lastlog |
| chmod 666 ${LOCALSTATEDIR}/log/lastlog |
| fi |
| fi |
| |
| # Create /var/empty file used as chroot jail for privilege separation |
| if [ -f ${LOCALSTATEDIR}/empty ] |
| then |
| echo "Creating ${LOCALSTATEDIR}/empty failed!" |
| else |
| mkdir -p ${LOCALSTATEDIR}/empty |
| if [ ${_nt} -gt 0 ] |
| then |
| chmod 755 ${LOCALSTATEDIR}/empty |
| fi |
| fi |
| |
| # First generate host keys if not already existing |
| |
| if [ ! -f "${SYSCONFDIR}/ssh_host_key" ] |
| then |
| echo "Generating ${SYSCONFDIR}/ssh_host_key" |
| ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null |
| fi |
| |
| if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ] |
| then |
| echo "Generating ${SYSCONFDIR}/ssh_host_rsa_key" |
| ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null |
| fi |
| |
| if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ] |
| then |
| echo "Generating ${SYSCONFDIR}/ssh_host_dsa_key" |
| ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null |
| fi |
| |
| # Check if ssh_config exists. If yes, ask for overwriting |
| |
| if [ -f "${SYSCONFDIR}/ssh_config" ] |
| then |
| if request "Overwrite existing ${SYSCONFDIR}/ssh_config file?" |
| then |
| rm -f "${SYSCONFDIR}/ssh_config" |
| if [ -f "${SYSCONFDIR}/ssh_config" ] |
| then |
| echo "Can't overwrite. ${SYSCONFDIR}/ssh_config is write protected." |
| fi |
| fi |
| fi |
| |
| # Create default ssh_config from skeleton file in /etc/defaults/etc |
| |
| if [ ! -f "${SYSCONFDIR}/ssh_config" ] |
| then |
| echo "Generating ${SYSCONFDIR}/ssh_config file" |
| cp ${SYSCONFDIR}/defaults/etc/ssh_config ${SYSCONFDIR}/ssh_config |
| if [ "${port_number}" != "22" ] |
| then |
| echo "Host localhost" >> ${SYSCONFDIR}/ssh_config |
| echo " Port ${port_number}" >> ${SYSCONFDIR}/ssh_config |
| fi |
| fi |
| |
| # Check if sshd_config exists. If yes, ask for overwriting |
| |
| if [ -f "${SYSCONFDIR}/sshd_config" ] |
| then |
| if request "Overwrite existing ${SYSCONFDIR}/sshd_config file?" |
| then |
| rm -f "${SYSCONFDIR}/sshd_config" |
| if [ -f "${SYSCONFDIR}/sshd_config" ] |
| then |
| echo "Can't overwrite. ${SYSCONFDIR}/sshd_config is write protected." |
| fi |
| else |
| grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes |
| fi |
| fi |
| |
| # Prior to creating or modifying sshd_config, care for privilege separation |
| |
| if [ "${privsep_configured}" != "yes" ] |
| then |
| if [ ${_nt} -gt 0 ] |
| then |
| echo "Privilege separation is set to yes by default since OpenSSH 3.3." |
| echo "However, this requires a non-privileged account called 'sshd'." |
| echo "For more info on privilege separation read /usr/share/doc/openssh/README.privsep." |
| echo |
| if request "Should privilege separation be used?" |
| then |
| privsep_used=yes |
| grep -q '^sshd:' ${SYSCONFDIR}/passwd && sshd_in_passwd=yes |
| net user sshd >/dev/null 2>&1 && sshd_in_sam=yes |
| if [ "${sshd_in_passwd}" != "yes" ] |
| then |
| if [ "${sshd_in_sam}" != "yes" ] |
| then |
| echo "Warning: The following function requires administrator privileges!" |
| if request "Should this script create a local user 'sshd' on this machine?" |
| then |
| dos_var_empty=`cygpath -w ${LOCALSTATEDIR}/empty` |
| net user sshd /add /fullname:"sshd privsep" "/homedir:${dos_var_empty}" /active:no > /dev/null 2>&1 && sshd_in_sam=yes |
| if [ "${sshd_in_sam}" != "yes" ] |
| then |
| echo "Warning: Creating the user 'sshd' failed!" |
| fi |
| fi |
| fi |
| if [ "${sshd_in_sam}" != "yes" ] |
| then |
| echo "Warning: Can't create user 'sshd' in ${SYSCONFDIR}/passwd!" |
| echo " Privilege separation set to 'no' again!" |
| echo " Check your ${SYSCONFDIR}/sshd_config file!" |
| privsep_used=no |
| else |
| mkpasswd -l -u sshd | sed -e 's/bash$/false/' >> ${SYSCONFDIR}/passwd |
| fi |
| fi |
| else |
| privsep_used=no |
| fi |
| else |
| # On 9x don't use privilege separation. Since security isn't |
| # available it just adds useless additional processes. |
| privsep_used=no |
| fi |
| fi |
| |
| # Create default sshd_config from skeleton files in /etc/defaults/etc or |
| # modify to add the missing privsep configuration option |
| |
| if [ ! -f "${SYSCONFDIR}/sshd_config" ] |
| then |
| echo "Generating ${SYSCONFDIR}/sshd_config file" |
| sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/ |
| s/^#Port 22/Port ${port_number}/ |
| s/^#StrictModes yes/StrictModes no/" \ |
| < ${SYSCONFDIR}/defaults/etc/sshd_config \ |
| > ${SYSCONFDIR}/sshd_config |
| elif [ "${privsep_configured}" != "yes" ] |
| then |
| echo >> ${SYSCONFDIR}/sshd_config |
| echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config |
| fi |
| |
| # Care for services file |
| _my_etcdir="/ssh-host-config.$$" |
| if [ ${_nt} -gt 0 ] |
| then |
| _win_etcdir="${SYSTEMROOT}\\system32\\drivers\\etc" |
| _services="${_my_etcdir}/services" |
| # On NT, 27 spaces, no space after the hash |
| _spaces=" #" |
| else |
| _win_etcdir="${WINDIR}" |
| _services="${_my_etcdir}/SERVICES" |
| # On 9x, 18 spaces (95 is very touchy), a space after the hash |
| _spaces=" # " |
| fi |
| _serv_tmp="${_my_etcdir}/srv.out.$$" |
| |
| mount -t -f "${_win_etcdir}" "${_my_etcdir}" |
| |
| # Depends on the above mount |
| _wservices=`cygpath -w "${_services}"` |
| |
| # Remove sshd 22/port from services |
| if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ] |
| then |
| grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}" |
| if [ -f "${_serv_tmp}" ] |
| then |
| if mv "${_serv_tmp}" "${_services}" |
| then |
| echo "Removing sshd from ${_wservices}" |
| else |
| echo "Removing sshd from ${_wservices} failed!" |
| fi |
| rm -f "${_serv_tmp}" |
| else |
| echo "Removing sshd from ${_wservices} failed!" |
| fi |
| fi |
| |
| # Add ssh 22/tcp and ssh 22/udp to services |
| if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ] |
| then |
| if awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh 22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh 22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}" |
| then |
| if mv "${_serv_tmp}" "${_services}" |
| then |
| echo "Added ssh to ${_wservices}" |
| else |
| echo "Adding ssh to ${_wservices} failed!" |
| fi |
| rm -f "${_serv_tmp}" |
| else |
| echo "WARNING: Adding ssh to ${_wservices} failed!" |
| fi |
| fi |
| |
| umount "${_my_etcdir}" |
| |
| # Care for inetd.conf file |
| _inetcnf="${SYSCONFDIR}/inetd.conf" |
| _inetcnf_tmp="${SYSCONFDIR}/inetd.conf.$$" |
| |
| if [ -f "${_inetcnf}" ] |
| then |
| # Check if ssh service is already in use as sshd |
| with_comment=1 |
| grep -q '^[ \t]*sshd' "${_inetcnf}" && with_comment=0 |
| # Remove sshd line from inetd.conf |
| if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ] |
| then |
| grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}" |
| if [ -f "${_inetcnf_tmp}" ] |
| then |
| if mv "${_inetcnf_tmp}" "${_inetcnf}" |
| then |
| echo "Removed sshd from ${_inetcnf}" |
| else |
| echo "Removing sshd from ${_inetcnf} failed!" |
| fi |
| rm -f "${_inetcnf_tmp}" |
| else |
| echo "Removing sshd from ${_inetcnf} failed!" |
| fi |
| fi |
| |
| # Add ssh line to inetd.conf |
| if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ] |
| then |
| if [ "${with_comment}" -eq 0 ] |
| then |
| echo 'ssh stream tcp nowait root /usr/sbin/sshd sshd -i' >> "${_inetcnf}" |
| else |
| echo '# ssh stream tcp nowait root /usr/sbin/sshd sshd -i' >> "${_inetcnf}" |
| fi |
| echo "Added ssh to ${_inetcnf}" |
| fi |
| fi |
| |
| # On NT ask if sshd should be installed as service |
| if [ ${_nt} -gt 0 ] |
| then |
| # But only if it is not already installed |
| if ! cygrunsrv -Q sshd > /dev/null 2>&1 |
| then |
| echo |
| echo |
| echo "Warning: The following functions require administrator privileges!" |
| echo |
| echo "Do you want to install sshd as service?" |
| if request "(Say \"no\" if it's already installed as service)" |
| then |
| if [ $_nt2003 -gt 0 ] |
| then |
| grep -q '^sshd_server:' ${SYSCONFDIR}/passwd && sshd_server_in_passwd=yes |
| if [ "${sshd_server_in_passwd}" = "yes" ] |
| then |
| # Drop sshd_server from passwd since it could have wrong settings |
| grep -v '^sshd_server:' ${SYSCONFDIR}/passwd > ${SYSCONFDIR}/passwd.$$ |
| rm -f ${SYSCONFDIR}/passwd |
| mv ${SYSCONFDIR}/passwd.$$ ${SYSCONFDIR}/passwd |
| chmod g-w,o-w ${SYSCONFDIR}/passwd |
| fi |
| net user sshd_server >/dev/null 2>&1 && sshd_server_in_sam=yes |
| if [ "${sshd_server_in_sam}" != "yes" ] |
| then |
| echo |
| echo "You appear to be running Windows 2003 Server or later. On 2003 and" |
| echo "later systems, it's not possible to use the LocalSystem account" |
| echo "if sshd should allow passwordless logon (e. g. public key authentication)." |
| echo "If you want to enable that functionality, it's required to create a new" |
| echo "account 'sshd_server' with special privileges, which is then used to run" |
| echo "the sshd service under." |
| echo |
| echo "Should this script create a new local account 'sshd_server' which has" |
| if request "the required privileges?" |
| then |
| _admingroup=`mkgroup -l | awk -F: '{if ( $2 == "S-1-5-32-544" ) print $1;}' ` |
| if [ -z "${_admingroup}" ] |
| then |
| echo "mkgroup -l produces no group with SID S-1-5-32-544 (Local administrators group)." |
| exit 1 |
| fi |
| dos_var_empty=`cygpath -w ${LOCALSTATEDIR}/empty` |
| while [ "${sshd_server_in_sam}" != "yes" ] |
| do |
| if [ -n "${password_value}" ] |
| then |
| _password="${password_value}" |
| # Allow to ask for password if first try fails |
| password_value="" |
| else |
| echo |
| echo "Please enter a password for new user 'sshd_server'. Please be sure that" |
| echo "this password matches the password rules given on your system." |
| echo -n "Entering no password will exit the configuration. PASSWORD=" |
| read -e _password |
| if [ -z "${_password}" ] |
| then |
| echo |
| echo "Exiting configuration. No user sshd_server has been created," |
| echo "no sshd service installed." |
| exit 1 |
| fi |
| fi |
| net user sshd_server "${_password}" /add /fullname:"sshd server account" "/homedir:${dos_var_empty}" /yes > /tmp/nu.$$ 2>&1 && sshd_server_in_sam=yes |
| if [ "${sshd_server_in_sam}" != "yes" ] |
| then |
| echo "Creating the user 'sshd_server' failed! Reason:" |
| cat /tmp/nu.$$ |
| rm /tmp/nu.$$ |
| fi |
| done |
| net localgroup "${_admingroup}" sshd_server /add > /dev/null 2>&1 && sshd_server_in_admingroup=yes |
| if [ "${sshd_server_in_admingroup}" != "yes" ] |
| then |
| echo "WARNING: Adding user sshd_server to local group ${_admingroup} failed!" |
| echo "Please add sshd_server to local group ${_admingroup} before" |
| echo "starting the sshd service!" |
| echo |
| fi |
| passwd_has_expiry_flags=`passwd -v | awk '/^passwd /{print ( $3 >= 1.5 ) ? "yes" : "no";}'` |
| if [ "${passwd_has_expiry_flags}" != "yes" ] |
| then |
| echo |
| echo "WARNING: User sshd_server has password expiry set to system default." |
| echo "Please check that password never expires or set it to your needs." |
| elif ! passwd -e sshd_server |
| then |
| echo |
| echo "WARNING: Setting password expiry for user sshd_server failed!" |
| echo "Please check that password never expires or set it to your needs." |
| fi |
| editrights -a SeAssignPrimaryTokenPrivilege -u sshd_server && |
| editrights -a SeCreateTokenPrivilege -u sshd_server && |
| editrights -a SeDenyInteractiveLogonRight -u sshd_server && |
| editrights -a SeDenyNetworkLogonRight -u sshd_server && |
| editrights -a SeDenyRemoteInteractiveLogonRight -u sshd_server && |
| editrights -a SeIncreaseQuotaPrivilege -u sshd_server && |
| editrights -a SeServiceLogonRight -u sshd_server && |
| sshd_server_got_all_rights="yes" |
| if [ "${sshd_server_got_all_rights}" != "yes" ] |
| then |
| echo |
| echo "Assigning the appropriate privileges to user 'sshd_server' failed!" |
| echo "Can't create sshd service!" |
| exit 1 |
| fi |
| echo |
| echo "User 'sshd_server' has been created with password '${_password}'." |
| echo "If you change the password, please keep in mind to change the password" |
| echo "for the sshd service, too." |
| echo |
| echo "Also keep in mind that the user sshd_server needs read permissions on all" |
| echo "users' .ssh/authorized_keys file to allow public key authentication for" |
| echo "these users!. (Re-)running ssh-user-config for each user will set the" |
| echo "required permissions correctly." |
| echo |
| fi |
| fi |
| if [ "${sshd_server_in_sam}" = "yes" ] |
| then |
| mkpasswd -l -u sshd_server | sed -e 's/bash$/false/' >> ${SYSCONFDIR}/passwd |
| fi |
| fi |
| if [ -n "${cygwin_value}" ] |
| then |
| _cygwin="${cygwin_value}" |
| else |
| echo |
| echo "Which value should the environment variable CYGWIN have when" |
| echo "sshd starts? It's recommended to set at least \"ntsec\" to be" |
| echo "able to change user context without password." |
| echo -n "Default is \"ntsec\". CYGWIN=" |
| read -e _cygwin |
| fi |
| [ -z "${_cygwin}" ] && _cygwin="ntsec" |
| if [ $_nt2003 -gt 0 -a "${sshd_server_in_sam}" = "yes" ] |
| then |
| if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a -D -u sshd_server -w "${_password}" -e "CYGWIN=${_cygwin}" |
| then |
| echo |
| echo "The service has been installed under sshd_server account." |
| echo "To start the service, call \`net start sshd' or \`cygrunsrv -S sshd'." |
| fi |
| else |
| if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a -D -e "CYGWIN=${_cygwin}" |
| then |
| echo |
| echo "The service has been installed under LocalSystem account." |
| echo "To start the service, call \`net start sshd' or \`cygrunsrv -S sshd'." |
| fi |
| fi |
| fi |
| # Now check if sshd has been successfully installed. This allows to |
| # set the ownership of the affected files correctly. |
| if cygrunsrv -Q sshd > /dev/null 2>&1 |
| then |
| if [ $_nt2003 -gt 0 -a "${sshd_server_in_sam}" = "yes" ] |
| then |
| _user="sshd_server" |
| else |
| _user="system" |
| fi |
| chown "${_user}" ${SYSCONFDIR}/ssh* |
| chown "${_user}".544 ${LOCALSTATEDIR}/empty |
| if [ -f ${LOCALSTATEDIR}/log/sshd.log ] |
| then |
| chown "${_user}".544 ${LOCALSTATEDIR}/log/sshd.log |
| fi |
| fi |
| if ! ( mount | egrep -q 'on /(|usr/(bin|lib)) type system' ) |
| then |
| echo |
| echo "Warning: It appears that you have user mode mounts (\"Just me\"" |
| echo "chosen during install.) Any daemons installed as services will" |
| echo "fail to function unless system mounts are used. To change this," |
| echo "re-run setup.exe and choose \"All users\"." |
| echo |
| echo "For more information, see http://cygwin.com/faq/faq0.html#TOC33" |
| fi |
| fi |
| fi |
| |
| echo |
| echo "Host configuration finished. Have fun!" |