net-tns 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/bin/tns_oradb_version.rb +15 -0
  4. data/bin/tns_sid_enumeration.rb +52 -0
  5. data/bin/tns_sid_list.rb +43 -0
  6. data/lib/net/tns/client.rb +94 -0
  7. data/lib/net/tns/connection.rb +201 -0
  8. data/lib/net/tns/exceptions.rb +34 -0
  9. data/lib/net/tns/gem_version.rb +5 -0
  10. data/lib/net/tns/helpers/string_helpers.rb +49 -0
  11. data/lib/net/tns/packet.rb +82 -0
  12. data/lib/net/tns/packets/abort_packet.rb +12 -0
  13. data/lib/net/tns/packets/accept_packet.rb +19 -0
  14. data/lib/net/tns/packets/ack_packet.rb +7 -0
  15. data/lib/net/tns/packets/attention_packet.rb +9 -0
  16. data/lib/net/tns/packets/connect_packet.rb +55 -0
  17. data/lib/net/tns/packets/control_packet.rb +7 -0
  18. data/lib/net/tns/packets/data_packet.rb +20 -0
  19. data/lib/net/tns/packets/marker_packet.rb +18 -0
  20. data/lib/net/tns/packets/null_packet.rb +7 -0
  21. data/lib/net/tns/packets/redirect_packet.rb +10 -0
  22. data/lib/net/tns/packets/refuse_packet.rb +12 -0
  23. data/lib/net/tns/packets/resend_packet.rb +7 -0
  24. data/lib/net/tns/version.rb +15 -0
  25. data/lib/net/tns.rb +20 -0
  26. data/lib/net/tti/client.rb +90 -0
  27. data/lib/net/tti/connection.rb +142 -0
  28. data/lib/net/tti/crypto.rb +189 -0
  29. data/lib/net/tti/data_types/chunked_string.rb +63 -0
  30. data/lib/net/tti/data_types/key_value_pair.rb +25 -0
  31. data/lib/net/tti/data_types.rb +2 -0
  32. data/lib/net/tti/exceptions.rb +62 -0
  33. data/lib/net/tti/message.rb +50 -0
  34. data/lib/net/tti/messages/data_type_negotiation_request.rb +133 -0
  35. data/lib/net/tti/messages/data_type_negotiation_response.rb +9 -0
  36. data/lib/net/tti/messages/error_message.rb +14 -0
  37. data/lib/net/tti/messages/function_call.rb +46 -0
  38. data/lib/net/tti/messages/function_calls/authentication.rb +45 -0
  39. data/lib/net/tti/messages/function_calls/authentication_x64.rb +42 -0
  40. data/lib/net/tti/messages/function_calls/authentication_x86.rb +53 -0
  41. data/lib/net/tti/messages/function_calls/pre_authentication_response.rb +32 -0
  42. data/lib/net/tti/messages/protocol_negotiation_request.rb +29 -0
  43. data/lib/net/tti/messages/protocol_negotiation_response.rb +44 -0
  44. data/lib/net/tti.rb +18 -0
  45. metadata +128 -0
@@ -0,0 +1,189 @@
1
+ require 'openssl'
2
+
3
+ module Net::TTI
4
+ class Crypto
5
+ # Generates the encrypted password and encrypted client session key for
6
+ # authentication with a 10g server.
7
+ #
8
+ # @param username [String] The username for authentication.
9
+ # @param password [String] The password for authentication.
10
+ # @param enc_server_session_key [String] The encrypted server session key.
11
+ # provided by the server. This should be a 32-byte binary packed string.
12
+ # @return [Array<String>] The encrypted password and the encrypted client
13
+ # session key to use to authenticate with the server. These are returned
14
+ # as binary packed strings.
15
+ def self.get_10g_auth_values( username, password, enc_server_session_key )
16
+ # Hash the password and pad it to 16 bytes. This will be used as the key
17
+ # for encrypting the client session key and decrypting the server session key.
18
+ password_hash = hash_password_10g( username, password )
19
+ password_hash += "\0" * 8
20
+
21
+ # TODO: make random client session key
22
+ client_session_key = "FAF5034314546426F329B1DAB1CDC5B8FF94349E0875623160350B0E13A0DA36".tns_unhexify
23
+
24
+ # Encrypt client session key and decrypt the server session key, using the
25
+ # password hash as a key.
26
+ enc_client_session_key = openssl_encrypt( "AES-128-CBC", password_hash, nil, client_session_key )
27
+ server_session_key = openssl_decrypt( "AES-128-CBC", password_hash, nil, enc_server_session_key )
28
+
29
+ # Make the combined session key hash. This is used as the key to encrypt
30
+ # the password.
31
+ combo_session_key = create_combined_session_key_hash_10g( server_session_key, client_session_key )
32
+
33
+ # TODO: make random salt
34
+ salt = "4C31AFE05F3B012C0AE9AB0CDFF0C508".tns_unhexify
35
+ # Encrypt the salted password
36
+ enc_password = openssl_encrypt( "AES-128-CBC", combo_session_key, nil, salt + password, true )
37
+
38
+ return enc_password, enc_client_session_key
39
+ end
40
+
41
+ # Generates the encrypted password and encrypted client session key for
42
+ # authentication with an 11g server.
43
+ #
44
+ # @param password [String] The password for authentication.
45
+ # @param enc_server_session_key [String] The encrypted server session key.
46
+ # provided by the server. This should be a 48-byte binary packed string.
47
+ # @param auth_vfr_data [String] The value from the AUTH_VFR_DATA key-value
48
+ # pair provided by the server.
49
+ # @return [Array<String>] The encrypted password and the encrypted client
50
+ # session key to use to authenticate with the server. These are returned
51
+ # as binary packed strings.
52
+ def self.get_11g_auth_values( password, enc_server_session_key, auth_vfr_data )
53
+ # Hash the password and auth_vfr_data and pad it to 24 bytes. This will be
54
+ # used as the key for encrypting the client session key and decrypting the
55
+ # server session key.
56
+ password_hash = sha1_digest( password + auth_vfr_data ) + ("\0" * 4)
57
+
58
+ # TODO: make random client session key
59
+ client_session_key = "080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808".tns_unhexify
60
+
61
+ # Encrypt client session key and decrypt the server session key, using the
62
+ # password hash as a key.
63
+ enc_client_session_key = openssl_encrypt( "AES-192-CBC", password_hash, nil, client_session_key )
64
+ server_session_key = openssl_decrypt( "AES-192-CBC", password_hash, nil, enc_server_session_key )
65
+
66
+ # Make the combined session key hash. This is used as the key to encrypt
67
+ # the password.
68
+ combo_session_key = create_combined_session_key_hash_11g( server_session_key, client_session_key )
69
+
70
+ # TODO: make random salt
71
+ salt = "4C31AFE05F3B012C0AE9AB0CDFF0C508".tns_unhexify
72
+ # Encrypt the salted password
73
+ enc_password = openssl_encrypt( "AES-192-CBC", combo_session_key, nil, salt + password, true )
74
+
75
+ return enc_password, enc_client_session_key
76
+ end
77
+
78
+
79
+
80
+ # Generates the password hash for use in 10g authentication.
81
+ #
82
+ # @param username [String] The username for authentication.
83
+ # @param password [String] The password for authentication.
84
+ # @return [String] The password hash, as a binary packed string.
85
+ def self.hash_password_10g( username, password )
86
+ uspw = (username + password).upcase().encode( Encoding::UTF_16BE )
87
+ key = "0123456789abcdef".tns_unhexify # fixed key used for 10g hashing
88
+
89
+ # Pad the username-password to an 8-byte boundary
90
+ if ( uspw.length % 4 > 0 )
91
+ padding_length = 4 - ( uspw.length % 4 )
92
+ uspw += ("\0".encode( Encoding::UTF_16BE )) * padding_length
93
+ end
94
+
95
+ key2 = openssl_encrypt( "DES-CBC", key, nil, uspw, false )
96
+ key2 = key2[-8,8]
97
+
98
+ pwhash = openssl_encrypt( "DES-CBC", key2, nil, uspw, false )
99
+ pwhash = pwhash[-8,8]
100
+ end
101
+
102
+ # Generates the combined session key hash, for use in encrypting the
103
+ # password in authentication.
104
+ #
105
+ # @param server_session_key [String] The unencrypted server session key, as
106
+ # a binary packed string.
107
+ # @param client_session_key [String] The unencrypted client session key, as
108
+ # a binary packed string.
109
+ # @return [String] The hash of the combined session key, as a binary packed
110
+ # string.
111
+ def self.create_combined_session_key_hash_10g( server_session_key, client_session_key )
112
+ # Unpack the session keys into byte arrays
113
+ server_key_bytes = server_session_key.unpack( "C*" )
114
+ client_key_bytes = client_session_key.unpack( "C*" )
115
+ combo_session_key = ""
116
+
117
+ # XOR bytes 17-32 of the session keys to make the combined session key
118
+ for byte_itr in (16..31)
119
+ combo_session_key += (server_key_bytes[ byte_itr ] ^ client_key_bytes[ byte_itr ]).chr
120
+ end
121
+
122
+ # Hash the combined session key
123
+ return md5_digest( combo_session_key )
124
+ end
125
+
126
+ # Generates the combined session key hash, for use in encrypting the
127
+ # password in authentication.
128
+ #
129
+ # @param server_session_key [String] The unencrypted server session key, as
130
+ # a binary packed string.
131
+ # @param client_session_key [String] The unencrypted client session key, as
132
+ # a binary packed string.
133
+ # @return [String] The hash of the combined session key, as a binary packed
134
+ # string.
135
+ def self.create_combined_session_key_hash_11g( server_session_key, client_session_key )
136
+ # make combined session key
137
+ server_key_bytes = server_session_key.unpack( "C*" )
138
+ client_key_bytes = client_session_key.unpack( "C*" )
139
+ combo_session_key = ""
140
+ for byte_itr in (16..39)
141
+ combo_session_key += (server_key_bytes[ byte_itr ] ^ client_key_bytes[ byte_itr ]).chr
142
+ end
143
+
144
+ # hash combined session key
145
+ combo_session_key = ( md5_digest(combo_session_key[0,16]) +
146
+ md5_digest(combo_session_key[16,combo_session_key.length]) )
147
+ combo_session_key = combo_session_key[0,24]
148
+
149
+ return combo_session_key
150
+ end
151
+
152
+
153
+ # Helper function for encryption.
154
+ def self.openssl_encrypt( cipher, key, iv, data, padding=false )
155
+ cipher = OpenSSL::Cipher::Cipher.new( cipher )
156
+ cipher.encrypt
157
+ cipher.key = key
158
+ cipher.iv = iv unless iv.nil?
159
+ cipher.padding = 0 unless padding
160
+
161
+ ciphertext = cipher.update( data ) + cipher.final
162
+ end
163
+
164
+ # Helper function for decryption.
165
+ def self.openssl_decrypt( cipher, key, iv, data, padding=false )
166
+ cipher = OpenSSL::Cipher::Cipher.new( cipher )
167
+ cipher.decrypt
168
+ cipher.key = key
169
+ cipher.iv = iv unless iv.nil?
170
+ cipher.padding = 0 unless padding
171
+
172
+ ciphertext = cipher.update( data ) + cipher.final
173
+ end
174
+
175
+ # @return the MD5 digest (as a binary string) for the given input string
176
+ def self.md5_digest(input_str)
177
+ digester=Digest::MD5.new()
178
+ digester.update(input_str)
179
+ return digester.digest
180
+ end
181
+
182
+ # @return the SHA1 digest (as a binary string) for the given input string
183
+ def self.sha1_digest(input_str)
184
+ digester=Digest::SHA1.new()
185
+ digester.update(input_str)
186
+ return digester.digest
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,63 @@
1
+ require "bindata"
2
+
3
+ module Net
4
+ module TTI
5
+ module DataTypes
6
+ class ChunkedString < BinData::BasePrimitive
7
+ # The marker to indicate that a string is being divided into multiple chunks
8
+ MULTI_CHUNK_MARKER = 0xFE
9
+ MULTI_CHUNK_TERMINATOR = 0x00
10
+ # The apparent maximum chunk length used by Oracle TNS implementations
11
+ MAX_CHUNK_LENGTH = 0x40
12
+
13
+ def sensible_default
14
+ return ""
15
+ end
16
+
17
+ def read_and_return_value(io)
18
+ begin
19
+ length = unmarshal_uint8(io)
20
+ rescue EOFError
21
+ return ""
22
+ end
23
+
24
+ if length == MULTI_CHUNK_MARKER
25
+ data = ""
26
+ while (length = unmarshal_uint8(io)) != MULTI_CHUNK_TERMINATOR
27
+ data += io.readbytes(length)
28
+ end
29
+
30
+ return data
31
+ else
32
+ return io.readbytes(length)
33
+ end
34
+ end
35
+
36
+ def value_to_binary_string(value)
37
+ return "" if value.empty?
38
+
39
+ if value.length > MAX_CHUNK_LENGTH
40
+ value_index = 0
41
+
42
+ binary_string = ""
43
+ binary_string << [MULTI_CHUNK_MARKER].pack("C")
44
+ while value_index < value.length
45
+ chunk = value[value_index, MAX_CHUNK_LENGTH]
46
+ binary_string << [chunk.length, chunk].pack("Ca*")
47
+ value_index += MAX_CHUNK_LENGTH
48
+ end
49
+ binary_string << [MULTI_CHUNK_TERMINATOR].pack("C")
50
+ else
51
+ return [value.length, value].pack("Ca*")
52
+ end
53
+ end
54
+
55
+ private
56
+ def unmarshal_uint8(io)
57
+ int_string = io.readbytes(1)
58
+ return int_string.unpack("C").first
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,25 @@
1
+ require "bindata"
2
+ require "net/tti/data_types/chunked_string"
3
+
4
+ module Net
5
+ module TTI
6
+ module DataTypes
7
+ class KeyValuePair < BinData::Record
8
+ # In earlier dialects, the 4 bytes before the strings appeared to contain
9
+ # the total length of the string. In more recent dialects, this no longer
10
+ # seems to be the case. However, a 32-bit null here still appears to
11
+ # signal that there is no value.
12
+ uint32le :unknown1, :value => lambda {kvp_key.length}
13
+ chunked_string :kvp_key, :onlyif => lambda {unknown1 != 0}
14
+ uint32le :unknown2, :value => lambda {kvp_value.length}
15
+ chunked_string :kvp_value, :onlyif => lambda {unknown2 != 0}
16
+ uint32le :flags
17
+
18
+ def set(key, value)
19
+ self.kvp_key.data = key
20
+ self.kvp_value.data = value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ require "net/tti/data_types/chunked_string"
2
+ require "net/tti/data_types/key_value_pair"
@@ -0,0 +1,62 @@
1
+ module Net::TTI
2
+ module Exceptions
3
+ class TTIException < StandardError
4
+ end
5
+
6
+ class ProtocolException < TTIException
7
+ end
8
+
9
+ class UnsupportedTarget < TTIException
10
+ end
11
+
12
+ class UnsupportedPlatform < UnsupportedTarget
13
+ def initialize( platform )
14
+ super( "Unsupported platform: #{platform}" )
15
+ end
16
+ end
17
+
18
+ class UnsupportedTNSVersion < UnsupportedTarget
19
+ def initialize( version )
20
+ super( "Unsupported version: #{version}" )
21
+ end
22
+ end
23
+
24
+
25
+
26
+ class ErrorMessageReceived < TTIException
27
+ ERROR_REGEX = /ORA\-(\d+)(?:\:\ (.*))?/
28
+ ERROR_REGEX_INDEX_CODE = 1
29
+ ERROR_REGEX_INDEX_DESCRIPTION = 2
30
+
31
+ # Attempts to parse and return the "ORA-xxxxx" error code from the error message
32
+ # @return [Integer] A numeric error code, or nil if the code could not be determined
33
+ def error_code()
34
+ matches = ERROR_REGEX.match( self.message )
35
+ error_code = matches[ERROR_REGEX_INDEX_CODE] unless( matches.nil? or matches[ERROR_REGEX_INDEX_CODE].nil? )
36
+ error_code = error_code.to_i unless error_code.nil?
37
+ return error_code
38
+ end
39
+
40
+
41
+ # Attempts to parse and return the error description after the "ORA-xxxxx"
42
+ # error code in the error message
43
+ # @return [String] A string containing the error description, or nil if the description could not be determined
44
+ def error_description()
45
+ matches = ERROR_REGEX.match( self.message )
46
+ return matches[ERROR_REGEX_INDEX_DESCRIPTION] unless( matches.nil? or matches[ERROR_REGEX_INDEX_DESCRIPTION].nil? )
47
+ end
48
+ end
49
+
50
+ class AuthenticationError < ErrorMessageReceived
51
+ end
52
+
53
+ class InvalidCredentialsError < AuthenticationError
54
+ end
55
+
56
+ class AccountLockedOutError < AuthenticationError
57
+ end
58
+
59
+ class PasswordExpiredError < AuthenticationError
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ require "bindata"
2
+
3
+ module Net
4
+ module TTI
5
+ class Message < BinData::Record
6
+ TTC_CODE_PROTOCOL_NEGOTIATION = 0x1
7
+ TTC_CODE_DATA_TYPE_NEGOTIATION = 0x2
8
+ TTC_CODE_FUNCTION_CALL = 0x3
9
+ TTC_CODE_ERROR = 0x4
10
+ TTC_CODE_OK = 0x8
11
+
12
+ # BinData fields
13
+ uint8 :ttc_code, :initial_value => :_ttc_code
14
+
15
+ def _ttc_code
16
+ raise NotImplementedError
17
+ end
18
+ private :_ttc_code
19
+
20
+ def self.handles_response_for_ttc_code(ttc_code)
21
+ @@ttc_classes ||= {}
22
+ @@ttc_codes ||= {}
23
+ if @@ttc_classes.has_key?(ttc_code)
24
+ existing_class = @@ttc_classes[ttc_code]
25
+ raise("Duplicate TTC response handlers defined: #{existing_class} and #{self} both have TTC code of #{ttc_code}")
26
+ end
27
+
28
+ @@ttc_classes[ttc_code] = self
29
+ @@ttc_codes[self] = ttc_code
30
+ return nil
31
+ end
32
+
33
+ def self.from_data_string( raw_message )
34
+ ttc_code = raw_message[0].unpack("C").first
35
+
36
+ unless message_class = @@ttc_classes[ ttc_code ]
37
+ raise Net::TNS::Exceptions::TnsException.new( "Unknown TTC code: #{ttc_code}" )
38
+ end
39
+
40
+ new_message = message_class.new
41
+ new_message.read( raw_message )
42
+
43
+ return new_message
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ require "pathname"
50
+ Dir.glob("#{Pathname.new(__FILE__).dirname}/messages/**/*.rb") { |file| require file }
@@ -0,0 +1,133 @@
1
+ module Net
2
+ module TTI
3
+ class DataTypeNegotiationRequest < Message
4
+ # BinData fields
5
+
6
+ # Not sure why this is duplicated, but clients always send the same
7
+ # character set in both fields.
8
+ # Character sets:
9
+ # 0x00b2 (178) - US-ASCII
10
+ # 0x0369 (873) - UTF-8
11
+ uint16le :charset1
12
+ uint16le :charset2
13
+ uint8 :unknown1
14
+ uint8 :unknown2_length, :value => lambda { unknown2.length }
15
+ string :unknown2
16
+ uint8 :unknown3_length, :value => lambda { unknown3.length }
17
+ string :unknown3
18
+ string :unknown4
19
+
20
+ UNKNOWN4_LINUX = (
21
+ "800000003c3c3c80000000d007000100010001000000020002000a0000000800" +
22
+ "0800010000000c000c000a000000170017000100000018001800010000001900" +
23
+ "190018001900010000001a001a0019001a00010000001b001b000a001b000100" +
24
+ "00001c001c0016001c00010000001d001d0017001d00010000001e001e001700" +
25
+ "1e00010000001f001f0019001f0001000000200020000a002000010000002100" +
26
+ "21000a002100010000000a000a00010000000b000b0001000000280028000100" +
27
+ "0000290029000100000075007500010000007800780001000001220122000100" +
28
+ "0001230123000101230001000001240124000100000125012500010000012601" +
29
+ "2600010000012a012a00010000012b012b00010000012c012c00010000012d01" +
30
+ "2d00010000012e012e00010000012f012f000100000130013000010000013101" +
31
+ "3100010000013201320001000001330133000100000134013400010000013501" +
32
+ "3500010000013601360001000001370137000100000138013800010000013901" +
33
+ "3900010000013b013b00010000013c013c00010000013d013d00010000013e01" +
34
+ "3e00010000013f013f0001000001400140000100000141014100010000014201" +
35
+ "4200010000014301430001000001470147000100000148014800010000014901" +
36
+ "4900010000014b014b00010000014d014d00010000014e014e00010000014f01" +
37
+ "4f00010000015001500001000001510151000100000152015200010000015301" +
38
+ "5300010000015401540001000001550155000100000156015600010000015701" +
39
+ "57000101570001000001580158000100000159015900010000015a015a000100" +
40
+ "00015c015c00010000015d015d00010000016201620001000001630163000100" +
41
+ "000167016700010000016b016b00010000017c017c0001014200010000017d01" +
42
+ "7d00010000017e017e00010000017f017f000100000180018000010000018101" +
43
+ "8100010000018201820001000001830183000100000184018400010000018501" +
44
+ "8500010000018601860001000001870187000100000189018900010000018a01" +
45
+ "8a00010000018b018b00010000018c018c00010000018d018d00010000018e01" +
46
+ "8e00010000018f018f0001000001900190000100000191019100010000019401" +
47
+ "9400010125000100000195019500010000019601960001000001970197000100" +
48
+ "00019d019d00010000019e019e00010000019f019f0001000001a001a0000100" +
49
+ "0001a101a10001000001a201a20001000001a301a30001000001a401a4000100" +
50
+ "0001a501a50001000001a601a60001000001a701a70001000001a801a8000100" +
51
+ "0001a901a90001000001aa01aa0001000001ab01ab0001000001ad01ad000100" +
52
+ "0001ae01ae0001000001af01af0001000001b001b00001000001b101b1000100" +
53
+ "0001c101c10001000001c201c2000101250001000001c601c60001000001c701" +
54
+ "c70001000001c801c80001000001c901c90001000001ca01ca0001019f000100" +
55
+ "0001cb01cb000101a00001000001cc01cc000101a20001000001cd01cd000101" +
56
+ "a30001000001ce01ce000101b10001000001cf01cf000101220001000001d201" +
57
+ "d20001000001d301d3000101ab0001000001d401d40001000001d501d5000100" +
58
+ "0001d601d60001000001d701d70001000001d801d80001000001d901d9000100" +
59
+ "0001da01da0001000001db01db0001000001dc01dc0001000001dd01dd000100" +
60
+ "0001de01de0001000001df01df0001000001e001e00001000001e101e1000100" +
61
+ "0001e201e20001000001e301e30001016b0001000001e401e40001000001e501" +
62
+ "e50001000001e601e60001000001ea01ea0001000001eb01eb0001000001ec01" +
63
+ "ec0001000001ed01ed0001000001ee01ee0001000001ef01ef0001000001f001" +
64
+ "f00001000001f201f20001000001f301f30001000001f401f40001000001f501" +
65
+ "f50001000001f601f60001000001fd01fd0001000001fe01fe00010000020102" +
66
+ "0100010000020202020001000002040204000100000205020500010000020602" +
67
+ "0600010000020702070001000002080208000100000209020900010000020a02" +
68
+ "0a00010000020b020b00010000020c020c00010000020d020d00010000020e02" +
69
+ "0e00010000020f020f0001000002100210000100000211021100010000021202" +
70
+ "1200010000021302130001000002140214000100000215021500010000021602" +
71
+ "1600010000021702170001000002180218000100000219021900010000021a02" +
72
+ "1a00010000021b021b00010000021c021c00010000021d021d00010000021e02" +
73
+ "1e00010000021f021f0001000002200220000100000221022100010000022202" +
74
+ "2200010000022302230001000002240224000100000225022500010000022602" +
75
+ "2600010000022702270001000002280228000100000229022900010000022a02" +
76
+ "2a00010000022b022b00010000022c022c00010000022d022d00010000022e02" +
77
+ "2e00010000022f022f0001000002310231000100000232023200010000023302" +
78
+ "3300010000023402340001000002370237000100000238023800010000023902" +
79
+ "3900010000023a023a00010000023b023b00010000023c023c00010000023d02" +
80
+ "3d00010000023e023e00010000023f023f000100000240024000010000024102" +
81
+ "4100010000024202420001000002430243000100000244024400010000024502" +
82
+ "4500010000024602460001000002470247000100000248024800010000024902" +
83
+ "490001000000030002000a000000040002000a00000005000100010000000600" +
84
+ "02000a000000070002000a00000009000100010000000d0000000e0000000f00" +
85
+ "1700010000001000000011000000120000001300000014000000150000001600" +
86
+ "00002700780001015d0001012600010000003a003a0001000000440002000a00" +
87
+ "000045000000460000004a006d00010000004c0000005b0002000a0000005e00" +
88
+ "0100010000005f00170001000000600060000100000061006000010000006400" +
89
+ "6400010000006500650001000000660066000100000068000000690000006a00" +
90
+ "6a00010000006c006d00010000006d006d00010000006e006f00010000006f00" +
91
+ "6f00010000007000700001000000710071000100000072007200010000007300" +
92
+ "7300010000007400660001000000760000007700000079007900010000007a00" +
93
+ "7a00010000007b007b0001000000880000009200920001000000930093000100" +
94
+ "0000980002000a000000990002000a0000009a0002000a0000009b0001000100" +
95
+ "00009c000c000a000000ac0002000a000000b200b20001000000b300b3000100" +
96
+ "0000b400b40001000000b500b50001000000b600b60001000000b700b7000100" +
97
+ "0000b8000c000a000000b900b20001000000ba00b30001000000bb00b4000100" +
98
+ "0000bc00b50001000000bd00b60001000000be00b70001000000bf000000c000" +
99
+ "0000c300700001000000c400710001000000c500720001000000d000d0000100" +
100
+ "0000d1000000e700e70001000000e800e70001000000e900e90001000000f100" +
101
+ "6d0001000002030203000100000000").tns_unhexify
102
+
103
+ def _ttc_code()
104
+ TTC_CODE_DATA_TYPE_NEGOTIATION
105
+ end
106
+ private :_ttc_code
107
+
108
+ def self.create_request(platform)
109
+ request = self.new
110
+ request.character_set = 0x00b2
111
+ request.unknown1 = 0x02
112
+ request.unknown2 = "060101010d01010401010101010101ffff0308030001003f01073f010101010301".tns_unhexify
113
+ request.unknown3 = "0201000018".tns_unhexify
114
+
115
+ case platform
116
+ when :linux
117
+ request.unknown4 = UNKNOWN4_LINUX
118
+ when :windows
119
+ request.unknown4 = "800000003c3c3c80000000d007".tns_unhexify
120
+ else
121
+ raise Net::TTI::Exceptions::UnsupportedPlatform.new( platform )
122
+ end
123
+
124
+ return request
125
+ end
126
+
127
+ def character_set=(charset)
128
+ self.charset1 = charset
129
+ self.charset2 = charset
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,9 @@
1
+ module Net
2
+ module TTI
3
+ class DataTypeNegotiationResponse < Message
4
+ handles_response_for_ttc_code TTC_CODE_DATA_TYPE_NEGOTIATION
5
+ # BinData fields
6
+ rest :data
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module Net
2
+ module TTI
3
+ class ErrorMessage < Message
4
+ handles_response_for_ttc_code TTC_CODE_ERROR
5
+
6
+ # BinData fields
7
+ string :unknown1, :read_length => 6
8
+ uint16le :unknown2
9
+ string :unknown3, :read_length => lambda { unknown2 == 0x01 ? 87 : 57 }
10
+ uint8 :message_length
11
+ string :message, :read_length => lambda { message_length }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ module Net
2
+ module TTI
3
+ class FunctionCall < Message
4
+ handles_response_for_ttc_code TTC_CODE_FUNCTION_CALL
5
+
6
+ FUNCTION_CODE_PRE_AUTH = 0x76
7
+ FUNCTION_CODE_AUTH = 0x73
8
+
9
+ # BinData fields
10
+ # The function code: 0x76 => preauth, 0x73 => auth
11
+ uint8 :function_code, :initial_value => :_function_code
12
+ uint8 :sequence_number, :initial_value => :_sequence_number
13
+
14
+ def _ttc_code
15
+ return TTC_CODE_FUNCTION_CALL
16
+ end
17
+ private :_ttc_code
18
+
19
+ def _function_code
20
+ raise NotImplementedError
21
+ end
22
+ private :_function_code
23
+
24
+ def _sequence_number
25
+ @@seq_num ||= 0
26
+ @@seq_num += 1
27
+ return @@seq_num
28
+ end
29
+ private :_sequence_number
30
+
31
+ def to_binary_s
32
+ if sequence_number == 0
33
+ sequence_number = FunctionCall.next_sequence_number
34
+ end
35
+
36
+ super
37
+ end
38
+
39
+ def self.next_sequence_number
40
+ @@last_sequence_number ||= 0
41
+ @@last_sequence_number = (@@last_sequence_number + 1) % 256
42
+ return @@last_sequence_number
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,45 @@
1
+ require "net/tti/data_types"
2
+
3
+ module Net
4
+ module TTI
5
+ class Authentication < FunctionCall
6
+ LOGON_MODE_PRE_AUTH = 0x00000001
7
+ LOGON_MODE_AUTH = 0x00000101
8
+
9
+ def self.create_pre_auth_request(target_architecture)
10
+ case target_architecture
11
+ when :x86
12
+ return PreAuthenticationX86.new
13
+ when :x64
14
+ return PreAuthenticationX64.new
15
+ else
16
+ raise Net::TTI::Exceptions::UnsupportedPlatform.new(target_architecture)
17
+ end
18
+ end
19
+
20
+ def self.create_auth_request(target_architecture)
21
+ case target_architecture
22
+ when :x86
23
+ return AuthenticationX86.new
24
+ when :x64
25
+ return AuthenticationX64.new
26
+ else
27
+ raise Net::TTI::Exceptions::UnsupportedPlatform.new(target_architecture)
28
+ end
29
+ end
30
+
31
+ def add_parameter( key, value, flags=0 )
32
+ kvp = DataTypes::KeyValuePair.new( :kvp_key => key, :kvp_value => value, :flags => flags )
33
+ self.parameters << kvp
34
+ end
35
+
36
+ def enc_client_session_key=(enc_client_session_key)
37
+ add_parameter( "AUTH_SESSKEY", enc_client_session_key.tns_hexify.upcase, 1 )
38
+ end
39
+
40
+ def enc_password=(enc_password)
41
+ add_parameter( "AUTH_PASSWORD", enc_password.tns_hexify.upcase )
42
+ end
43
+ end
44
+ end
45
+ end