Como o SCP funciona
O funcionamento interno de scp
depende de duas formas não documentadas de scp
, que é scp -f
e scp -t
. Eles são basicamente servidores remotos ouvindo stdin e gerando dados sobre stdout. Esses processos usam um protocolo semelhante ao que o sftp faria. Mais informações podem ser encontradas em um Blog da Oracle .
Quando scp
for iniciado, primeiro ele iniciará uma sessão ssh para iniciar scp -t
ou scp -f
. Seu processo scp
local se comunicará com o processo scp
remoto por meio de stdout e stdin canalizado para ssh (totalmente criptografado) e servirá como stdin / stdout para sua sessão scp
remota.
Como personalizar
O comando scp
fornece uma opção -s
que permite personalizar o programa usado para configurar a sessão scp
remota. Espera-se lidar com todas as opções típicas de ssh
. Para ajudar a depurar como isso pode parecer, configuramos um programa fictício que apenas elimina os parâmetros:
/tmp/scp-dump.sh:
echo $0 $*
Vamos executá-lo da seguinte forma:
scp -S /tmp/scp-dump.sh /tmp/dump.txt [email protected]:/tmp
E, apropriadamente, obtemos a seguinte saída:
/home/me/dump.sh \
-x -oForwardAgent=no \
-oPermitLocalCommand=no \
-oClearAllForwardings=yes \
-l me -- server.com scp -t /tmp
Quebras de linha com contrabarra foram adicionadas para facilitar a leitura.
Isso nos permite uma oportunidade de modificar os parâmetros e comandos antes de enviá-lo para o comando ssh
.
Configurando o sudo
agora podemos escrever um programa para modificar os parâmetros conforme necessário, iniciar o ssh e usar um formulário modificado para iniciar o scp -t
. Basicamente capturaremos os parâmetros, prendemos aqueles que queremos usar internamente, apenas adicionamos outros e fazemos alterações.
/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
Agora podemos usar o formulário scp modificado:
scp -oSudoUser=other \
-i /tmp/me-id_rsa \
/tmp/scp-sudo.sh \
/tmp/dump.txt \
[email protected]:/tmp
Isso funciona bem para enviar um arquivo para remoto. No entanto, quando eu recuperar um arquivo remoto, de alguma forma, trava. Quando eu quebro a sessão (control-c), vejo que a transferência foi bem sucedida, mas de alguma forma eu tenho um arquivo extra chamado "0". Imagino se alguém pode me ajudar com isso?
Melhor Opção: sftp
No entanto, o sftp é muito melhor.
- tem a opção
-S
- permitindo definir toda a linha de comando ssh. Eu tive dificuldade em descobrir e fazer funcionar. Eu suspeito que eu não entendo como vincular corretamente stdin / stdout de dentro de um wrapper shell-ssh. - tem uma opção
-s
(minúscula) - permitindo definir apenas o subcomando responsável por configurar apenas o servidor remoto. Eu achei mais fácil fazer isso funcionar. - Você pode definir o caminho remoto, permissões de arquivos remotos, fazer as duas coisas, etc. de acordo com as páginas de manual do sftp.
Neste caso, simplesmente
sftp -s "sudo -u sudo-user -- /usr/libexec/openssh/sftp-server" [email protected]
Isso me deu o alerta " sftp>
" feliz
Observe que o subprograma às vezes está localizado em caminhos diferentes, por exemplo, /usr/libexec/openssh/sftp-server
. Eu sugeriria a análise da string " Subsystem sftp
" de dentro do arquivo /etc/ssh/sshd_conf
?