#!/bin/sh
#----------------------------------------------------------------------------
# /var/install/config.d/inet.sh - configuration generator script for inet
#
# Creation:     2002-11-06  jh
# Last Update:  $Id: ssh.sh 36632 2015-01-18 10:36:08Z jed $
#
# Copyright (c) 2002-2015 the eisfair team, team(at)eisfair(dot)org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#----------------------------------------------------------------------------

# include eislib
. /var/install/include/eislib

#exec 2>/tmp/ssh-$$.log
#set -x

package_name='ssh'

# set variables
base_file=/etc/config.d/base
ssh_file=/etc/config.d/${package_name}
ssh_config_file=/etc/ssh/ssh_config
sshd_config_file=/etc/ssh/sshd_config
ssh_authorized_keys_file=/root/.ssh/authorized_keys
ssh_authorized_keys_file_tmp=/root/.ssh/authorized_keys_tmp.$$
xinetd_conf='/etc/xinetd.d/ssh'
services_file='/etc/services.ssh'

default_ciphers='chacha20-poly1305@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr'
default_kexs='curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256'
default_macs='hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com'

# read configuration
. ${ssh_file}
. ${base_file}

#----------------------------------------------------------------------------
# quiet suppress all normal output
#----------------------------------------------------------------------------
myecho ()
{
    if ! ${_quiet:-false}
    then
        _me_exit=0
        _me_switch=''
        _me_outstr=''
        while [ ${_me_exit} -eq 0 ]
        do
            case $1 in
                -n|*-std|*stdbr|*-info|*-warn|*-error|*-link|*-ok|*-fail|*-tty|*-html|*-file )
                    _me_switch="${_me_switch}$1 "
                    shift
                    ;;
                * )
                    _me_outstr="$*"
                    _me_exit=1
                    ;;
            esac
        done

        # be verbose
        mecho ${_me_switch} "${_me_outstr}"
    fi
}

#----------------------------------------------------------------------------
# ssh start
#----------------------------------------------------------------------------
ssh_start ()
{
    cd /etc/rc2.d
    ln -sf ../init.d/${package_name} S51${package_name}
}

#----------------------------------------------------------------------------
# ssh stop
#----------------------------------------------------------------------------
ssh_stop ()
{
    /etc/init.d/${package_name} ${__quiet} stop
    rm -f /etc/rc2.d/S??${package_name}
}

#----------------------------------------------------------------------------
# check input values
#
# input:  $1 - ciphers/kexs/macs
#         $2 - parameter string
#         $3 - checkonly
# output: verified parameter string
#----------------------------------------------------------------------------
check_input_values ()
{
    # ssh -V
    # OpenSSH_6.6.1p1, OpenSSL 1.0.1k-fips 8 Jan 2015
    #
    # ssh -Q cipher
    #   3des-cbc
    #   blowfish-cbc
    #   cast128-cbc
    #   arcfour
    #   arcfour128
    #   arcfour256
    #   aes128-cbc
    #   aes192-cbc
    #   aes256-cbc
    #   rijndael-cbc@lysator.liu.se
    #   aes128-ctr (default)
    #   aes192-ctr (default)
    #   aes256-ctr (default)
    #   aes128-gcm@openssh.com (default)
    #   aes256-gcm@openssh.com (default)
    #   chacha20-poly1305@openssh.com (default)
    #
    # ssh -Q kex
    #   diffie-hellman-group1-sha1
    #   diffie-hellman-group14-sha1 (default)
    #   diffie-hellman-group-exchange-sha1
    #   diffie-hellman-group-exchange-sha256 (default)
    #   ecdh-sha2-nistp256 (default)
    #   ecdh-sha2-nistp384 (default)
    #   ecdh-sha2-nistp521 (default)
    #   diffie-hellman-group1-sha1
    #   curve25519-sha256@libssh.org (default)

    # ssh -Q mac
    #   hmac-sha1
    #   hmac-sha1-96
    #   hmac-sha2-256 (default)
    #   hmac-sha2-512 (default)
    #   hmac-md5
    #   hmac-md5-96
    #   hmac-ripemd160
    #   hmac-ripemd160@openssh.com
    #   umac-64@openssh.com (default)
    #   umac-128@openssh.com (default)
    #   hmac-sha1-etm@openssh.com
    #   hmac-sha1-96-etm@openssh.com
    #   hmac-sha2-256-etm@openssh.com (default)
    #   hmac-sha2-512-etm@openssh.com (default)
    #   hmac-md5-etm@openssh.com
    #   hmac-md5-96-etm@openssh.com
    #   hmac-ripemd160-etm@openssh.com
    #   umac-64-etm@openssh.com (default)
    #   umac-128-etm@openssh.com (default)

    _civ_label=''
    _civ_parameter=''
    _civ_checkonly=0
    _civ_defaults=''
    _civ_buildins=''
    _civ_input=''
    _civ_output=''

    case $1 in
        cipher* )
            _civ_label='Ciphers'
            _civ_parameter='SSH_SERVER_CIPHERS'
            _civ_defaults="${default_ciphers}"
            _civ_buildins="`ssh -Q cipher | tr -s '\n' ',' | sed -e 's/^,*/,/' -e 's/,*$/,/'`"
            ;;
        kex* )
            _civ_label='KexAlgorithms'
            _civ_parameter='SSH_SERVER_KEXS'
            _civ_defaults="${default_kexs}"
            _civ_buildins="`ssh -Q kex | tr -s '\n' ',' | sed -e 's/^,*/,/' -e 's/,*$/,/'`"
            ;;
        mac* )
            _civ_label='MACs'
            _civ_parameter='SSH_SERVER_MACS'
            _civ_defaults="${default_macs}"
            _civ_buildins="`ssh -Q mac | tr -s '\n' ',' | sed -e 's/^,*/,/' -e 's/,*$/,/'`"
            ;;
        * ) # invalid selection
            ;;
    esac

    _civ_input="$2"

    if [ "$3" = "checkonly" ]
    then
        _civ_checkonly=1
    fi

    if [ "${_civ_defaults}" != "" -a "${_civ_buildins}" != "" -a "${_civ_input}" != "" ]
    then
        # non-empty values given, go on ...
        case ${_civ_input} in
            all )
                # all - do not write a custom entry and use the build in default values
                # default OpenSSH values: Ciphers AnyStdCipher
                #                         MACs AnyStdMac
                _civ_output="# ${_civ_label}: use OpenSSH build in default values"
                ;;
            default )
                # default - use 'hardened' default values
                _civ_output="${_civ_label} ${_civ_defaults}"
                ;;
            * )
                # * | default,* - use individual values and include 'hardened'
                #                 default values if the keyword 'default' is used
                _civ_tmpstr=','
                _ifs="${IFS}"
                IFS=','
                for VALUE in ${_civ_input}
                do

                if [ "${VALUE}" = 'default' ]
                then
                    _civ_tmpstr="${_civ_tmpstr},${_civ_defaults},"
                else
                    echo "${_civ_buildins}" | grep -q ",${VALUE},"

                    if [ $? -eq 0 ]
                    then
                        # valid value, add it
                        _civ_tmpstr="${_civ_tmpstr}${VALUE},"
                    else
                        # invalid value, discard it
                        if [ ${_civ_checkonly} -eq 1 ]
                        then
                            mecho --warn "${_civ_parameter} - skipping invalid value '${VALUE}'!"
                        fi
                    fi
                fi
                done
                IFS=${_ifs}

                _civ_output="${_civ_label} `echo "${_civ_tmpstr}" | sed -e 's/^,*//' -e 's/,*$//'`"
                ;;
        esac
    else
        if [ ${_civ_checkonly} -eq 1 ]
        then
            mecho --error "fatal error appear during in function 'check_input_values'."
        fi
    fi

    if [ ${_civ_checkonly} -eq 0 ]
    then
        echo "${_civ_output}"
    fi
}

#----------------------------------------------------------------------------
# create ssh_config file
#----------------------------------------------------------------------------
create_ssh_config ()
{
    myecho "Creating ssh configuration ..."

cat > ${ssh_config_file} << EOF
#----------------------------------------------------------------------------
# sshd_config file generated by ${package_name}
#
# Do not edit this file, edit ${ssh_file}
# Creation date: ${EISDATE} ${EIS_TIME}
#----------------------------------------------------------------------------
#   \$OpenBSD: ssh_config,v 1.28 2013/09/16 11:35:43 sthen Exp $

# This is the ssh client system-wide configuration file.  See
# ssh_config(5) for more information.  This file provides defaults for
# users, and the values can be changed in per-user configuration files
# or on the command line.

# Configuration data is parsed as follows:
#  1. command line options
#  2. user-specific file
#  3. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.

# Site-wide defaults for some commonly used options.  For a comprehensive
# list of available options, their meanings and defaults, please see the
# ssh_config(5) man page.

#Host *
#   ForwardAgent no
#   ForwardX11 no

# If you do not trust your remote host (or its administrator), you
# should not forward X11 connections to your local X11-display for
# security reasons: Someone stealing the authentification data on the
# remote side (the "spoofed" X-server by the remote sshd) can read your
# keystrokes as you type, just like any other X11 client could do.
# Set this to "no" here for global effect or in your own ~/.ssh/config
# file if you want to have the remote X11 authentification data to
# expire after two minutes after remote login.
#   ForwardX11Trusted yes

#   RhostsRSAAuthentication no
#   RSAAuthentication yes
#   PasswordAuthentication yes
#   HostbasedAuthentication no
#   GSSAPIAuthentication no
#   GSSAPIDelegateCredentials no
#   BatchMode no
#   CheckHostIP yes
#   AddressFamily any
#   ConnectTimeout 0
#   StrictHostKeyChecking ask
#   IdentityFile ~/.ssh/identity
#   IdentityFile ~/.ssh/id_rsa
#   IdentityFile ~/.ssh/id_dsa
#   Port 22
#   Protocol 2
#   Cipher 3des
#   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
#   MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
#   EscapeChar ~
#   Tunnel no
#   TunnelDevice any:any
#   PermitLocalCommand no
#   VisualHostKey no
#   ProxyCommand ssh -q -W %h:%p gateway.example.com

# Set this to 'yes' to enable support for the deprecated 'gssapi' authentication
# mechanism to OpenSSH 3.8p1. The newer 'gssapi-with-mic' mechanism is included
# in this release. The use of 'gssapi' is deprecated due to the presence of
# potential man-in-the-middle attacks, which 'gssapi-with-mic' is not susceptible to.
#   GSSAPIEnableMITMAttack no

# This enables sending locale enviroment variables LC_* LANG, see ssh_config(5).
# SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
# SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
# SendEnv LC_IDENTIFICATION LC_ALL

#   RekeyLimit 1G 1h

Host *
    Protocol 2

    Ciphers ${default_ciphers}
    MACs ${default_macs}
    KexAlgorithms ${default_kexs}
EOF
}

#----------------------------------------------------------------------------
# create sshd_config file
#----------------------------------------------------------------------------
create_sshd_config ()
{
    myecho "Creating sshd configuration ..."

    SSH_USEPAM='yes'
    if [ "${SSH_PASSWDAUTH}" = "no" ]
    then
        SSH_USEPAM='no'
        myecho --info "UsePAM will be set to 'no', because SSH_PASSWDAUTH was set to 'no'"
    fi

    # set ssh allow users
    if [ "$SSH_ALLOW_USER_N" -gt "0" ]
    then
        tmp_str=''
        idx=1
        while [ "${idx}" -le "${SSH_ALLOW_USER_N}" ]
        do
            eval active='${SSH_ALLOW_USER_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval name='${SSH_ALLOW_USER_'${idx}'}'
                tmp_str="$tmp_str$name "
                idx=$(/usr/bin/expr ${idx} + 1)
            fi
        done
        ssh_allowusers="AllowUsers ${tmp_str}"
    else
        ssh_allowusers="#AllowUsers"
    fi

    # set ssh deny users
    if [ "$SSH_DENY_USER_N" -gt "0" ]
    then
        tmp_str=''
        idx=1
        while [ "${idx}" -le "${SSH_DENY_USER_N}" ]
        do
            eval active='${SSH_DENY_USER_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval name='${SSH_DENY_USER_'${idx}'}'
                tmp_str="$tmp_str$name "
                idx=$(/usr/bin/expr ${idx} + 1)
            fi
        done
        ssh_denyusers="DenyUsers ${tmp_str}"
    else
        ssh_denyusers="#DenyUsers"
    fi

    # set ssh allow groups
    if [ "$SSH_ALLOW_GROUP_N" -gt "0" ]
    then
        tmp_str=''
        idx=1
        while [ "$idx" -le "$SSH_ALLOW_GROUP_N" ]
        do
            eval active='${SSH_ALLOW_GROUP_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval name='${SSH_ALLOW_GROUP_'${idx}'}'
                tmp_str="$tmp_str$name "
                idx=$(/usr/bin/expr ${idx} + 1)
            fi
        done
        ssh_allowgroups="AllowGroups ${tmp_str}"
    else
        ssh_allowgroups="#AllowGroups"
    fi


    # set ssh deny groups
    if [ "$SSH_DENY_GROUP_N" -gt "0" ]
    then
        tmp_str=''
        idx=1
        while [ "$idx" -le "$SSH_DENY_GROUP_N" ]
        do
            eval active='${SSH_DENY_GROUP_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval name='${SSH_DENY_GROUP_'${idx}'}'
                tmp_str="$tmp_str$name "
                idx=$(/usr/bin/expr ${idx} + 1)
            fi
        done
        ssh_denygroups="DenyGroups ${tmp_str}"
    else
        ssh_denygroups="#DenyGroups"
    fi

    # enable sftp
    if [ "${SSH_ENABLE_SFTP}" = "yes" ]
    then
        ssh_usesftp="Subsystem sftp /usr/lib/ssh/sftp-server"
    else
        ssh_usesftp="#Subsystem sftp /usr/lib/ssh/sftp-server"
    fi

    # set ssh listen port
    if [ "$SSH_LISTEN_ADDR_N" -gt "0" ]
    then
        idx=1
        while [ "$idx" -le "$SSH_LISTEN_ADDR_N" ]
        do
            eval active='${SSH_LISTEN_ADDR_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval laddr='${SSH_LISTEN_ADDR_'${idx}'}'
                if [ -z "$laddr" ]
                then
                    myecho --warn "Empty listen address, SSH_LISTEN_ADDR_$idx will be ignored"
                else
                    # check number, substitution has to result in an empty string
                    e_laddr=`echo "$laddr" | sed 's|[0-9]*||'`
                    if [ -n "$e_laddr" ]
                    then
                        myecho --warn "Invalid SSH_LISTEN_ADDR_$idx ($laddr) will be ignored"
                    else
                        eval ipaddr='${IP_ETH_'${laddr}'_IPADDR}'
                        if [ -z "$ipaddr" ]
                        then
                            myecho --warn "Empty ip address, IP_ETH_${laddr}_IPADDR will be ignored"
                        else
                            if [ -z "${ssh_listen_addr}" ]
                            then
                                ssh_listen_addr=$(echo "ListenAddress ${ipaddr}")
                            else
                                ssh_listen_addr=$(echo "${ssh_listen_addr}"; \
                                                echo "ListenAddress ${ipaddr}")
                            fi
                        fi
                    fi
                fi
            fi

            idx=`/usr/bin/expr $idx + 1`
        done
        # generate default ListenAddress 127.0.0.1
        ssh_listen_addr=$(echo "${ssh_listen_addr}"; \
                          echo "ListenAddress 127.0.0.1")
    else
        ssh_listen_addr="#ListenAddress 0.0.0.0
#ListenAddress ::"
    fi

    ssh_test=`check_input_values 'ciphers' "${SSH_SERVER_CIPHERS}" 'checkonly'`
    if [ "${ssh_test}" != "" ]
    then
        mecho "${ssh_test}"
    fi
    ssh_test=`check_input_values 'kexs' "${SSH_SERVER_KEXS}" 'checkonly'`
    if [ "${ssh_test}" != "" ]
    then
        mecho "${ssh_test}"
    fi
    ssh_test=`check_input_values 'macs' "${SSH_SERVER_MACS}" 'checkonly'`
    if [ "${ssh_test}" != "" ]
    then
        mecho "${ssh_test}"
    fi

cat > ${sshd_config_file} << EOF
#----------------------------------------------------------------------------
# sshd_config file generated by ${package_name}
#
# Do not edit this file, edit ${ssh_file}
# Creation date: ${EISDATE} ${EIS_TIME}
#----------------------------------------------------------------------------
#       \$OpenBSD: sshd_config,v 1.87 2012/07/10 02:19:15 djm Exp $
#
# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.
#
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
#
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

# Logging
# obsoletes QuietMode and FascistLogging
SyslogFacility AUTH
LogLevel $SSH_LOGLEVEL

Port ${SSH_PORT}
#AddressFamily any

${ssh_listen_addr}

# The default requires explicit activation of protocol 1
Protocol 2

${ssh_allowgroups}
${ssh_allowusers}
${ssh_denygroups}
${ssh_denyusers}

# 2015-01-08/JED - applied changes recommended on the following website to harden ssh:
#                  https://stribika.github.io/2015/01/04/secure-secure-shell.html
#                  - deactivating protocol version 1
#                  - deactivating protocol version 2 keys: dsa, ecdsa
#                  - adding protocol version 2 key: ed25519
#                  - adding new parameters: Ciphers, KexAlgorithms, MACs

# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_dsa_key

# Ciphers, KexAlgorithms, MACs
`check_input_values 'ciphers' "${SSH_SERVER_CIPHERS}"`
`check_input_values 'kexs' "${SSH_SERVER_KEXS}"`
`check_input_values 'macs' "${SSH_SERVER_MACS}"`

# Authentication:

LoginGraceTime 2m
PermitRootLogin $SSH_PERMITROOTLOGIN
StrictModes $SSH_STRICTMODES
#MaxAuthTries 6
#MaxSessions 10

RSAAuthentication yes
PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
#AuthorizedKeysFile    .ssh/authorized_keys

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication ${SSH_PASSWDAUTH}
PermitEmptyPasswords no

# Change to no to disable s/key passwords
ChallengeResponseAuthentication $SSH_CH_RESPONSEAUTH

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'
UsePAM ${SSH_USEPAM}

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding no
X11DisplayOffset 10
#X11UseLocalhost yes
PrintMotd yes
#PrintLastLog yes
TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation $SSH_ENABLE_PRIV_SEPARATION
#PermitUserEnvironment no
Compression $SSH_COMPRESSION
ClientAliveInterval $SSH_CLIENTALIVEINTERVAL
ClientAliveCountMax $SSH_CLIENTALIVECOUNTMAX
#UseDNS yes
#PidFile /var/run/sshd.pid
MaxStartups $SSH_MAX_STARTUPS
#PermitTunnel no
#ChrootDirectory none


# no default banner path
#Banner none

# override default of no subsystems'
${ssh_usesftp}

# Example of overriding settings on a per-user basis
#Match User anoncvs
#	X11Forwarding no
#	AllowTcpForwarding no
#	ForceCommand cvs server
EOF

}

#----------------------------------------------------------------------------
# verify host keys
# input: $1 - key directory
#        $2 - correct invalid keys: yes/no
#        $3 - passphrase for key generation
#----------------------------------------------------------------------------
verify_host_keys ()
{
    # get key directory and correction mode
    kdir="$1"
    correct="$2"
    passphrase="$3"

    # rights for keyfile and publiv keyfile
    def_rights='-rw-------'
    def_rights_pub='-rw-r--r--'
    def_mod='0600'
    def_mod_pub='0644'

    quiet="-q"

    # wouldn't it be fine to return 0
    return=0

    # loop over key types
    # 2015-01-08/JED - reworked based on information about SSH hardening on the following
    #                  website https://stribika.github.io/2015/01/04/secure-secure-shell.html
    for KEY in ed25519 rsa ecdsa dsa rsa1
    do
        valid=true
        # recreate key if it doesn't exist?

        recreate=true
        case ${KEY} in
            dsa )   # DSA keys must be exactly be 1024 bits so let’s disable that as well
                recreate=false
                ;;
            ecdsa ) # involves NIST suckage and should be disabled
                recreate=false
                ;;
            rsa1 )  # rsa1 !! less secure, should be disabled!
                recreate=false
                ;;
            * )
                ;;
        esac

        # construct keyfile name
        _key_file="${kdir}/ssh_host_${KEY}_key"

        # check if file exists
        if [ -e "${_key_file}" ]
        then
            case ${KEY} in
                dsa )   # DSA keys must be exactly be 1024 bits so let’s disable that as well
                    myecho --warn "keyfile ${_key_file} is a DSA type key, which shouldn't be used anymore!"
                    ;;
                ecdsa ) # involves NIST suckage and should be disabled
                    myecho --warn "keyfile ${_key_file} is an ECDSA type key which shouldn't be used anymore!"
                    ;;
                rsa1 )  # rsa1 !! less secure, should be disabled!
                    myecho --warn "keyfile ${_key_file} is a RSA (proto. 1) type key which should certainly NOT be used anymore!"
                    ;;
                * )
                    ;;
            esac

            # check if file is a regular file and has a size greater than zero
            if [ ! -f "${_key_file}" -o ! -s "${_key_file}" ]
            then
                myecho --error "keyfile ${_key_file} is not a regular file or has file size 0"
                valid=false
                return=2

                if [ "${correct}" = 'yes' ]
                then
                    rm -rf "${_key_file}"
                    rm -rf "${_key_file}.pub"
                    myecho "        bad keyfile has been removed"
                fi
            else
                # check access rights and ownership of both key files
                for last in '' .pub
                do
                    _key_file_tmp="${_key_file}${last}"

                    # get access rights, user and group
                    # handle ACLs, use only first 10 characters, remove trailing +
                    act_rights=`stat --format='%A' ${_key_file_tmp} | cut -c -10`
                    act_user=`stat --format='%U' ${_key_file_tmp}`
                    act_group=`stat --format='%G' ${_key_file_tmp}`

                    # check access rights
                    case "${last}" in
                        '' ) # type ''
                            if [ "${act_rights}" != "${def_rights}" ]
                            then
                                myecho --error "keyfile ${_key_file_tmp} has wrong rights, should be ${def_rights} is ${act_rights}"
                                return=2

                                if [ "${correct}" = 'yes' ]
                                then
                                    chmod ${def_mod} ${_key_file_tmp}
                                    myecho "        rights have been corrected"
                                    return=1
                                fi
                            fi
                            ;;

                        '.pub' ) # type '.pub'
                            if [ "${act_rights}" != "${def_rights_pub}" ]
                            then
                                myecho --error "keyfile ${_key_file_tmp} has wrong rights, should be ${def_rights_pub} is ${act_rights}"
                                return=2

                                if [ "${correct}" = 'yes' ]
                                then
                                    chmod ${def_mod_pub} ${_key_file_tmp}
                                    myecho "        rights have been corrected"
                                    return=1
                                fi
                            fi
                            ;;
                    esac

                    # check ownership
                    if [ "${act_user}" != 'root' -o "${act_group}" != 'root' ]
                    then
                        myecho --error "keyfile ${_key_file_tmp} has wrong owner or group, should be root:root is ${act_user}:${act_group}"
                        return=2

                        if [ ${correct} = 'yes' ]
                        then
                            chown root:root ${_key_file_tmp}
                            myecho "        owner:group has been corrected"
                            return=1
                        fi
                    fi
                done  # for last in '' .pub
            fi  # if [ ! -f "${_key_file}" -o ! -s "${_key_file}" ]
        else
            #echo "keyfile $keyfile does not exist"
            valid=false
            return=2
        fi  # if [ -e ${_key_file} ]

        # check if at least one file was not valid
        if ! ${valid:-false}
        then
            return=2
            if [ "${correct}" = "yes" -a "${recreate}" = "true" ]
            then
                # passphrase option
                #  set to '-N ""' for no passphrase
                #  set to ''      to ask for a passphrase
                option="-N \"${passphrase}\""

                # -a number - number of KDF rounds for new key format or moduli primality tests
                # -b bits   - number of bits in the key to create
                case ${KEY} in
                    dsa )
                        # DSA keys must be exactly 1024 bits as specified by FIPS 186-2
                        run_option="${option} -a 100 -b 1024"
                        ;;
                    rsa )
                        run_option="${option} -a 100 -b 4096"
                        ;;
                    * )
                        run_option="${option} -a 100"
                        ;;
                esac

                _key_file="${kdir}/ssh_host_${KEY}_key"

                rm -rf ${_key_file}
                rm -rf ${_key_file}.pub

                # command need to be called by eval to make sure
                # that empty passwords are handled correctly
                eval /usr/bin/ssh-keygen ${quiet} -t ${KEY} ${run_option} -f ${_key_file}

                chmod ${def_mod}     ${_key_file}
                chmod ${def_mod_pub} ${_key_file}.pub
                return=1
            fi
        fi
    done # for KEY

    return ${return}
}

#----------------------------------------------------------------------------
# create authorized_keys file and add public keys
#----------------------------------------------------------------------------
create_ssh_authorized_keys ()
{
    myecho "Creating authorized_keys file ..."

    mkdir -p /root/.ssh

    # check first
    idx=1
    while [ "$idx" -le "$SSH_PUBLIC_KEY_N" ]
    do
        eval active='${SSH_PUBLIC_KEY_'${idx}'_ACTIVE}'
        if [ "${active}" = "yes" ]
        then
            eval key='$SSH_PUBLIC_KEY_'$idx
            if [ -z "$key" ]
            then
                myecho --warn "Empty SSH_PUBLIC_KEY_$idx will be ignored"
            fi

            _key=$(echo "${key}" | cut -c -1)

            if [ "${_key}" = '/' ]
            then
                if [ ! -r "$key" ]
                then
                    myecho --error "SSH_PUBLIC_KEY_$idx - File $key does not exist or is not readable"
                fi
            fi
        fi
        idx=$(/usr/bin/expr ${idx} + 1)
    done


    # create temporary file
    {
        idx=1
        while [ "$idx" -le "$SSH_PUBLIC_KEY_N" ]
        do
            eval active='${SSH_PUBLIC_KEY_'${idx}'_ACTIVE}'
            if [ "${active}" = "yes" ]
            then
                eval key='$SSH_PUBLIC_KEY_'$idx
                if [ -z "$key" ]
                then
                    true
                else
                    _key=$(echo "${key}" | cut -c -1)

                    if [ "${_key}" = '/' ]
                    then
                        if [ -r "$key" ]
                        then
                            cat "$key"
                            # add newline
                            echo
                        fi
                    else
                        echo "$key"
                        # add newline
                        echo
                    fi
                fi
            fi
            idx=$(/usr/bin/expr ${idx} + 1)
        done
    } > ${ssh_authorized_keys_file_tmp}

    # copy temporary file to final file
    # omit empty lines
    grep -v '^$' $ssh_authorized_keys_file_tmp > $ssh_authorized_keys_file

    rm -f $ssh_authorized_keys_file_tmp
}

#----------------------------------------------------------------------------
# delete public keys from authorized_keys file
#----------------------------------------------------------------------------
delete_ssh_authorized_keys ()
{
    if [ -f $ssh_authorized_keys_file ]
    then
        myecho "Deleting authorized_keys file ..."
        rm -f $ssh_authorized_keys_file
    fi
}

#----------------------------------------------------------------------------
# create xinetd ssh configuration
#----------------------------------------------------------------------------
stop_xinetd_ssh ()
{
    if [ -f ${xinetd_conf} ]
    then
        rm -f ${xinetd_conf}
    fi

    if [ -f ${services_file} ]
    then
        rm -f ${services_file}
        /var/install/bin/update-services ssh
    fi
}

#----------------------------------------------------------------------------
# create xinetd ssh configuration
#----------------------------------------------------------------------------
create_xinetd_ssh ()
{
    if [ ${SSH_DAEMON_START_METHOD} = 'xi' ]
    then

        cat >${xinetd_conf} <<EOF
#
# ${xinetd_conf}
# generated by /var/install/config.d/${package_name}.sh
#
service ssh
{
    port = ${SSH_PORT}
    socket_type = stream
    protocol = tcp
    wait = no
    user = root
    server = /usr/sbin/sshd
    server_args = -i
    disable = no
}
EOF

        if [ "${SSH_PORT}" -ne "22" ]
        then

            cat >${services_file} <<EOF
#
# ${services_file}
# generated by /var/install/config.d/${package_name}.sh
#
ssh             ${SSH_PORT}/tcp
ssh             ${SSH_PORT}/udp
EOF
            /var/install/bin/update-services ssh
        else
            if [ -f ${services_file} ]
            then
                rm -f ${services_file}
                /var/install/bin/update-services ssh
            fi
        fi
    else
        stop_xinetd_ssh
    fi
}

# ===========================================================================
# main
# ===========================================================================
while [ ${#} -ne 0 ]
do
    case "$1" in
        --quiet )
            _quiet=true
            __quiet='--quiet'
            shift
            ;;
        * )
            _action=${1}
            shift
            ;;
    esac
done

case "${_action}" in
    * )
        if [ "${START_SSH}" = "yes" ]
        then
            # backup ssh_config file if it exists
            /var/install/bin/backup-file --quiet ${ssh_config_file}
            create_ssh_config

            if [ "${SSH_DAEMON_MAN_CONFIG}" != "yes" ]
            then
                create_sshd_config
            fi

            if [ "${SSH_PUBLIC_KEY_N}" -gt "0" ]
            then
                create_ssh_authorized_keys
            else
                delete_ssh_authorized_keys
            fi

            # verify / create SSH Server Keys (Host Keys)
            verify_host_keys '/etc/ssh' 'yes' ''

            create_xinetd_ssh
            ssh_start
        else
            ssh_stop
            stop_xinetd_ssh
        fi
        ;;
esac

# ===========================================================================
# end
# ===========================================================================
exit 0
