SCP如何運作

SCP如何運作

WinSCP 工具能夠sudo在遠端電腦上以scpsudo 使用者身分執行該操作。這讓我認為這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使用 a 來處理直接複製到遠端的操作sudo來更改用戶,以便我獲得對其權限的存取權限。

答案1

scpScp 的工作原理是與遠端伺服器建立 ssh 連接,然後使用該連接在遠端系統上執行另一個命令。本機 scp 實例和遠端實例透過 ssh 連結進行通訊以傳送或接收檔案。

OpenSSH scp 特別建構了一個要在遠端系統上執行的 scp 指令字串。然後它啟動 ssh 來運行該命令。最終調用的 ssh 命令與此等效:

/path/to/ssh [ssh options...] "scp [scp options...]"
  • /path/to/ssh 通常是 ssh 程式內建的路徑。
  • [ssh options...] 是 ssh 程式的一個或多個選項。
  • 「scp [scp options...]」是包含 scp 指令及其在遠端系統上執行的參數的單一參數。

OpenSSH scp 沒有提供太多用於更改遠端 scp 指令形式的選項。沒有辦法讓它呼叫“scp”以外的東西,或在“scp”部分前面插入“sudo”之類的東西。

正如您所注意到的,scp 確實可以選擇呼叫其他程式而不是 ssh。知道如何編寫 ssh 包裝程式並讓 scp 呼叫包裝器而不是直接呼叫 ssh 的人。包裝器必須檢查其命令列參數以找到包含 scp 命令的參數,根據需要更改命令,然後使用更改後的命令列參數來呼叫 ssh。

答案2

SCP如何運作

的內部運作scp取決於兩種未記錄的形式scp,即scp -fscp -t。它們基本上是監聽標準輸入並透過標準輸出產生資料的遠端伺服器。這些進程使用類似 sftp 的協定。更多資訊可以在以下位置找到:甲骨文博客

啟動時scp,會先啟動一個ssh會話來啟動scp -tscp -f。然後,您的本機scp進程將透過管道傳輸到 ssh(完全​​加密)的 stdout 和 stdin 與遠端scp進程進行通信,並將充當遠端scp會話的 stdin/stdout。

如何客製化

scp命令提供了一個選項 -s,可讓您自訂用於設定遠端會話的程式scp。它預計能夠處理 的所有典型選項ssh。為了幫助調試它的樣子,我們設定了一個僅轉儲參數的虛擬程式:

/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. 它有一個-S選項 - 允許設定整個 ssh 命令行。我很難弄清楚並使其發揮作用。我懷疑我不明白如何從 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

相關內容