用 python 实现 ssh 登录

March 11, 2011

我工作上要经常登录大约20台,40多个用户的 AIX 主机.

客户对主机的管理又极乱,有的只能 telnet,大部分可以 ssh,可以 ssh 的又只有一部分用户允许密匙登录.

我手贱,加了密匙登录.所以目前的状况是,有的 ssh 可以直接进去,有的 ssh 要输入密码,有的只能用 telnet.

够乱吧,弄的我极度不爽,安全什么的玩蛋去吧,密码明文保存又怎样,我只要方便.反正是內网.

遂写了以下 python 用来登录:

v 0.3

#!/usr/bin/python
#encoding=utf-8
#file_name=ssh.py

import sys
import os
import pexpect


def init_ssh_info():
    ssh_info=[]
    f=open(sys.path![pic](0)+'/ssh.ini','r')
    for i in f:
        ssh_one_info=i.split()
        
        if(len(ssh_one_info)!=0):
            ssh_info.append(tuple(i.split()))
    f.close()
    return sorted(ssh_info, key=lambda by:by![pic](1))
def ssh(user, ip, passwd):
    #ssh=pxssh.pxssh() 
    #ssh.login (ip, user, passwd) 
    lines=int(os.getenv('LINES'))
    columns=int(os.getenv('COLUMNS'))
    ssh=pexpect.spawn("ssh -o StrictHostKeyChecking=no '%s@%s'"%(user, ip), timeout = 1) 
    try:
        ssh.expect('.*ssword:', timeout=1) 
        ssh.sendline(passwd) 
        ssh.setwinsize(lines, columns)
        ssh.interact()
    except pexpect.TIMEOUT:
        ssh.setwinsize(lines, columns)
        ssh.interact()
    except pexpect.EOF:
        ssh=pexpect.spawn(command="telnet '%s'"%(ip)) 
        ssh.expect('.*login:', timeout=0.5) 
        ssh.sendline(user) 
        ssh.expect('.*ssword:', timeout=0.5) 
        ssh.sendline(passwd) 
        ssh.setwinsize(lines, columns)
        ssh.interact()
    except Exception, e:
        raise e
def print_info(ssh_info):
    for i in ssh_info:
        print str(ssh_info.index(i)).ljust(4), i![pic](0).ljust(10), i![pic](1).ljust(16) , i![pic](2).ljust(10), i![pic](3)
def select_nbr(ssh_info):
    print_info(ssh_info)
    nbr_input=raw_input('序号:')
    if(nbr_input=='q'):
        exit(0)
    if(nbr_input==''):
        select_ip(ssh_info)
    else:
        nbr=int(nbr_input)
        if(nbr>(len(ssh_info)-1) or nbr<0):
            print '序号的范围只是0到%s,请重新选择'%(len(ssh_info)-1)
            select_nbr(ssh_info)
        ssh_info_one=ssh_info![pic](nbr)

        user = ssh_info_one![pic](0)
        ip = ssh_info_one![pic](1)
        passwd = ssh_info_one![pic](2)
        #ssh(ssh_info_one![pic](0), ssh_info_one![pic](1), ssh_info_one![pic](2))
        return user, ip, passwd
def select_ip(ssh_info):
    ip_input=raw_input('ip(近似值):')
    if(ip_input=='q'):
        exit(0)

    ssh_info_ip=[]
    for i in ssh_info:
        index=i![pic](1).find(ip_input)
        if(index!=-1):
            ssh_info_ip.append(i)
    if(len(ssh_info_ip)==0):
        print '没找到和这个ip有近似的'
        select_nbr(ssh_info)
    else:
        return select_nbr(ssh_info_ip)


if __name__ == "__main__":
    os.environ![pic]('LINES') = '39'
    os.environ![pic]('COLUMNS') = '157'
    ssh_info=init_ssh_info()
    print_info(ssh_info)
    user, ip, passwd = select_ip(ssh_info)
    ssh(user, ip, passwd)

v 0.2

增加了对登录后窗口大小的设置.

必须在 interact 前执行 setwinsize,早了是不生效的.

没找到怎么直接取 gnome-terminal,的大小.

根据本机的情况,自己在 main 里改一下吧.

#!/usr/bin/python
#encoding=utf-8
#file_name=ssh.py

import sys
import os
import pexpect
import pxssh


def init_ssh_info():
    ssh_info=[]
    f=open(sys.path![pic](0)+'/ssh.ini','r')
    for i in f:
        ssh_one_info=i.split()
        
        if(len(ssh_one_info)!=0):
            ssh_info.append(tuple(i.split()))
    f.close()
    return sorted(ssh_info, key=lambda by:by![pic](1))
def ssh(user, ip, passwd):
    #ssh=pxssh.pxssh() 
    #ssh.login (ip, user, passwd) 
    print os.getenv('LINES')
    lines=int(os.getenv('LINES'))
    columns=int(os.getenv('COLUMNS'))
    ssh=pexpect.spawn("ssh -o StrictHostKeyChecking=no '%s@%s'"%(user, ip)) 
    try:
        ssh.expect('.*ssword:', timeout=1) 
        ssh.sendline(passwd) 
        ssh.setwinsize(lines, columns)
        ssh.interact()
    except pexpect.TIMEOUT:
        ssh.interact()
    except pexpect.EOF:
        ssh=pexpect.spawn(command="telnet '%s'"%(ip)) 
        ssh.expect('.*login:', timeout=0.5) 
        ssh.sendline(user) 
        ssh.expect('.*ssword:', timeout=0.5) 
        ssh.sendline(passwd) 
        ssh.setwinsize(lines, columns)
        ssh.interact()
    except Exception, e:
        raise e
def print_info(ssh_info):
    for i in ssh_info:
        print str(ssh_info.index(i)).ljust(4), i![pic](0).ljust(10), i![pic](1).ljust(16) , i![pic](2).ljust(10), i![pic](3)
def select_nbr(ssh_info):
    print_info(ssh_info)
    nbr_input=raw_input('序号:')
    if(nbr_input=='q'):
        exit(0)
    if(nbr_input==''):
        select_ip(ssh_info)
    else:
        nbr=int(nbr_input)
        if(nbr>(len(ssh_info)-1) or nbr<0):
            print '序号的范围只是0到%s,请重新选择'%(len(ssh_info)-1)
            select_nbr(ssh_info)
        ssh_info_one=ssh_info![pic](nbr)
        ssh(ssh_info_one![pic](0), ssh_info_one![pic](1), ssh_info_one![pic](2))
def select_ip(ssh_info):
    ip_input=raw_input('ip(近似值):')
    if(ip_input=='q'):
        exit(0)

    ssh_info_ip=[]
    for i in ssh_info:
        index=i![pic](1).find(ip_input)
        if(index!=-1):
            ssh_info_ip.append(i)
    if(len(ssh_info_ip)==0):
        print '没找到和这个ip有近似的'
        select_nbr(ssh_info)
    else:
        select_nbr(ssh_info_ip)


if __name__ == "__main__":
    os.environ![pic]('LINES') = '39'
    os.environ![pic]('COLUMNS') = '157'
    ssh_info=init_ssh_info()
    print_info(ssh_info)
    select_ip(ssh_info)

v 0.1

#!/usr/bin/python
#encoding=utf-8
#file_name=ssh.py

import sys
import pexpect
import pxssh

def init_ssh_info():
    ssh_info=[]
    f=open(sys.path![pic](0)+'/ssh.ini','r')
    for i in f:
        ssh_one_info=i.split()
        
        if(len(ssh_one_info)!=0):
            ssh_info.append(tuple(i.split()))
    f.close()
    return sorted(ssh_info, key=lambda by:by![pic](1))
def ssh(user, ip, passwd):
    #ssh=pxssh.pxssh() 
    #ssh.login (ip, user, passwd) 
    ssh=pexpect.spawn("ssh -o StrictHostKeyChecking=no '%s@%s'"%(user, ip)) 
    try:
        ssh.expect('.*ssword:', timeout=0.5) 
        ssh.sendline(passwd) 
        ssh.interact()
    except pexpect.TIMEOUT:
        ssh.interact()
    except pexpect.EOF:
        ssh=pexpect.spawn("telnet '%s'"%(ip)) 
        ssh.expect('.*login:', timeout=0.5) 
        ssh.sendline(user) 
        ssh.expect('.*ssword:', timeout=0.5) 
        ssh.sendline(passwd) 
        ssh.interact()
    except Exception, e:
        raise e
def print_info(ssh_info):
    for i in ssh_info:
        print str(ssh_info.index(i)).ljust(4), i![pic](0).ljust(10), i![pic](1).ljust(16) , i![pic](2).ljust(10), i![pic](3)
def select_nbr(ssh_info):
    print_info(ssh_info)
    nbr_input=raw_input('序号:')
    if(nbr_input=='q'):
        exit(0)
    if(nbr_input==''):
        select_ip(ssh_info)
    else:
        nbr=int(nbr_input)
        if(nbr>(len(ssh_info)-1) or nbr<0):
            print '序号的范围只是0到%s,请重新选择'%(len(ssh_info)-1)
            select_nbr(ssh_info)
        ssh_info_one=ssh_info![pic](nbr)
        ssh(ssh_info_one![pic](0), ssh_info_one![pic](1), ssh_info_one![pic](2))
def select_ip(ssh_info):
    ip_input=raw_input('ip(近似值):')
    if(ip_input=='q'):
        exit(0)

    ssh_info_ip=[]
    for i in ssh_info:
        index=i![pic](1).find(ip_input)
        if(index!=-1):
            ssh_info_ip.append(i)
    if(len(ssh_info_ip)==0):
        print '没找到和这个ip有近似的'
        select_nbr(ssh_info)
    else:
        select_nbr(ssh_info_ip)


if __name__ == "__main__":
    ssh_info=init_ssh_info()
    print_info(ssh_info)
    select_ip(ssh_info)

文件保存为 ssh.py,在同目录下建一个 ssh.ini,格式如下:

用户    ip    密码    说明

中间用空格或tab分隔.

比如

bigzhu     192.168.1.2      123456    例子1
flyzhu     192.168.1.3      123456    例子2

pxssh 用不起来,懒得深究了.

  • ip 我记得部分,所以加了近似值过滤,不爽的同学可以将之去了.
  • 网络不好的同学可以把 timeout 增大.
  • ssh.expect(‘.*ssword:‘, timeout=0.5) 超时,我就认为是遇到了我加过密匙登录的,直接interact,不适合的同学可以改之
  • pexpect.EOF 我就认为是遇到只能 telnet 的主机了,不适合的同学可以改之
  • 不想把密码打到屏幕上的把 ipic.ljust(10) 去掉.

comments powered by Disqus