Search code examples
bashsshroot

Downloading a File from SSH with Sudo


I am trying to retrieve a file file.txt from a remote server accessible from ssh, and copy its content to a file on local. But I want this process to be done in a .sh file.

The problem arises from the fact that file.txt is only accessible from the root, meaning that in order to manually see the contents of the file I have to run:sudo cat file.txt, and insert my password through terminal. So commands such as scp will not do the job as they throw a Permission Denied error.

To bypass this, I have done the following.

ssh -t user@remote 'sudo cat file.txt'

However, in the bash file I intend to save the result in a variable as follows:

CONTENT=$(ssh -t user@remote 'sudo cat file.txt')

Which stores the content of the file in the variable CONTENT after asking for my password.

This works, if the user types in their password and press enter the variable gets populated with the contents of file.txt; but the password interface is no longer printed in the terminal. This means that whoever runs this bash file does not see the line:

[sudo] password for user:

or the line below when the password entered is incorrect.

Sorry, try again.
[sudo] password for user:

To make matters worse, sometimes the first few characters of the password actually get typed into the terminal!

Is there a way to work around this? Is there a way for the user to actually see the password interface?

Interestingly, the lines [sudo] password for user: and Sorry, try again. can be seen in the variable CONTENT, so not only the password interface disappears, but it also pollutes the variable CONTENT. This is not an issue however as we can simply parse CONTENT.


Solution

  • I put some research and effort in it and actually made it as to meet my expectation (hopefully yours as well).

    I treated your file.txt as a one line file since variable CONTENT stores only one line of output.

    $ cat file.txt
    lorem ipsum dolor sit amet
    

    one-liner:

    $ CONTENT=$(expect -c 'spawn ssh -t user@localhost "sudo cat /tmp/file.txt"; expect "password"; send "userpassword\r"; expect "password"; send "userpassword\r"; interact' | sed -n '4p')
    

    here is what I get

    $ echo $CONTENT
    lorem ipsum dolor sit amet
    

    note that userpassword is to be replaced with the password you type in.

    Non one-liner

        $ CONTENT=$(expect -c 
           'spawn ssh -t user@localhost "sudo cat /tmp/deneme.txt";
            expect "password"; send "userpassword\r";       #for first prompt of remote connection.
            expect "password"; send "userpassword\r";       #for second prompt of sudo.
            interact' | sed -n '4p')                        #4th line displayed in the terminal is the file content.
    

    you can also see the actual output in the terminal without CONTENT and sed parts;

    $ expect -c 'spawn ssh -t user@localhost "sudo cat /tmp/file.txt"; expect "password"; send "userpassword\r"; expect "password"; send "userpassword\r"; interact'
    spawn ssh -t user@localhost sudo cat /tmp/file.txt
    user@localhost's password: 
    [sudo] password for user: 
    lorem ipsum dolor sit amet
    Connection to localhost closed.
    

    I referred to this post https://unix.stackexchange.com/a/252782/434132 for the usage of expect -c 'spawn command; expect; send; interact'.

    Also note that I worked between users on my local host not on a remote host so I don't know if it results in a different way.

    Does this answer your question?