module RubySMB module Dcerpc module Samr UUID = '12345778-1234-abcd-ef00-0123456789ac' VER_MAJOR = 1 VER_MINOR = 0 # Operation numbers SAMR_CONNECT = 0x0000 SAMR_CLOSE_HANDLE = 0x0001 SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER = 0x0005 SAMR_OPEN_DOMAIN = 0x0007 SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D SAMR_GET_ALIAS_MEMBERSHIP = 0x0010 SAMR_OPEN_USER = 0x0022 SAMR_GET_GROUPS_FOR_USER = 0x0027 SAMR_RID_TO_SID = 0x0041 class SamprHandle < Ndr::NdrContextHandle; end # [2.2.10.2 USER_PROPERTY](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7c0f2eca-1783-450b-b5a0-754cf11f22c9) class UserProperty < BinData::Record endian :little uint16 :name_length, initial_value: -> { property_name.num_bytes } uint16 :value_length, initial_value: -> { property_value.num_bytes } uint16 :reserved string16 :property_name, read_length: :name_length string :property_value, read_length: :value_length end # [2.2.10.1 USER_PROPERTIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8263e7ab-aba9-43d2-8a36-3a9cb2dd3dad) class UserProperties < BinData::Record endian :little uint32 :reserved1 uint32 :struct_length, initial_value: -> { num_bytes - 12 } uint16 :reserved2 uint16 :reserved3 string :reserved4, length: 96 uint16 :property_signature, initial_value: 0x50 uint16 :property_count, initial_value: -> { user_properties.size } array :user_properties, type: :user_property, initial_length: :property_count uint8 :reserved5 end class KerbKeyDataNew < BinData::Record endian :little uint16 :reserved1 uint16 :reserved2 uint32 :reserved3 uint32 :iteration_count uint32 :key_type uint32 :key_length uint32 :key_offset end # [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) class KerbStoredCredentialNew < BinData::Record endian :little uint16 :revision uint16 :flags uint16 :credential_count uint16 :service_credential_count uint16 :old_credential_count uint16 :older_credential_count uint16 :default_salt_length uint16 :default_salt_maximum_length uint32 :default_salt_offset uint32 :default_iteration_count array :credentials, type: :kerb_key_data_new, initial_length: :credential_count array :service_credentials, type: :kerb_key_data_new, initial_length: :service_credential_count array :old_credentials, type: :kerb_key_data_new, initial_length: :old_credential_count array :older_credentials, type: :kerb_key_data_new, initial_length: :older_credential_count string :default_salt, read_length: -> { credentials.map { |e| e.key_offset }.min - @obj.abs_offset } string :key_values, read_length: -> { credentials.map { |e| e.key_length }.sum } def get_key_values credentials.map do |credential| offset = credential.key_offset - key_values.abs_offset key_values[offset, credential.key_length] end end end ################################# # Constants # ################################# ################ # ACCESS_MASK Values # [2.2.1.1 Common ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/15b9ebf7-161d-4c83-a672-dceb2ac8c448) DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 ACCESS_SYSTEM_SECURITY = 0x01000000 MAXIMUM_ALLOWED = 0x02000000 # [2.2.1.3 Server ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e8afb15e-c053-4984-b84b-66877236e141) SAM_SERVER_CONNECT = 0x00000001 SAM_SERVER_SHUTDOWN = 0x00000002 SAM_SERVER_INITIALIZE = 0x00000004 SAM_SERVER_CREATE_DOMAIN = 0x00000008 SAM_SERVER_ENUMERATE_DOMAINS = 0x00000010 SAM_SERVER_LOOKUP_DOMAIN = 0x00000020 SAM_SERVER_ALL_ACCESS = 0x000F003F SAM_SERVER_READ = 0x00020010 SAM_SERVER_WRITE = 0x0002000E SAM_SERVER_EXECUTE = 0x00020021 # [2.2.1.4 Domain ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/aef23495-f6aa-48e9-aebc-22e022a2b4eb) DOMAIN_READ_PASSWORD_PARAMETERS = 0x00000001 DOMAIN_WRITE_PASSWORD_PARAMS = 0x00000002 DOMAIN_READ_OTHER_PARAMETERS = 0x00000004 DOMAIN_WRITE_OTHER_PARAMETERS = 0x00000008 DOMAIN_CREATE_USER = 0x00000010 DOMAIN_CREATE_GROUP = 0x00000020 DOMAIN_CREATE_ALIAS = 0x00000040 DOMAIN_GET_ALIAS_MEMBERSHIP = 0x00000080 DOMAIN_LIST_ACCOUNTS = 0x00000100 DOMAIN_LOOKUP = 0x00000200 DOMAIN_ADMINISTER_SERVER = 0x00000400 DOMAIN_ALL_ACCESS = 0x000F07FF DOMAIN_READ = 0x00020084 DOMAIN_WRITE = 0x0002047A DOMAIN_EXECUTE = 0x00020301 # [2.2.1.5 Group ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/f24f9fa8-798d-4e7d-a110-a5eda6900f41) GROUP_READ_INFORMATION = 0x00000001 GROUP_WRITE_ACCOUNT = 0x00000002 GROUP_ADD_MEMBER = 0x00000004 GROUP_REMOVE_MEMBER = 0x00000008 GROUP_LIST_MEMBERS = 0x00000010 GROUP_ALL_ACCESS = 0x000F001F GROUP_READ = 0x00020010 GROUP_WRITE = 0x0002000E GROUP_EXECUTE = 0x00020001 # [2.2.1.6 Alias ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2da21c6c-5b15-46c8-bd4e-6a8443216e1a) ALIAS_ADD_MEMBER = 0x00000001 ALIAS_REMOVE_MEMBER = 0x00000002 ALIAS_LIST_MEMBERS = 0x00000004 ALIAS_READ_INFORMATION = 0x00000008 ALIAS_WRITE_ACCOUNT = 0x00000010 ALIAS_ALL_ACCESS = 0x000F001F ALIAS_READ = 0x00020004 ALIAS_WRITE = 0x00020013 ALIAS_EXECUTE = 0x00020008 # [2.2.1.7 User ACCESS_MASK Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/c0be3f43-bcf9-43ee-b027-3d02ab372c53) USER_READ_GENERAL = 0x00000001 USER_READ_PREFERENCES = 0x00000002 USER_WRITE_PREFERENCES = 0x00000004 USER_READ_LOGON = 0x00000008 USER_READ_ACCOUNT = 0x00000010 USER_WRITE_ACCOUNT = 0x00000020 USER_CHANGE_PASSWORD = 0x00000040 USER_FORCE_PASSWORD_CHANGE = 0x00000080 USER_LIST_GROUPS = 0x00000100 USER_READ_GROUP_INFORMATION = 0x00000200 USER_WRITE_GROUP_INFORMATION = 0x00000400 USER_ALL_ACCESS = 0x000F07FF USER_READ = 0x0002031A USER_WRITE = 0x00020044 USER_EXECUTE = 0x00020041 # [2.2.1.8 USER_ALL Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/2675c176-72e0-4ac9-ae6d-cdd87b8ba520) USER_ALL_USERNAME = 0x00000001 USER_ALL_FULLNAME = 0x00000002 USER_ALL_USERID = 0x00000004 USER_ALL_PRIMARYGROUPID = 0x00000008 USER_ALL_ADMINCOMMENT = 0x00000010 USER_ALL_USERCOMMENT = 0x00000020 USER_ALL_HOMEDIRECTORY = 0x00000040 USER_ALL_HOMEDIRECTORYDRIVE = 0x00000080 USER_ALL_SCRIPTPATH = 0x00000100 USER_ALL_PROFILEPATH = 0x00000200 USER_ALL_WORKSTATIONS = 0x00000400 USER_ALL_LASTLOGON = 0x00000800 USER_ALL_LASTLOGOFF = 0x00001000 USER_ALL_LOGONHOURS = 0x00002000 USER_ALL_BADPASSWORDCOUNT = 0x00004000 USER_ALL_LOGONCOUNT = 0x00008000 USER_ALL_PASSWORDCANCHANGE = 0x00010000 USER_ALL_PASSWORDMUSTCHANGE = 0x00020000 USER_ALL_PASSWORDLASTSET = 0x00040000 USER_ALL_ACCOUNTEXPIRES = 0x00080000 USER_ALL_USERACCOUNTCONTROL = 0x00100000 USER_ALL_PARAMETERS = 0x00200000 USER_ALL_COUNTRYCODE = 0x00400000 USER_ALL_CODEPAGE = 0x00800000 USER_ALL_NTPASSWORDPRESENT = 0x01000000 USER_ALL_LMPASSWORDPRESENT = 0x02000000 USER_ALL_PRIVATEDATA = 0x04000000 USER_ALL_PASSWORDEXPIRED = 0x08000000 USER_ALL_SECURITYDESCRIPTOR = 0x10000000 USER_ALL_UNDEFINED_MASK = 0xC0000000 # [2.2.1.9 ACCOUNT_TYPE Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e742be45-665d-4576-b872-0bc99d1e1fbe) SAM_DOMAIN_OBJECT = 0x00000000 SAM_GROUP_OBJECT = 0x10000000 SAM_NON_SECURITY_GROUP_OBJECT = 0x10000001 SAM_ALIAS_OBJECT = 0x20000000 SAM_NON_SECURITY_ALIAS_OBJECT = 0x20000001 SAM_USER_OBJECT = 0x30000000 SAM_MACHINE_ACCOUNT = 0x30000001 SAM_TRUST_ACCOUNT = 0x30000002 SAM_APP_BASIC_GROUP = 0x40000000 SAM_APP_QUERY_GROUP = 0x40000001 # [2.2.1.10 SE_GROUP Attributes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9e093bd2-e451-4dd5-9700-97b977d7ebb2) SE_GROUP_MANDATORY = 0x00000001 SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002 SE_GROUP_ENABLED = 0x00000004 # [2.2.1.11 GROUP_TYPE Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/1f8d7ea1-fcc1-4833-839a-f94d67c08fcd) GROUP_TYPE_ACCOUNT_GROUP = 0x00000002 GROUP_TYPE_RESOURCE_GROUP = 0x00000004 GROUP_TYPE_UNIVERSAL_GROUP = 0x00000008 GROUP_TYPE_SECURITY_ENABLED = 0x80000000 GROUP_TYPE_SECURITY_ACCOUNT = 0x80000002 GROUP_TYPE_SECURITY_RESOURCE = 0x80000004 GROUP_TYPE_SECURITY_UNIVERSAL = 0x80000008 # [2.2.1.12 USER_ACCOUNT Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/b10cfda1-f24f-441b-8f43-80cb93e786ec) USER_ACCOUNT_DISABLED = 0x00000001 USER_HOME_DIRECTORY_REQUIRED = 0x00000002 USER_PASSWORD_NOT_REQUIRED = 0x00000004 USER_TEMP_DUPLICATE_ACCOUNT = 0x00000008 USER_NORMAL_ACCOUNT = 0x00000010 USER_MNS_LOGON_ACCOUNT = 0x00000020 USER_INTERDOMAIN_TRUST_ACCOUNT = 0x00000040 USER_WORKSTATION_TRUST_ACCOUNT = 0x00000080 USER_SERVER_TRUST_ACCOUNT = 0x00000100 USER_DONT_EXPIRE_PASSWORD = 0x00000200 USER_ACCOUNT_AUTO_LOCKED = 0x00000400 USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x00000800 USER_SMARTCARD_REQUIRED = 0x00001000 USER_TRUSTED_FOR_DELEGATION = 0x00002000 USER_NOT_DELEGATED = 0x00004000 USER_USE_DES_KEY_ONLY = 0x00008000 USER_DONT_REQUIRE_PREAUTH = 0x00010000 USER_PASSWORD_EXPIRED = 0x00020000 USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x00040000 USER_NO_AUTH_DATA_REQUIRED = 0x00080000 USER_PARTIAL_SECRETS_ACCOUNT = 0x00100000 USER_USE_AES_KEYS = 0x00200000 # [2.2.1.13 UF_FLAG Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/10bf6c8e-34af-4cf9-8dff-6b6330922863) UF_SCRIPT = 0x00000001 UF_ACCOUNTDISABLE = 0x00000002 UF_HOMEDIR_REQUIRED = 0x00000008 UF_LOCKOUT = 0x00000010 UF_PASSWD_NOTREQD = 0x00000020 UF_PASSWD_CANT_CHANGE = 0x00000040 UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x00000080 UF_TEMP_DUPLICATE_ACCOUNT = 0x00000100 UF_NORMAL_ACCOUNT = 0x00000200 UF_INTERDOMAIN_TRUST_ACCOUNT = 0x00000800 UF_WORKSTATION_TRUST_ACCOUNT = 0x00001000 UF_SERVER_TRUST_ACCOUNT = 0x00002000 UF_DONT_EXPIRE_PASSWD = 0x00010000 UF_MNS_LOGON_ACCOUNT = 0x00020000 UF_SMARTCARD_REQUIRED = 0x00040000 UF_TRUSTED_FOR_DELEGATION = 0x00080000 UF_NOT_DELEGATED = 0x00100000 UF_USE_DES_KEY_ONLY = 0x00200000 UF_DONT_REQUIRE_PREAUTH = 0x00400000 UF_PASSWORD_EXPIRED = 0x00800000 UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x01000000 UF_NO_AUTH_DATA_REQUIRED = 0x02000000 UF_PARTIAL_SECRETS_ACCOUNT = 0x04000000 UF_USE_AES_KEYS = 0x08000000 # [2.2.1.14 Predefined RIDs](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/565a6584-3061-4ede-a531-f5c53826504b) DOMAIN_USER_RID_ADMIN = 0x000001F4 DOMAIN_USER_RID_GUEST = 0x000001F5 DOMAIN_USER_RID_KRBTGT = 0x000001F6 DOMAIN_GROUP_RID_ADMINS = 0x00000200 DOMAIN_GROUP_RID_USERS = 0x00000201 DOMAIN_GROUP_RID_COMPUTERS = 0x00000203 DOMAIN_GROUP_RID_CONTROLLERS = 0x00000204 DOMAIN_ALIAS_RID_ADMINS = 0x00000220 DOMAIN_GROUP_RID_READONLY_CONTROLLERS = 0x00000209 # [2.2.10.8 Kerberos Encryption Algorithm Identifiers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/1355fa6b-d097-4ecc-8d5e-75b3a6533e04) KERBEROS_TYPE = { 1 => 'dec-cbc-crc', 3 => 'des-cbc-md5', 17 => 'aes128-cts-hmac-sha1-96', 18 => 'aes256-cts-hmac-sha1-96', 0xffffff74 => 'rc4_hmac' } require 'ruby_smb/dcerpc/samr/rpc_sid' require 'ruby_smb/dcerpc/samr/samr_connect_request' require 'ruby_smb/dcerpc/samr/samr_connect_response' require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request' require 'ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response' require 'ruby_smb/dcerpc/samr/samr_open_domain_request' require 'ruby_smb/dcerpc/samr/samr_open_domain_response' require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request' require 'ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response' require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_request' require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_response' require 'ruby_smb/dcerpc/samr/samr_close_handle_request' require 'ruby_smb/dcerpc/samr/samr_close_handle_response' require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_request' require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_response' require 'ruby_smb/dcerpc/samr/samr_open_user_request' require 'ruby_smb/dcerpc/samr/samr_open_user_response' require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_request' require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_response' # Returns a handle to a server object. # # @param server_name [Char] the first character of the NETBIOS name of # the server (optional) # @param access [Numeric] access requested for ServerHandle upon output: # bitwise OR of common and server ACCESS_MASK values (defined in # lib/ruby_smb/dcerpc/samr.rb). # @return [RubySMB::Dcerpc::Samr::SamprHandle] handle to the server object. # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrConnectResponse packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_connect(server_name: '', access: MAXIMUM_ALLOWED) samr_connect_request = SamrConnectRequest.new( server_name: server_name, desired_access: access ) response = dcerpc_request(samr_connect_request) begin samr_connect_response = SamrConnectResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrConnectResponse' end unless samr_connect_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned with samr_connect: "\ "#{WindowsError::NTStatus.find_by_retval(samr_connect_response.error_status.value).join(',')}" end samr_connect_response.server_handle end # Obtains the SID of a domain object # # @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context # handle representing the server object # @param name [String] The domain name # @return [RubySMB::Dcerpc::RpcSid] SID value of a domain that # corresponds to the Name passed in # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrLookupDomainInSamServerResponse packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_lookup_domain(server_handle:, name:) samr_lookup_domain_in_sam_server_request = SamrLookupDomainInSamServerRequest.new( server_handle: server_handle, name: name ) response = dcerpc_request(samr_lookup_domain_in_sam_server_request) begin samr_lookup_domain_in_sam_server_response = SamrLookupDomainInSamServerResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrLookupDomainInSamServerResponse' end unless samr_lookup_domain_in_sam_server_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned during domain lookup in SAM server: "\ "#{WindowsError::NTStatus.find_by_retval(samr_lookup_domain_in_sam_server_response.error_status.value).join(',')}" end samr_lookup_domain_in_sam_server_response.domain_id end # Returns a handle to a domain object. # # @param server_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context # handle representing the server object # @param access [Numeric] access requested for ServerHandle upon output: # bitwise OR of common and server ACCESS_MASK values (defined in # lib/ruby_smb/dcerpc/samr.rb). # @param domain_id [RubySMB::Dcerpc::RpcSid] SID value of a domain # @return [RubySMB::Dcerpc::Samr::SamprHandle] handle to the domain object. # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrOpenDomainResponse packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_open_domain(server_handle:, access: MAXIMUM_ALLOWED, domain_id:) samr_open_domain_request = SamrOpenDomainRequest.new( server_handle: server_handle, desired_access: access, domain_id: domain_id ) response = dcerpc_request(samr_open_domain_request) begin samr_open_domain_response = SamrOpenDomainResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrLookupDomainInSamServerResponse' end unless samr_open_domain_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned during domain lookup in SAM server: "\ "#{WindowsError::NTStatus.find_by_retval(samr_open_domain_response.error_status.value).join(',')}" end samr_open_domain_response.domain_handle end # Enumerates all users in the specified domain. # # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] RPC context # handle representing the domain object # @return [Hash] hash mapping RID and username # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrEnumerateUsersInDomainResponse packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_enumerate_users_in_domain(domain_handle:, enumeration_context: 0, user_account_control: USER_NORMAL_ACCOUNT | USER_WORKSTATION_TRUST_ACCOUNT | USER_SERVER_TRUST_ACCOUNT | USER_INTERDOMAIN_TRUST_ACCOUNT) samr_enum_users_request = SamrEnumerateUsersInDomainRequest.new( domain_handle: domain_handle, user_account_control: user_account_control, prefered_maximum_length: 0xFFFFFFFF ) res = {} loop do samr_enum_users_request.enumeration_context = enumeration_context response = dcerpc_request(samr_enum_users_request) begin samr_enum_users_reponse= SamrEnumerateUsersInDomainResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrEnumerateUsersInDomainResponse' end unless samr_enum_users_reponse.error_status == WindowsError::NTStatus::STATUS_SUCCESS || samr_enum_users_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES raise RubySMB::Dcerpc::Error::SamrError, "Error returned during users enumeration in SAM server: "\ "#{WindowsError::NTStatus.find_by_retval(samr_enum_users_reponse.error_status.value).join(',')}" end samr_enum_users_reponse.buffer.buffer.each_with_object(res) do |entry, hash| hash[entry.relative_id] = entry.name.buffer end break unless samr_enum_users_reponse.error_status == WindowsError::NTStatus::STATUS_MORE_ENTRIES enumeration_context = samr_enum_users_reponse.enumeration_context end res end # Returns the SID of an account, given a RID. # # @param rid [Numeric] the RID # @return [String] The SID of the account referenced by RID # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrRidToSidResponse packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_rid_to_sid(object_handle:, rid:) samr_rid_to_sid_request = SamrRidToSidRequest.new( object_handle: object_handle, rid: rid ) response = dcerpc_request(samr_rid_to_sid_request) begin samr_rid_to_sid_response = SamrRidToSidResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrRidToSidResponse' end unless samr_rid_to_sid_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned during SID lookup in SAM server: "\ "#{WindowsError::NTStatus.find_by_retval(samr_rid_to_sid_response.error_status.value).join(',')}" end samr_rid_to_sid_response.sid end # Closes (that is, releases server-side resources used by) any context # handle obtained from this RPC interface # # @param sam_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context # handle to close # @return [RubySMB::Dcerpc::Samr::SamprHandle] A zero handle on success # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrCloseHandle packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def close_handle(sam_handle) samr_close_handle_request = SamrCloseHandleRequest.new(sam_handle: sam_handle) response = dcerpc_request(samr_close_handle_request) begin samr_close_handle_response = SamrCloseHandleResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrCloseHandleResponse' end unless samr_close_handle_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned with samr_connect: "\ "#{WindowsError::NTStatus.find_by_retval(samr_close_handle_response.error_status.value).join(',')}" end samr_close_handle_response.sam_handle end # Returns the union of all aliases that a given set of SIDs is a member of. # # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context # representing a domain object. # @param sids [Array, RubySMB::Dcerpc::Samr::RpcSid] List of SID's # @return [Array] The union of all aliases represented by RID's # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrGetAliasMembership packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_get_alias_membership(domain_handle:, sids:) sids = [sids] unless sids.is_a?(::Array) samr_get_alias_membership_request = SamrGetAliasMembershipRequest.new( domain_handle: domain_handle ) sids.each do |sid| samr_get_alias_membership_request.sid_array.sids << {sid_pointer: sid} end response = dcerpc_request(samr_get_alias_membership_request) begin samr_get_alias_membership_reponse= SamrGetAliasMembershipResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrGetAliasMembershipResponse' end unless samr_get_alias_membership_reponse.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned while getting alias membership: "\ "#{WindowsError::NTStatus.find_by_retval(samr_get_alias_membership_reponse.error_status.value).join(',')}" end return [] if samr_get_alias_membership_reponse.membership.elem_count == 0 samr_get_alias_membership_reponse.membership.elements.to_ary end # Returns a handle to a user, given a RID # # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context # representing a domain object # @param access [Integer] An access control that indicates the requested # access for the returned handle. It is a bitwise OR of common # ACCESS_MASK and user ACCESS_MASK values (see # lib/ruby_smb/dcerpc/samr.rb) # @param user_id [Integer] RID of a user account # @return [RubySMB::Dcerpc::Samr::SamprHandle] The user handle # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrOpenUser packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_open_user(domain_handle:, access: MAXIMUM_ALLOWED, user_id:) samr_open_user_request = SamrOpenUserRequest.new( domain_handle: domain_handle, desired_access: access, user_id: user_id ) response = dcerpc_request(samr_open_user_request) begin samr_open_user_response = SamrOpenUserResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrOpenUserResponse' end unless samr_open_user_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned when getting a handle to user #{user_id}: "\ "#{WindowsError::NTStatus.find_by_retval(samr_open_user_response.error_status.value).join(',')}" end samr_open_user_response.user_handle end # Returns a listing of groups that a user is a member of # # @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context # representing a user object. # @return [Array] Array of # GroupMembership containing RID and Attributes # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # SamrGetGroupsForUser packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def samr_get_group_for_user(user_handle:) samr_get_groups_for_user_request = SamrGetGroupsForUserRequest.new( user_handle: user_handle ) response = dcerpc_request(samr_get_groups_for_user_request) begin samr_get_groups_for_user_reponse= SamrGetGroupsForUserResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrGetGroupsForUserResponse' end unless samr_get_groups_for_user_reponse.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::SamrError, "Error returned while getting user groups: "\ "#{WindowsError::NTStatus.find_by_retval(samr_get_groups_for_user_reponse.error_status.value).join(',')}" end samr_get_groups_for_user_reponse.groups.groups.to_ary end end end end