diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb index 3cfd38010..90ec26b0f 100644 --- a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +++ b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb @@ -1,11 +1,3 @@ -RSpec.describe RubySMB::Dcerpc::Wkssvc::WkssvcIdentifyHandle do - subject(:packet) { described_class.new } - - it 'is a Ndr::NdrWideStringPtr' do - expect(packet).to be_a(RubySMB::Dcerpc::Ndr::NdrWideStringPtr) - end -end - RSpec.describe RubySMB::Dcerpc::Wkssvc::NetrWkstaGetInfoRequest do subject(:packet) { described_class.new } diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb index 4e8e251cb..c29c67e25 100644 --- a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +++ b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb @@ -305,7 +305,7 @@ it 'is little endian' do expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little end - it 'it is a Ndr::NdrStruct' do + it 'is a Ndr::NdrStruct' do expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct end describe '#level' do diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_identity_handle.rb b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_identity_handle.rb new file mode 100644 index 000000000..6fa4c8feb --- /dev/null +++ b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_identity_handle.rb @@ -0,0 +1,7 @@ +RSpec.describe RubySMB::Dcerpc::Wkssvc::WkssvcIdentifyHandle do + subject(:packet) { described_class.new } + + it 'is a Ndr::NdrWideStringPtr' do + expect(packet).to be_a(RubySMB::Dcerpc::Ndr::NdrWideStringPtr) + end +end diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request_spec.rb b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request_spec.rb new file mode 100644 index 000000000..8c07268e8 --- /dev/null +++ b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request_spec.rb @@ -0,0 +1,71 @@ +RSpec.describe RubySMB::Dcerpc::Wkssvc::NetrWkstaUserEnumRequest do + subject(:packet) { described_class.new } + + def random_str(nb = 8) + nb.times.map { rand('a'.ord..'z'.ord).chr }.join + end + + it { is_expected.to respond_to :server_name } + it { is_expected.to respond_to :user_info } + it { is_expected.to respond_to :preferred_max_length } + it { is_expected.to respond_to :result_handle } + it { is_expected.to respond_to :opnum } + + it 'is little endian' do + expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little + end + it 'is a BinData::Record' do + expect(packet).to be_a(BinData::Record) + end + describe '#server_name' do + it 'is a WkssvcIdentifyHandle structure' do + expect(packet.server_name).to be_a RubySMB::Dcerpc::Wkssvc::WkssvcIdentifyHandle + end + end + describe '#user_info' do + it 'is a LpwkssvcUserEnumStructure structure' do + expect(packet.user_info).to be_a RubySMB::Dcerpc::Wkssvc::LpwkssvcUserEnumStructure + end + end + describe '#preferred_max_length' do + it 'is a NdrUint32 structure' do + expect(packet.preferred_max_length).to be_a RubySMB::Dcerpc::Ndr::NdrUint32 + end + + it 'has a default value of 0xFFFFFFFF' do + expect(packet.preferred_max_length).to eq(0xFFFFFFFF) + end + end + describe '#result_handle' do + it 'is a NdrUint32Ptr structure' do + expect(packet.result_handle).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr + end + + it 'has a default value of 0' do + expect(packet.result_handle).to eq(0) + end + end + describe '#initialize_instance' do + it 'sets #opnum to NETR_WKSTA_USER_ENUM constant' do + expect(packet.opnum).to eq(RubySMB::Dcerpc::Wkssvc::NETR_WKSTA_USER_ENUM) + end + end + it 'reads itself' do + packet = described_class.new( + server_name: 'TestServer', + user_info: { + level: RubySMB::Dcerpc::Wkssvc::WKSTA_USER_INFO_0, + info: { + wkui0_entries_read: 1, + wkui0_buffer: [{ + wkui0_username: random_str + }], + }, + }, + preferred_max_length: 0xFFFFFFFF, + result_handle: 0 + ) + binary = packet.to_binary_s + expect(described_class.read(binary)).to eq(packet) + end +end diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response_spec.rb b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response_spec.rb new file mode 100644 index 000000000..bfae967d3 --- /dev/null +++ b/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response_spec.rb @@ -0,0 +1,65 @@ +RSpec.describe RubySMB::Dcerpc::Wkssvc::NetrWkstaUserEnumResponse do + subject(:packet) { described_class.new } + + def random_str(nb = 8) + nb.times.map { rand('a'.ord..'z'.ord).chr }.join + end + + it { is_expected.to respond_to :user_info } + it { is_expected.to respond_to :total_entries } + it { is_expected.to respond_to :result_handle } + it { is_expected.to respond_to :error_status } + + it 'is little endian' do + expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little + end + it 'is a BinData::Record' do + expect(packet).to be_a(BinData::Record) + end + describe '#user_info' do + it 'is a LpwkssvcUserEnumStructure structure' do + expect(packet.user_info).to be_a RubySMB::Dcerpc::Wkssvc::LpwkssvcUserEnumStructure + end + end + describe '#total_entries' do + it 'is a NdrUint32Ptr structure' do + expect(packet.total_entries).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr + end + end + describe '#result_handle' do + it 'is a NdrUint32Ptr structure' do + expect(packet.result_handle).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr + end + end + describe '#error_status' do + it 'is a NdrUint32 structure' do + expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32 + end + end + describe '#initialize_instance' do + it 'sets #opnum to NETR_WKSTA_USER_ENUM constant' do + expect(packet.opnum).to eq(RubySMB::Dcerpc::Wkssvc::NETR_WKSTA_USER_ENUM) + end + end + it 'reads itself' do + packet = described_class.new( + user_info: { + level: RubySMB::Dcerpc::Wkssvc::WKSTA_USER_INFO_1, + info: { + wkui1_entries_read: 1, + wkui1_buffer: [{ + wkui1_username: random_str, + wkui1_logon_domain: random_str, + wkui1_oth_domains: random_str, + wkui1_logon_server: random_str + }], + }, + }, + total_entries: 1, + result_handle: 0, + error_status: 0 + ) + binary = packet.to_binary_s + expect(described_class.read(binary)).to eq(packet) + end +end diff --git a/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb b/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb index fb5020d8e..6a8469fe8 100644 --- a/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +++ b/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb @@ -1,3 +1,11 @@ +RSpec.describe RubySMB::Dcerpc::Wkssvc::WkssvcIdentifyHandle do + subject(:packet) { described_class.new } + + it 'is a Ndr::NdrWideStringPtr' do + expect(packet).to be_a(RubySMB::Dcerpc::Ndr::NdrWideStringPtr) + end +end + RSpec.describe RubySMB::Dcerpc::Wkssvc do let(:wkssvc) do RubySMB::SMB1::Pipe.new( @@ -67,4 +75,53 @@ end end end + + describe '#netr_wksta_user_enum' do + let(:wkst_netr_wksta_user_enum_request) { double('NetrWkstaUserEnumRequest') } + let(:response) { double('Response') } + let(:wkst_netr_wksta_user_enum_response) { double('NetrWkstaUserEnumResponse') } + let(:info) { double('info') } + before :example do + allow(described_class::NetrWkstaUserEnumRequest).to receive(:new).and_return(wkst_netr_wksta_user_enum_request) + allow(wkssvc).to receive(:dcerpc_request).and_return(response) + allow(described_class::NetrWkstaUserEnumResponse).to receive(:read).and_return(wkst_netr_wksta_user_enum_response) + allow(wkst_netr_wksta_user_enum_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS) + allow(wkst_netr_wksta_user_enum_response).to receive_message_chain(:user_info, :info => info) + end + + it 'sets the request with the expected values' do + wkssvc.netr_wksta_user_enum + expect(described_class::NetrWkstaUserEnumRequest).to have_received(:new).with( + server_name: "\x00", + user_info: { + level: described_class::WKSTA_USER_INFO_0, + tag: described_class::WKSTA_USER_INFO_0, + info: { + wkui0_entries_read: 0, + }, + }, + preferred_max_length: 0xFFFFFFFF, + result_handle: 0 + ) + end + it 'send the expected request structure' do + wkssvc.netr_wksta_user_enum + expect(wkssvc).to have_received(:dcerpc_request).with(wkst_netr_wksta_user_enum_request) + end + context 'when an IOError occurs while parsing the response' do + it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do + allow(described_class::NetrWkstaUserEnumResponse).to receive(:read).and_raise(IOError) + expect { wkssvc.netr_wksta_user_enum }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket) + end + end + context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do + it 'raises a RubySMB::Dcerpc::Error::WinregError' do + allow(wkst_netr_wksta_user_enum_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA) + expect { wkssvc.netr_wksta_user_enum }.to raise_error(RubySMB::Dcerpc::Error::WkssvcError) + end + end + it 'returns the expected handler' do + expect(wkssvc.netr_wksta_user_enum).to eq(info) + end + end end