18273e63d0e9085918d66a30cef5c3a9366aa943
[openwrt/openwrt.git] / package / network / services / dropbear / files / dropbear.init
1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2006-2010 OpenWrt.org
3 # Copyright (C) 2006 Carlos Sobrinho
4
5 START=19
6 STOP=50
7
8 USE_PROCD=1
9 PROG=/usr/sbin/dropbear
10 NAME=dropbear
11 PIDCOUNT=0
12
13 extra_command "killclients" "Kill ${NAME} processes except servers and yourself"
14
15 _dropbearkey()
16 {
17 /usr/bin/dropbearkey "$@" 0<&- 1>&- 2>&-
18 }
19
20 # $1 - host key file name
21 hk_verify()
22 {
23 [ -f "$1" ] || return 1
24 [ -s "$1" ] || return 2
25 _dropbearkey -y -f "$1" || return 3
26 return 0
27 }
28
29 # $1 - hk_verify() return code
30 hk_errmsg()
31 {
32 case "$1" in
33 0) ;;
34 1) echo "file does not exist" ;;
35 2) echo "file has zero length" ;;
36 3) echo "file is not valid host key or not supported" ;;
37 *) echo "unknown error" ;;
38 esac
39 }
40
41 # $1 - config option
42 # $2 - host key file name
43 hk_config()
44 {
45 local x m
46 hk_verify "$2"; x=$?
47 case "$x" in
48 0) procd_append_param command -r "$2"
49 ;;
50 *) m=$(hk_errmsg "$x")
51 logger -t "${NAME}" -p daemon.warn \
52 "option '$1', value '$2': $m, skipping"
53 ;;
54 esac
55 }
56
57 # $1 - host key file name
58 hk_config__keyfile()
59 {
60 hk_config 'keyfile' "$1"
61 }
62
63 hk_generate_as_needed()
64 {
65 local kdir kgen ktype tdir kcount tfile
66 kdir='/etc/dropbear'
67
68 kgen=''
69 for ktype in ed25519 ecdsa rsa; do
70 hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue
71
72 kgen="${kgen} ${ktype}"
73 done
74
75 [ -z "${kgen}" ] && return
76
77 tdir=$(mktemp -d); chmod 0700 "${tdir}"
78
79 kcount=0
80 for ktype in ${kgen}; do
81 tfile="${tdir}/dropbear_${ktype}_host_key"
82
83 if ! _dropbearkey -t ${ktype} -f "${tfile}"; then
84 # unsupported key type
85 rm -f "${tfile}"
86 continue
87 fi
88
89 kcount=$((kcount+1))
90 done
91
92 if [ ${kcount} -ne 0 ]; then
93 mkdir -p "${kdir}"; chmod 0700 "${kdir}"; chown root "${kdir}"
94 mv -f "${tdir}/"* "${kdir}/"
95 fi
96
97 rm -rf "${tdir}"
98 }
99
100 append_ports()
101 {
102 local ipaddrs="$1"
103 local port="$2"
104
105 [ -z "$ipaddrs" ] && {
106 procd_append_param command -p "$port"
107 return
108 }
109
110 for addr in $ipaddrs; do
111 procd_append_param command -p "$addr:$port"
112 done
113 }
114
115 validate_section_dropbear()
116 {
117 uci_load_validate dropbear dropbear "$1" "$2" \
118 'PasswordAuth:bool:1' \
119 'enable:bool:1' \
120 'Interface:string' \
121 'GatewayPorts:bool:0' \
122 'ForceCommand:string' \
123 'RootPasswordAuth:bool:1' \
124 'RootLogin:bool:1' \
125 'rsakeyfile:file' \
126 'keyfile:list(file)' \
127 'BannerFile:file' \
128 'Port:port:22' \
129 'SSHKeepAlive:uinteger:300' \
130 'IdleTimeout:uinteger:0' \
131 'MaxAuthTries:uinteger:3' \
132 'RecvWindowSize:uinteger:0' \
133 'mdns:bool:1'
134 }
135
136 dropbear_instance()
137 {
138 local ipaddrs
139
140 [ "$2" = 0 ] || {
141 echo "validation failed"
142 return 1
143 }
144
145 [ -n "${Interface}" ] && {
146 [ -n "${BOOT}" ] && return 0
147
148 network_get_ipaddrs_all ipaddrs "${Interface}" || {
149 echo "interface ${Interface} has no physdev or physdev has no suitable ip"
150 return 1
151 }
152 }
153
154 [ "${enable}" = "0" ] && return 1
155 PIDCOUNT="$(( ${PIDCOUNT} + 1))"
156 local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
157
158 # Increase default receive window size to increase
159 # throughput on high latency links
160 if [ "${RecvWindowSize}" -eq "0" ]; then
161 RecvWindowSize="262144"
162 fi
163
164 procd_open_instance
165 procd_set_param command "$PROG" -F -P "$pid_file"
166 [ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
167 [ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
168 [ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}"
169 [ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
170 [ "${RootLogin}" -eq 0 ] && procd_append_param command -w
171 config_list_foreach "$1" 'keyfile' hk_config__keyfile
172 if [ -n "${rsakeyfile}" ]; then
173 logger -s -t "${NAME}" -p daemon.crit \
174 "Option 'rsakeyfile' is considered to be DEPRECATED and will be REMOVED in future releases, use 'keyfile' list instead"
175 sed -i.before-upgrade -E -e 's/option(\s+)rsakeyfile/list keyfile/' \
176 "/etc/config/${NAME}"
177 logger -s -t "${NAME}" -p daemon.crit \
178 "Auto-transition 'option rsakeyfile' => 'list keyfile' in /etc/config/${NAME} is done, please verify your configuration"
179 hk_config 'rsakeyfile' "${rsakeyfile}"
180 fi
181 [ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
182 append_ports "${ipaddrs}" "${Port}"
183 [ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
184 [ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
185 [ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
186 [ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \
187 procd_append_param command -W "${RecvWindowSize}"
188 [ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
189 procd_set_param respawn
190 procd_close_instance
191 }
192
193 load_interfaces()
194 {
195 config_get interface "$1" Interface
196 config_get enable "$1" enable 1
197
198 [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
199 }
200
201 boot()
202 {
203 BOOT=1
204 start "$@"
205 }
206
207 start_service()
208 {
209 hk_generate_as_needed
210
211 . /lib/functions.sh
212 . /lib/functions/network.sh
213
214 config_load "${NAME}"
215 config_foreach validate_section_dropbear dropbear dropbear_instance
216 }
217
218 service_triggers()
219 {
220 local interfaces
221
222 procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
223
224 config_load "${NAME}"
225 config_foreach load_interfaces dropbear
226
227 [ -n "${interfaces}" ] && {
228 for n in $interfaces ; do
229 procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
230 done
231 }
232
233 procd_add_validation validate_section_dropbear
234 }
235
236 shutdown() {
237 # close all open connections
238 killall dropbear
239 }
240
241 killclients()
242 {
243 local ignore=''
244 local server
245 local pid
246
247 # if this script is run from inside a client session, then ignore that session
248 pid="$$"
249 while [ "${pid}" -ne 0 ]
250 do
251 # get parent process id
252 pid=$(cut -d ' ' -f 4 "/proc/${pid}/stat")
253 [ "${pid}" -eq 0 ] && break
254
255 # check if client connection
256 grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" && {
257 append ignore "${pid}"
258 break
259 }
260 done
261
262 # get all server pids that should be ignored
263 for server in $(cat /var/run/${NAME}.*.pid)
264 do
265 append ignore "${server}"
266 done
267
268 # get all running pids and kill client connections
269 local skip
270 for pid in $(pidof "${NAME}")
271 do
272 # check if correct program, otherwise process next pid
273 grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" || {
274 continue
275 }
276
277 # check if pid should be ignored (servers, ourself)
278 skip=0
279 for server in ${ignore}
280 do
281 if [ "${pid}" = "${server}" ]
282 then
283 skip=1
284 break
285 fi
286 done
287 [ "${skip}" -ne 0 ] && continue
288
289 # kill process
290 echo "${initscript}: Killing ${pid}..."
291 kill -KILL ${pid}
292 done
293 }