1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2006-2010 OpenWrt.org
3 # Copyright (C) 2006 Carlos Sobrinho
9 PROG
=/usr
/sbin
/dropbear
13 extra_command
"killclients" "Kill ${NAME} processes except servers and yourself"
15 # most of time real_stat() will be failing
16 # due to missing "stat" binary (by default)
17 real_stat
() { env stat
-L "$@" 2>/dev
/null
; }
18 dumb_stat
() { ls -Ldln "$1" |
tr -s '\t ' ' ' ; }
19 stat_perm
() { real_stat
-c '%A' "$1" || dumb_stat
"$1" | cut
-d ' ' -f 1 ; }
20 stat_owner
() { real_stat
-c '%u' "$1" || dumb_stat
"$1" | cut
-d ' ' -f 3 ; }
24 /usr
/bin
/dropbearkey
"$@" </dev
/null
>/dev
/null
2>&1
27 # $1 - file name (host key or config)
30 [ -f "$1" ] ||
return 1
31 # checking file ownership
32 [ "$(stat_owner "$1")" = "0" ] ||
{
34 [ "$(stat_owner "$1")" = "0" ] ||
return 2
36 # checking file permissions
37 [ "$(stat_perm "$1")" = "-rw-------" ] ||
{
39 [ "$(stat_perm "$1")" = "-rw-------" ] ||
return 3
41 # file is host key or not?
42 # if $2 is empty string - file is "host key"
43 # if $2 is non-empty string - file is "config"
44 [ -z "$2" ] ||
return 0
45 # checking file contents (finally)
46 [ -s "$1" ] ||
return 4
47 _dropbearkey
-y -f "$1" ||
return 5
51 # $1 - file_verify() return code
56 1) echo "file does not exist" ;;
57 2) echo "file has wrong owner (must be owned by root)" ;;
58 3) echo "file has wrong permissions (must not have group/other write bit)" ;;
59 4) echo "file has zero length" ;;
60 5) echo "file is not valid host key or not supported" ;;
61 *) echo "unknown error" ;;
66 # $2 - host key file name
70 file_verify
"$2" ; x
=$?
71 if [ "$x" = 0 ] ; then
72 procd_append_param
command -r "$2"
76 logger
-s -t "${NAME}" -p daemon.warn \
77 "Option '$1', skipping '$2': $m"
80 # $1 - host key file name
81 hk_config__keyfile
() { hk_config keyfile
"$1" ; }
83 ktype_all
='ed25519 ecdsa rsa'
85 hk_generate_as_needed
()
87 local hk_cfg_dir kgen ktype kfile hk_tmp_dir
88 hk_cfg_dir
='/etc/dropbear'
90 [ -d "${hk_cfg_dir}" ] || mkdir
-p "${hk_cfg_dir}"
93 for ktype
in ${ktype_all} ; do
94 kfile
="${hk_cfg_dir}/dropbear_${ktype}_host_key"
96 if file_verify
"${kfile}" ; then continue ; fi
98 kgen
="${kgen}${kgen:+ }${ktype}"
102 [ -n "${kgen}" ] ||
return 0
104 hk_tmp_dir
=$
(mktemp
-d)
105 # system in bad state?
106 [ -n "${hk_tmp_dir}" ] ||
return 1
108 chmod 0700 "${hk_tmp_dir}"
110 for ktype
in ${kgen} ; do
111 kfile
="${hk_tmp_dir}/dropbear_${ktype}_host_key"
113 if ! _dropbearkey
-t ${ktype} -f "${kfile}" ; then
114 # unsupported key type
119 chmod 0600 "${kfile}"
123 for ktype
in ${ktype_all} ; do
124 kfile
="${hk_tmp_dir}/dropbear_${ktype}_host_key"
126 [ -s "${kfile}" ] ||
continue
128 kgen
="${kgen}${kgen:+ }${ktype}"
131 if [ -n "${kgen}" ] ; then
132 for ktype
in ${kgen} ; do
133 kfile
="${hk_tmp_dir}/dropbear_${ktype}_host_key"
134 [ -s "${kfile}" ] ||
continue
135 mv -f "${kfile}" "${hk_cfg_dir}/"
139 rm -rf "${hk_tmp_dir}"
141 # cleanup empty files
142 for ktype
in ${ktype_all} ; do
143 kfile
="${hk_cfg_dir}/dropbear_${ktype}_host_key"
145 [ -s "${kfile}" ] ||
rm -f "${kfile}"
154 [ -z "$ipaddrs" ] && {
155 procd_append_param
command -p "$port"
159 for addr
in $ipaddrs; do
160 procd_append_param
command -p "$addr:$port"
164 validate_section_dropbear
()
166 uci_load_validate dropbear dropbear
"$1" "$2" \
167 'PasswordAuth:bool:1' \
170 'GatewayPorts:bool:0' \
171 'ForceCommand:string' \
172 'RootPasswordAuth:bool:1' \
175 'keyfile:list(file)' \
178 'SSHKeepAlive:uinteger:300' \
179 'IdleTimeout:uinteger:0' \
180 'MaxAuthTries:uinteger:3' \
181 'RecvWindowSize:uinteger:262144' \
190 echo "validation failed"
194 [ -n "${Interface}" ] && {
195 [ -n "${BOOT}" ] && return 0
197 network_get_ipaddrs_all ipaddrs
"${Interface}" ||
{
198 echo "interface ${Interface} has no physdev or physdev has no suitable ip"
203 [ "${enable}" = "0" ] && return 1
204 PIDCOUNT
="$(( ${PIDCOUNT} + 1))"
205 local pid_file
="/var/run/${NAME}.${PIDCOUNT}.pid"
208 procd_set_param
command "$PROG" -F -P "$pid_file"
209 [ "${PasswordAuth}" -eq 0 ] && procd_append_param
command -s
210 [ "${GatewayPorts}" -eq 1 ] && procd_append_param
command -a
211 [ -n "${ForceCommand}" ] && procd_append_param
command -c "${ForceCommand}"
212 [ "${RootPasswordAuth}" -eq 0 ] && procd_append_param
command -g
213 [ "${RootLogin}" -eq 0 ] && procd_append_param
command -w
214 config_list_foreach
"$1" 'keyfile' hk_config__keyfile
215 if [ -n "${rsakeyfile}" ]; then
216 logger
-s -t "${NAME}" -p daemon.crit \
217 "Option 'rsakeyfile' is considered to be DEPRECATED and will be REMOVED in future releases, use 'keyfile' list instead"
218 sed -i.before-upgrade
-E -e 's/option(\s+)rsakeyfile/list keyfile/' \
219 "/etc/config/${NAME}"
220 logger
-s -t "${NAME}" -p daemon.crit \
221 "Auto-transition 'option rsakeyfile' => 'list keyfile' in /etc/config/${NAME} is done, please verify your configuration"
222 hk_config
'rsakeyfile' "${rsakeyfile}"
224 [ -n "${BannerFile}" ] && procd_append_param
command -b "${BannerFile}"
225 append_ports
"${ipaddrs}" "${Port}"
226 [ "${IdleTimeout}" -ne 0 ] && procd_append_param
command -I "${IdleTimeout}"
227 [ "${SSHKeepAlive}" -ne 0 ] && procd_append_param
command -K "${SSHKeepAlive}"
228 [ "${MaxAuthTries}" -ne 0 ] && procd_append_param
command -T "${MaxAuthTries}"
229 [ "${RecvWindowSize}" -gt 0 ] && {
230 # NB: OpenWrt increases receive window size to increase throughput on high latency links
231 # ref: validate_section_dropbear()
232 # default receive window size is 24576 (DEFAULT_RECV_WINDOW in default_options.h)
235 local MAX_RECV_WINDOW
=10485760
236 if [ "${RecvWindowSize}" -gt ${MAX_RECV_WINDOW} ] ; then
237 # separate logging is required because syslog misses dropbear's message
238 # Bad recv window '${RecvWindowSize}', using ${MAX_RECV_WINDOW}
239 # it's probably dropbear issue but we should handle this and notify user
240 logger
-s -t "${NAME}" -p daemon.warn \
241 "Option 'RecvWindowSize' is too high (${RecvWindowSize}), limiting to ${MAX_RECV_WINDOW}"
242 RecvWindowSize
=${MAX_RECV_WINDOW}
244 procd_append_param
command -W "${RecvWindowSize}"
246 [ "${mdns}" -ne 0 ] && procd_add_mdns
"ssh" "tcp" "$Port" "daemon=dropbear"
247 procd_set_param respawn
253 config_get interface
"$1" Interface
254 config_get
enable "$1" enable 1
256 [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
267 hk_generate_as_needed
268 file_verify
/etc
/dropbear
/authorized_keys config
271 .
/lib
/functions
/network.sh
273 config_load
"${NAME}"
274 config_foreach validate_section_dropbear dropbear dropbear_instance
281 procd_add_config_trigger
"config.change" "dropbear" /etc
/init.d
/dropbear reload
283 config_load
"${NAME}"
284 config_foreach load_interfaces dropbear
286 [ -n "${interfaces}" ] && {
287 for n
in $interfaces ; do
288 procd_add_interface_trigger
"interface.*" $n /etc
/init.d
/dropbear reload
292 procd_add_validation validate_section_dropbear
296 # close all open connections
306 # if this script is run from inside a client session, then ignore that session
308 while [ "${pid}" -ne 0 ]
310 # get parent process id
311 pid
=$
(cut
-d ' ' -f 4 "/proc/${pid}/stat")
312 [ "${pid}" -eq 0 ] && break
314 # check if client connection
315 grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" && {
316 append ignore
"${pid}"
321 # get all server pids that should be ignored
322 for server
in $
(cat /var
/run
/${NAME}.
*.pid
)
324 append ignore
"${server}"
327 # get all running pids and kill client connections
329 for pid
in $
(pidof
"${NAME}")
331 # check if correct program, otherwise process next pid
332 grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" ||
{
336 # check if pid should be ignored (servers, ourself)
338 for server
in ${ignore}
340 if [ "${pid}" = "${server}" ]
346 [ "${skip}" -ne 0 ] && continue
349 echo "${initscript}: Killing ${pid}..."