#!/bin/sh

alterator_api_version=1
po_domain="alterator-sshd"

set -f

. alterator-sh-functions
. shell-config
. shell-quote
. shell-ini-config


service=/etc/init.d/sshd
cron=/etc/init.d/crond
CONF=/etc/openssh/sshd_config
authorizedkeys=/etc/openssh/authorized_keys

UID_MIN=5000

keys_list() {
	while IFS=' ' read -r line; do
	write_table_item  \
            name "$(fingerprint "$line")" \
            type "$(parse_authorized_keys "$line" type)" \
            comment "$(parse_authorized_keys "$line" comment)"
	done<"$authorizedkeys/$in_file"
}

keyfile_list() {
    for file in `ls $authorizedkeys`; do
	write_enum_item "$file" "$file"
    done
}

parse_authorized_keys() {
    local line="$1" && shift
    local opts= keytype= key= comment=
    local tempfile="$(mktemp -t alterator-sshd.XXXXXX)"

    printf '%s\n' "$line" >"$tempfile"
    case "$line" in
	ssh-*)
	    IFS=' ' read keytype key comment <"$tempfile"
	    ;;
	*)
	    IFS=' ' read opts keytype key comment <"$tempfile"
	;;
    esac

    case "$1" in
	options)
	    printf '%s' "$opts"
	    ;;
	type)
	    printf '%s' "$keytype"
	    ;;
	key)
	    printf '%s' "$key"
	    ;;
	comment)
	    printf '%s' "$comment"
	    ;;
	*)
	    printf '%s\t%s\t%s\t%s' "$opts" "$keytype" "$key" "$comment"
	    ;;
    esac

    rm -rf -- "$tempfile"
}

ssh_key_del() {
    local file="$1";shift
    local old_fp="$1";shift
    local tempfile="$(mktemp -t alterator-sshd.XXXXXX)"

    while IFS=' ' read -r line; do
	local fp="$(fingerprint "$line")"
	local comment="$(parse_authorized_keys "$line" comment)"
	[ "$fp" = "$old_fp" -o '(' -n "$comment" -a -z "${comment##alterator-trust@*}" ')'  ] ||
	    echo "$line"
    done<"$authorizedkeys/$file" >"$tempfile"

    mv -f "$tempfile" "$authorizedkeys/$file"
}

del_keylist() {
    local IFS=';'
    for key in $in_keylist; do
	ssh_key_del $in_file $key
    done

    [ $(grep -cv "^$" "$authorizedkeys/$in_file") -eq 0 ] && rm -rf -- "$authorizedkeys/$in_file"
}

fingerprint() {

    local line="$1";shift
    local tempfile="$(mktemp -t alterator-sshd.XXXXXX)"

    echo "$line">"$tempfile"
    local v=
    v="$(ssh-keygen -l -f "$tempfile")" &&
	echo "$v"|cut -f2 -d' '
    rm -f -- "$tempfile"
}

ssh_key_add() {
    [ -s "$in_key_file" ] || return 0

    local new_line="$(cat "$in_key_file")"
    local new_fp="$(fingerprint "$new_line")"
    local comment

    comment="$(parse_authorized_keys "$new_line" comment)"
    if [ -z "$new_fp" -o '(' -n "$comment" -a -z "${comment##alterator-trust@*}" ')' ];then
	write_error "`_ "Invalid ssh key"`"
	return
    fi

    [ ! -s "$authorizedkeys/$in_file" ] ||
	while IFS=' ' read -r line; do
	    local fp="$(fingerprint "$line")"
	    if [ "$fp" = "$new_fp" ];then
		write_error "`_ "Same ssh key already exists"`"
		return
	    fi
	done<"$authorizedkeys/$in_file"

    echo "$new_line" >>"$authorizedkeys/$in_file"
}

users_list()
{
    write_enum_item "none" "`_ "-= Select one =-"`"
    write_enum_item "root" "`_ "root (System Administrator)"`"

    getent passwd|
    while IFS=':' read name password uid gid gecos home shell; do
        [ "$uid" -ge "$UID_MIN" ] || continue
	[ "$shell" == "/sbin/nologin" ] || grep -qs "^$shell$" /etc/shells || continue
	[ -x "$shell" ] || continue
	write_enum_item "$name" "$name ($gecos)"
    done 2>/dev/null

}
state()
{
    echo "$(/sbin/chkconfig --list | grep sshd)" | grep -v -q ":on"; write_bool_param daemon "$?"
    write_string_param cur_status "$($service status)"
    
}

daemon()
{
    if test_bool "$in_status"; then
        $service start
	chkconfig sshd on
    else
        $service stop
        chkconfig sshd off
    fi
}

reload()
{
	$service reload
	write_string_param retcode "$?"
}

test_b(){
    grep -sc "^$1" "$CONF"
}

check_param(){
    grep -m 1 "\(^\|^#\)$1" "$CONF" | sed -e "s/\(^\|^#\)$1[[:space:]]//g"
}

shell_set()
{
    local name="$1";shift;
    quote_sed_regexp_variable value "$1";shift;
    local msg="${1:-invalid value}"

    if [ -n "$name" -a -n "$value" ];then
	sed -e "/^#$name\s/s/^#//g" -i "$CONF"
        sed -e "/^$name/s/.*/$name $value/g" -i "$CONF"
    else
        write_error "$msg"
        return 1
    fi
    return 0
}

shell_off()
{
    local name="$1";shift;
    sed -e "/^$name\s/s/.*/#&/g" -i "$CONF"

}

shell_on()
{
    local name="$1";shift;
    sed -e "/^#$name\s/s/^#//g" -i "$CONF"
}

math_group()
{
   case "$1" in
   off)
	sed -e "/^Match Group wheel/{n;s/^[[:space:]]*PasswordAuthentication/#&/g}" -i "$CONF" 
	sed -e "/^Match Group wheel/s/.*/#&/g" -i "$CONF"
   ;;
   no)
	sed -e "/\(^\|^#\)Match Group wheel/s/^#//g" -i "$CONF"
	sed -e "/\(^\|^#\)Match Group wheel/{n;s/^#//g}" -i "$CONF" 
	sed -e "/^Match Group wheel/{n;s/.*/\tPasswordAuthentication no/g}" -i "$CONF" 
   ;;
   yes)
	sed -e "/\(^\|^#\)Match Group wheel/s/^#//g" -i "$CONF"
	sed -e "/\(^\|^#\)Match Group wheel/{n;s/^#//g}" -i "$CONF" 
	sed -e "/^Match Group wheel/{n;s/.*/\tPasswordAuthentication yes/g}" -i "$CONF" 
   ;;
   without-password)
	sed -e "/\(^\|^#\)Match Group wheel/s/^#//g" -i "$CONF"
	sed -e "/\(^\|^#\)Match Group wheel/{n;s/^#//g}" -i "$CONF" 
	sed -e "/^Match Group wheel/{n;s/.*/\tPasswordAuthentication without-password/g}" -i "$CONF" 
   ;;
   esac
}

read_addresses()
{
    write_bool_param use_ipv4address $(grep -sc "^ListenAddress[[:space:]]\([0-9]\{0,3\}\.\)" "$CONF")
    write_bool_param use_ipv6address $(grep -sc  "^ListenAddress[[:space:]]\([0-9]\{0,4\}\:\)" "$CONF")
    write_string_param sshd_ipv4address "$(grep "\(^\|^#\)ListenAddress[[:space:]]\([0-9]\{1,3\}\.\)" "$CONF" | sed -e "s/\(^\|^#\)ListenAddress[[:space:]]//g")"
    write_string_param sshd_ipv6address "$(grep "\(^\|^#\)ListenAddress[[:space:]]\([0-9]\{0,4\}\:\)" "$CONF" | sed -e "s/\(^\|^#\)ListenAddress[[:space:]]//g")"
}

write_addresses()
{
    [ -n "$in_sshd_ipv4address" -a -n "$in_use_ipv4address" ] \
     && sed -e "/ListenAddress[[:space:]]\([0-9]\{1,3\}\.\)/s/.*/ListenAddress $in_sshd_ipv4address/g" -i "$CONF"
    [ -n "$in_sshd_ipv6address" -a -n "$in_use_ipv6address" ] \
     && sed -e "/ListenAddress[[:space:]]\([0-9]\{0,4\}\:\)/s/.*/ListenAddress $in_sshd_ipv6address/g" -i "$CONF"

    [ -n "$in_use_ipv4address" ] \
	&& sed -e "/ListenAddress[[:space:]]\([0-9]\{1,3\}\.\)/s/^#//g" -i "$CONF" \
	|| sed -e "/ListenAddress[[:space:]]\([0-9]\{1,3\}\.\)/s/.*/#&/g" -i "$CONF" 

    [ -n "$in_use_ipv6address" ] \
	&& sed -e "/ListenAddress[[:space:]]\([0-9]\{,4\}\:\)/s/^#//g" -i "$CONF" \
	|| sed -e "/ListenAddress[[:space:]]\([0-9]\{,4\}\:\)/s/.*/#&/g" -i "$CONF" 
}

read_settings()
{
    read_addresses

    write_bool_param use_port $(test_b "Port")
    write_bool_param use_family $(test_b "AddressFamily")
    write_bool_param use_prl $(test_b "PermitRootLogin")
    write_bool_param use_sftp $(test_b "Subsystem")
    write_bool_param use_banner $(test_b "Banner")
    write_bool_param use_groups $(test_b "AllowGroups")
    write_bool_param use_users $(test_b "AllowUsers")
    write_bool_param use_auth $(test_b "PasswordAuthentication")
    write_bool_param math_wheel $(grep -sc "^Match Group wheel" "$CONF")
    
    write_string_param sshd_port "$(check_param Port)"
    write_string_param loginmode "$(check_param PermitRootLogin)"
    write_string_param addr_family "$(check_param AddressFamily)"
    write_string_param sftp_subsys "$(grep "\(^\|^#\)Subsystem" "$CONF" | sed -e "s/\(^\|^#\)Subsystem[[:space:]]sftp[[:space:]]//g")"
    write_string_param banner_path "$(check_param Banner)"
    write_string_param allowed_groups "$(check_param AllowGroups)"
    write_string_param allowed_users "$(check_param AllowUsers)"
    write_string_param authmode "$(check_param PasswordAuthentication)"
    write_string_param wheelmode "$(sed -n "/\(^\|^#\)Match Group wheel/{n;p}" "$CONF" | sed -e "s/\(^\|^#\)[[:space:]]*PasswordAuthentication[[:space:]]//g")"
}

write_settings()
{
    write_addresses
    
    [ -n "$in_sshd_port" ] && shell_set "Port" "$in_sshd_port"
    [ -n "$in_loginmode" ] && shell_set "PermitRootLogin" "$in_loginmode"
    [ -n "$in_addr_family" ] && shell_set "AddressFamily" "$in_addr_family"
    [ -n "$in_authmode" ] && shell_set "PasswordAuthentication" "$in_authmode"
    [ -n "$in_allowed_groups" ] && shell_config_set "$CONF" "AllowGroups" "$in_allowed_groups" " " " "
    [ -n "$in_allowed_users" ] && shell_config_set "$CONF" "AllowUsers" "$in_allowed_users" " " " "
    [ -n "$in_banner_path" ] && shell_set "Banner" "$in_banner_path"
    [ -n "$in_sftp_subsys" ] && shell_set "Subsystem" "sftp $in_sftp_subsys"
    
    [ -n "$in_use_port" ] && shell_on "Port" || shell_off "Port"
    [ -n "$in_use_family" ] && shell_on "AddressFamily" || shell_off "AddressFamily"
    [ -n "$in_use_prl" ] && shell_on "PermitRootLogin" || shell_off "PermitRootLogin"
    [ -n "$in_use_sftp" ] && shell_on "Subsystem" || shell_off "Subsystem"
    [ -n "$in_use_banner" ] && shell_on "Banner" || shell_off "Banner"
    [ -n "$in_use_groups" ] && shell_on "AllowGroups" || shell_off "AllowGroups"
    [ -n "$in_use_users" ] && shell_on "AllowUsers" || shell_off "AllowUsers"
    [ -n "$in_use_auth" ] && shell_on "PasswordAuthentication" || shell_off "PasswordAuthentication"
    [ -n "$in_math_wheel" -a -n "$in_wheelmode" ] && math_group "$in_wheelmode" || math_group off
    
    $service condreload
}

on_message()
{
        case "$in_action" in
		type)
		    write_type_item 	sshd_port 		tcp-port
		    write_type_item	sshd_ipv4address	ipv4-address
		    write_type_item	sshd_ipv6address	ipv6-address
		;;
               list)
                 case "$in__objects" in
                 loginmodes)
                    write_enum_item "yes"            	   "`_ "Yes"`"
                    write_enum_item "no"            	   "`_ "No"`"
                    write_enum_item "without-password"     "`_ "Without password (key only)"`"
                 ;;
                 addrfamily)
                    write_enum_item "any"        "`_ "Any"`"
                    write_enum_item "inet"       "`_ "Use IPv4 only"`"
                    write_enum_item "inet6"      "`_ "Use IPv6 only"`"
                 ;;
                 passwdauth)
                    write_enum_item "yes"	"`_ "Yes"`"
                    write_enum_item "no"	"`_ "No"`"
                 ;;
                 users) users_list;;
                 keys) [ -s "$authorizedkeys/$in_file" ] && keys_list;;
                 keyfiles) keyfile_list;;
                 *)
                 ;;
                 esac
                ;;
               read)
                      case "$in__objects" in
                        state) 
                    	    state
                    	;;
                    	settings)
                    	    read_settings
                    	;;
                        *)
                        ;;
                      esac
                ;;
                write)
                      case "$in__objects" in
                        daemon) daemon;;
                        reload) reload;;
                        settings) write_settings;;
                        key) [ -n "$in_file" -a -n "$in_key_file" ] && ssh_key_add;;
                        *)
                        ;;
                      esac
                ;;
                delete)
            	    case "$in__objects" in
            		keylist) [ -n "$in_file" -a -n "$in_keylist" ] && del_keylist;;
            	        *)
            		;;
            	    esac
        	;;
        esac
}
message_loop
