]> rtime.felk.cvut.cz Git - novaboot.git/blob - server/novaboot-shell
server: Fix quoting of commands from config file
[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
14 - reset
15 - on
16 - off
17 - rsync ...
18
19 Management commands:
20 - help
21 EOF
22
23     if [ "$NB_ADMIN" ]; then
24         cat <<EOF
25 - add-key
26 - shell (use with ssh -t)
27 EOF
28     fi
29     exit 0
30 }
31
32 add_key() {
33     local user
34     [ "$NB_ADMIN" ] || return 1
35
36     case $# in
37         0) die "Username argument missing";;
38         1) break;;
39         *) die "User name must not contain spaces: $*";;
40     esac
41     user="$1"
42     key=$(cat)
43
44     tmp=$(mktemp ~/.ssh/authorized_keys.XXXXXXXX)
45     {
46         cat ~/.ssh/authorized_keys
47         echo "command=\"user $user\" $key"
48     } | sort -u > $tmp
49
50     mv $tmp ~/.ssh/authorized_keys
51 }
52
53 exec_shell() {
54     [ "$NB_ADMIN" ] || die "Permission denied"
55     exec /bin/bash || exec /bin/sh
56 }
57
58 lock_queue() {
59     lslocks | awk '{ if ($9 == "'"$RUN_DIR"'") { print $2 } }'
60 }
61
62 print_queue() {
63     local queue
64
65     queue=$(
66         for pid in $(lock_queue); do
67             echo $pid $(sed --null-data -ne '/^NOVABOOT_ID=/ s///p' /proc/$pid/environ)
68         done | sort)
69     if [ "$queue" ]; then
70         echo "Target is occupied by:"
71         ( echo "PID USER LOGIN_TIME FROM"; echo "$queue" ) | column -t
72     fi
73 }
74
75 locked() {
76     print_queue
77     tmp=$(mktemp)
78     no_fork=
79     flock -h 2>&1 | grep -q -e "--no-fork" && no_fork=--no-fork
80     rm -f "$tmp"
81     exec flock $no_fork "$RUN_DIR" "$@"
82 }
83
84 unlocked() {
85     exec "$@"
86 }
87
88 check_var() {
89     if eval [ "\"\$$1\"" ]; then
90         return 0
91     else
92         die "$1 variable not defined in $CFG"
93     fi
94 }
95
96 # run_subcommand should be called only after permission checks and/or locking
97 run_subcommand() {
98     case "$*" in
99         "console")
100             trap "rm -f $RUN_DIR/ppid" EXIT
101             echo $NOVABOOT_PPID > $RUN_DIR/ppid
102             echo 'novaboot-shell: Connected'
103             # TODO: $reset_begin_cmd
104             check_var console_cmd && eval exec "$console_cmd";;
105         "reset")
106             check_var reset_cmd && eval exec "$reset_cmd";;
107         "rsync --server "*" . .")
108             if ! [ $# -eq 5 -o \( $# -eq 6 -a "$4" = '--log-format=X' \) ]; then
109                 die "Unexpected rsync invocation: $*"
110             fi
111             mkdir -p "$HOME/tftproot"
112             cd "$HOME/tftproot"
113             exec "$@";;
114         "on")
115             check_var on_cmd && eval exec "$on_cmd";;
116         "off")
117             check_var off_cmd && eval exec "$off_cmd";;
118     esac
119 }
120
121 main() {
122     if [ "$1" = "-c" ]; then shift
123     else die "Permission denied"; fi
124
125     NB_ADMIN=
126     if [ "${1%% *}" = "user" ]; then
127         # Get user name encoded in ~/.ssh/authorized_keys
128         set -- $1
129         NB_USER="$2";
130         [ "$3" = "admin" ] && NB_ADMIN=1
131         set -- $SSH_ORIGINAL_COMMAND
132     fi
133
134     if [ $# -eq 0 ]; then print_help; fi
135
136     IP=${SSH_CONNECTION%% *}
137     HOST=$(getent hosts $IP) || HOST=$IP
138     REMOTE=${HOST##* }
139     DATE=$(LANG=C date +'%F_%T')
140     export NOVABOOT_ID="${NB_USER:-?} $DATE ${REMOTE}"
141     export NOVABOOT_PPID=$PPID
142
143     mkdir -p "$RUN_DIR"
144
145     case "$1" in
146         # Commands allowed at any time
147         "console") locked $0 console;;
148         "get-config") target_config; exit;;
149         "add-key") shift; add_key "$@"; exit;;
150         "shell") exec_shell; exit;;
151         "help") print_help;;
152
153         # Commands allowed only when nobody or the same user is connected
154         # to the console. "The same user" means that we were executed by
155         # the same sshd process that has the lock. This is ensured by
156         # using SSH connection sharing on cline side.
157         reset | rsync | on | off)
158             ALLOWED_PPID=$(cat $RUN_DIR/ppid 2>/dev/null || :)
159             if [ "$PPID" -eq "${ALLOWED_PPID:-0}" ]; then run=unlocked; else run=locked; fi
160             $run $0 "$@";;
161         *)
162             echo >&2 "novaboot-shell: Command not allowed: $*"
163             logger -p error "novaboot-shell: Command not allowed: $*"
164             exit 1;;
165     esac
166 }
167
168 RUN_DIR="$HOME"
169
170 if [ "$NOVABOOT_SHELL_CONFIG" ]; then
171     CFG="$NOVABOOT_SHELL_CONFIG"
172 else
173     CFG="$HOME/.novaboot-shell"
174 fi
175
176 . "$CFG"
177
178 if [ -z "$NOVABOOT_ID" ]; then
179     main "$@"
180 else
181     run_subcommand "$@"
182 fi