上一篇说到利用expect来访问远程ssh服务器,并输入命令,但是expect有一些不足,而且有些麻烦。使用sshpass这个程序,支持密码作为参数使用,这样方便很多。

我在使用expect的时候,等待的时候比较长,下面介绍一个响应速度快的程序,那就是sshpass。

安装sshpass

这个程序需要自己编译安装,步骤很简单。

从网站上下载代码,http://sourceforge.net/projects/sshpass/

tar -zxvf sshpass-1.05.tar.gz
cd sshpass-1.05
./configure 
make && make install

这个程序很快就安装完了。

命令参数

接下来我们看看如何使用sshpass。

[root@www ~/sshpass-1.05]# sshpass
Usage: sshpass [-f|-d|-p|-e] [-hV] command parameters
   -f filename   Take password to use from file
   -d number     Use number as file descriptor for getting password
   -p password   Provide password as argument (security unwise)
   -e            Password is passed as env-var "SSHPASS"
   With no parameters - password will be taken from stdin

   -h            Show help (this screen)
   -V            Print version information
At most one of -f, -d, -p or -e should be used

结合ssh一起使用

sshpass -p "mypassword" ssh -p 22 user@127.0.0.1 "ls"

这样,通过sshpass参数-p指定密码,在ssh命令的等待输入密码的时候就能自动将密码写入到输入流中了。

解决著名的第一次问题

在ssh第一次去访问机器的时候,ssh会提示你是否需要将目标ip写入到系统的已知主机中。因为这个的输出会干扰sshpass判断何时应该输入密码。下面程序分析会说。

ssh user@127.0.0.1
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
RSA key fingerprint is c4:4e:a1:56:ad:32:a0:b5:90:13:4e:b8:a2:cf:24:a0.
Are you sure you want to continue connecting (yes/no)? 

通过制定参数-o StrictHostKeyChecking=no让ssh自动添加到已知主机文件中。

ssh -o StrictHostKeyChecking=no user@127.0.0.1
Warning: Permanently added '127.0.0.1' (RSA) to the list of known hosts.
user@127.0.0.1's password: 

sshpass底层源码分析

底层的工作原理和expect差不多,都是去等待输出,

int handleoutput( int fd )
{   
    // We are looking for the string
    static int prevmatch=0; // If the "password" prompt is repeated, we have the wrong password.
    static int state1, state2;
    static const char compare1[]="assword:"; // Asking for a password
    static const char compare2[]="The authenticity of host "; // Asks to authenticate host
    // static const char compare3[]="WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!"; // Warns about man in the middle     attack
    // The remote identification changed error is sent to stderr, not the tty, so we do not handle it.
    // This is not a problem, as ssh exists immediately in such a case
    char buffer[40];
    int ret=0;
    
    int numread=read(fd, buffer, sizeof(buffer) );

    state1=match( compare1, buffer, numread, state1 );

    // Are we at a password prompt? 
    if( compare1[state1]=='\0' ) {
    if( !prevmatch ) {
        write_pass( fd );
        state1=0;
        prevmatch=1;
    } else {                                                                                                             
        // Wrong password - terminate with proper error code
        ret=RETURN_INCORRECT_PASSWORD;
    }   
    }
.....
}

优缺点

先说一下不足吧。

1.我使用的Linux是公司修改过的,账户使用LDAP帐号登录(其实我至今还不懂LDAP是什么,但是都这么叫),输入ssh命名后和普通的ssh的不一样。

####  公司的ssh输出
ssh  -p 22 user@10.168.123.145 
Keyboard-interactive:
PAM authentication
Password: 
Keyboard-interactive:
PAM authentication
LDAP Password: 

#### 普通的ssh命令输出
ssh user@localhost
user@localhost's password: 

所以现在在公司里面没办法使用sshpass,但是在没有修改过的Linux系统上是可以使用sshpass的。这个问题我得找个懂C语言的大神问问。

初步分析好像是公司的Linux经过安全设置,阻止了获取子进程的tty终端,导致无法获取子进程的输出。

2.就是密码放在参数里使用,有些不安全,别人可以使用history来查看到历史的命令,虽然指定了参数可以从文件中获取,但是这个文件里面也是需要进行权限控制的。

优点就是简单,速度会比使用expect快很多。

声明:未经允许禁止转载 东东东 陈煜东的博客 文章,谢谢。如经授权,转载请注明: 转载自东东东 陈煜东的博客

本文链接地址: ssh非交互式密码授权(二):sshpass让ssh支持password参数 – https://www.chenyudong.com/archives/sshpass-ssh-password-parameter-non-interactive-ssh.html