~ubuntu-branches/ubuntu/trusty/ruby1.9/trusty

« back to all changes in this revision

Viewing changes to ext/openssl/lib/net/telnets.rb

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2008-01-24 11:42:29 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20080124114229-jw2f87rdxlq6gp11
Tags: 1.9.0.0-2ubuntu1
* Merge from debian unstable, remaining changes:
  - Robustify check for target_os, fixing build failure on lpia.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
=begin
2
 
= $RCSfile$ -- SSL/TLS enhancement for Net::Telnet.
3
 
 
4
 
= Info
5
 
  'OpenSSL for Ruby 2' project
6
 
  Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
7
 
  All rights reserved.
8
 
 
9
 
= Licence
10
 
  This program is licenced under the same licence as Ruby.
11
 
  (See the file 'LICENCE'.)
12
 
 
13
 
= Version
14
 
  $Id: telnets.rb 11708 2007-02-12 23:01:19Z shyouhei $
15
 
  
16
 
  2001/11/06: Contiributed to Ruby/OpenSSL project.
17
 
 
18
 
== class Net::Telnet
19
 
 
20
 
This class will initiate SSL/TLS session automaticaly if the server
21
 
sent OPT_STARTTLS. Some options are added for SSL/TLS.
22
 
 
23
 
  host = Net::Telnet::new({
24
 
           "Host"       => "localhost",
25
 
           "Port"       => "telnets",
26
 
           ## follows are new options.
27
 
           'CertFile'   => "user.crt",
28
 
           'KeyFile'    => "user.key",
29
 
           'CAFile'     => "/some/where/certs/casert.pem",
30
 
           'CAPath'     => "/some/where/caserts",
31
 
           'VerifyMode' => SSL::VERIFY_PEER,
32
 
           'VerifyCallback' => verify_proc
33
 
         })
34
 
 
35
 
Or, the new options ('Cert', 'Key' and 'CACert') are available from
36
 
Michal Rokos's OpenSSL module.
37
 
 
38
 
  cert_data = File.open("user.crt"){|io| io.read }
39
 
  pkey_data = File.open("user.key"){|io| io.read }
40
 
  cacert_data = File.open("your_ca.pem"){|io| io.read }
41
 
  host = Net::Telnet::new({
42
 
           "Host"       => "localhost",
43
 
           "Port"       => "telnets",
44
 
           'Cert'       => OpenSSL::X509::Certificate.new(cert_data)
45
 
           'Key'        => OpenSSL::PKey::RSA.new(pkey_data)
46
 
           'CACert'     => OpenSSL::X509::Certificate.new(cacert_data)
47
 
           'CAFile'     => "/some/where/certs/casert.pem",
48
 
           'CAPath'     => "/some/where/caserts",
49
 
           'VerifyMode' => SSL::VERIFY_PEER,
50
 
           'VerifyCallback' => verify_proc
51
 
         })
52
 
 
53
 
This class is expected to be a superset of usual Net::Telnet.
54
 
=end
55
 
 
56
 
require "net/telnet"
57
 
require "openssl"
58
 
 
59
 
module Net
60
 
  class Telnet
61
 
    attr_reader :ssl
62
 
 
63
 
    OPT_STARTTLS       =  46.chr # "\056" # "\x2e" # Start TLS
64
 
    TLS_FOLLOWS        =   1.chr # "\001" # "\x01" # FOLLOWS (for STARTTLS)
65
 
 
66
 
    alias preprocess_orig preprocess
67
 
 
68
 
    def ssl?; @ssl; end
69
 
 
70
 
    def preprocess(string)
71
 
      # combine CR+NULL into CR
72
 
      string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
73
 
 
74
 
      # combine EOL into "\n"
75
 
      string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"]
76
 
 
77
 
      string.gsub(/#{IAC}(
78
 
                   [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
79
 
                   [#{DO}#{DONT}#{WILL}#{WONT}][#{OPT_BINARY}-#{OPT_EXOPL}]|
80
 
                   #{SB}[#{OPT_BINARY}-#{OPT_EXOPL}]
81
 
                     (#{IAC}#{IAC}|[^#{IAC}])+#{IAC}#{SE}
82
 
                 )/xno) do
83
 
        if    IAC == $1  # handle escaped IAC characters
84
 
          IAC
85
 
        elsif AYT == $1  # respond to "IAC AYT" (are you there)
86
 
          self.write("nobody here but us pigeons" + EOL)
87
 
          ''
88
 
        elsif DO[0] == $1[0]  # respond to "IAC DO x"
89
 
          if    OPT_BINARY[0] == $1[1]
90
 
            @telnet_option["BINARY"] = true
91
 
            self.write(IAC + WILL + OPT_BINARY)
92
 
          elsif OPT_STARTTLS[0] == $1[1]
93
 
            self.write(IAC + WILL + OPT_STARTTLS)
94
 
            self.write(IAC + SB + OPT_STARTTLS + TLS_FOLLOWS + IAC + SE)
95
 
          else
96
 
            self.write(IAC + WONT + $1[1..1])
97
 
          end
98
 
          ''
99
 
        elsif DONT[0] == $1[0]  # respond to "IAC DON'T x" with "IAC WON'T x"
100
 
          self.write(IAC + WONT + $1[1..1])
101
 
          ''
102
 
        elsif WILL[0] == $1[0]  # respond to "IAC WILL x"
103
 
          if    OPT_BINARY[0] == $1[1]
104
 
            self.write(IAC + DO + OPT_BINARY)
105
 
          elsif OPT_ECHO[0] == $1[1]
106
 
            self.write(IAC + DO + OPT_ECHO)
107
 
          elsif OPT_SGA[0]  == $1[1]
108
 
            @telnet_option["SGA"] = true
109
 
            self.write(IAC + DO + OPT_SGA)
110
 
          else
111
 
            self.write(IAC + DONT + $1[1..1])
112
 
          end
113
 
          ''
114
 
        elsif WONT[0] == $1[0]  # respond to "IAC WON'T x"
115
 
          if    OPT_ECHO[0] == $1[1]
116
 
            self.write(IAC + DONT + OPT_ECHO)
117
 
          elsif OPT_SGA[0]  == $1[1]
118
 
            @telnet_option["SGA"] = false
119
 
            self.write(IAC + DONT + OPT_SGA)
120
 
          else
121
 
            self.write(IAC + DONT + $1[1..1])
122
 
          end
123
 
          ''
124
 
        elsif SB[0] == $1[0]    # respond to "IAC SB xxx IAC SE"
125
 
          if    OPT_STARTTLS[0] == $1[1] && TLS_FOLLOWS[0] == $2[0]
126
 
            @sock = OpenSSL::SSL::SSLSocket.new(@sock)
127
 
            @sock.cert            = @options['Cert'] unless @sock.cert
128
 
            @sock.key             = @options['Key'] unless @sock.key
129
 
            @sock.ca_cert         = @options['CACert']
130
 
            @sock.ca_file         = @options['CAFile']
131
 
            @sock.ca_path         = @options['CAPath']
132
 
            @sock.timeout         = @options['Timeout']
133
 
            @sock.verify_mode     = @options['VerifyMode']
134
 
            @sock.verify_callback = @options['VerifyCallback']
135
 
            @sock.verify_depth    = @options['VerifyDepth']
136
 
            @sock.connect
137
 
            @ssl = true
138
 
          end
139
 
          ''
140
 
        else
141
 
          ''
142
 
        end
143
 
      end
144
 
    end # preprocess
145
 
    
146
 
    alias waitfor_org waitfor
147
 
 
148
 
    def waitfor(options)
149
 
      time_out = @options["Timeout"]
150
 
      waittime = @options["Waittime"]
151
 
 
152
 
      if options.kind_of?(Hash)
153
 
        prompt   = if options.has_key?("Match")
154
 
                     options["Match"]
155
 
                   elsif options.has_key?("Prompt")
156
 
                     options["Prompt"]
157
 
                   elsif options.has_key?("String")
158
 
                     Regexp.new( Regexp.quote(options["String"]) )
159
 
                   end
160
 
        time_out = options["Timeout"]  if options.has_key?("Timeout")
161
 
        waittime = options["Waittime"] if options.has_key?("Waittime")
162
 
      else
163
 
        prompt = options
164
 
      end
165
 
 
166
 
      if time_out == false
167
 
        time_out = nil
168
 
      end
169
 
 
170
 
      line = ''
171
 
      buf = ''
172
 
      @rest = '' unless @rest
173
 
 
174
 
      until(prompt === line and not IO::select([@sock], nil, nil, waittime))
175
 
        unless IO::select([@sock], nil, nil, time_out)
176
 
          raise TimeoutError, "timed-out; wait for the next data"
177
 
        end
178
 
        begin
179
 
          c = @rest + @sock.sysread(1024 * 1024)
180
 
          @dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
181
 
          if @options["Telnetmode"]   
182
 
            pos = 0
183
 
            catch(:next){
184
 
              while true
185
 
                case c[pos]
186
 
                when IAC[0]
187
 
                  case c[pos+1]
188
 
                  when DO[0], DONT[0], WILL[0], WONT[0]
189
 
                    throw :next unless c[pos+2]
190
 
                    pos += 3
191
 
                  when SB[0]
192
 
                    ret = detect_sub_negotiation(c, pos)
193
 
                    throw :next unless ret
194
 
                    pos = ret
195
 
                  when nil
196
 
                    throw :next
197
 
                  else
198
 
                    pos += 2
199
 
                  end
200
 
                when nil
201
 
                  throw :next
202
 
                else
203
 
                  pos += 1
204
 
                end
205
 
              end
206
 
            }
207
 
 
208
 
            buf = preprocess(c[0...pos])
209
 
            @rest = c[pos..-1]
210
 
          end
211
 
          @log.print(buf) if @options.has_key?("Output_log")
212
 
          line.concat(buf)
213
 
          yield buf if block_given?   
214
 
        rescue EOFError # End of file reached
215
 
          if line == ''
216
 
            line = nil
217
 
            yield nil if block_given? 
218
 
          end
219
 
          break
220
 
        end
221
 
      end
222
 
      line
223
 
    end
224
 
 
225
 
    private
226
 
 
227
 
    def detect_sub_negotiation(data, pos)
228
 
      return nil if data.length < pos+6  # IAC SB x param IAC SE
229
 
      pos += 3
230
 
      while true
231
 
        case data[pos]
232
 
        when IAC[0]
233
 
          if data[pos+1] == SE[0]
234
 
            pos += 2
235
 
            return pos
236
 
          else
237
 
            pos += 2
238
 
          end
239
 
        when nil
240
 
          return nil
241
 
        else
242
 
          pos += 1
243
 
        end
244
 
      end
245
 
    end
246
 
 
247
 
  end
248
 
end