There are several solutions for piping a password to ssh. One of the solutions can be found under http://www.debian-administration.org/articles/587. But starting from openssh 5.6p1 the approach described there won’t work anymore. The reason behind is the following piece of code, that was added in version 5.6:

/*                                           
 * Discard other fds that are hanging around. 
 * These can cause problem  with backgrounded 
 * ssh processes started by ControlPersist.
 */

closefrom(STDERR_FILENO + 1);

closefrom(int startingfd); closes all opened file descriptors starting from startingfd. In this case it closes all file descriptors starting from stderr (stderr is equivalent to two). At this point every approach that passes the password by inheriting file descriptors to ssh will fail. That means another solution must be found, mine is the usage of SSH_ASKPASS.

The SSH_ASKPASS approach

As stated in the ssh man page, the environment variable SSH_ASKPASS can be used to pass a password to ssh:

If ssh needs a passphrase, it will read the passphrase from the current terminal if it was run from a terminal. If ssh does not have a terminal associated with it but DISPLAY and SSH_ASKPASS are set, it will execute the program specified by SSH_ASKPASS and open an X11 window to read the passphrase. This is particularly useful when calling ssh from a .xsession or related script. (Note that on some machines it may be necessary to redirect the input from /dev/null to make this work.)

To retrieve the password, ssh calls the program specified in the SSH_ASKPASS environment variable. In a perfect world it would be sufficient to set the DISPLAY variable to a bogus value and tell ssh to use the program in SSH_ASKPASS to retrieve the password. But this is not enough, because ssh always looks for a valid terminal and always asks there for a password. The trick is to detach ssh from the current terminal by starting it in a new session. The command setsid – a wrapper around the setsid system call – does exactly this.

sshaskpass script

I put the pieces together and wrote a script that passes a password from stdin to ssh. First the script creates a temp file by callin mktemp and sets then the file permissions so that only the user can read/write the file. Then it writes the password to the temp file where it is read later via the SSH_ASKPASS mechanism. The temp file containing the password is delete at the end of the script or in case the script receives a signal, the file is delete by a signal handler.

#!/bin/bash
# 
# script that passes password from stdin to ssh. 
# 
# Copyright (C) 2010 André Frimberger <andre OBVIOUS_SIGN frimberger.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or 
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

if [ -n "$SSH_ASKPASS_TMPFILE" ]; then
    cat “$SSH_ASKPASS_TMPFILE”
    exit 0
elif [ $# -lt 1 ]; then
    echo “Usage: echo password | $0 <ssh command line options>” >&2
    exit 1
fi

sighandler() {
    rm “$TMP_PWD”
}

TMP_PWD=$(mktemp)
chmod 600 “$TMP_PWD”
trap ’sighandler’ SIGHUP SIGINT SIGQUIT SIGABRT SIGKILL SIGALRM SIGTERM

export SSH_ASKPASS=$0
export SSH_ASKPASS_TMPFILE=$TMP_PWD

[ "$DISPLAY" ] || export DISPLAY=dummydisplay:0
read password
echo $password >> “$TMP_PWD”

# use setsid to detach from tty
exec setsid “$@”

rm “$TMP_PWD”

Q & A

Q: How to use the script

echo “my_password” | ./sshaskpass.sh ssh user@someMachine “ls -l”

Q: Why don’t you use public keys instead?

Public key authentication doesn’t work with pam_mount. This is because pam_mount passes the ssh password to mount.fuse.