Ваш сценарий предназначен для реализации оболочки. Таким образом, интерпретатор командной строки.
Когда Вы работаете:
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)
как отдельный аргумент (даже если не расширение его).
#!/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 /\`
Я предложу более простой подход, который требует немного большего количества установки, но сохраняет запись сложного, подверженного ошибкам сценария.
Можно объявить, что открытому ключу 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
.