Seu script destina-se a implementar um shell . Isto é, um interpretador de linha de comando.
Quando você executa:
ssh host echo '$foo;' rm -rf '/*'
ssh
(o cliente) concatena os argumentos (com caracteres ASCII SPC) e os envia para sshd
. sshd
chama o shell de login do usuário como:
exec("the-shell", "-c", "the command-line")
Está aqui:
exec("the-shell", "-c", "echo $foo; rm -rf /*")
E isso seria exatamente o mesmo se você tivesse executado:
ssh host echo '$foo;' 'rm -rf' '/*'
ssh host 'echo $foo;' "rm -rf /*"
ssh host 'echo $foo; rm -rf /*'
(o mais recente é o preferido, pois deixa mais claro o que está sendo feito).
Depende de the-shell
decidir o que fazer com essa linha de comando. Por exemplo, um shell parecido com o Bourne expandiria $foo
para o conteúdo da variável foo
, consideraria ;
como um separador de comando e expandiria /*
para uma lista classificada de arquivos não ocultos em /
.
Agora, no seu caso desde então, você pode fazer o que quiser. Mas como isso é um usuário restrito , você pode querer fazer o mínimo possível, por exemplo, não expandir variável, substituição de comando, globs, não permitir vários comandos, não redirecionar ...
Outra coisa a ter em conta é que bash
lê ~/.bashrc
quando chamado sobre ssh
mesmo quando não é interativo (como na interpretação de scripts). Então, você provavelmente deve evitar bash
(ou pelo menos chamá-lo como sh
) ou certificar-se de que ~/.bashrc
não seja escrito pelo usuário ou use a opção --norc
.
Agora, desde que você define como a linha de comando é interpretada, basta dividir um espaço, nova linha ou guia:
#!/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
Mas isso significa que record
não poderá receber argumentos que contenham espaços, tabulações ou novas linhas ou que estejam vazios.
Se você quiser que eles consigam fazer isso, você precisa fornecer algum tipo de sintaxe de cotação.
zsh
tem uma ferramenta de análise de cotações que pode ajudá-lo:
#! /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
Isso suporta aspas duplas e as barras invertidas. Mas também consideraria coisas como $(foo bar)
como um único argumento (mesmo que não o expandisse).