ruby_smb 3.1.2 → 3.1.5

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 (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/examples/file_server.rb +6 -68
  4. data/examples/virtual_file_server.rb +10 -62
  5. data/lib/ruby_smb/client/authentication.rb +29 -4
  6. data/lib/ruby_smb/client/negotiation.rb +2 -0
  7. data/lib/ruby_smb/client.rb +18 -3
  8. data/lib/ruby_smb/dcerpc/error.rb +13 -0
  9. data/lib/ruby_smb/dcerpc/fault.rb +83 -0
  10. data/lib/ruby_smb/dcerpc/ndr.rb +19 -8
  11. data/lib/ruby_smb/dcerpc/request.rb +15 -10
  12. data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +5 -0
  13. data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request.rb +24 -0
  14. data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response.rb +24 -0
  15. data/lib/ruby_smb/dcerpc/samr/samr_delete_user_request.rb +21 -0
  16. data/lib/ruby_smb/dcerpc/samr/samr_delete_user_response.rb +22 -0
  17. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request.rb +25 -0
  18. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response.rb +25 -0
  19. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +0 -31
  20. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +1 -14
  21. data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb +23 -0
  22. data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb +23 -0
  23. data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb +23 -0
  24. data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb +21 -0
  25. data/lib/ruby_smb/dcerpc/samr.rb +453 -83
  26. data/lib/ruby_smb/dcerpc.rb +1 -0
  27. data/lib/ruby_smb/error.rb +4 -0
  28. data/lib/ruby_smb/gss.rb +1 -0
  29. data/lib/ruby_smb/ntlm/client.rb +74 -0
  30. data/lib/ruby_smb/ntlm.rb +1 -0
  31. data/lib/ruby_smb/server/cli.rb +121 -0
  32. data/lib/ruby_smb/server.rb +1 -0
  33. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +11 -0
  34. data/lib/ruby_smb/smb1/pipe.rb +4 -1
  35. data/lib/ruby_smb/smb2/pipe.rb +4 -2
  36. data/lib/ruby_smb/version.rb +1 -1
  37. data/spec/lib/ruby_smb/client_spec.rb +1 -0
  38. data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request_spec.rb +69 -0
  39. data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response_spec.rb +69 -0
  40. data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_request_spec.rb +42 -0
  41. data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_response_spec.rb +51 -0
  42. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request_spec.rb +60 -0
  43. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response_spec.rb +75 -0
  44. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +0 -195
  45. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request_spec.rb +62 -0
  46. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response_spec.rb +54 -0
  47. data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb +67 -0
  48. data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb +35 -0
  49. data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +194 -0
  50. data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +114 -0
  51. data/spec/lib/ruby_smb/ntlm/client_spec.rb +36 -0
  52. data.tar.gz.sig +0 -0
  53. metadata +39 -2
  54. 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'
@@ -99,6 +99,10 @@ module RubySMB
99
99
  # unsupported protocol.
100
100
  class NegotiationFailure < RubySMBError; end
101
101
 
102
+ # Raised when Authentication fails, possibly due to an
103
+ # unsupported GSS mechanism type.
104
+ class AuthenticationFailure < RubySMBError; end
105
+
102
106
  # Raised when trying to parse raw binary into a BitField and the data
103
107
  # is invalid.
104
108
  class InvalidBitField < RubySMBError; end
data/lib/ruby_smb/gss.rb CHANGED
@@ -14,6 +14,7 @@ module RubySMB
14
14
  # @param asn The ASN object to apply the traversal path on.
15
15
  # @param [Array] path The path to traverse, each element is passed to the
16
16
  # ASN object's #value's #[] operator.
17
+ # @return [OpenSSL::ASN1::Sequence, nil]
17
18
  def self.asn1dig(asn, *path)
18
19
  path.each do |part|
19
20
  return nil unless asn&.value