]> rtime.felk.cvut.cz Git - novaboot.git/blobdiff - server/novaboot-shell
nix: Update flake inputs
[novaboot.git] / server / novaboot-shell
index c2b91a5d3d26e7502f1a02c224004110bd0674a8..5e8621adf3b37689b4cdd375c188fa304f7e9134 100755 (executable)
@@ -10,11 +10,12 @@ die() {
 print_help() {
     cat <<EOF
 Target commands:
-- console
+- console (default command)
 - reset
 - on
 - off
 - rsync ...
+- get-config
 
 Management commands:
 - help
@@ -23,6 +24,7 @@ EOF
     if [ "$NB_ADMIN" ]; then
        cat <<EOF
 - add-key
+- shell (use with ssh -t)
 EOF
     fi
     exit 0
@@ -30,9 +32,31 @@ EOF
 
 add_key() {
     local user
+    [ "$NB_ADMIN" ] || return 1
 
+    case $# in
+       0) die "Usage: ssh ... add-key USERNAME < id_rsa.pub";;
+       1) break;;
+       *) die "User name must not contain spaces: $*";;
+    esac
     user="$1"
-    die "Not implemented"
+    key=$(cat)
+
+    tmp=$(mktemp ~/.ssh/authorized_keys.XXXXXXXX)
+    {
+       cat ~/.ssh/authorized_keys
+       echo "command=\"user $user\" $key"
+    } | sort -u > $tmp
+
+    mv $tmp ~/.ssh/authorized_keys
+}
+
+exec_shell() {
+    [ "$NB_ADMIN" ] || die "Permission denied"
+    if ! tty > /dev/null; then
+       echo "novaboot-shell: Consider starting the shell with 'ssh -t'"
+    fi
+    exec /usr/bin/env bash || exec /bin/sh
 }
 
 lock_queue() {
@@ -61,54 +85,100 @@ unlocked() {
     exec "$@"
 }
 
-check_var() {
-    if eval [ "\"\$$1\"" ]; then
-       return 0
+read_config() {
+    . "${NOVABOOT_SHELL_CONFIG:-$HOME/.novaboot-shell}"
+}
+
+power() {
+    local cmd
+    case "$1" in
+       "on")  cmd="${on_cmd:?}";;
+       "off") cmd="${off_cmd:?}";;
+       *) die "Unexpected power parameter";;
+    esac
+
+    if [ "$PPID" -ne 1 ] && systemctl --user is-enabled --quiet novaboot-delayed-power-off.service; then
+        case "$1" in
+            "on") systemctl --user start novaboot-delayed-power-off.service;;
+            "off") sudo novaboot-power off;;
+        esac
     else
-       die "$1 variable not defined in $CFG"
+       eval "$cmd"
     fi
 }
 
+run_console() {
+    trap "rm -f $RUN_DIR/ppid" EXIT
+    echo $NOVABOOT_PPID > $RUN_DIR/ppid
+    echo 'novaboot-shell: Connected'
+    # TODO: $reset_begin_cmd
+    [ -n "${on_cmd}" ] && power on
+    eval "$1"
+}
+
+# Run novaboot with the same configuration as specified in
+# ~/.novaboot-shell, but allow the caller to extend of override them
+# via parameters of this function.
+run_novaboot() {
+    nbscript=$1
+    shift
+    OLD_IFS=$IFS
+    # Split $target_config below by newlines, not by words
+    IFS="
+"
+    novaboot "$nbscript" $target_config --server="$HOME/tftproot" --reset-cmd="${reset_cmd:?}" --remote-cmd="${console_cmd:?}" "$@"
+    IFS=$OLD_IFS
+}
+
 # run_subcommand should be called only after permission checks and/or locking
 run_subcommand() {
+    read_config
     case "$*" in
+       "default")
+           run_console "${default_cmd:-${console_cmd:?}}";;
        "console")
-           trap "rm -f $RUN_DIR/ppid" EXIT
-           echo $NOVABOOT_PPID > $RUN_DIR/ppid
-           echo 'novaboot-shell: Connected'
-           # TODO: $target_reset_begin
-           check_var target_console && eval exec $target_console;;
+           run_console "${console_cmd:?}";;
        "reset")
-           check_var target_reset && eval exec $target_reset;;
+           eval "${reset_cmd:?}";;
        "rsync --server "*" . .")
-           if [ $# -ne 5 ]; then die "Unexpected rsync invocation: $*"; fi
+           if ! [ $# -eq 5 -o \( $# -eq 6 -a "$4" = '--log-format=X' \) ]; then
+               die "Unexpected rsync invocation: $*"
+           fi
            mkdir -p "$HOME/tftproot"
            cd "$HOME/tftproot"
-           exec rsync --server $3 . . ;;
+           exec "$@";;
        "on")
-           check_var target_on && eval exec $target_on;;
+           power on
+           exit;;
        "off")
-           check_var target_off && eval exec $target_off;;
+           power off
+           exit;;
+       *)
+           die "Unknown command: $*";;
     esac
 }
 
 main() {
-    if [ "$1" = "-c" ]; then shift
-    else die "Permission denied"; fi
+    if [ "$1" = "-c" ]; then
+       set -- $2
+    elif [ $# -gt 0 ]; then
+       die "Permission denied"
+    fi
 
     NB_ADMIN=
-    if [ "${1%% *}" = "user" ]; then
+    if [ "$1" = "user" ]; then
        # Get user name encoded in ~/.ssh/authorized_keys
-       set -- $1
-       NB_USER="$2";
+       export NB_USER="$2";
        [ "$3" = "admin" ] && NB_ADMIN=1
        set -- $SSH_ORIGINAL_COMMAND
     fi
 
-    if [ $# -eq 0 ]; then print_help; fi
-
     IP=${SSH_CONNECTION%% *}
-    HOST=$(getent hosts $IP) || HOST=$IP
+    if [ "$IP" ]; then
+       HOST=$(getent hosts $IP) || HOST=$IP
+    else
+       HOST=localhost
+    fi
     REMOTE=${HOST##* }
     DATE=$(LANG=C date +'%F_%T')
     export NOVABOOT_ID="${NB_USER:-?} $DATE ${REMOTE}"
@@ -118,15 +188,18 @@ main() {
 
     case "$1" in
        # Commands allowed at any time
+       "") locked $0 default;;
        "console") locked $0 console;;
-       "add-key") shift; add_key "$@"; exit $?;;
+       "get-config") read_config && echo -n "${target_config}"; exit;;
+       "add-key") shift; add_key "$@"; exit;;
+       "shell") exec_shell; exit;;
        "help") print_help;;
 
        # Commands allowed only when nobody or the same user is connected
        # to the console. "The same user" means that we were executed by
        # the same sshd process that has the lock. This is ensured by
-       # using SSH connection sharing on cline side.
-       console | reset | rsync | on | off)
+       # using SSH connection sharing on client side.
+       reset | rsync | on | off)
            ALLOWED_PPID=$(cat $RUN_DIR/ppid 2>/dev/null || :)
            if [ "$PPID" -eq "${ALLOWED_PPID:-0}" ]; then run=unlocked; else run=locked; fi
            $run $0 "$@";;
@@ -137,18 +210,15 @@ main() {
     esac
 }
 
-RUN_DIR="$XDG_RUNTIME_DIR/novaboot"
+if [ -d "$HOME" ]; then
+    RUN_DIR="$HOME"
+else
+    RUN_DIR="/tmp/novaboot-shell@$USER"
+    mkdir -p "$RUN_DIR"
+fi
 
-if [ -z "$NOVABOOT_ID" ]; then
+if [ -z "$NOVABOOT_ID" ] && [ "$PPID" -ne 1 ]; then
     main "$@"
 else
-    if [ "$NOVABOOT_SHELL_CONFIG" ]; then
-       CFG="$NOVABOOT_SHELL_CONFIG"
-    else
-       CFG="$HOME/.novaboot-shell"
-    fi
-
-    . "$CFG"
-
     run_subcommand "$@"
 fi