SCPの仕組み

SCPの仕組み

WinSCP ツールは、sudoリモート マシン上でを実行してscp、sudo ユーザーとして を実行できます。このことから、 のコマンド ライン バージョンでscpもこれが可能であるはずだと私は考えます。

秘密裏に、WinSCP はこれをどのように実行しているのでしょうか?

私はやりたくないユーザーステージングディレクトリを使用したソリューションファイルが大きすぎるため、ユーザーを使用して直接投稿する必要がある可能性がありますsudo。その結果、ファイルはコピーされましたが、sudo ディレクトリではなく、ローカル ディレクトリにコピーされました。

一つの解決策としては、手動でSSH経由でパイプする:

tar zcvf -  MyBackups | ssh user@server "cat > /path/to/backup/foo.tgz"

次のように sudo を実行するようにカスタマイズできると思います。

cat local.txt | ssh user@server "sudo -u sudouser cat > ~/remote_file"

唯一の問題は、この方法を実行すると、ベースを使用してすでに実装されている多くの問題を解決しなければscpならないことです。このため、およびその他の理由から、このソリューションも使用したくありません。

ユーザーを変更してその権限にアクセスできるようにし、scpリモートへの直接コピーを処理できるようにするにはどうすればよいでしょうか。sudo

答え1

Scp は、リモート サーバーに ssh 接続し、その接続を使用してscpリモート システムで別のコマンドを実行することによって機能します。ローカルの scp インスタンスとリモート インスタンスは、ssh リンクを介して通信し、ファイルを送受信します。

特に OpenSSH scp は、リモート システムで実行される scp コマンド文字列を構築します。次に、そのコマンドを実行するために ssh を起動します。最終的に呼び出される ssh コマンドは、次のものと同等です。

/path/to/ssh [ssh options...] "scp [scp options...]"
  • /path/to/ssh は通常、ssh プログラムへの組み込みパスです。
  • [ssh オプション...] は、ssh プログラムに対する 1 つ以上のオプションです。
  • 「scp [scp オプション...]」は、リモート システムで実行する scp コマンドとその引数を含む単一の引数です。

OpenSSH scp では、リモート scp コマンドの形式を変更するオプションはあまり提供されていません。「scp」以外のものを呼び出す方法や、「scp」の部分の前に「sudo」のようなものを挿入する方法はありません。

ご存知のとおり、scp には ssh 以外のプログラムを呼び出すオプションがあります。方法を知っている人なら、ssh ラッパー プログラムを作成して、scp に ssh を直接呼び出す代わりにラッパーを呼び出させることができます。ラッパーは、コマンドライン引数を調べて scp コマンドを含む引数を見つけ、必要に応じてコマンドを変更し、変更したコマンドライン引数で ssh を呼び出す必要があります。

答え2

SCPの仕組み

の内部動作は、とというscp2 つの文書化されていない形式に依存します。これらは基本的に、stdin をリッスンし、stdout を介してデータを生成するリモート サーバーです。これらのプロセスは、sftp が行うのと似たプロトコルを使用します。詳細については、scpscp -fscp -tOracle ブログ

が起動すると、最初にまたは をscp開始するための ssh セッションが開始されます。次に、ローカル プロセスは stdout および stdin を介してリモート プロセスと通信し、ssh にパイプされ (完全に暗号化されます)、リモート セッションの stdin/stdout として機能します。scp -tscp -fscpscpscp

カスタマイズ方法

このコマンドには、リモート セッションのセットアップに使用するプログラムをカスタマイズできるscpオプションがあります 。 の一般的なオプションをすべて処理することが期待されます。それがどのように見えるかをデバッグするために、パラメータをダンプするだけのダミー プログラムを設定します。-sscpssh

/tmp/scp-dump.sh:

echo $0 $*

以下のように実行します。

scp -S /tmp/scp-dump.sh /tmp/dump.txt [email protected]:/tmp

そして、適切に次の出力が得られます。

/home/me/dump.sh \
    -x -oForwardAgent=no \
    -oPermitLocalCommand=no \
    -oClearAllForwardings=yes \
    -l me -- server.com scp -t /tmp

読みやすくするために、バックスラッシュによる改行が追加されました。

これにより、コマンドに送信する前にパラメータとコマンドを変更する機会が得られますssh

sudoの設定

これで、必要に応じてパラメータを変更し、ssh を起動し、変更されたフォームを使用して を起動するプログラムを作成できますscp -t。基本的には、パラメータをキャプチャし、内部で使用したいパラメータのみをトラップして、追加のパラメータを追加し、変更を加えます。

/tmp/scp-sudo.sh:

add_ssh_option() {
  local option
  if [ $# = 2 ]; then
    option="$1 \"$2\""
  else
    option="$1"
  fi
  if [ -z "${ssh_options}" ]; then
    ssh_options=${option}
  else
    ssh_options="${ssh_options} ${option}"
  fi
}

parse_options() {
  ssh_options=
  local option
  while [ $# > 0 ] ; do
    case $1 in
      -oSudoUser=* )
        SSH_SUDO_USER=${option##*=}
        shift
        ;;
      -l ) ssh_user=$2 ; shift 2 ;;
      -i ) add_ssh_option "$1" "$2" ; shift 2 ;;
      -- ) shift ; break ;;
      -* ) add_ssh_option "${1}" ; shift ;;
      *  ) break ;;
    esac
  done
  ssh_host=$1
  shift
  ssh_command="$*"
}

parse_options "$@"
# To avoid intererence with Standard-In, we change this to
# Strict:
add_ssh_option "-oStrictHostKeyChecking=yes"

if [ -z "${SSH_SUDO_USER}" ]; then
  # As before without sudo
  cat | ssh $ssh_options -l $ssh_user $ssh_host $ssh_command
  exit $?
else
  # Send standard-in to the customized "scp -t" sink.
  cat | ssh $ssh_options -l $ssh_user $ssh_host sudo -i -u ${SSH_SUDO_USER} $ssh_command
  exit $?
fi

これで、修正された scp フォームを使用できるようになりました。

scp -oSudoUser=other \
    -i /tmp/me-id_rsa \
    /tmp/scp-sudo.sh \
    /tmp/dump.txt \
    [email protected]:/tmp

これはリモートにファイルを送信するにはうまく機能します。しかし、リモート ファイルを取得すると、何らかの理由でハングします。セッションを中断すると (control-c)、転送が成功したことがわかりますが、どういうわけか「0」という名前の余分なファイルがあります。誰か助けてくれる人はいませんか?

より良い選択肢: sftp

しかし、sftp の方がはるかに優れています。

  1. これには、ssh コマンドライン全体を設定するオプションがあります-S。これを理解して動作させるのに苦労しました。shell-ssh ラッパー内から stdin/stdout を正しくバインドする方法がわからないのではないかと思います。
  2. これには (小文字の) オプションがあり-s、リモート サーバーの設定のみを担当するサブコマンドのみを設定できます。これを使用すると、動作が簡単になりました。
  3. sftp のマニュアル ページに従って、リモート パス、リモート ファイルの権限を設定し、put/get の両方を実行できます。

この場合は単純に

sftp -s "sudo -u sudo-user -- /usr/libexec/openssh/sftp-server" [email protected]

それで私は嬉しい「sftp>」プロンプトを受け取りました

サブプログラムは異なるパスに配置される場合があることに注意してください (例 ) 。ファイル内の " " 文字列/usr/libexec/openssh/sftp-serverから解析することをお勧めします。Subsystem sftp/etc/ssh/sshd_conf

関連情報