スクリプトの引数を正しく解析し、S​​SHを介して呼び出されるシェルのように動作します。

スクリプトの引数を正しく解析し、S​​SHを介して呼び出されるシェルのように動作します。

私は使用が非常に限られたサーバーを持っており、SSHを介して非常に具体的な(およびカスタマイズされた)2つのコマンドを実行できるようにしたいと思います。これを実現するために、制限されたユーザーのシェルをこの2つだけ許可するカスタムBASHスクリプトに設定しました。「注文する」

/etc/passwdユーザーの情報は次のとおりです。

limited:x:1000:1000:,,,:/home/limited:/usr/sbin/limited_shell.bash

limited_shell.bashスクリプトは次のとおりです(これまで持っているスクリプトは機能しません)。

#!/bin/bash

readonly RECORDER_SCRIPT="/usr/sbin/record.py"
echo "Verifying params: \$1: $1, \$2: $2"
shift

case $1 in
  [0-9]*)
    nc -z localhost $1 < /dev/null >/dev/null 2>&1
    result=$?
    if [[ $result -eq 0 ]]
    then
      echo "O"
    else
      echo "C"
    fi
    exit $result
    ;;
  record)
    $RECORDER_SCRIPT ${*:3}
    exit $?
    ;;
  *)
    exit 0
    ;;
  esac
exit 0

おそらくスクリプトから推測できるように、limited_shell.bash私が受け入れたい2つのコマンドは数字と「記録」文字列です。limited_shell.bash番号で呼び出すと、開いているローカルポートに対応するのか、閉じているローカルポートに対応するのかを返します。別の許可されたコマンドは/usr/sbin/record.pyPythonスクリプト()への呼び出しをトリガーし、入力からいくつかのビデオを記録します。 2番目のコマンドは追加の引数を使用して呼び出す必要があり、ここで問題が発生します。

別のコンピュータでリモートでコマンドを実行しようとするとrecord...

ssh [email protected] record -option1 foo -option2 bar

...実際に到着するのはlimited_shell.bash次のとおりです。 (-c 'record -option1 foo -option2 bar'技術的には2つの引数があり、そのうちの1つは-c完全な文字列であり、2番目はコマンド+パラメータ処刑したい)

-c最初の引数()を移動し、2番目の引数をスペースに分割する方法(引数と実際のコマンド)を考えましたが、これは汚れていて、引数の1つをスクリプトに渡そうとするとrecord多くの問題を引き起こす可能性があります。record.pyスペースを含む文字列。

コマンドを解析する正しい方法は何ですか?移動して分割するよりも良い方法があると確信しています。

ベストアンサー1

あなたのスクリプト実装するように設計シェル。これがコマンドラインソルバーです。

実行時:

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

ssh(クライアント)、パラメータを連結し(ASCII SPC文字を使用)、次のようにユーザーのログインシェルに送信しますsshdsshd

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コマンドラインの使用方法を決定するのはユーザー次第です。たとえば、Bourneに似たシェルは$foo変数の内容に展開されfoo、これはコマンド区切り文字として扱われて拡張;されます。/*/

今あなたが望むものは何でもすることができます。しかし、これが意味するのは限られたユーザーは、おそらく、可変拡張禁止、コマンド置換、グローバル変数、複数のコマンド許可禁止、リダイレクト禁止など、できるだけ少ない操作をしたいと思います。

覚えておくべきもう1つの点は、非対話型の状況(スクリプトを解釈するときなど)でも呼び出されたbashときに読み取られることです。したがって、回避、少なくとも呼び出し、またはユーザーがオプションを作成または使用しないようにすることができます。~/.bashrcsshbashsh~/.bashrc--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)(拡張しなくても)。

おすすめ記事