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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -3
  3. data/.github/workflows/verify.yml +1 -1
  4. data/.simplecov +1 -1
  5. data/CONTRIBUTING.md +28 -3
  6. data/README.md +8 -0
  7. data/examples/pwsh_service.rb +112 -0
  8. data/lib/ruby_smb/client/encryption.rb +16 -4
  9. data/lib/ruby_smb/client/negotiation.rb +10 -8
  10. data/lib/ruby_smb/dcerpc/request.rb +2 -0
  11. data/lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb +35 -0
  12. data/lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb +24 -0
  13. data/lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb +21 -0
  14. data/lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb +21 -0
  15. data/lib/ruby_smb/dcerpc/svcctl.rb +66 -5
  16. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +1 -1
  17. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +1 -1
  18. data/lib/ruby_smb/dcerpc/winreg.rb +1 -1
  19. data/lib/ruby_smb/fscc/file_information.rb +4 -0
  20. data/lib/ruby_smb/gss/provider/ntlm.rb +4 -0
  21. data/lib/ruby_smb/server/server_client/encryption.rb +66 -0
  22. data/lib/ruby_smb/server/server_client/negotiation.rb +14 -3
  23. data/lib/ruby_smb/server/server_client/session_setup.rb +18 -3
  24. data/lib/ruby_smb/server/server_client/share_io.rb +17 -0
  25. data/lib/ruby_smb/server/server_client/tree_connect.rb +40 -3
  26. data/lib/ruby_smb/server/server_client.rb +147 -37
  27. data/lib/ruby_smb/server/share/provider/disk/file_system.rb +28 -0
  28. data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +42 -0
  29. data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +143 -0
  30. data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +359 -0
  31. data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +69 -0
  32. data/lib/ruby_smb/server/share/provider/disk/processor.rb +159 -0
  33. data/lib/ruby_smb/server/share/provider/disk.rb +4 -416
  34. data/lib/ruby_smb/server/share/provider/pipe.rb +2 -2
  35. data/lib/ruby_smb/server/share/provider/processor.rb +16 -0
  36. data/lib/ruby_smb/signing.rb +18 -4
  37. data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +1 -1
  38. data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +1 -1
  39. data/lib/ruby_smb/smb1/commands.rb +1 -0
  40. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +11 -1
  41. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +1 -1
  42. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +5 -4
  43. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +12 -4
  44. data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +9 -1
  45. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +52 -51
  46. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +37 -37
  47. data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_both_directory_info.rb +48 -0
  48. data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +28 -15
  49. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +51 -51
  50. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +36 -36
  51. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +40 -39
  52. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +40 -40
  53. data/lib/ruby_smb/smb1/packet/trans2/query_file_information_request.rb +60 -0
  54. data/lib/ruby_smb/smb1/packet/trans2/query_file_information_response.rb +59 -0
  55. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info.rb +31 -0
  56. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +40 -0
  57. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +46 -0
  58. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response.rb +59 -0
  59. data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_basic_info.rb +23 -0
  60. data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_standard_info.rb +22 -0
  61. data/lib/ruby_smb/smb1/packet/trans2/query_information_level.rb +62 -0
  62. data/lib/ruby_smb/smb1/packet/trans2/query_path_information_request.rb +65 -0
  63. data/lib/ruby_smb/smb1/packet/trans2/query_path_information_response.rb +59 -0
  64. data/lib/ruby_smb/smb1/packet/trans2/request.rb +24 -8
  65. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +4 -4
  66. data/lib/ruby_smb/smb1/packet/trans2/response.rb +29 -20
  67. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +42 -42
  68. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +23 -23
  69. data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +23 -5
  70. data/lib/ruby_smb/smb1/packet/trans2.rb +4 -0
  71. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -1
  72. data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +1 -1
  73. data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
  74. data/lib/ruby_smb/smb2/negotiate_context.rb +10 -1
  75. data/lib/ruby_smb/smb2/packet/transform_header.rb +7 -7
  76. data/lib/ruby_smb/smb2.rb +1 -0
  77. data/lib/ruby_smb/version.rb +1 -1
  78. data/ruby_smb.gemspec +1 -1
  79. data/spec/lib/ruby_smb/client_spec.rb +31 -8
  80. data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb +143 -0
  81. data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb +45 -0
  82. data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb +29 -0
  83. data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb +29 -0
  84. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +8 -8
  85. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +1 -1
  86. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +1 -1
  87. data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +4 -4
  88. data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +4 -4
  89. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +2 -2
  90. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +36 -2
  91. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +2 -2
  92. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +35 -1
  93. data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_request_spec.rb +74 -0
  94. data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_response_spec.rb +96 -0
  95. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +62 -0
  96. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response_spec.rb +88 -0
  97. data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_request_spec.rb +79 -0
  98. data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_response_spec.rb +96 -0
  99. data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
  100. data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +3 -3
  101. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +3 -2
  102. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +7 -2
  103. data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
  104. data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +4 -4
  105. data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +4 -4
  106. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +2 -2
  107. data/spec/spec_helper.rb +2 -3
  108. data.tar.gz.sig +0 -0
  109. metadata +48 -4
  110. 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: 0xFD534D42
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 either AES-128-CCM or AES-128-GCM')
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 either AES-128-CCM or AES-128-GCM')
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
 
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.0.5'.freeze
2
+ VERSION = '3.1.1'.freeze
3
3
  end
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.3'
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::AES_128_CCM,
966
- RubySMB::SMB2::EncryptionCapabilities::AES_128_GCM
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.maximum flag' do
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.maximum).to eq(1)
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.maximum flag' do
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.maximum).to eq(0)
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.maximum flag' do
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.maximum).to eq(0)
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.maximum flag' do
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.maximum).to eq(0)
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 :maximum }
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(maximum: 1),
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 :maximum }
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 '#maximum' do
149
+ describe '#maximum_allowed' do
150
150
  it 'should be a 1-bit field per the SMB spec' do
151
- expect(flags.maximum).to be_a BinData::Bit1
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', :maximum, 'V', 0x02000000
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 :maximum }
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 '#maximum' do
149
+ describe '#maximum_allowed' do
150
150
  it 'should be a 1-bit field per the SMB spec' do
151
- expect(flags.maximum).to be_a BinData::Bit1
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', :maximum, 'V', 0x02000000
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 OPEN2 subcommand' do
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 OPEN2 subcommand' do
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