ruby_smb 3.1.4 → 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/ruby_smb/client/authentication.rb +17 -2
  4. data/lib/ruby_smb/client.rb +10 -1
  5. data/lib/ruby_smb/dcerpc/error.rb +13 -0
  6. data/lib/ruby_smb/dcerpc/fault.rb +83 -0
  7. data/lib/ruby_smb/dcerpc/ndr.rb +19 -8
  8. data/lib/ruby_smb/dcerpc/request.rb +15 -10
  9. data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +5 -0
  10. data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request.rb +24 -0
  11. data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response.rb +24 -0
  12. data/lib/ruby_smb/dcerpc/samr/samr_delete_user_request.rb +21 -0
  13. data/lib/ruby_smb/dcerpc/samr/samr_delete_user_response.rb +22 -0
  14. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request.rb +25 -0
  15. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response.rb +25 -0
  16. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +0 -31
  17. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +1 -14
  18. data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb +23 -0
  19. data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb +23 -0
  20. data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb +23 -0
  21. data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb +21 -0
  22. data/lib/ruby_smb/dcerpc/samr.rb +453 -83
  23. data/lib/ruby_smb/dcerpc.rb +1 -0
  24. data/lib/ruby_smb/smb1/pipe.rb +4 -1
  25. data/lib/ruby_smb/smb2/pipe.rb +4 -2
  26. data/lib/ruby_smb/version.rb +1 -1
  27. data/spec/lib/ruby_smb/client_spec.rb +1 -0
  28. data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request_spec.rb +69 -0
  29. data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response_spec.rb +69 -0
  30. data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_request_spec.rb +42 -0
  31. data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_response_spec.rb +51 -0
  32. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request_spec.rb +60 -0
  33. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response_spec.rb +75 -0
  34. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +0 -195
  35. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request_spec.rb +62 -0
  36. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response_spec.rb +54 -0
  37. data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb +67 -0
  38. data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb +35 -0
  39. data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +194 -0
  40. data.tar.gz.sig +0 -0
  41. metadata +33 -2
  42. metadata.gz.sig +0 -0
@@ -6,91 +6,26 @@ module RubySMB
6
6
  VER_MAJOR = 1
7
7
  VER_MINOR = 0
8
8
 
9
- # Operation numbers
10
- SAMR_CONNECT = 0x0000
11
- SAMR_CLOSE_HANDLE = 0x0001
12
- SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER = 0x0005
13
- SAMR_OPEN_DOMAIN = 0x0007
14
- SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D
15
- SAMR_GET_ALIAS_MEMBERSHIP = 0x0010
16
- SAMR_OPEN_USER = 0x0022
17
- SAMR_GET_GROUPS_FOR_USER = 0x0027
18
- SAMR_RID_TO_SID = 0x0041
19
-
20
- class SamprHandle < Ndr::NdrContextHandle; end
21
-
22
- # [2.2.10.2 USER_PROPERTY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7c0f2eca-1783-450b-b5a0-754cf11f22c9)
23
- class UserProperty < BinData::Record
24
- endian :little
25
-
26
- uint16 :name_length, initial_value: -> { property_name.num_bytes }
27
- uint16 :value_length, initial_value: -> { property_value.num_bytes }
28
- uint16 :reserved
29
- string16 :property_name, read_length: :name_length
30
- string :property_value, read_length: :value_length
31
- end
32
-
33
- # [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad)
34
- class UserProperties < BinData::Record
35
- endian :little
36
-
37
- uint32 :reserved1
38
- uint32 :struct_length, initial_value: -> { num_bytes - 12 }
39
- uint16 :reserved2
40
- uint16 :reserved3
41
- string :reserved4, length: 96
42
- uint16 :property_signature, initial_value: 0x50
43
- uint16 :property_count, initial_value: -> { user_properties.size }
44
- array :user_properties, type: :user_property, initial_length: :property_count
45
- uint8 :reserved5
46
- end
47
-
48
- class KerbKeyDataNew < BinData::Record
49
- endian :little
50
-
51
- uint16 :reserved1
52
- uint16 :reserved2
53
- uint32 :reserved3
54
- uint32 :iteration_count
55
- uint32 :key_type
56
- uint32 :key_length
57
- uint32 :key_offset
58
- end
59
-
60
- # [2.2.10.6 Primary:Kerberos-Newer-Keys - KERB_STORED_CREDENTIAL_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/08cb3ca7-954b-45e3-902e-77512fe3ba8e)
61
- class KerbStoredCredentialNew < BinData::Record
62
- endian :little
63
-
64
- uint16 :revision
65
- uint16 :flags
66
- uint16 :credential_count
67
- uint16 :service_credential_count
68
- uint16 :old_credential_count
69
- uint16 :older_credential_count
70
- uint16 :default_salt_length
71
- uint16 :default_salt_maximum_length
72
- uint32 :default_salt_offset
73
- uint32 :default_iteration_count
74
- array :credentials, type: :kerb_key_data_new, initial_length: :credential_count
75
- array :service_credentials, type: :kerb_key_data_new, initial_length: :service_credential_count
76
- array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count
77
- array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count
78
- string :default_salt, read_length: -> { credentials.map { |e| e.key_offset }.min - @obj.abs_offset }
79
- string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum }
80
-
81
- def get_key_values
82
- credentials.map do |credential|
83
- offset = credential.key_offset - key_values.abs_offset
84
- key_values[offset, credential.key_length]
85
- end
86
- end
87
- end
88
-
89
-
90
9
  #################################
91
10
  # Constants #
92
11
  #################################
93
12
 
13
+ # Operation numbers
14
+ SAMR_CONNECT = 0x0000
15
+ SAMR_CLOSE_HANDLE = 0x0001
16
+ SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER = 0x0005
17
+ SAMR_ENUMERATE_DOMAINS_IN_SAM_SERVER = 0x0006
18
+ SAMR_OPEN_DOMAIN = 0x0007
19
+ SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D
20
+ SAMR_GET_ALIAS_MEMBERSHIP = 0x0010
21
+ SAMR_LOOKUP_NAMES_IN_DOMAIN = 0x0011
22
+ SAMR_OPEN_USER = 0x0022
23
+ SAMR_DELETE_USER = 0x0023
24
+ SAMR_GET_GROUPS_FOR_USER = 0x0027
25
+ SAMR_CREATE_USER2_IN_DOMAIN = 0x0032
26
+ SAMR_SET_INFORMATION_USER2 = 0x003a
27
+ SAMR_CONNECT5 = 0x0040
28
+ SAMR_RID_TO_SID = 0x0041
94
29
 
95
30
  ################
96
31
  # ACCESS_MASK Values
@@ -204,6 +139,33 @@ module RubySMB
204
139
  USER_ALL_SECURITYDESCRIPTOR = 0x10000000
205
140
  USER_ALL_UNDEFINED_MASK = 0xC0000000
206
141
 
142
+ # [2.2.6.28 USER_INFORMATION_CLASS Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/6b0dff90-5ac0-429a-93aa-150334adabf6)
143
+ USER_GENERAL_INFORMATION = 1
144
+ USER_PREFERENCES_INFORMATION = 2
145
+ USER_LOGON_INFORMATION = 3
146
+ USER_LOGON_HOURS_INFORMATION = 4
147
+ USER_ACCOUNT_INFORMATION = 5
148
+ USER_NAME_INFORMATION = 6
149
+ USER_ACCOUNT_NAME_INFORMATION = 7
150
+ USER_FULL_NAME_INFORMATION = 8
151
+ USER_PRIMARY_GROUP_INFORMATION = 9
152
+ USER_HOME_INFORMATION = 10
153
+ USER_SCRIPT_INFORMATION = 11
154
+ USER_PROFILE_INFORMATION = 12
155
+ USER_ADMIN_COMMENT_INFORMATION = 13
156
+ USER_WORK_STATIONS_INFORMATION = 14
157
+ USER_CONTROL_INFORMATION = 16
158
+ USER_EXPIRES_INFORMATION = 17
159
+ USER_INTERNAL1_INFORMATION = 18
160
+ USER_PARAMETERS_INFORMATION = 20
161
+ USER_ALL_INFORMATION = 21
162
+ USER_INTERNAL4_INFORMATION = 23
163
+ USER_INTERNAL5_INFORMATION = 24
164
+ USER_INTERNAL4_INFORMATION_NEW = 25
165
+ USER_INTERNAL5_INFORMATION_NEW = 26
166
+ USER_INTERNAL7_INFORMATION = 31
167
+ USER_INTERNAL8_INFORMATION = 32
168
+
207
169
  # [2.2.1.9 ACCOUNT_TYPE Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e742be45-665d-4576-b872-0bc99d1e1fbe)
208
170
  SAM_DOMAIN_OBJECT = 0x00000000
209
171
  SAM_GROUP_OBJECT = 0x10000000
@@ -300,14 +262,229 @@ module RubySMB
300
262
  0xffffff74 => 'rc4_hmac'
301
263
  }
302
264
 
265
+ # [2.2.3.9 SAMPR_RID_ENUMERATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5c94a35a-e7f2-4675-af34-741f5a8ee1a2)
266
+ class SamprRidEnumeration < Ndr::NdrStruct
267
+ default_parameters byte_align: 4
268
+ endian :little
269
+
270
+ ndr_uint32 :relative_id
271
+ rpc_unicode_string :name
272
+ end
273
+
274
+ class SamprRidEnumerationArray < Ndr::NdrConfArray
275
+ default_parameter type: :sampr_rid_enumeration
276
+ end
277
+
278
+ class PsamprRidEnumerationArray < SamprRidEnumerationArray
279
+ extend Ndr::PointerClassPlugin
280
+ end
281
+
282
+ # [2.2.3.10 SAMPR_ENUMERATION_BUFFER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/c53161a4-38e8-4a28-a33e-0d378fce03dd)
283
+ class SamprEnumerationBuffer < Ndr::NdrStruct
284
+ default_parameters byte_align: 4
285
+ endian :little
286
+
287
+ ndr_uint32 :entries_read
288
+ psampr_rid_enumeration_array :buffer
289
+ end
290
+
291
+ class PsamprEnumerationBuffer < SamprEnumerationBuffer
292
+ extend Ndr::PointerClassPlugin
293
+ end
294
+
295
+ class SamprHandle < Ndr::NdrContextHandle; end
296
+
297
+ class PulongArray < Ndr::NdrConfArray
298
+ default_parameter type: :ndr_uint32
299
+ extend Ndr::PointerClassPlugin
300
+ end
301
+
302
+ # [2.2.7.4 SAMPR_ULONG_ARRAY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2feb3806-4db2-45b7-90d2-86c8336a31ba)
303
+ class SamprUlongArray < Ndr::NdrStruct
304
+ default_parameter byte_align: 4
305
+
306
+ ndr_uint32 :element_count, initial_value: -> { elements.size }
307
+ pulong_array :elements
308
+ end
309
+
310
+ # [2.2.2.4 RPC_SHORT_BLOB](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/77dbfdbb-6627-4871-ab12-5333929347dc)
311
+ class RpcShortBlob < BinData::Record
312
+ ndr_uint16 :buffer_length, initial_value: -> { buffer.length }
313
+ ndr_uint16 :max_length, initial_value: -> { buffer.length }
314
+ ndr_uint16_array_ptr :buffer
315
+ end
316
+
317
+ # [2.2.6.22 SAMPR_ENCRYPTED_USER_PASSWORD_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/112ecc94-1cbe-41cd-b669-377402c20786)
318
+ class SamprEncryptedUserPasswordNew < BinData::Record
319
+ ndr_fixed_byte_array :buffer, initial_length: 532
320
+
321
+ def self.encrypt_password(password, key)
322
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
323
+ password = password.encode('UTF-16LE').force_encoding('ASCII-8bit')
324
+ buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
325
+ salt = SecureRandom.random_bytes(16)
326
+ key = OpenSSL::Digest::MD5.new(salt + key).digest
327
+ cipher = OpenSSL::Cipher.new('RC4').tap do |cipher|
328
+ cipher.encrypt
329
+ cipher.key = key
330
+ end
331
+ cipher.update(buffer) + salt
332
+ end
333
+ end
334
+
335
+ # [2.2.6.5 SAMPR_LOGON_HOURS](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d83c356b-7dda-4096-8270-5c581f84a4d9)
336
+ class SamprLogonHours < BinData::Record
337
+ ndr_uint16 :units_per_week
338
+ ndr_byte_array_ptr :logon_hours
339
+ end
340
+
341
+ # [2.2.7.11 SAMPR_SR_SECURITY_DESCRIPTOR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/675e37d9-bb97-4f14-bba2-be081c87cd5d)
342
+ class SamprSrSecurityDescriptor < BinData::Record
343
+ ndr_uint32 :buffer_length, initial_value: -> { buffer.length }
344
+ ndr_byte_array_ptr :buffer
345
+ end
346
+
347
+ # [2.2.6.6 SAMPR_USER_ALL_INFORMATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/dc966b81-da27-4dae-a28c-ec16534f1cb9)
348
+ class SamprUserAllInformation < BinData::Record
349
+ ndr_uint64 :last_logon
350
+ ndr_uint64 :last_logoff
351
+ ndr_uint64 :password_last_set
352
+ ndr_uint64 :account_expires
353
+ ndr_uint64 :password_can_change
354
+ ndr_uint64 :password_must_change
355
+ rpc_unicode_string :user_name
356
+ rpc_unicode_string :full_name
357
+ rpc_unicode_string :home_directory
358
+ rpc_unicode_string :home_directory_drive
359
+ rpc_unicode_string :script_path
360
+ rpc_unicode_string :profile_path
361
+ rpc_unicode_string :admin_comment
362
+ rpc_unicode_string :work_stations
363
+ rpc_unicode_string :user_comment
364
+ rpc_unicode_string :parameters
365
+ rpc_short_blob :lm_owf_password
366
+ rpc_short_blob :nt_owf_password
367
+ rpc_unicode_string :private_data
368
+ sampr_sr_security_descriptor :security_descriptor
369
+ ndr_uint32 :user_id
370
+ ndr_uint32 :primary_group_id
371
+ ndr_uint32 :user_account_control
372
+ ndr_uint32 :which_fields
373
+ sampr_logon_hours :logon_hours
374
+ ndr_uint16 :bad_password_count
375
+ ndr_uint16 :logon_count
376
+ ndr_uint16 :country_code
377
+ ndr_uint16 :code_page
378
+ ndr_uint8 :lm_password_present
379
+ ndr_uint8 :nt_password_present
380
+ ndr_uint8 :password_expired
381
+ ndr_uint8 :private_data_sensitive
382
+ end
383
+
384
+ # [2.2.6.25 SAMPR_USER_INTERNAL4_INFORMATION_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/b2f614b9-0312-421a-abed-10ee002ef780)
385
+ class SamprUserInternal4InformationNew < BinData::Record
386
+ sampr_user_all_information :i1
387
+ sampr_encrypted_user_password_new :user_password
388
+ end
389
+
390
+ # [2.2.6.3 USER_CONTROL_INFORMATION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/eb5f1508-ede1-4ff1-be82-55f3e2ef1633)
391
+ class UserControlInformation < BinData::Record
392
+ endian :little
393
+
394
+ ndr_uint32 :user_account_control
395
+ end
396
+
397
+ # [2.2.6.29 SAMPR_USER_INFO_BUFFER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9496c26e-490b-4e76-827f-2695fc216f35)
398
+ class SamprUserInfoBuffer < BinData::Record
399
+ ndr_uint16 :tag
400
+ choice :member, selection: :tag do
401
+ user_control_information USER_CONTROL_INFORMATION
402
+ sampr_user_internal4_information_new USER_INTERNAL4_INFORMATION_NEW
403
+ end
404
+ end
405
+
406
+ # [2.2.10.2 USER_PROPERTY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7c0f2eca-1783-450b-b5a0-754cf11f22c9)
407
+ class UserProperty < BinData::Record
408
+ endian :little
409
+
410
+ uint16 :name_length, initial_value: -> { property_name.num_bytes }
411
+ uint16 :value_length, initial_value: -> { property_value.num_bytes }
412
+ uint16 :reserved
413
+ string16 :property_name, read_length: :name_length
414
+ string :property_value, read_length: :value_length
415
+ end
416
+
417
+ # [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad)
418
+ class UserProperties < BinData::Record
419
+ endian :little
420
+
421
+ uint32 :reserved1
422
+ uint32 :struct_length, initial_value: -> { num_bytes - 12 }
423
+ uint16 :reserved2
424
+ uint16 :reserved3
425
+ string :reserved4, length: 96
426
+ uint16 :property_signature, initial_value: 0x50
427
+ uint16 :property_count, initial_value: -> { user_properties.size }
428
+ array :user_properties, type: :user_property, initial_length: :property_count
429
+ uint8 :reserved5
430
+ end
431
+
432
+ # [2.2.10.7 KERB_KEY_DATA_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/447520a5-e1cc-48cc-8fdc-b90db57f7eac)
433
+ class KerbKeyDataNew < BinData::Record
434
+ endian :little
435
+
436
+ uint16 :reserved1
437
+ uint16 :reserved2
438
+ uint32 :reserved3
439
+ uint32 :iteration_count
440
+ uint32 :key_type
441
+ uint32 :key_length
442
+ uint32 :key_offset
443
+ end
444
+
445
+ # [2.2.10.6 Primary:Kerberos-Newer-Keys - KERB_STORED_CREDENTIAL_NEW](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/08cb3ca7-954b-45e3-902e-77512fe3ba8e)
446
+ class KerbStoredCredentialNew < BinData::Record
447
+ endian :little
448
+
449
+ uint16 :revision
450
+ uint16 :flags
451
+ uint16 :credential_count
452
+ uint16 :service_credential_count
453
+ uint16 :old_credential_count
454
+ uint16 :older_credential_count
455
+ uint16 :default_salt_length
456
+ uint16 :default_salt_maximum_length
457
+ uint32 :default_salt_offset
458
+ uint32 :default_iteration_count
459
+ array :credentials, type: :kerb_key_data_new, initial_length: :credential_count
460
+ array :service_credentials, type: :kerb_key_data_new, initial_length: :service_credential_count
461
+ array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count
462
+ array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count
463
+ string :default_salt, read_length: -> { credentials.map { |e| e.key_offset }.min - @obj.abs_offset }
464
+ string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum }
465
+
466
+ def get_key_values
467
+ credentials.map do |credential|
468
+ offset = credential.key_offset - key_values.abs_offset
469
+ key_values[offset, credential.key_length]
470
+ end
471
+ end
472
+ end
473
+
303
474
  require 'ruby_smb/dcerpc/samr/rpc_sid'
304
475
 
305
476
  require 'ruby_smb/dcerpc/samr/samr_connect_request'
306
477
  require 'ruby_smb/dcerpc/samr/samr_connect_response'
478
+ require 'ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request'
479
+ require 'ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response'
307
480
  require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request'
308
481
  require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response'
482
+ require 'ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request'
483
+ require 'ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response'
309
484
  require 'ruby_smb/dcerpc/samr/samr_open_domain_request'
310
485
  require 'ruby_smb/dcerpc/samr/samr_open_domain_response'
486
+ require 'ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request'
487
+ require 'ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response'
311
488
  require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request'
312
489
  require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response'
313
490
  require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_request'
@@ -320,6 +497,10 @@ module RubySMB
320
497
  require 'ruby_smb/dcerpc/samr/samr_open_user_response'
321
498
  require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_request'
322
499
  require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_response'
500
+ require 'ruby_smb/dcerpc/samr/samr_set_information_user2_request'
501
+ require 'ruby_smb/dcerpc/samr/samr_set_information_user2_response'
502
+ require 'ruby_smb/dcerpc/samr/samr_delete_user_request'
503
+ require 'ruby_smb/dcerpc/samr/samr_delete_user_response'
323
504
 
324
505
  # Returns a handle to a server object.
325
506
  #
@@ -352,6 +533,75 @@ module RubySMB
352
533
  samr_connect_response.server_handle
353
534
  end
354
535
 
536
+ # Create a new user.
537
+ #
538
+ # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
539
+ # handle representing the domain object
540
+ # @param name [String] The name of the account to add
541
+ # @param account_type [Integer] The type of account to add, one of either
542
+ # USER_NORMAL_ACCOUNT, USER_WORKSTATION_TRUST_ACCOUNT, or
543
+ # USER_SERVER_TRUST_ACCOUNT
544
+ # @param desired_access [Integer] The access requested on the returned
545
+ # object
546
+ # @return [RubySMB::Dcerpc::Samr::SamprHandle] handle to the server object.
547
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
548
+ # SamrConnectResponse packet
549
+ # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
550
+ # is not STATUS_SUCCESS
551
+ def samr_create_user2_in_domain(domain_handle:, name:, account_type: USER_NORMAL_ACCOUNT, desired_access: GROUP_ALL_ACCESS)
552
+ samr_create_request = SamrCreateUser2InDomainRequest.new(
553
+ domain_handle: domain_handle,
554
+ name: name,
555
+ account_type: account_type,
556
+ desired_access: desired_access
557
+ )
558
+ response = dcerpc_request(samr_create_request)
559
+ begin
560
+ samr_create_response = SamrCreateUser2InDomainResponse.read(response)
561
+ rescue IOError
562
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrCreateUser2InDomainResponse'
563
+ end
564
+ unless samr_create_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
565
+ raise RubySMB::Dcerpc::Error::SamrError,
566
+ "Error returned with samr_create_user2_in_domain: "\
567
+ "#{WindowsError::NTStatus.find_by_retval(samr_create_response.error_status.value).join(',')}"
568
+ end
569
+
570
+ {
571
+ user_handle: samr_create_response.user_handle,
572
+ granted_access: samr_create_response.granted_access.to_i,
573
+ relative_id: samr_create_response.relative_id.to_i
574
+ }
575
+ end
576
+
577
+ # Delete an existing user.
578
+ #
579
+ # @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
580
+ # handle representing the user object to delete
581
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
582
+ # SamrDeleteUserResponse packet
583
+ # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
584
+ # is not STATUS_SUCCESS
585
+ def samr_delete_user(user_handle:)
586
+ samr_delete_user_request = SamrDeleteUserRequest.new(
587
+ user_handle: user_handle
588
+ )
589
+
590
+ response = dcerpc_request(samr_delete_user_request)
591
+ begin
592
+ samr_delete_user_response = SamrDeleteUserResponse.read(response)
593
+ rescue IOError
594
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrDeleteUserResponse'
595
+ end
596
+ unless samr_delete_user_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
597
+ raise RubySMB::Dcerpc::Error::SamrError,
598
+ "Error returned while deleting user in SAM server: "\
599
+ "#{WindowsError::NTStatus.find_by_retval(samr_delete_user_response.error_status.value).join(',')}"
600
+ end
601
+
602
+ nil
603
+ end
604
+
355
605
  # Obtains the SID of a domain object
356
606
  #
357
607
  # @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
@@ -382,6 +632,50 @@ module RubySMB
382
632
  samr_lookup_domain_in_sam_server_response.domain_id
383
633
  end
384
634
 
635
+ # Obtains the SID of a domain object
636
+ #
637
+ # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
638
+ # handle representing the domain object
639
+ # @param name [Array<String>] An array of string account names to
640
+ # translate to RIDs.
641
+ # @return [Hash<String, Hash<Symbol, Integer>>, Nil] Returns a hash mapping
642
+ # the requested names to their information. Nil is returned if one or
643
+ # more names could not be found.
644
+ # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
645
+ # is not STATUS_SUCCESS, STATUS_NONE_MAPPED, or STATUS_SOME_NOT_MAPPED
646
+ def samr_lookup_names_in_domain(domain_handle:, names:)
647
+ raise ArgumentError.new('names may not be longer than 1000') if names.length > 1000
648
+
649
+ samr_lookup_request = SamrLookupNamesInDomainRequest.new(
650
+ domain_handle: domain_handle,
651
+ names_count: names.length,
652
+ names: names
653
+ )
654
+ samr_lookup_request.names.set_max_count(1000)
655
+ response = dcerpc_request(samr_lookup_request)
656
+ begin
657
+ samr_lookup_response = SamrLookupNamesInDomainResponse.read(response)
658
+ rescue IOError
659
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrLookupNamesInDomainResponse'
660
+ end
661
+ return nil if samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_NONE_MAPPED
662
+ return nil if samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_SOME_NOT_MAPPED
663
+ unless samr_lookup_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
664
+ raise RubySMB::Dcerpc::Error::SamrError,
665
+ "Error returned during names lookup in SAM server: "\
666
+ "#{WindowsError::NTStatus.find_by_retval(samr_lookup_response.error_status.value).join(',')}"
667
+ end
668
+
669
+ result = {}
670
+ names.each_with_index do |name, index|
671
+ result[name] = {
672
+ rid: samr_lookup_response.relative_ids.elements[index].to_i,
673
+ use: samr_lookup_response.use.elements[index].to_i
674
+ }
675
+ end
676
+ result
677
+ end
678
+
385
679
  # Returns a handle to a domain object.
386
680
  #
387
681
  # @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
@@ -415,11 +709,58 @@ module RubySMB
415
709
  samr_open_domain_response.domain_handle
416
710
  end
417
711
 
712
+ # Enumerates all domains on the remote server.
713
+ #
714
+ # @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
715
+ # handle representing the server object
716
+ # @param enumeration_context [Integer] a cookie used by the server to
717
+ # resume an enumeration
718
+ # @return [Array<String>] an array containing the domain names
719
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
720
+ # SamrEnumerateDomainsInSamServerResponse packet
721
+ # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
722
+ # is not STATUS_SUCCESS
723
+ def samr_enumerate_domains_in_sam_server(server_handle:, enumeration_context: 0)
724
+ samr_enum_domains_request = SamrEnumerateDomainsInSamServerRequest.new(
725
+ server_handle: server_handle,
726
+ enumeration_context: enumeration_context,
727
+ prefered_maximum_length: 0xFFFFFFFF
728
+ )
729
+ res = []
730
+ loop do
731
+ samr_enum_domains_request.enumeration_context = enumeration_context
732
+ response = dcerpc_request(samr_enum_domains_request)
733
+ begin
734
+ samr_enum_domains_reponse = SamrEnumerateDomainsInSamServerResponse.read(response)
735
+ rescue IOError
736
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrEnumerateDomainsInSamServerResponse'
737
+ end
738
+ unless samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_SUCCESS ||
739
+ samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES
740
+ raise RubySMB::Dcerpc::Error::SamrError,
741
+ "Error returned during domains enumeration in SAM server: "\
742
+ "#{WindowsError::NTStatus.find_by_retval(samr_enum_domains_reponse.error_status.value).join(',')}"
743
+ end
744
+ samr_enum_domains_reponse.buffer.buffer.each_with_object(res) do |entry, array|
745
+ array << entry.name.buffer
746
+ end
747
+ break unless samr_enum_domains_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES
748
+
749
+ enumeration_context = samr_enum_domains_reponse.enumeration_context
750
+ end
751
+
752
+ res
753
+ end
754
+
418
755
  # Enumerates all users in the specified domain.
419
756
  #
420
757
  # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context
421
758
  # handle representing the domain object
422
- # @return [Hash] hash mapping RID and username
759
+ # @param enumeration_context [Integer] a cookie used by the server to
760
+ # resume an enumeration
761
+ # @param user_account_control [Integer] a value to use for filtering on
762
+ # the userAccountControl attribute
763
+ # @return [Hash<Integer, String>] hash mapping RID and username
423
764
  # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
424
765
  # SamrEnumerateUsersInDomainResponse packet
425
766
  # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
@@ -486,6 +827,35 @@ module RubySMB
486
827
  samr_rid_to_sid_response.sid
487
828
  end
488
829
 
830
+ # Update attributes on a user object.
831
+ #
832
+ # @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
833
+ # representing a user object.
834
+ # @param user_info: [RubySMB::Dcerpc::Samr::SamprUserInfoBuffer] the user
835
+ # information to set.
836
+ # @return nothing is returned on success
837
+ # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
838
+ # is not STATUS_SUCCESS
839
+ def samr_set_information_user2(user_handle:, user_info:)
840
+ samr_set_information_user2_request = SamrSetInformationUser2Request.new(
841
+ user_handle: user_handle,
842
+ buffer: user_info
843
+ )
844
+ response = dcerpc_request(samr_set_information_user2_request)
845
+ begin
846
+ samr_set_information_user2_response = SamrSetInformationUser2Response.read(response)
847
+ rescue IOError
848
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrSetInformationUser2Response'
849
+ end
850
+ unless samr_set_information_user2_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
851
+ raise RubySMB::Dcerpc::Error::SamrError,
852
+ "Error returned while setting user information: "\
853
+ "#{WindowsError::NTStatus.find_by_retval(samr_set_information_user2_response.error_status.value).join(',')}"
854
+ end
855
+
856
+ nil
857
+ end
858
+
489
859
  # Closes (that is, releases server-side resources used by) any context
490
860
  # handle obtained from this RPC interface
491
861
  #
@@ -541,7 +911,7 @@ module RubySMB
541
911
  "Error returned while getting alias membership: "\
542
912
  "#{WindowsError::NTStatus.find_by_retval(samr_get_alias_membership_reponse.error_status.value).join(',')}"
543
913
  end
544
- return [] if samr_get_alias_membership_reponse.membership.elem_count == 0
914
+ return [] if samr_get_alias_membership_reponse.membership.element_count == 0
545
915
  samr_get_alias_membership_reponse.membership.elements.to_ary
546
916
  end
547
917
 
@@ -29,6 +29,7 @@ module RubySMB
29
29
 
30
30
  require 'windows_error/win32'
31
31
  require 'ruby_smb/dcerpc/error'
32
+ require 'ruby_smb/dcerpc/fault'
32
33
  require 'ruby_smb/dcerpc/uuid'
33
34
  require 'ruby_smb/dcerpc/ndr'
34
35
  require 'ruby_smb/dcerpc/ptypes'
@@ -142,7 +142,10 @@ module RubySMB
142
142
 
143
143
  def dcerpc_response_from_raw_response(raw_data)
144
144
  dcerpc_response = RubySMB::Dcerpc::Response.read(raw_data)
145
- unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
145
+ if dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::FAULT
146
+ status = dcerpc_response.stub.unpack('V').first
147
+ raise RubySMB::Dcerpc::Error::FaultError.new('A fault occurred', status: status)
148
+ elsif dcerpc_response.pdu_header.ptype != RubySMB::Dcerpc::PTypes::RESPONSE
146
149
  raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
147
150
  end
148
151
  dcerpc_response
@@ -135,12 +135,14 @@ module RubySMB
135
135
  end
136
136
  end
137
137
 
138
-
139
138
  private
140
139
 
141
140
  def dcerpc_response_from_raw_response(raw_data)
142
141
  dcerpc_response = RubySMB::Dcerpc::Response.read(raw_data)
143
- unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
142
+ if dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::FAULT
143
+ status = dcerpc_response.stub.unpack('V').first
144
+ raise RubySMB::Dcerpc::Error::FaultError.new('A fault occurred', status: status)
145
+ elsif dcerpc_response.pdu_header.ptype != RubySMB::Dcerpc::PTypes::RESPONSE
144
146
  raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
145
147
  end
146
148
  dcerpc_response
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.1.4'.freeze
2
+ VERSION = '3.1.5'.freeze
3
3
  end
@@ -1881,6 +1881,7 @@ RSpec.describe RubySMB::Client do
1881
1881
  before :example do
1882
1882
  smb2_client.smb3 = true
1883
1883
  smb2_client.session_encrypt_data = false
1884
+ smb2_client.preauth_integrity_hash_value = ''
1884
1885
  end
1885
1886
 
1886
1887
  it 'sets the session_encrypt_data parameter to true if the server requires encryption' do