それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Rubyで exptect や ptyを使ってパスワードを自動入力する

SSHパスワード省略について書くと,公開鍵エントリに埋もれてしまうのですが。。。

Sudoや、SSHを踏み台にしてその先のPCにRsyncするときなど、パスワード入力が毎回出てきて煩わしい.公開鍵が使えない業者のサーバーに限って,SSHで多段アクセスだったり頻繁にRsyncが必要だったりする

ruby でパスワード入力する方法

#!/usr/bin/env ruby
require 'pty'
require 'expect'
cmd = 'rsync -avz server0:/mnt/test /home/takuya '
PTY.getpty(cmd) do | i,o |
    o.sync = true
    i.expect(/password:/,10){|line| ##入力プロンプトくるまでreadline繰り返す
        puts line
        o.puts "my_pass"
        o.flush
    }
    while( i.eof? == false )
        puts i.gets
    end

end

解説

pty モジュールで、疑似TTYを確保する(pty = pseudo TTY )
expect モジュールで、文字列がくるのを待つ.
以降は標準入力をEchoするだけ

pty は疑似的にターミナルを作る.つまり IOクラスが二つ(input,output)が使える

PTY.getpty(cmd) do | input_io, output_io |

PTYを確保すると,/dev/ttyにIO用にファイルが作られる(らしい)

pty/expectのインストール

rubyの標準添付ライブラリなのでRubyあればそのまま使える。

2012-07-13追加 STDIN(標準入力)から パスワードを受け取りたい。

ソースコードにパスワード直書きが精神衛生上良くない。パスワードを取り込みたい。普通に$stdin.getsすると、パスワードが丸見えになる。パスワードマスクして隠したい。

コマンドラインの文字列から、パスワードを入力するように改良した

#!/usr/bin/env ruby
require 'pty'
require 'expect'
cmd = 'rsync -avz server0:/mnt/test /home/takuya '
PTY.getpty(cmd) do | i,o |
    o.sync = true
    i.expect(/password:/,10){|line| ##入力プロンプトくるまでreadline繰り返す
        puts line
        system "stty -echo"
        o.puts STDIN.gets
        system "stty echo"
        o.flush
    }
    while( i.eof? == false )
        puts i.gets
    end
end


ちなみに、rsyncの場合にSSH鍵を指定することができるので、例のrsyncの場合、秘密鍵を指定すればパスワードをexpectしなくても大丈夫

rsync -avz -e "ssh -i /home/takuya/.ssh/id_rsa -o StrictHostKeyChecking=no "

2013-03-25追記

ちなみに expect は expect コマンドをRubyのpopenで書いたものらしいです。