]> rtime.felk.cvut.cz Git - novaboot.git/blob - server/novaboot-shell
server: Mention get-config command in help message
[novaboot.git] / server / novaboot-shell
1 #!/bin/sh
2
3 set -e
4
5 die() {
6     echo >&2 "novaboot-shell: $*"
7     exit 1
8 }
9
10 print_help() {
11     cat <<EOF
12 Target commands:
13 - console (default command)
14 - reset
15 - on
16 - off
17 - rsync ...
18 - get-config
19
20 Management commands:
21 - help
22 EOF
23
24     if [ "$NB_ADMIN" ]; then
25         cat <<EOF
26 - add-key
27 - shell (use with ssh -t)
28 EOF
29     fi
30     exit 0
31 }
32
33 add_key() {
34     local user
35     [ "$NB_ADMIN" ] || return 1
36
37     case $# in
38         0) die "Usage: ssh ... add-key USERNAME < id_rsa.pub";;
39         1) break;;
40         *) die "User name must not contain spaces: $*";;
41     esac
42     user="$1"
43     key=$(cat)
44
45     tmp=$(mktemp ~/.ssh/authorized_keys.XXXXXXXX)
46     {
47         cat ~/.ssh/authorized_keys
48         echo "command=\"user $user\" $key"
49     } | sort -u > $tmp
50
51     mv $tmp ~/.ssh/authorized_keys
52 }
53
54 exec_shell() {
55     [ "$NB_ADMIN" ] || die "Permission denied"
56     if ! tty > /dev/null; then
57         echo "novaboot-shell: Consider starting the shell with 'ssh -t'"
58     fi
59     exec /bin/bash || exec /bin/sh
60 }
61
62 lock_queue() {
63     lslocks | awk '{ if ($9 == "'"$RUN_DIR"'") { print $2 } }'
64 }
65
66 print_queue() {
67     local queue
68
69     queue=$(
70         for pid in $(lock_queue); do
71             echo $pid $(sed --null-data -ne '/^NOVABOOT_ID=/ s///p' /proc/$pid/environ)
72         done | sort)
73     if [ "$queue" ]; then
74         echo "Target is occupied by:"
75         ( echo "PID USER LOGIN_TIME FROM"; echo "$queue" ) | column -t
76     fi
77 }
78
79 locked() {
80     print_queue
81     no_fork=
82     #flock -h 2>&1 | grep -q -e "--no-fork" && no_fork=--no-fork
83     exec flock $no_fork "$RUN_DIR" "$@"
84 }
85
86 unlocked() {
87     exec "$@"
88 }
89
90 read_config() {
91     . "${NOVABOOT_SHELL_CONFIG:-$HOME/.novaboot-shell}"
92 }
93
94 # run_subcommand should be called only after permission checks and/or locking
95 run_subcommand() {
96     read_config
97     case "$*" in
98         "console")
99             trap "rm -f $RUN_DIR/ppid" EXIT
100             echo $NOVABOOT_PPID > $RUN_DIR/ppid
101             echo 'novaboot-shell: Connected'
102             # TODO: $reset_begin_cmd
103             eval exec "${console_cmd:?}";;
104         "reset")
105             eval exec "${reset_cmd:?}";;
106         "rsync --server "*" . .")
107             if ! [ $# -eq 5 -o \( $# -eq 6 -a "$4" = '--log-format=X' \) ]; then
108                 die "Unexpected rsync invocation: $*"
109             fi
110             mkdir -p "$HOME/tftproot"
111             cd "$HOME/tftproot"
112             exec "$@";;
113         "on")
114             eval exec "${on_cmd:?}";;
115         "off")
116             eval exec "${off_cmd:?}";;
117     esac
118 }
119
120 main() {
121     if [ "$1" = "-c" ]; then
122         set -- $2
123     elif [ $# -gt 0 ]; then
124         die "Permission denied"
125     fi
126
127     NB_ADMIN=
128     if [ "$1" = "user" ]; then
129         # Get user name encoded in ~/.ssh/authorized_keys
130         NB_USER="$2";
131         [ "$3" = "admin" ] && NB_ADMIN=1
132         set -- $SSH_ORIGINAL_COMMAND
133     fi
134
135     IP=${SSH_CONNECTION%% *}
136     if [ "$IP" ]; then
137         HOST=$(getent hosts $IP) || HOST=$IP
138     else
139         HOST=localhost
140     fi
141     REMOTE=${HOST##* }
142     DATE=$(LANG=C date +'%F_%T')
143     export NOVABOOT_ID="${NB_USER:-?} $DATE ${REMOTE}"
144     export NOVABOOT_PPID=$PPID
145
146     mkdir -p "$RUN_DIR"
147
148     case "$1" in
149         # Commands allowed at any time
150         "console"|"") locked $0 console;;
151         "get-config") read_config && echo -n "${target_config}"; exit;;
152         "add-key") shift; add_key "$@"; exit;;
153         "shell") exec_shell; exit;;
154         "help") print_help;;
155
156         # Commands allowed only when nobody or the same user is connected
157         # to the console. "The same user" means that we were executed by
158         # the same sshd process that has the lock. This is ensured by
159         # using SSH connection sharing on client side.
160         reset | rsync | on | off)
161             ALLOWED_PPID=$(cat $RUN_DIR/ppid 2>/dev/null || :)
162             if [ "$PPID" -eq "${ALLOWED_PPID:-0}" ]; then run=unlocked; else run=locked; fi
163             $run $0 "$@";;
164         *)
165             echo >&2 "novaboot-shell: Command not allowed: $*"
166             logger -p error "novaboot-shell: Command not allowed: $*"
167             exit 1;;
168     esac
169 }
170
171 RUN_DIR="$HOME"
172
173 if [ -z "$NOVABOOT_ID" ]; then
174     main "$@"
175 else
176     run_subcommand "$@"
177 fi
178 exit
179
180 : <<EOF
181 =encoding utf8
182
183 =head1 NAME
184
185 novaboot-shell - provides novaboot with unified SSH-based interface for controlling target hardware
186
187 =head1 SYNOPSIS
188
189 B<novaboot-shell> -c "[command [arguments...]]"
190
191 B<novaboot-shell> [command [arguments...]]
192
193 B<ssh target@server> [command [arguments...]]
194
195 =head1 DESCRIPTION
196
197 B<novaboot-shell> provides L<novaboot(1)> with a unified SSH-based
198 interface for controlling the target hardware. This simplifies
199 client-side configuration, because clients typically need only the
200 I<--ssh=...> option. B<novaboot-shell> is typically configured as a
201 login shell of special user accounts associated with the target
202 hardware (as set by L<adduser-novaboot(8)>). It ensures that users can
203 perform only a limited set of actions (see L</COMMANDS> below) with
204 the target and have no shell access on the server.
205
206 =head1 COMMANDS
207
208 =over 8
209
210 =item console
211
212 Connect to target console (usually serial line). When somebody is
213 connected to the console, other users are blocked from controlling the
214 target. Blocked users see a message indicating who blocks them.
215
216 The user connected to the console is able to invoke other commands
217 such as L</reset>, but only when the command is invoked via the same
218 SSH connection. This can be accomplished by using SSH connection
219 sharing, which is what L<novaboot(1)> uses (see I<-M> and I<-S> in
220 L<ssh(1)>).
221
222 This is the default command when no command is specified on command
223 line.
224
225 =item reset
226
227 Reset the target hardware.
228
229 =item on
230
231 Power on the target hardware.
232
233 =item off
234
235 Power off the target hardware.
236
237 =item rsync [...]
238
239 This command is not meant to be invoked directly by the user. It
240 allows using L<rsync(1)> to copy files to the target, perhaps for TFTP
241 server. The rsync command must be invoked as: C<rsync ...
242 target@server:>, i.e. without specifying destination path. The files
243 will be stored into I<$HOME/tftproot>.
244
245 =item user <uernamename> [admin]
246
247 User command is meant to be used with C<command=> option in SSH's
248 L<authorized_keys(5)> file. It allows the shell to display
249 human-readable names when printing information about who blocks the
250 target. Then, the real command is taken from SSH_ORIGINAL_COMMAND
251 environment variable.
252
253 When "admin" is specified after the user name, this user is considered
254 an administrator and is allowed to run L</add-key> and L</shell>
255 commands.
256
257 =back
258
259 =head2 Administration commands
260
261 Only administrators (see L</user>) are allowed to execute these
262 commands.
263
264 =over 8
265
266 =item add-key <username>
267
268 Reads the SSH public key from standard input and adds it into in
269 F<~/.ssh/authorized_keys>.
270
271 Example: C<ssh target@server add-key johndoe < john_rsa.pub>
272
273 =item shell
274
275 Runs shell on the server. Useful for editing configuration file. It is
276 better used with allocated pseudo-terminal.
277
278 Example: C<ssh -t target@server shell>
279
280 =back
281
282 =head1 CONFIGURATION FILE
283
284 B<novaboot-shell> reads configuration file from
285 F<$HOME/.novaboot-shell>. It should define values for the following
286 variables in the SH syntax.
287
288 =over 8
289
290 =item console_cmd
291
292 Command to C<exec> that connects to target's console.
293
294 =item reset_cmd
295
296 Command to C<exec> that resets the Target.
297
298 =item on_cmd
299
300 Command to C<exec> that powers the target on.
301
302 =item off_cmd
303
304 Command to C<exec> that powers the target off.
305
306 =item target_config
307
308 Novaboot command line options that specify which boot loader is used
309 by the target (L<novaboot(1)> rejects other, possibly dangerous, options).
310 Each option is on its own line and no quoting, escaping or stripping
311 is performed on the values.
312
313 Example:
314
315   target_config="\
316   --uboot=(uboot)
317   --uboot-init=setenv serverip 192.168.1.1; setenv ipaddr 192.168.1.10
318   --uboot-addr=kernel=0x8100000
319   --uboot-addr=fdt=0x83000000
320   --uboot-addr=ramdisk=0x83100000
321   "
322
323
324 =back
325
326 =head1 AUTHORS
327
328 Michal Sojka <sojkam1@fel.cvut.cz>
329
330 Latest version can be found at
331 L<https://github.com/wentasah/novaboot>.
332
333 =cut
334 EOF