Ruby pty/expect help

i’ve been up for a really long time, so perhaps i’m missing something silly,
but this script ‘seems’ to work (all three dots are printed), but no id_rsa
file is made? do i have to signal the child to die or something? any other
useful debugging tips? it would be great if PTY could ‘tee’ it’s output to
stdout for debugging

~/eg/ruby > cat ssh-keygen.rb
require ‘pty’
require ‘expect’

path = ARGV.shift || ‘id_rsa’
File.unlink path rescue nil

PTY.spawn(‘ssh-keygen -t rsa’) do |r,w,cid|
r.expect %r/^Enter.:\s+/ do
print ‘.’
w.puts path
end
r.expect %r/^Enter.
:\s+/ do
print ‘.’
w.puts ‘’
end
r.expect %r/^Enter.*:\s+/ do
print ‘.’
w.puts ‘’
end

w.flush
w.close
puts
end

-a

···

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

i've been up for a really long time, so perhaps i'm missing something silly,
but this script 'seems' to work (all three dots are printed), but no id_rsa
file is made?

You must read its output

do i have to signal the child to die or something? any other
useful debugging tips?

   $expect_verbose = true

Guy Decoux

i’ve been up for a really long time, so perhaps i’m missing something silly,
but this script ‘seems’ to work (all three dots are printed), but no id_rsa
file is made?

You must read its output

thanks guy - what exactly do you mean? there’s only one thing to read, and
reading it seems the throw errors:

~/eg/ruby > cat ssh-keygen.rb
require ‘pty’
require ‘expect’
$VERBOSE=nil

path = ARGV.shift || ‘id_rsa’
File.unlink path rescue nil

PTY.spawn ‘ssh-keygen -t rsa’ do |r,w,cid|
r.expect %r/^Enter.:\s+/ do |line|
print line
w.puts path
end
r.expect %r/^Enter.
:\s+/ do |line|
print line
w.puts ‘’
end
r.expect %r/^Enter.*:\s+/ do |line|
print line
w.puts ‘’
end

r.read # ?? this raises Errno::EIO
w.flush
w.close
puts
end

~/eg/ruby > ruby ssh-keygen.rb
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ahoward/.ssh/id_rsa): id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again: ssh-keygen.rb:22:in read': Input/output error - /dev/pts/19 (Errno::EIO) from ssh-keygen.rb:22 from ssh-keygen.rb:8:in spawn’
from ssh-keygen.rb:8

without the read it generates the expected output, but no id_rsa file is
produced and no error is given… doesn’t the call to IO.expect do the reading
anyhow? also, the example in ext/pty/example_expect.rb doesn’t seem to do any
reading either?

do i have to signal the child to die or something? any other
useful debugging tips?

$expect_verbose = true

Guy Decoux

this is very helpful - and it was right in the example! :wink:

-a

···

On Wed, 14 Apr 2004, ts wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

without the read it generates the expected output, but no id_rsa file is
produced and no error is given... doesn't the call to IO.expect do the reading
anyhow? also, the example in ext/pty/example_expect.rb doesn't seem to do any
reading either?

Without the read it don't give an error and don't generate the id_rsa
files.

With the read it give an error and generate the id_rsa files, no ?

Then protect the read :slight_smile:

Guy DEcoux

Hi,

At Thu, 15 Apr 2004 01:09:20 +0900,
Ara.T.Howard wrote in [ruby-talk:97152]:

~/eg/ruby > ruby ssh-keygen.rb
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ahoward/.ssh/id_rsa): id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again: ssh-keygen.rb:22:in read': Input/output error - /dev/pts/19 (Errno::EIO) from ssh-keygen.rb:22 from ssh-keygen.rb:8:in spawn’
from ssh-keygen.rb:8

without the read it generates the expected output, but no id_rsa file is
produced and no error is given… doesn’t the call to IO.expect do the reading
anyhow? also, the example in ext/pty/example_expect.rb doesn’t seem to do any
reading either?

Because the watchdog thread created by PTY.spawn signals the
main thread when child exits, and read(2) is interrupted. In
such case, however, I feel that IO#read should return already
read data, if exists.

BTW, you don’t need PTY at all to generate ssh key
automatically.

$ rm -f id_rsa{,.pub}
$ ssh-keygen -t rsa -N “” -f id_rsa
Generating public/private rsa key pair.
Your identification has been saved in id_rsa.
Your public key has been saved in id_rsa.pub.
The key fingerprint is:
42:1f:bc:76:60:45:a1:2b:fd:cc:4c:a2:3a:0c:87:c6 nobu@sharui.nakada.niregi.kanuma.tochigi.jp

Index: io.c

···

===================================================================
RCS file: /cvs/ruby/src/ruby/io.c,v
retrieving revision 1.271
diff -u -2 -p -r1.271 io.c
— io.c 14 Apr 2004 04:06:25 -0000 1.271
+++ io.c 15 Apr 2004 01:18:27 -0000
@@ -953,10 +953,9 @@ rb_io_fread(ptr, len, f)
case EWOULDBLOCK:
#endif

  •       if (len - n >= 0) {
    
  •       if (len > n) {
      	clearerr(f);
    
  •   	return len - n;
          }
      }
    
  •   return 0;
    
  •   if (len == n) return 0;
      }
      *ptr = '\0';
    


Nobu Nakada

guy-

you are a saint. why on earth would one be required to do a read which
generates an error? and why don’t the example scripts do this?

-a

···

On Thu, 15 Apr 2004, ts wrote:

without the read it generates the expected output, but no id_rsa file is
produced and no error is given… doesn’t the call to IO.expect do the reading
anyhow? also, the example in ext/pty/example_expect.rb doesn’t seem to do any
reading either?

Without the read it don’t give an error and don’t generate the id_rsa
files.

With the read it give an error and generate the id_rsa files, no ?

Then protect the read :slight_smile:

Guy DEcoux

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi,

At Thu, 15 Apr 2004 01:09:20 +0900,
Ara.T.Howard wrote in [ruby-talk:97152]:

~/eg/ruby > ruby ssh-keygen.rb
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ahoward/.ssh/id_rsa): id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again: ssh-keygen.rb:22:in read': Input/output error - /dev/pts/19 (Errno::EIO) from ssh-keygen.rb:22 from ssh-keygen.rb:8:in spawn’
from ssh-keygen.rb:8

without the read it generates the expected output, but no id_rsa file is
produced and no error is given… doesn’t the call to IO.expect do the reading
anyhow? also, the example in ext/pty/example_expect.rb doesn’t seem to do any
reading either?

Because the watchdog thread created by PTY.spawn signals the main thread
when child exits, and read(2) is interrupted. In such case, however, I feel
that IO#read should return already read data, if exists.

perhaps a handle on an object which can be ‘closed’ could be returned instead
of an array of Files, etc:

passphrase = gen_random_passphrase

pty = PTY.spawn ‘ssh-keygen’

pty.stdin.puts ‘id_rsa.pub’
pty.stdin.puts passphrase
pty.stdin.puts passphrase
pts.close # do the right thing

pty = PTY.spawn ‘ssh-agent’

pty.stdin.write passphrase

BTW, you don’t need PTY at all to generate ssh key
automatically.

see above - i want to pass it to ssh-agent. thanks though, didn’t know
that…

-a

···

On Thu, 15 Apr 2004 nobu.nokada@softhome.net wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi,

At Thu, 15 Apr 2004 12:09:12 +0900,
Ara.T.Howard wrote in [ruby-talk:97212]:

perhaps a handle on an object which can be ‘closed’ could be returned instead
of an array of Files, etc:

passphrase = gen_random_passphrase

pty = PTY.spawn ‘ssh-keygen’

pty.stdin.puts ‘id_rsa.pub’
pty.stdin.puts passphrase
pty.stdin.puts passphrase
pts.close # do the right thing

Yes, I’ve thought about same strategy for open3.

pty = PTY.spawn ‘ssh-agent’

pty.stdin.write passphrase

BTW, you don’t need PTY at all to generate ssh key
automatically.

see above - i want to pass it to ssh-agent. thanks though, didn’t know
that…

ssh-agent doesn’t read passphrase but prints some environment
variables and runs as a daemon, like as:

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-FGmutb8164/agent.8164; export SSH_AUTH_SOCK;
SSH_AGENT_PID=8165; export SSH_AGENT_PID;
echo Agent pid 8165;

Therefore you should set those variables instead. e.g.,

ssh-agent.scan(/^(SSH_[A-Z_]+)=([^; ]*)/, &ENV.method(:=))

Then, you’ll need to send passphrase to ssh-add. At this time,
you have 2 methods:

  1. with pty.
    PTY.spawn(“ssh-add”) do |r,w,pid|
    r.expect %r/^Enter.*:\s+/ {w.puts passphrase}
    end

  2. without control terminal. Since ssh-add reads passphrase
    from stdin when no ctty or X are available, you can:

    IO.popen(“-”, “w”) do |f|
    if f
    f.puts passphrase
    else
    ENV.delete(“SSH_ASKPASS”)
    ENV.delete(“DISPLAY”)
    Process.setsid
    exec(“ssh-add”)
    end
    end

    or, if setsid command is available and env command has -u option:

    IO.popen(“env -u SSH_ASKPASS -u DISPLAY setsid ssh-add”, “w”) do |f|
    f.puts passphrase
    end

···


Nobu Nakada

Hi,

At Thu, 15 Apr 2004 12:09:12 +0900,
Ara.T.Howard wrote in [ruby-talk:97212]:

perhaps a handle on an object which can be ‘closed’ could be returned instead
of an array of Files, etc:

passphrase = gen_random_passphrase

pty = PTY.spawn ‘ssh-keygen’

pty.stdin.puts ‘id_rsa.pub’
pty.stdin.puts passphrase
pty.stdin.puts passphrase
pts.close # do the right thing

Yes, I’ve thought about same strategy for open3.

have you seen my session-2.1.6 package which wraps open3 in this way? it is
more specific but same idea…

ssh-agent doesn’t read passphrase but prints some environment variables and
runs as a daemon, like as:

right, right… i’ve slept three hourse in the last 48… basically i’m just
trying to get around security :wink:

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-FGmutb8164/agent.8164; export SSH_AUTH_SOCK;
SSH_AGENT_PID=8165; export SSH_AGENT_PID;
echo Agent pid 8165;

Therefore you should set those variables instead. e.g.,

ssh-agent.scan(/^(SSH_[A-Z_]+)=([^; ]*)/, &ENV.method(:=))

                                            ^
                                            ^
                                            ^

                                          i learn something every day
                                          i guess that makes it a
                                          block - neat.

Then, you’ll need to send passphrase to ssh-add. At this time,
you have 2 methods:

  1. with pty.
    PTY.spawn(“ssh-add”) do |r,w,pid|
    r.expect %r/^Enter.*:\s+/ {w.puts passphrase}
    end

  2. without control terminal. Since ssh-add reads passphrase
    from stdin when no ctty or X are available, you can:

    IO.popen(“-”, “w”) do |f|
    if f
    f.puts passphrase
    else
    ENV.delete(“SSH_ASKPASS”)
    ENV.delete(“DISPLAY”)
    Process.setsid
    exec(“ssh-add”)
    end
    end

    or, if setsid command is available and env command has -u option:

    IO.popen(“env -u SSH_ASKPASS -u DISPLAY setsid ssh-add”, “w”) do |f|
    f.puts passphrase
    end

-a

···

On Thu, 15 Apr 2004 nobu.nokada@softhome.net wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================