ruby_smb 3.0.5 → 3.1.1
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -3
- data/.github/workflows/verify.yml +1 -1
- data/.simplecov +1 -1
- data/CONTRIBUTING.md +28 -3
- data/README.md +8 -0
- data/examples/pwsh_service.rb +112 -0
- data/lib/ruby_smb/client/encryption.rb +16 -4
- data/lib/ruby_smb/client/negotiation.rb +10 -8
- data/lib/ruby_smb/dcerpc/request.rb +2 -0
- data/lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/svcctl.rb +66 -5
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg.rb +1 -1
- data/lib/ruby_smb/fscc/file_information.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +4 -0
- data/lib/ruby_smb/server/server_client/encryption.rb +66 -0
- data/lib/ruby_smb/server/server_client/negotiation.rb +14 -3
- data/lib/ruby_smb/server/server_client/session_setup.rb +18 -3
- data/lib/ruby_smb/server/server_client/share_io.rb +17 -0
- data/lib/ruby_smb/server/server_client/tree_connect.rb +40 -3
- data/lib/ruby_smb/server/server_client.rb +147 -37
- data/lib/ruby_smb/server/share/provider/disk/file_system.rb +28 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +42 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +143 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +359 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +69 -0
- data/lib/ruby_smb/server/share/provider/disk/processor.rb +159 -0
- data/lib/ruby_smb/server/share/provider/disk.rb +4 -416
- data/lib/ruby_smb/server/share/provider/pipe.rb +2 -2
- data/lib/ruby_smb/server/share/provider/processor.rb +16 -0
- data/lib/ruby_smb/signing.rb +18 -4
- data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +1 -1
- data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +1 -1
- data/lib/ruby_smb/smb1/commands.rb +1 -0
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +11 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +5 -4
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +12 -4
- data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +9 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +52 -51
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +37 -37
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_both_directory_info.rb +48 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +28 -15
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +51 -51
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +36 -36
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +40 -39
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +40 -40
- data/lib/ruby_smb/smb1/packet/trans2/query_file_information_request.rb +60 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_file_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info.rb +31 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +40 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +46 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_basic_info.rb +23 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_standard_info.rb +22 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level.rb +62 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_path_information_request.rb +65 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_path_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +24 -8
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +4 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +29 -20
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +42 -42
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +23 -23
- data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +23 -5
- data/lib/ruby_smb/smb1/packet/trans2.rb +4 -0
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -1
- data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/negotiate_context.rb +10 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +7 -7
- data/lib/ruby_smb/smb2.rb +1 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +31 -8
- data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb +143 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb +29 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb +29 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +8 -8
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +36 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +35 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_response_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response_spec.rb +88 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_request_spec.rb +79 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_response_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +3 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +7 -2
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -3
- data.tar.gz.sig +0 -0
- metadata +48 -4
- metadata.gz.sig +1 -2
|
@@ -8,7 +8,7 @@ module RubySMB
|
|
|
8
8
|
hide :reserved0
|
|
9
9
|
|
|
10
10
|
endian :little
|
|
11
|
-
bit32 :protocol, label: 'Protocol ID Field', initial_value:
|
|
11
|
+
bit32 :protocol, label: 'Protocol ID Field', initial_value: RubySMB::SMB2::SMB2_TRANSFORM_PROTOCOL_ID
|
|
12
12
|
string :signature, label: 'Signature', length: 16
|
|
13
13
|
string :nonce, label: 'Nonce', length: 16
|
|
14
14
|
uint32 :original_message_size, label: 'Original Message Size'
|
|
@@ -22,13 +22,13 @@ module RubySMB
|
|
|
22
22
|
encrypted_data = self.encrypted_data.to_ary.pack('C*')
|
|
23
23
|
|
|
24
24
|
case algorithm
|
|
25
|
-
when 'AES-128-CCM'
|
|
25
|
+
when 'AES-128-CCM', 'AES-256-CCM'
|
|
26
26
|
cipher = OpenSSL::CCM.new('AES', key, 16)
|
|
27
27
|
unencrypted_data = cipher.decrypt(encrypted_data + self.signature, self.nonce[0...11], auth_data)
|
|
28
28
|
unless unencrypted_data.length > 0
|
|
29
29
|
raise OpenSSL::Cipher::CipherError # raised for consistency with GCM mode
|
|
30
30
|
end
|
|
31
|
-
when 'AES-128-GCM'
|
|
31
|
+
when 'AES-128-GCM', 'AES-256-GCM'
|
|
32
32
|
cipher = OpenSSL::Cipher.new(algorithm).decrypt
|
|
33
33
|
cipher.key = key
|
|
34
34
|
cipher.iv = self.nonce[0...12]
|
|
@@ -37,7 +37,7 @@ module RubySMB
|
|
|
37
37
|
unencrypted_data = cipher.update(encrypted_data)
|
|
38
38
|
cipher.final # raises OpenSSL::Cipher::CipherError on signature failure
|
|
39
39
|
else
|
|
40
|
-
raise ArgumentError.new('Invalid algorithm, must be
|
|
40
|
+
raise ArgumentError.new('Invalid algorithm, must be one of AES-128-CCM, AES-128-GCM, AES-256-CCM, or AES-256-GCM')
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
unencrypted_data[0...self.original_message_size]
|
|
@@ -53,14 +53,14 @@ module RubySMB
|
|
|
53
53
|
self.original_message_size.assign(unencrypted_data.length)
|
|
54
54
|
|
|
55
55
|
case algorithm
|
|
56
|
-
when 'AES-128-CCM'
|
|
56
|
+
when 'AES-128-CCM', 'AES-256-CCM'
|
|
57
57
|
cipher = OpenSSL::CCM.new('AES', key, 16)
|
|
58
58
|
random_iv = OpenSSL::Random.random_bytes(11)
|
|
59
59
|
self.nonce.assign(random_iv)
|
|
60
60
|
result = cipher.encrypt(unencrypted_data, random_iv, self.to_binary_s[20...52])
|
|
61
61
|
encrypted_data = result[0...-16]
|
|
62
62
|
auth_tag = result[-16..-1]
|
|
63
|
-
when 'AES-128-GCM'
|
|
63
|
+
when 'AES-128-GCM', 'AES-256-GCM'
|
|
64
64
|
cipher = OpenSSL::Cipher.new(algorithm).encrypt
|
|
65
65
|
cipher.iv_len = 12
|
|
66
66
|
cipher.key = key
|
|
@@ -69,7 +69,7 @@ module RubySMB
|
|
|
69
69
|
encrypted_data = cipher.update(unencrypted_data) + cipher.final
|
|
70
70
|
auth_tag = cipher.auth_tag
|
|
71
71
|
else
|
|
72
|
-
raise ArgumentError.new('Invalid algorithm, must be
|
|
72
|
+
raise ArgumentError.new('Invalid algorithm, must be one of AES-128-CCM, AES-128-GCM, AES-256-CCM, or AES-256-GCM')
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
self.encrypted_data.assign(encrypted_data.bytes)
|
data/lib/ruby_smb/smb2.rb
CHANGED
|
@@ -5,6 +5,7 @@ module RubySMB
|
|
|
5
5
|
module SMB2
|
|
6
6
|
# Protocol ID value. Translates to \xFESMB
|
|
7
7
|
SMB2_PROTOCOL_ID = 0xFE534D42
|
|
8
|
+
SMB2_TRANSFORM_PROTOCOL_ID = 0xFD534D42
|
|
8
9
|
# Wildcard revision, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/63abf97c-0d09-47e2-88d6-6bfa552949a5
|
|
9
10
|
SMB2_WILDCARD_REVISION = 0x02ff
|
|
10
11
|
|
data/lib/ruby_smb/version.rb
CHANGED
data/ruby_smb.gemspec
CHANGED
|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_development_dependency 'yard'
|
|
35
35
|
|
|
36
36
|
spec.add_runtime_dependency 'rubyntlm'
|
|
37
|
-
spec.add_runtime_dependency 'windows_error', '>= 0.1.
|
|
37
|
+
spec.add_runtime_dependency 'windows_error', '>= 0.1.4'
|
|
38
38
|
spec.add_runtime_dependency 'bindata'
|
|
39
39
|
spec.add_runtime_dependency 'openssl-ccm'
|
|
40
40
|
spec.add_runtime_dependency 'openssl-cmac'
|
|
@@ -962,8 +962,10 @@ RSpec.describe RubySMB::Client do
|
|
|
962
962
|
expect(nc.length).to eq(1)
|
|
963
963
|
expect(nc.first.data.ciphers).to eq(
|
|
964
964
|
[
|
|
965
|
-
RubySMB::SMB2::EncryptionCapabilities::
|
|
966
|
-
RubySMB::SMB2::EncryptionCapabilities::
|
|
965
|
+
RubySMB::SMB2::EncryptionCapabilities::AES_256_GCM,
|
|
966
|
+
RubySMB::SMB2::EncryptionCapabilities::AES_256_CCM,
|
|
967
|
+
RubySMB::SMB2::EncryptionCapabilities::AES_128_GCM,
|
|
968
|
+
RubySMB::SMB2::EncryptionCapabilities::AES_128_CCM
|
|
967
969
|
]
|
|
968
970
|
)
|
|
969
971
|
end
|
|
@@ -1277,6 +1279,9 @@ RSpec.describe RubySMB::Client do
|
|
|
1277
1279
|
end
|
|
1278
1280
|
|
|
1279
1281
|
it 'calls the backing methods' do
|
|
1282
|
+
request_packet = double('Request packet')
|
|
1283
|
+
allow(client).to receive(:negotiate_request).and_return(request_packet)
|
|
1284
|
+
allow(request_packet).to receive(:packet_smb_version)
|
|
1280
1285
|
expect(client).to receive(:negotiate_request)
|
|
1281
1286
|
expect(client).to receive(:send_recv)
|
|
1282
1287
|
expect(client).to receive(:negotiate_response)
|
|
@@ -1317,14 +1322,20 @@ RSpec.describe RubySMB::Client do
|
|
|
1317
1322
|
|
|
1318
1323
|
it 'increments the message ID' do
|
|
1319
1324
|
expect(client).to receive(:smb2_message_id=).with(1)
|
|
1325
|
+
expect(client).to receive(:negotiate_request).twice.and_call_original
|
|
1326
|
+
expect(client).to receive(:parse_negotiate_response).twice do
|
|
1327
|
+
client.smb1 = false
|
|
1328
|
+
end
|
|
1320
1329
|
client.negotiate
|
|
1321
1330
|
end
|
|
1322
1331
|
|
|
1323
1332
|
it 're-negotiates' do
|
|
1324
|
-
expect(client).to receive(:negotiate_request).twice
|
|
1333
|
+
expect(client).to receive(:negotiate_request).twice.and_call_original
|
|
1325
1334
|
expect(client).to receive(:send_recv).twice
|
|
1326
1335
|
expect(client).to receive(:negotiate_response).twice
|
|
1327
|
-
expect(client).to receive(:parse_negotiate_response).twice
|
|
1336
|
+
expect(client).to receive(:parse_negotiate_response).twice do
|
|
1337
|
+
client.smb1 = false
|
|
1338
|
+
end
|
|
1328
1339
|
client.negotiate
|
|
1329
1340
|
end
|
|
1330
1341
|
end
|
|
@@ -2681,13 +2692,15 @@ RSpec.describe RubySMB::Client do
|
|
|
2681
2692
|
context "with #{dialect} dialect" do
|
|
2682
2693
|
before :example do
|
|
2683
2694
|
client.dialect = dialect
|
|
2695
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2684
2696
|
end
|
|
2685
2697
|
|
|
2686
2698
|
it 'generates the client encryption key with the expected parameters' do
|
|
2687
2699
|
expect(RubySMB::Crypto::KDF).to receive(:counter_mode).with(
|
|
2688
2700
|
session_key,
|
|
2689
2701
|
"SMB2AESCCM\x00",
|
|
2690
|
-
"ServerIn \x00"
|
|
2702
|
+
"ServerIn \x00",
|
|
2703
|
+
{length: 128}
|
|
2691
2704
|
).and_call_original
|
|
2692
2705
|
client.smb3_encrypt(data)
|
|
2693
2706
|
end
|
|
@@ -2698,10 +2711,12 @@ RSpec.describe RubySMB::Client do
|
|
|
2698
2711
|
it 'generates the client encryption key with the expected parameters' do
|
|
2699
2712
|
client.preauth_integrity_hash_value = ''
|
|
2700
2713
|
client.dialect = '0x0311'
|
|
2714
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2701
2715
|
expect(RubySMB::Crypto::KDF).to receive(:counter_mode).with(
|
|
2702
2716
|
session_key,
|
|
2703
2717
|
"SMBC2SCipherKey\x00",
|
|
2704
|
-
''
|
|
2718
|
+
'',
|
|
2719
|
+
{length: 128}
|
|
2705
2720
|
).and_call_original
|
|
2706
2721
|
client.smb3_encrypt(data)
|
|
2707
2722
|
end
|
|
@@ -2723,6 +2738,7 @@ RSpec.describe RubySMB::Client do
|
|
|
2723
2738
|
|
|
2724
2739
|
it 'generates the expected client encryption key with 0x0302 dialect' do
|
|
2725
2740
|
client.dialect = '0x0302'
|
|
2741
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2726
2742
|
expected_enc_key =
|
|
2727
2743
|
"\xa4\xfa\x23\xc1\xb0\x65\x84\xce\x47\x08\x5b\xe0\x64\x98\xd7\x87".b
|
|
2728
2744
|
client.smb3_encrypt(data)
|
|
@@ -2731,6 +2747,7 @@ RSpec.describe RubySMB::Client do
|
|
|
2731
2747
|
|
|
2732
2748
|
it 'generates the expected client encryption key with 0x0311 dialect' do
|
|
2733
2749
|
client.dialect = '0x0311'
|
|
2750
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2734
2751
|
client.session_key =
|
|
2735
2752
|
"\x5c\x00\x4a\x3b\xf0\xa2\x4f\x75\x4c\xb2\x74\x0a\xcf\xc4\x8e\x1a".b
|
|
2736
2753
|
client.preauth_integrity_hash_value =
|
|
@@ -2765,13 +2782,15 @@ RSpec.describe RubySMB::Client do
|
|
|
2765
2782
|
context "with #{dialect} dialect" do
|
|
2766
2783
|
before :example do
|
|
2767
2784
|
client.dialect = dialect
|
|
2785
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2768
2786
|
end
|
|
2769
2787
|
|
|
2770
2788
|
it 'generates the client encryption key with the expected parameters' do
|
|
2771
2789
|
expect(RubySMB::Crypto::KDF).to receive(:counter_mode).with(
|
|
2772
2790
|
session_key,
|
|
2773
2791
|
"SMB2AESCCM\x00",
|
|
2774
|
-
"ServerOut\x00"
|
|
2792
|
+
"ServerOut\x00",
|
|
2793
|
+
{length: 128}
|
|
2775
2794
|
).and_call_original
|
|
2776
2795
|
client.smb3_decrypt(transform_packet)
|
|
2777
2796
|
end
|
|
@@ -2782,10 +2801,12 @@ RSpec.describe RubySMB::Client do
|
|
|
2782
2801
|
it 'generates the client encryption key with the expected parameters' do
|
|
2783
2802
|
client.preauth_integrity_hash_value = ''
|
|
2784
2803
|
client.dialect = '0x0311'
|
|
2804
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2785
2805
|
expect(RubySMB::Crypto::KDF).to receive(:counter_mode).with(
|
|
2786
2806
|
session_key,
|
|
2787
2807
|
"SMBS2CCipherKey\x00",
|
|
2788
|
-
''
|
|
2808
|
+
'',
|
|
2809
|
+
{length: 128}
|
|
2789
2810
|
).and_call_original
|
|
2790
2811
|
client.smb3_decrypt(transform_packet)
|
|
2791
2812
|
end
|
|
@@ -2806,6 +2827,7 @@ RSpec.describe RubySMB::Client do
|
|
|
2806
2827
|
|
|
2807
2828
|
it 'generates the expected server encryption key with 0x0302 dialect' do
|
|
2808
2829
|
client.dialect = '0x0302'
|
|
2830
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2809
2831
|
expected_enc_key =
|
|
2810
2832
|
"\x65\x21\xd3\x6d\xe9\xe3\x5a\x66\x09\x61\xae\x3e\xc6\x49\x6b\xdf".b
|
|
2811
2833
|
client.smb3_decrypt(transform_packet)
|
|
@@ -2814,6 +2836,7 @@ RSpec.describe RubySMB::Client do
|
|
|
2814
2836
|
|
|
2815
2837
|
it 'generates the expected server encryption key with 0x0311 dialect' do
|
|
2816
2838
|
client.dialect = '0x0311'
|
|
2839
|
+
client.encryption_algorithm = 'AES-128-CCM'
|
|
2817
2840
|
client.session_key =
|
|
2818
2841
|
"\x5c\x00\x4a\x3b\xf0\xa2\x4f\x75\x4c\xb2\x74\x0a\xcf\xc4\x8e\x1a".b
|
|
2819
2842
|
client.preauth_integrity_hash_value =
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::CreateServiceWRequest do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
it { is_expected.to respond_to :h_sc_object }
|
|
5
|
+
it { is_expected.to respond_to :lp_service_name }
|
|
6
|
+
it { is_expected.to respond_to :lp_display_name }
|
|
7
|
+
it { is_expected.to respond_to :dw_desired_access }
|
|
8
|
+
it { is_expected.to respond_to :dw_service_type }
|
|
9
|
+
it { is_expected.to respond_to :dw_start_type }
|
|
10
|
+
it { is_expected.to respond_to :dw_error_control }
|
|
11
|
+
it { is_expected.to respond_to :lp_binary_path_name }
|
|
12
|
+
it { is_expected.to respond_to :lp_load_order_group }
|
|
13
|
+
it { is_expected.to respond_to :lp_dw_tag_id }
|
|
14
|
+
it { is_expected.to respond_to :lp_dependencies }
|
|
15
|
+
it { is_expected.to respond_to :dw_depend_size }
|
|
16
|
+
it { is_expected.to respond_to :lp_service_start_name }
|
|
17
|
+
it { is_expected.to respond_to :lp_password }
|
|
18
|
+
it { is_expected.to respond_to :dw_pw_size }
|
|
19
|
+
|
|
20
|
+
it 'is little endian' do
|
|
21
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
describe '#h_sc_object' do
|
|
26
|
+
it 'is a ScRpcHandle structure' do
|
|
27
|
+
expect(packet.h_sc_object).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#lp_service_name' do
|
|
32
|
+
it 'is a NdrConfVarWideStringz structure' do
|
|
33
|
+
expect(packet.lp_service_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#lp_display_name' do
|
|
38
|
+
it 'is a NdrWideStringzPtr structure' do
|
|
39
|
+
expect(packet.lp_display_name).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#dw_desired_access' do
|
|
44
|
+
it 'is a NdrUint32' do
|
|
45
|
+
expect(packet.dw_desired_access).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe '#dw_service_type' do
|
|
50
|
+
it 'is a NdrUint32' do
|
|
51
|
+
expect(packet.dw_service_type).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#dw_start_type' do
|
|
56
|
+
it 'is a NdrUint32' do
|
|
57
|
+
expect(packet.dw_start_type).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe '#dw_error_control' do
|
|
62
|
+
it 'is a NdrUint32' do
|
|
63
|
+
expect(packet.dw_error_control).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '#lp_binary_path_name' do
|
|
68
|
+
it 'is a NdrConfVarWideStringz structure' do
|
|
69
|
+
expect(packet.lp_binary_path_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe '#lp_load_order_group' do
|
|
74
|
+
it 'is a NdrWideStringzPtr structure' do
|
|
75
|
+
expect(packet.lp_load_order_group).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe '#lp_dw_tag_id' do
|
|
80
|
+
it 'is a NdrUint32Ptr' do
|
|
81
|
+
expect(packet.lp_dw_tag_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#lp_dependencies' do
|
|
86
|
+
it 'is a SvcctlByteArrayPtr structure' do
|
|
87
|
+
expect(packet.lp_dependencies).to be_a RubySMB::Dcerpc::Svcctl::SvcctlByteArrayPtr
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe '#dw_depend_size' do
|
|
92
|
+
it 'is a NdrUint32' do
|
|
93
|
+
expect(packet.dw_depend_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#lp_service_start_name' do
|
|
98
|
+
it 'is a NdrWideStringzPtr structure' do
|
|
99
|
+
expect(packet.lp_service_start_name).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe '#lp_password' do
|
|
104
|
+
it 'is a SvcctlByteArrayPtr structure' do
|
|
105
|
+
expect(packet.lp_password).to be_a RubySMB::Dcerpc::Svcctl::SvcctlByteArrayPtr
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe '#dw_pw_size' do
|
|
110
|
+
it 'is a NdrUint32' do
|
|
111
|
+
expect(packet.dw_pw_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'should keep #dw_desired_access 4-byte aligned' do
|
|
116
|
+
5.times do |i1|
|
|
117
|
+
5.times do |i2|
|
|
118
|
+
packet.lp_service_name = "A" * i1
|
|
119
|
+
packet.lp_display_name = "B" * i2
|
|
120
|
+
expect(packet.dw_desired_access.abs_offset % 4).to eq 0
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe '#initialize_instance' do
|
|
126
|
+
it 'sets #opnum to CREATE_SERVICE_W constant' do
|
|
127
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::CREATE_SERVICE_W)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'reads its own binary representation and outputs the same packet' do
|
|
132
|
+
packet = described_class.new(
|
|
133
|
+
h_sc_object: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'},
|
|
134
|
+
lp_service_name: 'test',
|
|
135
|
+
lp_display_name: 'Test',
|
|
136
|
+
dw_desired_access: 3,
|
|
137
|
+
lp_binary_path_name: 'test',
|
|
138
|
+
lp_password: 'test'.bytes
|
|
139
|
+
)
|
|
140
|
+
binary = packet.to_binary_s
|
|
141
|
+
expect(described_class.read(binary)).to eq(packet)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::CreateServiceWResponse do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
it { is_expected.to respond_to :lp_dw_tag_id }
|
|
5
|
+
it { is_expected.to respond_to :lp_sc_handle }
|
|
6
|
+
it { is_expected.to respond_to :error_status }
|
|
7
|
+
|
|
8
|
+
it 'is little endian' do
|
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe '#lp_dw_tag_id' do
|
|
13
|
+
it 'is a NdrUint32Ptr' do
|
|
14
|
+
expect(packet.lp_dw_tag_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#lp_sc_handle' do
|
|
19
|
+
it 'is a ScRpcHandle structure' do
|
|
20
|
+
expect(packet.lp_sc_handle).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '#error_status' do
|
|
25
|
+
it 'is a NdrUint32' do
|
|
26
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#initialize_instance' do
|
|
31
|
+
it 'sets #opnum to CREATE_SERVICE_W constant' do
|
|
32
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::CREATE_SERVICE_W)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'reads its own binary representation and outputs the same packet' do
|
|
37
|
+
packet = described_class.new(
|
|
38
|
+
lp_dw_tag_id: 3,
|
|
39
|
+
lp_sc_handle: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'},
|
|
40
|
+
error_status: 3
|
|
41
|
+
)
|
|
42
|
+
binary = packet.to_binary_s
|
|
43
|
+
expect(described_class.read(binary)).to eq(packet)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::DeleteServiceRequest do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
it { is_expected.to respond_to :lp_sc_handle }
|
|
5
|
+
|
|
6
|
+
it 'is little endian' do
|
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe '#lp_sc_handle' do
|
|
11
|
+
it 'is a ScRpcHandle structure' do
|
|
12
|
+
expect(packet.lp_sc_handle).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#initialize_instance' do
|
|
17
|
+
it 'sets #opnum to DELETE_SERVICE constant' do
|
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::DELETE_SERVICE)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
|
23
|
+
packet = described_class.new(
|
|
24
|
+
lp_sc_handle: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'}
|
|
25
|
+
)
|
|
26
|
+
binary = packet.to_binary_s
|
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::DeleteServiceResponse do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
it { is_expected.to respond_to :error_status }
|
|
5
|
+
|
|
6
|
+
it 'is little endian' do
|
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe '#error_status' do
|
|
11
|
+
it 'is a NdrUint32' do
|
|
12
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#initialize_instance' do
|
|
17
|
+
it 'sets #opnum to DELETE_SERVICE constant' do
|
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::DELETE_SERVICE)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
|
23
|
+
packet = described_class.new(
|
|
24
|
+
error_status: 3
|
|
25
|
+
)
|
|
26
|
+
binary = packet.to_binary_s
|
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -57,30 +57,30 @@ RSpec.describe RubySMB::Dcerpc::Winreg::OpenRootKeyRequest do
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
context 'when #opnum is not OPEN_HKPD, OPEN_HKPT or OPEN_HKPN' do
|
|
60
|
-
it 'sets the #sam_desired.
|
|
60
|
+
it 'sets the #sam_desired.maximum_allowed flag' do
|
|
61
61
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKCR)
|
|
62
|
-
expect(packet.sam_desired.
|
|
62
|
+
expect(packet.sam_desired.maximum_allowed).to eq(1)
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
context 'when #opnum is OPEN_HKPD' do
|
|
67
|
-
it 'does not set the #sam_desired.
|
|
67
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
|
68
68
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPD)
|
|
69
|
-
expect(packet.sam_desired.
|
|
69
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
context 'when #opnum is OPEN_HKPT' do
|
|
74
|
-
it 'does not set the #sam_desired.
|
|
74
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
|
75
75
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPT)
|
|
76
|
-
expect(packet.sam_desired.
|
|
76
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
context 'when #opnum is OPEN_HKPN' do
|
|
81
|
-
it 'does not set the #sam_desired.
|
|
81
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
|
82
82
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPN)
|
|
83
|
-
expect(packet.sam_desired.
|
|
83
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
end
|
|
@@ -22,7 +22,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg::Regsam do
|
|
|
22
22
|
it { is_expected.to respond_to :generic_execute }
|
|
23
23
|
it { is_expected.to respond_to :generic_all }
|
|
24
24
|
it { is_expected.to respond_to :reserved4 }
|
|
25
|
-
it { is_expected.to respond_to :
|
|
25
|
+
it { is_expected.to respond_to :maximum_allowed }
|
|
26
26
|
it { is_expected.to respond_to :system_security }
|
|
27
27
|
|
|
28
28
|
|
|
@@ -755,7 +755,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
|
755
755
|
lp_sub_key: sub_key,
|
|
756
756
|
lp_class: :null,
|
|
757
757
|
dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
|
|
758
|
-
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(
|
|
758
|
+
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum_allowed: 1),
|
|
759
759
|
lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
|
|
760
760
|
lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
|
|
761
761
|
}
|
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
|
22
|
-
it { is_expected.to respond_to :
|
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
|
23
23
|
it { is_expected.to respond_to :system_security }
|
|
24
24
|
|
|
25
25
|
it 'is little endian' do
|
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
describe '#
|
|
149
|
+
describe '#maximum_allowed' do
|
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
|
151
|
-
expect(flags.
|
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
describe '#generic_all' do
|
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
|
22
|
-
it { is_expected.to respond_to :
|
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
|
23
23
|
it { is_expected.to respond_to :system_security }
|
|
24
24
|
|
|
25
25
|
it 'is little endian' do
|
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
describe '#
|
|
149
|
+
describe '#maximum_allowed' do
|
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
|
151
|
-
expect(flags.
|
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
describe '#generic_all' do
|
|
@@ -26,7 +26,7 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Request do
|
|
|
26
26
|
expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
it 'should have the setup set to the
|
|
29
|
+
it 'should have the setup set to the FIND_FIRST2 subcommand' do
|
|
30
30
|
expect(parameter_block.setup).to include RubySMB::SMB1::Packet::Trans2::Subcommands::FIND_FIRST2
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -47,7 +47,7 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Request do
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
it 'should keep #trans2_data 4-byte aligned' do
|
|
50
|
-
expect(data_block.trans2_data.abs_offset % 4).to eq 0
|
|
50
|
+
expect(data_block.trans2_data.abs_offset % 4).to eq 0 if data_block.trans2_data.num_bytes != 0
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
describe '#trans2_parameters' do
|
|
@@ -24,7 +24,7 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
|
24
24
|
describe '#parameter_block' do
|
|
25
25
|
subject(:parameter_block) { packet.parameter_block }
|
|
26
26
|
|
|
27
|
-
it 'should have the setup set to the
|
|
27
|
+
it 'should have the setup set to the FIND_FIRST2 subcommand' do
|
|
28
28
|
expect(parameter_block.setup).to include RubySMB::SMB1::Packet::Trans2::Subcommands::FIND_FIRST2
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -40,7 +40,7 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it 'should keep #trans2_data 4-byte aligned' do
|
|
43
|
-
expect(data_block.trans2_data.abs_offset % 4).to eq 0
|
|
43
|
+
expect(data_block.trans2_data.abs_offset % 4).to eq 0 if data_block.trans2_data.num_bytes != 0
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
describe '#trans2_parameters' do
|
|
@@ -57,6 +57,40 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
|
57
57
|
subject(:data) { data_block.trans2_data }
|
|
58
58
|
|
|
59
59
|
it { is_expected.to respond_to :buffer }
|
|
60
|
+
|
|
61
|
+
describe '#buffer' do
|
|
62
|
+
it 'is a String field' do
|
|
63
|
+
expect(data.buffer).to be_a BinData::String
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'when the buffer is empty' do
|
|
68
|
+
before :each do
|
|
69
|
+
data.buffer = ''
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'should not be padded' do
|
|
73
|
+
expect(data_block.pad2.num_bytes).to eq 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should read its own binary representation' do
|
|
77
|
+
expect(packet.class.read(packet.to_binary_s).data_block.trans2_data.buffer).to eq ''
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'when the buffer is not empty' do
|
|
82
|
+
before :each do
|
|
83
|
+
data.buffer = 'test'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'should be padded to a 4-byte boundary' do
|
|
87
|
+
expect(data_block.trans2_data.abs_offset % 4).to eq 0
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'should read its own binary representation' do
|
|
91
|
+
expect(packet.class.read(packet.to_binary_s).data_block.trans2_data.buffer).to eq 'test'
|
|
92
|
+
end
|
|
93
|
+
end
|
|
60
94
|
end
|
|
61
95
|
end
|
|
62
96
|
|