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
使用 a 來處理直接複製到遠端的操作sudo
來更改用戶,以便我獲得對其權限的存取權限。
答案1
scp
Scp 的工作原理是與遠端伺服器建立 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 -f
和scp -t
。它們基本上是監聽標準輸入並透過標準輸出產生資料的遠端伺服器。這些進程使用類似 sftp 的協定。更多資訊可以在以下位置找到:甲骨文博客。
啟動時scp
,會先啟動一個ssh會話來啟動scp -t
或scp -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 更好。
- 它有一個
-S
選項 - 允許設定整個 ssh 命令行。我很難弄清楚並使其發揮作用。我懷疑我不明白如何從 shell-ssh 包裝器中正確綁定 stdin/stdout 。 - 它有一個
-s
(小寫)選項 - 允許僅設定負責設定遠端伺服器的子命令。我發現這更容易使其發揮作用。 - 您可以按照 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
?