source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/net/telnets.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 7.7 KB
Line 
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 <[email protected]>
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
20This class will initiate SSL/TLS session automaticaly if the server
21sent 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
35Or, the new options ('Cert', 'Key' and 'CACert') are available from
36Michal 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
53This class is expected to be a superset of usual Net::Telnet.
54=end
55
56require "net/telnet"
57require "openssl"
58
59module 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
248end
Note: See TracBrowser for help on using the repository browser.