Reputation: 2298
When I need to copy a file from local server (server A) to remote server(server B) via SSH, using a user with enough privileges, I do this successfuly like below
localpath='/this/is/local/path/file1.txt'
remotepath='/this/is/remote/path/'
mypass='MyPassword123'
sshpass -p $mypass scp username@hostname:$localpath $remotepath
Now, I have to transfer a file from server A to server C with a user that doesn't have enough privileges to copy. Then once
I connected to Server C, I need to send su
in order to be able to send commands like cd
, ls
, etc.
Manually, I access the server C via SSH like this:
[root@ServerA ~]# ssh username@hostname
You are trying to access a restricted zone. Only Authorized Users allowed.
Password:
Last login: Sat Jun 13 10:17:40 2020 from XXX.XXX.XXX.XXX
ServerC ~ $
ServerC ~ $ su
Password:
ServerC /home/myuser #
ServerC /home/myuser # cd /documents/backups/
ServerC /documents/backups #
At this moment myuser
has superuser privileges and I can send commands.
Then, how can I automate the task to copy files from server A to server C with the need to send su
once I'm connected to Server C?
I've tried so far doing like this:
sshpass -p $mypass ssh -t username@hostname "su -c \"cd /documents/backups/ && ls\""
it requests password for su
and I'm able to send cd
and ls
but with this command, I'm not copying files from Server A to Server C, only semi-automating the access to Server C and sending the su
in Server C.
Thanks in advance for any help.
UPDATE
# $TAR | ssh $username@$hostname "$COMMAND"
+ tar -cv -C /this/is/local/path/file1.txt .
+ ssh [email protected] 'set -x; rm -f /tmp/copy && mknod /tmp/copy p; su - <<< "su_password
set -x; tar -xv -C /this/is/remote/path/ . < /tmp/copy" & cat > /tmp/copy'
tar: /this/is/local/path/file1.txt: Cannot chdir: Not a directory
tar: Error is not recoverable: exiting now
You are trying to access a restricted zone. Only Authorized Users allowed.
Password:
+ rm -f /tmp/copy
+ mknod /tmp/copy p
+ su -
+ cat
Password:
Upvotes: 0
Views: 871
Reputation: 6048
Editorial note: the previous version of this answer used sudo
, the current version uses su
as requested in the question.
You could use tar
and pipes, like so:
TAR="tar -cv -C $localpath ."
UNTAR="tar -xv -C $remotepath ."
PREPARE_PIPE="rm -f /tmp/copy && mknod /tmp/copy p"
NEWLINE=$'\n' # that's the easiest way to get a literal newline
ROOT_PASSWORD=rootpasswordverydangerous
COMMAND="set -x; $PREPARE_PIPE; su - <<< \"${ROOT_PASSWORD}${NEWLINE} set -x; $UNTAR < /tmp/copy\" & cat > /tmp/copy"
$TAR | ssh username@hostname "$COMMAND"
Explanation:
tar -c .
archives the current directory into a single file. We aren't passing -f
to tar
, so that single file is standard output.
tar -x .
extracts the content of a single tar archive file to the current directory. We aren't passing -f
to tar
, so that single file is standard input.
-C <path>
tells tar
to cd
into <path>
so that it will be the current directory in which files are copied from/to.
-v
just tells tar to list the files tar archives/extracts, for debugging purposes.
Likewise, set -x
is just to have bash
to emit trace information, for debugging purposes.
So we're archiving $localpath
into stdout, and piping it to ssh
, which will pipe it to $COMMAND
.
If there was a way to give su
the password in the command line, we would have used something like:
$TAR | ssh ... su --password ${ROOT_PASSWORD} -c "$UNTAR"
and things would have been simple.
But su
doesn't have that. su
runs like a shell, reading from stdin. So it will first read the password, and once the password is read and su
has established a root session, it reads commands from stdin. That's why we have su - <<< \"${ROOT_PASSWORD}${NEWLINE}${UNTAR}
.
But now stdin is used by the password and command, so we can't use it as the archive. We could use another file descriptor, but I prefer not to, because then the solution can be more easily ported to work with sudo
instead of su
. sudo
closes all file descriptors, and sudo -C 200
(only close file descriptors above 200) may not work (didn't work on my test machine).
if we went that direction, we would have used something like
$TAR | ssh ... 'exec 9<&2 && sudo -S <<< $mypass bash -c "$UNTAR <&9"'
Our next option is to do something like cat > /tmp/archive.tar
in order to write the entire archive into a file, and then have something like $UNTAR < /tmp/archive.tar
. But the archive may be huge and we may run out of disk space.
So the idea is to create a dedicated pipe - that's PREPARE_PIPE
. Pipes don't save anything to disk, and don't store the entire stream in memory, so the reader and the writer have to work concurrently (you know, like with a real pipe).
So having redirected su
's stdin from $ROOT_PASSWORD
, we pull ssh
's stdin into our pipe with cat > /tmp/copy
, and in parallel (&
) having $UNTAR
read from the pipe (< /tmp/copy
).
Notes:
-z
to both tar
commands to pass it compressed, if your network is too slow.tar
will preserve the source's metadata, e.g. timestamps and ownership.$ROOT_PASSWORD
to commands is not good practice, anyone who runs ps -ef
can see the password. There are ways to pass the password to server C in a more secure way, I didn't include it in order to not further complicate this answer.sudo
, so that if the password is compromised via ps -ef
, at least it's not the root password.Upvotes: 1