Send in your Unix questions today! |
See additional Unix tips and tricks
If you Google the terms "ssh" and "password", you will come up with a generous number of hits on how to set up SSH so that you can log in to a system or run commands remotely on that system without entering a password. While representing something of a security risk (anyone who breaks into your account on one system can access your account on the other as well), this configuration is extremely handy if you need to collect data from the system using a script. For example, you could type "ssh bandana uptime" to find out how long bandana has been running since its last reboot.
Detecting whether a command run via ssh within a script required entry of a password or made use of public key authentication, on the other hand, is more than a little tricky.
To make this situation plausible, let's consider an example. You are preparing a script that will collect various pieces of information from a remote system. You would like the script to take advantage of whatever privilege access the user has established. If the user has set up ssh access to run without requiring a password, you want to take advantage of this. If, on the other hand, he has established password-free access using rsh, you want to use that. Let's see how this can be done.
First, let's consider rsh. While generally frowned upon because it sends usernames and passwords over the network in the clear, rsh still provides an easy means for users to establish password-free access to remote systems and is extremely simple to set up. For a script to determine whether its user has password-free rsh access to a remote system, all it has to do is issue a command using rsh (such as "rsh date") and then determine whether the command was run successfully. Unlike ssh, rsh does not prompt for a password to run remote commands. If the remote system is configured to trust the system issuing the command, the command will be run and, if not, it will fail. All you have to do, therefore, to figure out whether the user can run commands remotely without entering his password is look at the return code.
rsh bandana date
if [ $? == 0 ]; then
use_rsh="yes"
fi
|
If you don't want the person running your script to wonder why the output from some arbitrary command -- like "date" -- is appearing on his screen, you can toss the output into the bit bucket with a simple redirect. After all, you're only interested in whether the rsh command was successful. In bash, this would look like this:
rsh bandana date 2>&1 > /dev/null
if [ $? == 0 ]; then
use_rsh="yes"
fi
|
If the return code is 0, you know that the command succeeded.
The same basic logic in perl would look like this:
#!/usr/bin/perl -w
system("rsh teapot date 2>&1 > /dev/null");
if ( $? == 0 ) {
$use_rsh="yes"
}
|
You can't be nearly as stealthy when checking a user's ssh access. If you include an ssh command in your script and it runs successfully without the user having to enter a password, your script can continue to quietly use ssh commands to collect additional information from the remote system. However, there are problems with this approach. First, SSH will prompt for a password if it is not set up to run without one. Unlike how this works with rsh, you can't count on testing ssh access without potentially involving the user. Second, it's not easy to tell within a script whether the user was required to enter a password. There's no way to capture the prompt from the remote system and use it as evidence that the user entered a password -- unless, in any case, you are scripting the interaction between the systems with a tool such as expect.
The trick is to use ssh in verbose (-v) mode, redirect standard error to a temporary file and then examine the temporary file to see which authentication method was used. The code below works for both Solaris and Linux systems:
system("ssh -v bandana date 1>/dev/null 2>/tmp/ssh$$");
$auth=`egrep "successful|succeeded" /tmp/ssh$$`;
if ( $auth=~/publickey/ ) {
$use_ssh="yes"
} elsif ( $auth=~/password/ ) {
$use_ssh="maybe"
}
print "$use_ssh\n";
unlink "/tmp/ssh$$";
|
I've used egrep to search for "successful" or "succeeded" in the ssh debug log because different versions of ssh seem to use a different syntax. The code shown should work with messages of the following types:
debug1: ssh-userauth2 successful: method publickey
debug1: Authentication succeeded (publickey).
If the user had to enter a password to execute remote commands using ssh, you might opt to use rsh instead -- at least if this saves him the trouble of entering his password numerous times before the script has collected all of the data it requires.