I sometimes have a need to run commands as root on a remote server, and parse the output of the command on my local server. The remote server does not allow root login by ssh, but has sudo configured in a way that requires a password. A simplified example of what I need to do is
ssh remote sudo echo bar | tr bar foo
(Obviously in this simplified example, there's no good reason to need to run echo on a different machine to tr: this is just a toy example to explain what I'm trying to do.)
If I run the command above, I get an error that sudo has no way to prompt for a password:
richard#local:~$ ssh remote sudo echo bar | tr bar foo
sudo: no tty present and no askpass program specified
One way I can try to fix this is by adding the -t option to ssh. If I do that, sudo does wait for and accept a password, but the output of ssh's pseudo-terminal goes to stdout, meaning the sudo prompt message is piped to tr and not displayed to the user. If the user doesn't know sudo is waiting for a password, they will think the script has hung, and passing the prompt message to the pipe probably breaks further processing:
richard#local:~$ ssh -t remote sudo echo bar | tr bar foo
[sudo] posswood foo oichood:
foo
(This admittedly silly example shows the prompt has been processed by the tr command the output is piped to.)
The other way I can see to try to fix this is by adding the -S option to sudo. If I do that, sudo prompts on stderr for the password, so the prompt is not passed down the pipeline. That's good, but sudo also accepts the password on standard input meaning it's echoed to the terminal where anyone looking over the user's shoulder can read it:
richard#local:~$ ssh remote sudo -S echo bar | tr bar foo
[sudo] password for richard: p8ssw0rd
foo
I've found inelegant ways of working around the problems with these two options, but my workarounds hit a problem if the user gets their password wrong the first time. That in itself is a problem. Examples of this are:
richard#local:~$ echo "[sudo] password for $USER:"; \
ssh -t remote sudo echo bar | tail +2 | tr bar foo
richard#local:~$ (read -s password; echo $password; echo >&2) \
| ssh remote sudo -S echo bar | tr bar foo
I'm sure there must be a good solution to this, as it doesn't seem an uncommon thing to want to do. Any ideas?
The best solution I've come up with is to use sudo -S and disable local echo so the password isn't shown as you type it:
$ { stty -echo; ssh remote sudo -S echo hello; stty echo; echo 1>&2; }
[sudo] password for user:
hello
This leaves sudo in charge of the password prompting, so it works properly if the user types the password wrong.
I don't think any solution using ssh -t can ever work properly, since it combines stderr and stdout.
Related
To check, if user does have sudo (on multiple server at once), I'm using following command:
echo -e "$Password" | ssh -tt -q $Username#$Server "sudo -S -p '' echo ok" 2>&1
This approach seems to work, but only if the password is accepted. If you are (for whatever reason) asked for the password again, the command hangs, and the whole script with it.
Is there a way to force this command to end, if the password is not accepted?
The command is not hanging. It is waiting.
You have specified that the sudo command should read the password from stdin (-S) and not prompt the user to enter a password (-p ''). If you enter the wrong password, sudo will wait for you to try again -- by default, three times.
I cannot find any option to sudo -- either on the command line or in the sudo.conf config file -- that will allow you to ask only once for the password and then exit.
I am looking to script something in batch which will need to run remote ssh commands on Linux. I would want the output returned so I can either display it on the screen or log it.
I tried putty.exe -ssh user#host -pw password -m command_run but it doesn't return anything on my screen.
Anyone done this before?
The -m switch of PuTTY takes a path to a script file as an argument, not a command.
Reference: https://the.earth.li/~sgtatham/putty/latest/htmldoc/Chapter3.html#using-cmdline-m
So you have to save your command (command_run) to a plain text file (e.g. c:\path\command.txt) and pass that to PuTTY:
putty.exe -ssh user#host -pw password -m c:\path\command.txt
Though note that you should use Plink (a command-line connection tool from PuTTY suite). It's a console application, so you can redirect its output to a file (what you cannot do with PuTTY).
A command-line syntax is identical, an output redirection added:
plink.exe -ssh user#host -pw password -m c:\path\command.txt > output.txt
See Using the command-line connection tool Plink.
And with Plink, you can actually provide the command directly on its command-line:
plink.exe -ssh user#host -pw password command > output.txt
Similar questions:
Automating running command on Linux from Windows using PuTTY
Executing command in Plink from a batch file
You can also use Bash on Ubuntu on Windows directly. E.g.,
bash -c "ssh -t user#computer 'cd /; sudo my-command'"
Per Martin Prikryl's comment below:
The -t enables terminal emulation. Whether you need the terminal emulation for sudo depends on configuration (and by default you do no need it, while many distributions override the default). On the contrary, many other commands need terminal emulation.
As an alternative option you could install OpenSSH http://www.mls-software.com/opensshd.html and then simply ssh user#host -pw password -m command_run
Edit: After a response from user2687375 when installing, select client only. Once this is done you should be able to initiate SSH from command.
Then you can create an ssh batch script such as
ECHO OFF
CLS
:MENU
ECHO.
ECHO ........................
ECHO SSH servers
ECHO ........................
ECHO.
ECHO 1 - Web Server 1
ECHO 2 - Web Server 2
ECHO E - EXIT
ECHO.
SET /P M=Type 1 - 2 then press ENTER:
IF %M%==1 GOTO WEB1
IF %M%==2 GOTO WEB2
IF %M%==E GOTO EOF
REM ------------------------------
REM SSH Server details
REM ------------------------------
:WEB1
CLS
call ssh user#xxx.xxx.xxx.xxx
cmd /k
:WEB2
CLS
call ssh user#xxx.xxx.xxx.xxx
cmd /k
i am wondering how does fabric execute commands.
Let's say I give him env.user=User, env.host=HOST. Then i ask him to sudo('ls')
Is that equivalent to me typing in a shell : ssh User#host 'sudo(/bin/ls)'
or it's more : ssh User#host in a first time, then sudo ls commande in a seconde time ?
I'm asking that because sometimes using a shell, if the TTY has a bad configuration (I am a bit blurry on this), ssh User#Host 'sudo /bin/ls'
return : sudo: no tty present and no askpass program specified
but you can first log in with ssh User#Host then sudo ls and it works.
I don't know how to replicate the no tty error, but I know it can occurs. Would this block the sudo commande from Fabric?
Basically how it works is:
First a connection is established (equivalent as doing ssh User#host)
Over this connection a command is executed as follows:
sudo -S -p 'sudo password:' /bin/bash -l -c "your_command"
You can also allow Fabric not to request a pty with either pty=False argument, env.always_use_pty=False or --no-pty commandline option.
I'm trying to login to a ssh server and to execute something like:
ssh user#domain.com 'sudo echo "foobar"'
Unfortunately I'm getting an error:
sudo: no tty present and no askpass program specified
Google told me to either set the environment variable SSH_ASKPASS or to set askpass in the sudoers file. My remote machine is running on Debian 6 and I've installed the packages ssh-askpass and ssh-askpass-gnome and my sudoers file looks like this:
Defaults env_reset
Defaults askpass=/usr/bin/ssh-askpass
# User privilege specification
root ALL=(ALL) ALL
user ALL=(ALL) ALL
Can someone tell what I'm doing wrong and how to do it better.
There are two ways to get rid of this error message. The easy way is to provide a pseudo terminal for the remote sudo process. You can do this with the option -t:
ssh -t user#domain.com 'sudo echo "foobar"'
Rather than allocating a TTY, or setting a password that can be seen in the command line, do something like this.
Create a shell file that echo's out your password like:
#!/bin/bash
echo "mypassword"
then copy that to the node you want using scp like this:
scp SudoPass.sh somesystem:~/bin
Then when you ssh do the following:
ssh somesystem "export SUDO_ASKPASS=~/bin/SudoPass.sh;sudo -A command -parameter"
Another way is to run sudo -S in order to "Write the prompt to the standard error and read the password from the standard input instead of using the terminal device" (according to man) together with cat:
cat | ssh user#domain.com 'sudo -S echo "foobar"'
Just input the password when being prompted to.
One advantage is that you can redirect the output of the remote command to a file without "[sudo] password for …" in it:
cat | ssh user#domain.com 'sudo -S tar c --one-file-system /' > backup.tar
Defaults askpass=/usr/bin/ssh-askpass
ssh-askpass requires X server, so instead of providing a terminal (via -t, as suggested by nosid), you may forward X connection via -X:
ssh -X user#domain.com 'sudo echo "foobar"'
However, according to current documentation, askpass is set in sudo.conf as Path, not in sudoers.
How about adding this in the sudoers file:
user ALL=(ALL) NOPASSWD: ALL
I want to make a shellscript to install Wine on a Mac
and i want the user to enter his/her password so the script can use it later on to make the installation unattended by automatically entering the password on "sudo" commands. This is what i got for now:
clear
echo Wine Installer v1.0
echo -------------------
echo by Sydcul
sleep 4
clear
echo "Please enter your OS X user password."
echo "It is needed in some parts of the installation."
read PASSWORD
echo "Wine installation starting."
echo "Please do not shut down your system."
mkdir winetmp
cd winetmp
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.0.3.tar.bz2
tar xjvf MacPorts-2.0.3.tar.bz2
cd MacPorts-2.0.3
echo $PASSWORD | ./configure && make && sudo make install
echo $PASSWORD | sudo port -v selfupdate
echo $PASSWORD | sudo port -v install xorg
echo $PASSWORD | sudo port -v install wine
rm -rf ~/winetmp
clear
echo "Wine is successfully installed and ready for use!"
But at a certain point is still asks for the password.
How can i fix this?
Honestly, I would drop all that $PASSWORD stuff and remove the sudo from all your commands. You are writing an installation script, which should be run with elevated privileges. Have your users execute your script with sudo ./installwine.sh, and then run the commands in the script without sudo. All your port -v stuff will inherit the elevated privileges.
If you'd like to offer your user a nice error message if they forget to run the script with sudo (rather than just having your first call to port fail cryptically), you could check to see if the effective user ID ($EUID) is 0, and print the error message and exit otherwise. See https://askubuntu.com/questions/30148/how-can-i-determine-whether-a-shellscript-runs-as-root-or-not.
You can prompt the user for the password for the first time and then save it in a file (and don't forget to encrypt it).
The next time when you need it you can easily read it from the same file and store it in a variable and then use this command
echo $variablename | sudo -S command
Actually I think sudo doesn't accept password from stdin (you need to specify -S parameter to enable this).
As workaround you can execute sudo su to gain root privileges for all commands.
UPD: I'm not recommend to save password to file cause it is very bad solution from security point.
UPD2: You forget about Xcode, if it is not installed this script fails on compile stage :)
Why don't you just use the custom prompt option for sudo, and let it ask for the password if it needs it?
You start by checking if they're already root or not like this:
SUDO=""
if [[ 0 == $(id -u) ]]
then
SUDO="sudo "
fi
$SUDO command 1
$SUDO command arg arg arg
and then optionally combine that with the ability to customize the sudo prompt using the -p option.
then
SUDO="sudo -p \"I need elevated access for this part. Please enter %u's password:\" "
fi
You still get control over the interface, but don't prompt for a password unless you need it. Some people may have sudo set up for nopassword operation, for example. Others might run your installer as root. Or maybe their pasword is already cached with sudo. Etc. It's best to let sudo manage prompting, possibly using an askpass program (see the -A option) if necessary.