Правильно проанализируйте аргументы в сценарии, ведущем себя как оболочка, названная через SSH

Можно использовать type команда, чтобы сделать это.

type yourfunc распечатает функцию к STDOUT. Как man type говорит,

Утилита типа должна указать, как каждый аргумент был бы интерпретирован, если используется в качестве названия команды.

3
19.11.2013, 15:15
3 ответа

Ваш сценарий предназначен для реализации оболочки. Таким образом, интерпретатор командной строки.

Когда Вы работаете:

ssh host echo '$foo;' rm -rf '/*'

ssh (клиент), связывает аргументы (с символами ASCII SPC) и отправляет это в sshd. sshd называет оболочку входа в систему пользователя как:

exec("the-shell", "-c", "the command-line")

Это здесь:

exec("the-shell", "-c", "echo $foo; rm -rf /*")

И это было бы точно тем же, сделал, чтобы Вы работали:

ssh host echo '$foo;' 'rm -rf' '/*'
ssh host 'echo $foo;' "rm -rf /*"
ssh host 'echo $foo; rm -rf /*'

(более поздний, являющийся предпочтительным, поскольку это делает это более ясным, что делается).

Это составило the-shell решить, что сделать с той командной строкой. Например, подобная Границе оболочка расширилась бы $foo к содержанию foo переменная, это рассмотрело бы ; как разделитель команды, и расширился бы /* в отсортированный список нескрытых файлов в /.

Теперь, в Вашем случае с тех пор, можно сделать то, что Вы хотите. Но так как это предназначено, чтобы быть ограниченным пользователем, можно хотеть сделать как можно меньше, например, не развернуть переменную, замену команды, шарики, не позволить несколько команд, не сделать перенаправления...

Другая вещь принять во внимание в этом bash чтения ~/.bashrc при вызывании ssh даже когда неинтерактивная (как в при интерпретации сценариев). Таким образом, Вы, вероятно, хотите избежать bash (или, по крайней мере, назовите его как sh) или удостоверьтесь ~/.bashrc не writabe пользователем, или используйте --norc опция.

Теперь, с тех пор Вам решать определяют, как командная строка интерпретируется, можно или просто разделить одно пространство, новую строку или вкладку:

#!/bin/sh -
[ "$1" = "-c" ] || exit
set -f
set -- $2
case $1 in
    (record) 
        shift
        exec /usr/sbin/record.py "$@"
        ;;
    ("" | *[!0-9]*)
        echo >&2 "command not supported"
        exit 1
        ;;
    (*)
        nc ...
        ;;
esac

Но это означает record не сможет взять аргументы, которые содержат пробелы, вкладки или новые строки или которые пусты.

Если Вы хотите, чтобы они смогли сделать это, необходимо предоставить своего рода синтаксис заключения в кавычки.

zsh имеет инструмент парсинга кавычки, который может помочь Вам там:

#! /bin/zsh -f
[ "$1" = "-c" ] || exit
set -- "${(Q@)${(Z:cn:)2}}"
case $1 in
    (record) 
        shift
        exec /usr/sbin/record.py "$@"
        ;;
    ("" | *[!0-9]*)
        echo >&2 "command not supported"
        exit 1
        ;;
    (*)
        nc ...
        ;;
esac

Это поддерживает единственные, двойные кавычки и обратные косые черты. Но это также рассмотрело бы вещи как $(foo bar) как отдельный аргумент (даже если не расширение его).

2
27.01.2020, 21:17
#!/bin/bash
shopt -s extglob

# domain-specific language: provide a "record" command
record () {
    /usr/sbin/record.py "$@"
}

command=$2
set -- $command   # re-use the positional parameters
case $1 in
    record) 
        # let the shell parse the given command
        eval "$command"
        ;;
    +([0-9]))    
        nc ... # as above
        ;;
    *) exit 0 ;;
esac

Обратите внимание, что я использую расширенный шаблон шарика +([0-9]) распознать слово, которое является одной или несколькими цифрами. Шаблон [0-9]* распознает слово, начинающееся с цифры, таким образом, 1foo соответствовал бы - я предполагаю, что это не то, что Вы хотите.

Предостерегите использование eval очень опасно. Рассмотрите добавляющую дополнительную проверку команды к команде, которую пользователь дает Вам. Что происходит когда:

ssh limited@192.168.1.5 record -option1 foo -option2 \`rm -rf /\`
2
27.01.2020, 21:17

Я предложу более простой подход, который требует немного большего количества установки, но сохраняет запись сложного, подверженного ошибкам сценария.

Можно объявить, что открытому ключу SSH только позволяют выполнить определенную команду. Генерируйте пару ключей, скопируйте открытый ключ в сервер и добавьте a command=… директива к нему. Сделайте это для каждого небольшого количества команд, которые Вы хотите позволить. Это означает Вас строки как это в ~/.ssh/authorized_keys файл на сервере:

command="/path/to/command1" ssh-rsa AAAA…== key1
command="/path/to/command2" no-pty ssh-rsa AAAA…== key2

Когда Вы выполняете удаленную команду, выбираете соответствующий закрытый ключ:

ssh -i ~/.ssh/key1.id_rsa server.example.com 'this is ignored'

Можно написать любой код оболочки в command директива. Команда, предоставленная клиентом, доступна в переменной SSH_ORIGINAL_COMMAND.

1
27.01.2020, 21:17

Теги

Похожие вопросы