#!/bin/sh /etc/rc.common # Copyright (C) 2006-2010 OpenWrt.org # Copyright (C) 2006 Carlos Sobrinho START=19 STOP=50 USE_PROCD=1 PROG=/usr/sbin/dropbear NAME=dropbear PIDCOUNT=0 extra_command "killclients" "Kill ${NAME} processes except servers and yourself" _dropbearkey() { /usr/bin/dropbearkey "$@" 0<&- 1>&- 2>&- } # $1 - host key file name hk_verify() { [ -f "$1" ] || return 1 [ -s "$1" ] || return 2 _dropbearkey -y -f "$1" || return 3 return 0 } # $1 - hk_verify() return code hk_errmsg() { case "$1" in 0) ;; 1) echo "file does not exist" ;; 2) echo "file has zero length" ;; 3) echo "file is not valid host key or not supported" ;; *) echo "unknown error" ;; esac } # $1 - config option # $2 - host key file name hk_config() { local x m hk_verify "$2"; x=$? case "$x" in 0) procd_append_param command -r "$2" ;; *) m=$(hk_errmsg "$x") logger -t "${NAME}" -p daemon.warn \ "option '$1', value '$2': $m, skipping" ;; esac } # $1 - host key file name hk_config__keyfile() { hk_config 'keyfile' "$1" } hk_generate_as_needed() { local kdir kgen ktype tdir kcount tfile kdir='/etc/dropbear' kgen='' for ktype in ed25519 ecdsa rsa; do hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue kgen="${kgen} ${ktype}" done [ -z "${kgen}" ] && return tdir=$(mktemp -d); chmod 0700 "${tdir}" kcount=0 for ktype in ${kgen}; do tfile="${tdir}/dropbear_${ktype}_host_key" if ! _dropbearkey -t ${ktype} -f "${tfile}"; then # unsupported key type rm -f "${tfile}" continue fi kcount=$((kcount+1)) done if [ ${kcount} -ne 0 ]; then mkdir -p "${kdir}"; chmod 0700 "${kdir}"; chown root "${kdir}" mv -f "${tdir}/"* "${kdir}/" fi rm -rf "${tdir}" } append_ports() { local ipaddrs="$1" local port="$2" [ -z "$ipaddrs" ] && { procd_append_param command -p "$port" return } for addr in $ipaddrs; do procd_append_param command -p "$addr:$port" done } validate_section_dropbear() { uci_load_validate dropbear dropbear "$1" "$2" \ 'PasswordAuth:bool:1' \ 'enable:bool:1' \ 'Interface:string' \ 'GatewayPorts:bool:0' \ 'ForceCommand:string' \ 'RootPasswordAuth:bool:1' \ 'RootLogin:bool:1' \ 'rsakeyfile:file' \ 'keyfile:list(file)' \ 'BannerFile:file' \ 'Port:port:22' \ 'SSHKeepAlive:uinteger:300' \ 'IdleTimeout:uinteger:0' \ 'MaxAuthTries:uinteger:3' \ 'RecvWindowSize:uinteger:0' \ 'mdns:bool:1' } dropbear_instance() { local ipaddrs [ "$2" = 0 ] || { echo "validation failed" return 1 } [ -n "${Interface}" ] && { [ -n "${BOOT}" ] && return 0 network_get_ipaddrs_all ipaddrs "${Interface}" || { echo "interface ${Interface} has no physdev or physdev has no suitable ip" return 1 } } [ "${enable}" = "0" ] && return 1 PIDCOUNT="$(( ${PIDCOUNT} + 1))" local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid" # Increase default receive window size to increase # throughput on high latency links if [ "${RecvWindowSize}" -eq "0" ]; then RecvWindowSize="262144" fi procd_open_instance procd_set_param command "$PROG" -F -P "$pid_file" [ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s [ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a [ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}" [ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g [ "${RootLogin}" -eq 0 ] && procd_append_param command -w if [ -n "${rsakeyfile}" ]; then logger -t ${NAME} -p daemon.warn \ "option 'rsakeyfile' is considered to be deprecated and" \ "will be removed in future releases, use 'keyfile' instead" hk_config 'rsakeyfile' "${rsakeyfile}" fi config_list_foreach "$1" "keyfile" hk_config__keyfile [ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}" append_ports "${ipaddrs}" "${Port}" [ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}" [ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}" [ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}" [ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \ procd_append_param command -W "${RecvWindowSize}" [ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear" procd_set_param respawn procd_close_instance } load_interfaces() { config_get interface "$1" Interface config_get enable "$1" enable 1 [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}" } boot() { BOOT=1 start "$@" } start_service() { hk_generate_as_needed . /lib/functions.sh . /lib/functions/network.sh config_load "${NAME}" config_foreach validate_section_dropbear dropbear dropbear_instance } service_triggers() { local interfaces procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload config_load "${NAME}" config_foreach load_interfaces dropbear [ -n "${interfaces}" ] && { for n in $interfaces ; do procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload done } procd_add_validation validate_section_dropbear } shutdown() { # close all open connections killall dropbear } killclients() { local ignore='' local server local pid # if this script is run from inside a client session, then ignore that session pid="$$" while [ "${pid}" -ne 0 ] do # get parent process id pid=$(cut -d ' ' -f 4 "/proc/${pid}/stat") [ "${pid}" -eq 0 ] && break # check if client connection grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" && { append ignore "${pid}" break } done # get all server pids that should be ignored for server in $(cat /var/run/${NAME}.*.pid) do append ignore "${server}" done # get all running pids and kill client connections local skip for pid in $(pidof "${NAME}") do # check if correct program, otherwise process next pid grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" || { continue } # check if pid should be ignored (servers, ourself) skip=0 for server in ${ignore} do if [ "${pid}" = "${server}" ] then skip=1 break fi done [ "${skip}" -ne 0 ] && continue # kill process echo "${initscript}: Killing ${pid}..." kill -KILL ${pid} done }