Quantcast
Channel: User Kamil Maciorowski - Super User
Viewing all articles
Browse latest Browse all 837

Answer by Kamil Maciorowski for How to SSH with sudo to a different user and launch shell in Bash?

$
0
0

Preliminary note

It seems your ssh host does not ask for password or passphrase. My answer assumes it really does not.


Analysis

I try a file for password, the command exits immediately.

$ ssh -t -q host "sudo -S -i -u user" <password.txt 2>&1

This happens because all the input the remote side gets comes from the stdin of your local ssh and you have redirected this; so all the input comes from password.txt. Additionally -t does not work with stdin of ssh not being a tty (you're not seeing the warning from ssh because of -q), so the remote shell spawned by sudo -i does not see a tty, it behaves like a shell being piped to: it does not print prompts, it exits when it detects "end of file" (EOF) on its stdin. If you placed shell code after the actual password in password.txt then the remote shell would run it and exited anyway.

You could use -tt to force tty allocation on the remote side (no need for -S in sudo then) and then you would even see a prompt from the remote shell and the shell would not exit by itself (detecting "EOF" on a tty is different); you wouldn't be able to type commands to it though, because ssh would not relay input from its (local) tty, it would only read from password.txt.

I modify the command using something like below, i.e., send the file first, then switch to stdin.

(cat password.txt ; cat) | ...

Although it works, it does not show the prompt

Again, -t does not work with stdin not being a tty, so … | ssh -t … is futile here.

Usefulness of using -tt in this case is discussed just below.


Poor man's solution

An improved version of your last try is like this:

cat password.txt - | ssh -tt -q host "sudo -i -u user"

Now there is a tty on the remote side, but there are also problems:

  • The password gets to the remote tty before sudo tells it not to echo input, so the remote tty echoes the password and ssh prints it locally.
  • Command line editing is provided by the local line discipline. It respects the size of the prompt coming from the remote side, it can erase a word (usually with Ctrl+w) or the whole line (usually Ctrl+u), but there's not much more it can do. The command line editor of the remote shell will get input only after you press Ctrl+d or Enter (or Ctrl+j or Ctrl+m). E.g. if the remote shell supports retrieving commands from history with then you will need Ctrl+d to actually see it "kinda working" and it will look ugly.
  • The local tty echoes input before it gets to cat (upon Enter or so), then the remote shell (or tty) echoes it again.
  • Characters generated by Ctrl+d, Ctrl+c or Ctrl+z don't get to the remote side, they get intercepted by the local tty and "act" locally (see this answer).
  • The remote tty does not know the size of your local tty.
  • Possibly more.

We can solve or mitigate some of these problems:

stty raw -echo; (sleep 2; cat -u password.txt -) | ssh -tt -q host "sudo -i -u user"; stty sane

Still this solution is not perfect.


About sshpass

In a comment you were given a suggestion to look at sshpass. In my tests (in Ubuntu) sshpass did not solve your problem.

Yes, sshpass can feed a password to ssh or (with the right -P) to another tool (e.g. sudo). It does this by providing a separate tty for the tool. Sane tools asking for password print a prompt to their /dev/tty and read a response from therein. sshpass is in control of the tty it gave the tool, it listens for a prompt and reacts by "typing" the password. But sshpass lets the tool inherit stdin, stdout and stderr, it does not try to act as a relay there, it only changes what tty the tool will reach by opening /dev/tty.

This means sshpass works well with tools I described as "sane". ssh is sane, (local) sudo is also sane. Still, if we do something like

sshpass -fpassword.txt … ssh -t …'sudo …'

(remember the assumption: our ssh does not ask) then the remote sudo will sanely use the tty provided by the SSH server, but the local ssh will use its stdout for writing arbitrary bytes generated by the remote side, and stdin for reading bytes to send to the remote side; it will not use its /dev/tty for this. In effect sshpass neither will see the prompt from sudo, nor be able to send anything to sudo.


Solution

The problem can be solved with expect. Basic example:

expect -c 'trap { set rows [stty rows] set cols [stty columns] stty rows $rows columns $cols < $spawn_out(slave,name)} WINCHlog_user 0set pw [exec cat password.txt]spawn ssh -t -q host "sudo -i -u user"expect "assword"send $pwsend "\n"interact'

(The trap credited to this other answer.)

Note the line expect "assword" tells expect what to expect as (a part of) the prompt and you may need to change it. E.g. if your remote sudo is localized and asks for password in a language other than English then you should adjust the line accordingly.


Viewing all articles
Browse latest Browse all 837

Trending Articles