ruby_smb 0.0.18 → 0.0.19
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +247 -7
- data/examples/anonymous_auth.rb +6 -3
- data/examples/append_file.rb +40 -0
- data/examples/authenticate.rb +12 -7
- data/examples/delete_file.rb +40 -0
- data/examples/list_directory.rb +45 -0
- data/examples/negotiate.rb +0 -1
- data/examples/negotiate_with_netbios_service.rb +36 -0
- data/examples/net_share_enum_all.rb +30 -0
- data/examples/read_file.rb +39 -0
- data/examples/rename_file.rb +41 -0
- data/examples/tree_connect.rb +2 -4
- data/examples/write_file.rb +40 -0
- data/lib/ruby_smb.rb +5 -0
- data/lib/ruby_smb/client.rb +196 -43
- data/lib/ruby_smb/client/authentication.rb +89 -48
- data/lib/ruby_smb/client/echo.rb +1 -4
- data/lib/ruby_smb/client/negotiation.rb +46 -45
- data/lib/ruby_smb/client/signing.rb +9 -16
- data/lib/ruby_smb/client/tree_connect.rb +8 -13
- data/lib/ruby_smb/client/utils.rb +79 -0
- data/lib/ruby_smb/dcerpc.rb +30 -0
- data/lib/ruby_smb/dcerpc/bind.rb +60 -0
- data/lib/ruby_smb/dcerpc/handle.rb +60 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +41 -0
- data/lib/ruby_smb/dcerpc/request.rb +43 -0
- data/lib/ruby_smb/dcerpc/response.rb +46 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +17 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +93 -0
- data/lib/ruby_smb/dcerpc/uuid.rb +28 -0
- data/lib/ruby_smb/dispatcher.rb +7 -3
- data/lib/ruby_smb/dispatcher/base.rb +23 -14
- data/lib/ruby_smb/dispatcher/socket.rb +71 -51
- data/lib/ruby_smb/dispositions.rb +32 -0
- data/lib/ruby_smb/error.rb +24 -18
- data/lib/ruby_smb/field.rb +5 -2
- data/lib/ruby_smb/field/extended_attribute_flag.rb +1 -1
- data/lib/ruby_smb/field/file_time.rb +3 -1
- data/lib/ruby_smb/field/security_descriptor.rb +6 -6
- data/lib/ruby_smb/field/smb2_fileid.rb +11 -0
- data/lib/ruby_smb/field/smb_fea.rb +3 -3
- data/lib/ruby_smb/field/smb_fea_list.rb +3 -3
- data/lib/ruby_smb/field/smb_gea.rb +12 -0
- data/lib/ruby_smb/field/smb_gea_list.rb +13 -0
- data/lib/ruby_smb/field/string16.rb +14 -0
- data/lib/ruby_smb/field/stringz16.rb +3 -7
- data/lib/ruby_smb/field/utime.rb +11 -10
- data/lib/ruby_smb/fscc.rb +12 -0
- data/lib/ruby_smb/fscc/control_codes.rb +26 -0
- data/lib/ruby_smb/{field → fscc}/ea_info_array.rb +12 -14
- data/lib/ruby_smb/fscc/file_attributes.rb +29 -0
- data/lib/ruby_smb/{field → fscc}/file_full_ea_info.rb +5 -5
- data/lib/ruby_smb/fscc/file_information.rb +60 -0
- data/lib/ruby_smb/fscc/file_information/file_both_directory_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_information/file_directory_information.rb +25 -0
- data/lib/ruby_smb/fscc/file_information/file_disposition_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_full_directory_information.rb +26 -0
- data/lib/ruby_smb/fscc/file_information/file_id_both_directory_information.rb +31 -0
- data/lib/ruby_smb/fscc/file_information/file_id_full_directory_information.rb +28 -0
- data/lib/ruby_smb/fscc/file_information/file_names_information.rb +18 -0
- data/lib/ruby_smb/fscc/file_information/file_rename_information.rb +44 -0
- data/lib/ruby_smb/generic_packet.rb +40 -18
- data/lib/ruby_smb/gss.rb +49 -56
- data/lib/ruby_smb/impersonation_levels.rb +7 -2
- data/lib/ruby_smb/nbss.rb +16 -0
- data/lib/ruby_smb/nbss/negative_session_response.rb +30 -0
- data/lib/ruby_smb/nbss/session_header.rb +13 -0
- data/lib/ruby_smb/nbss/session_request.rb +13 -0
- data/lib/ruby_smb/smb1.rb +20 -17
- data/lib/ruby_smb/smb1/bit_field.rb +3 -0
- data/lib/ruby_smb/smb1/bit_field/create_options.rb +5 -5
- data/lib/ruby_smb/smb1/bit_field/file_status_flags.rb +18 -0
- data/lib/ruby_smb/smb1/bit_field/open2_access_mode.rb +11 -11
- data/lib/ruby_smb/smb1/bit_field/open2_open_mode.rb +1 -1
- data/lib/ruby_smb/smb1/bit_field/optional_support.rb +0 -1
- data/lib/ruby_smb/smb1/bit_field/security_flags.rb +15 -0
- data/lib/ruby_smb/smb1/bit_field/share_access.rb +2 -3
- data/lib/ruby_smb/smb1/bit_field/smb_ext_file_attributes.rb +21 -24
- data/lib/ruby_smb/smb1/bit_field/smb_file_attributes.rb +1 -1
- data/lib/ruby_smb/smb1/commands.rb +5 -0
- data/lib/ruby_smb/smb1/create_actions.rb +3 -5
- data/lib/ruby_smb/smb1/file.rb +289 -0
- data/lib/ruby_smb/smb1/oplock_levels.rb +2 -4
- data/lib/ruby_smb/smb1/packet.rb +10 -0
- data/lib/ruby_smb/smb1/packet/close_request.rb +31 -0
- data/lib/ruby_smb/smb1/packet/close_response.rb +28 -0
- data/lib/ruby_smb/smb1/packet/echo_request.rb +5 -7
- data/lib/ruby_smb/smb1/packet/echo_response.rb +5 -7
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +1 -2
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +1 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +1 -4
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +22 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +22 -0
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +62 -0
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +66 -0
- data/lib/ruby_smb/smb1/packet/nt_trans.rb +1 -2
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +19 -13
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +8 -10
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +11 -11
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +10 -10
- data/lib/ruby_smb/smb1/packet/nt_trans/subcommands.rb +8 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +84 -0
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +47 -0
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -6
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +1 -4
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -6
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +6 -7
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +77 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +87 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +32 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_full_directory_info.rb +45 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +77 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +86 -0
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +10 -10
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +10 -12
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +15 -17
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +8 -10
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +11 -13
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +66 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +57 -0
- data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +5 -2
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -6
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +5 -7
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -4
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +68 -0
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +35 -0
- data/lib/ruby_smb/smb1/resource_type.rb +18 -0
- data/lib/ruby_smb/smb1/tree.rb +188 -5
- data/lib/ruby_smb/smb2.rb +16 -11
- data/lib/ruby_smb/smb2/bit_field.rb +1 -0
- data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +1 -2
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +4 -6
- data/lib/ruby_smb/smb2/create_context.rb +29 -0
- data/lib/ruby_smb/smb2/file.rb +251 -0
- data/lib/ruby_smb/smb2/info_type.rb +21 -0
- data/lib/ruby_smb/smb2/packet.rb +16 -0
- data/lib/ruby_smb/smb2/packet/close_request.rb +22 -0
- data/lib/ruby_smb/smb2/packet/close_response.rb +29 -0
- data/lib/ruby_smb/smb2/packet/create_request.rb +54 -0
- data/lib/ruby_smb/smb2/packet/create_response.rb +35 -0
- data/lib/ruby_smb/smb2/packet/echo_request.rb +1 -3
- data/lib/ruby_smb/smb2/packet/echo_response.rb +1 -3
- data/lib/ruby_smb/smb2/packet/error_packet.rb +1 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +54 -0
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +39 -0
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +1 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +1 -4
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +1 -1
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +35 -0
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +45 -0
- data/lib/ruby_smb/smb2/packet/read_request.rb +30 -0
- data/lib/ruby_smb/smb2/packet/read_response.rb +26 -0
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +4 -7
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +58 -0
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +20 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +3 -4
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +5 -9
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +1 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +1 -4
- data/lib/ruby_smb/smb2/packet/write_request.rb +29 -0
- data/lib/ruby_smb/smb2/packet/write_response.rb +26 -0
- data/lib/ruby_smb/smb2/tree.rb +163 -7
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +459 -120
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +14 -0
- data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +31 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +21 -0
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +15 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +12 -0
- data/spec/lib/ruby_smb/dispatcher/base_spec.rb +26 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +118 -18
- data/spec/lib/ruby_smb/field/extended_attribute_flag_spec.rb +0 -3
- data/spec/lib/ruby_smb/field/file_time_spec.rb +4 -2
- data/spec/lib/ruby_smb/field/security_descriptor.rb +0 -1
- data/spec/lib/ruby_smb/field/smb2_fileid_spec.rb +10 -0
- data/spec/lib/ruby_smb/field/smb_fea_list_spec.rb +3 -5
- data/spec/lib/ruby_smb/field/smb_gea_list_spec.rb +37 -0
- data/spec/lib/ruby_smb/field/smb_gea_spec.rb +22 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +7 -9
- data/spec/lib/ruby_smb/field/utime_spec.rb +4 -2
- data/spec/lib/ruby_smb/{field → fscc}/ea_info_array_spec.rb +7 -9
- data/spec/lib/ruby_smb/{field → fscc}/file_full_ea_info_spec.rb +2 -3
- data/spec/lib/ruby_smb/fscc/file_information/file_both_directory_information_spec.rb +71 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_directory_information_spec.rb +68 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_disposition_information_spec.rb +26 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_full_directory_information_spec.rb +69 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_id_both_directory_information_spec.rb +72 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_id_full_directory_information_spec.rb +70 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_names_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_rename_information_spec.rb +133 -0
- data/spec/lib/ruby_smb/fscc/fscc_file_attributes_spec.rb +143 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +46 -21
- data/spec/lib/ruby_smb/nbss/negative_session_response_spec.rb +29 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +30 -0
- data/spec/lib/ruby_smb/nbss/session_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/smb1/bit_field/create_options_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/bit_field/file_status_flags_spec.rb +35 -0
- data/spec/lib/ruby_smb/smb1/bit_field/open2_access_mode_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb1/bit_field/open2_flags_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/bit_field/open2_open_mode_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/bit_field/optional_support_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/bit_field/security_flags_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/bit_field/share_access_spec.rb +0 -3
- data/spec/lib/ruby_smb/smb1/bit_field/smb_ext_file_attributes_spec.rb +20 -39
- data/spec/lib/ruby_smb/smb1/bit_field/smb_file_attributes_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/bit_field/smb_nmpipe_status_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/bit_field/tree_connect_flags_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb1/file_spec.rb +469 -0
- data/spec/lib/ruby_smb/smb1/packet/close_request_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb1/packet/close_response_spec.rb +45 -0
- data/spec/lib/ruby_smb/smb1/packet/echo_request_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/echo_response_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb1/packet/logoff_request_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/logoff_response_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/negotiate_request_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_extended_spec.rb +37 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/smb1/packet/nt_create_andx_request_spec.rb +151 -0
- data/spec/lib/ruby_smb/smb1/packet/nt_create_andx_response_spec.rb +157 -0
- data/spec/lib/ruby_smb/smb1/packet/nt_trans/create_request_spec.rb +13 -6
- data/spec/lib/ruby_smb/smb1/packet/nt_trans/create_response_spec.rb +1 -7
- data/spec/lib/ruby_smb/smb1/packet/nt_trans/request_spec.rb +1 -6
- data/spec/lib/ruby_smb/smb1/packet/nt_trans/response_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/read_andx_request_spec.rb +149 -0
- data/spec/lib/ruby_smb/smb1/packet/read_andx_response_spec.rb +93 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +3 -8
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +180 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +104 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_full_directory_info_spec.rb +128 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +174 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +102 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_request_spec.rb +1 -6
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +2 -7
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_secondary_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +98 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +56 -0
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb +1 -5
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +1 -6
- data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_request_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_response_spec.rb +1 -4
- data/spec/lib/ruby_smb/smb1/packet/write_andx_request_spec.rb +148 -0
- data/spec/lib/ruby_smb/smb1/packet/write_andx_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +409 -7
- data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb2/bit_field/share_capabilities_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +0 -2
- data/spec/lib/ruby_smb/smb2/create_context_spec.rb +42 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +233 -0
- data/spec/lib/ruby_smb/smb2/packet/close_request_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb2/packet/close_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb2/packet/create_request_spec.rb +101 -0
- data/spec/lib/ruby_smb/smb2/packet/create_response_spec.rb +64 -0
- data/spec/lib/ruby_smb/smb2/packet/echo_request_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/echo_response_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/ioctl_request_spec.rb +48 -0
- data/spec/lib/ruby_smb/smb2/packet/logoff_request_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/logoff_response_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/query_directory_request_spec.rb +80 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +64 -0
- data/spec/lib/ruby_smb/smb2/packet/read_request_spec.rb +43 -0
- data/spec/lib/ruby_smb/smb2/packet/read_response_spec.rb +50 -0
- data/spec/lib/ruby_smb/smb2/packet/session_setup_request_spec.rb +3 -4
- data/spec/lib/ruby_smb/smb2/packet/session_setup_response_spec.rb +2 -3
- data/spec/lib/ruby_smb/smb2/packet/set_info_request_spec.rb +205 -0
- data/spec/lib/ruby_smb/smb2/packet/set_info_response_spec.rb +32 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +3 -5
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +1 -2
- data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_request_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_response_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb2/packet/write_request_spec.rb +51 -0
- data/spec/lib/ruby_smb/smb2/packet/write_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +191 -5
- data/spec/spec_helper.rb +1 -1
- metadata +195 -12
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dispositions.rb +0 -36
- data/spec/lib/ruby_smb/dispatcher/dispatcher_base_spec.rb +0 -22
@@ -0,0 +1,29 @@
|
|
1
|
+
RSpec.describe RubySMB::Nbss::NegativeSessionResponse do
|
2
|
+
subject(:negative_session_response) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :session_header }
|
5
|
+
it { is_expected.to respond_to :error_code }
|
6
|
+
|
7
|
+
it 'is big endian' do
|
8
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#session_header' do
|
12
|
+
it 'is a SessionHeader field' do
|
13
|
+
expect(negative_session_response.session_header).to be_a RubySMB::Nbss::SessionHeader
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#error_code' do
|
18
|
+
it 'is a 8-bit Unsigned Integer' do
|
19
|
+
expect(negative_session_response.error_code).to be_a BinData::Uint8
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#error_msg' do
|
24
|
+
it 'returns a string describing the error' do
|
25
|
+
negative_session_response.error_code = 0x80
|
26
|
+
expect(negative_session_response.error_msg).to eq 'Not listening on called name'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe RubySMB::Nbss::SessionHeader do
|
2
|
+
subject(:session_header) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :session_packet_type }
|
5
|
+
it { is_expected.to respond_to :flags }
|
6
|
+
it { is_expected.to respond_to :packet_length }
|
7
|
+
|
8
|
+
it 'is big endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#session_packet_type' do
|
13
|
+
it 'is a 8-bit Unsigned Integer' do
|
14
|
+
expect(session_header.session_packet_type).to be_a BinData::Uint8
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#flags' do
|
19
|
+
it 'is a 8-bit Unsigned Integer' do
|
20
|
+
expect(session_header.flags).to be_a BinData::Uint8
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#packet_length' do
|
25
|
+
it 'is a 16-bit Unsigned Integer' do
|
26
|
+
expect(session_header.packet_length).to be_a BinData::Uint16be
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe RubySMB::Nbss::SessionRequest do
|
2
|
+
subject(:session_request) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :session_header }
|
5
|
+
it { is_expected.to respond_to :called_name }
|
6
|
+
it { is_expected.to respond_to :calling_name }
|
7
|
+
|
8
|
+
it 'is big endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#session_header' do
|
13
|
+
it 'is a SessionHeader field' do
|
14
|
+
expect(session_request.session_header).to be_a RubySMB::Nbss::SessionHeader
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#called_name' do
|
19
|
+
it 'is a string' do
|
20
|
+
expect(session_request.called_name).to be_a BinData::String
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#calling_name' do
|
25
|
+
it 'is a string' do
|
26
|
+
expect(session_request.calling_name).to be_a BinData::String
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -171,6 +171,14 @@ RSpec.describe RubySMB::SMB1::BitField::CreateOptions do
|
|
171
171
|
it_behaves_like 'bit field with one flag set', :open_no_recall, 'V', 0x00400000
|
172
172
|
end
|
173
173
|
|
174
|
+
describe '#open_reparse_point' do
|
175
|
+
it 'is a 1-bit flag' do
|
176
|
+
expect(options.reserve_opfilter).to be_a BinData::Bit1
|
177
|
+
end
|
178
|
+
|
179
|
+
it_behaves_like 'bit field with one flag set', :open_reparse_point, 'V', 0x00200000
|
180
|
+
end
|
181
|
+
|
174
182
|
describe '#reserve_opfilter' do
|
175
183
|
it 'is a 1-bit flag' do
|
176
184
|
expect(options.reserve_opfilter).to be_a BinData::Bit1
|
@@ -178,4 +186,4 @@ RSpec.describe RubySMB::SMB1::BitField::CreateOptions do
|
|
178
186
|
|
179
187
|
it_behaves_like 'bit field with one flag set', :reserve_opfilter, 'V', 0x00100000
|
180
188
|
end
|
181
|
-
end
|
189
|
+
end
|
@@ -34,7 +34,6 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
34
34
|
it_behaves_like 'bit field with one flag set', :list, 'V', 0x00000001
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
37
|
describe '#add_file' do
|
39
38
|
it 'should be a 1-bit field per the SMB spec' do
|
40
39
|
expect(flags.add_file).to be_a BinData::Bit1
|
@@ -186,5 +185,4 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
186
185
|
|
187
186
|
it_behaves_like 'bit field with one flag set', :generic_read, 'V', 0x80000000
|
188
187
|
end
|
189
|
-
|
190
188
|
end
|
@@ -34,7 +34,6 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
34
34
|
it_behaves_like 'bit field with one flag set', :read_data, 'V', 0x00000001
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
37
|
describe '#write_data' do
|
39
38
|
it 'should be a 1-bit field per the SMB spec' do
|
40
39
|
expect(flags.write_data).to be_a BinData::Bit1
|
@@ -186,5 +185,4 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
186
185
|
|
187
186
|
it_behaves_like 'bit field with one flag set', :generic_read, 'V', 0x80000000
|
188
187
|
end
|
189
|
-
|
190
188
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::BitField::FileStatusFlags do
|
2
|
+
subject(:options) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :reparse_tag }
|
5
|
+
it { is_expected.to respond_to :no_substreams }
|
6
|
+
it { is_expected.to respond_to :no_eas }
|
7
|
+
|
8
|
+
it 'is little endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#reparse_tag' do
|
13
|
+
it 'is a 1-bit flag' do
|
14
|
+
expect(options.reparse_tag).to be_a BinData::Bit1
|
15
|
+
end
|
16
|
+
|
17
|
+
it_behaves_like 'bit field with one flag set', :reparse_tag, 'v', 0x0004
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#no_substreams' do
|
21
|
+
it 'is a 1-bit flag' do
|
22
|
+
expect(options.no_substreams).to be_a BinData::Bit1
|
23
|
+
end
|
24
|
+
|
25
|
+
it_behaves_like 'bit field with one flag set', :no_substreams, 'v', 0x0002
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#no_eas' do
|
29
|
+
it 'is a 1-bit flag' do
|
30
|
+
expect(options.no_eas).to be_a BinData::Bit1
|
31
|
+
end
|
32
|
+
|
33
|
+
it_behaves_like 'bit field with one flag set', :no_eas, 'v', 0x0001
|
34
|
+
end
|
35
|
+
end
|
@@ -73,9 +73,7 @@ RSpec.describe RubySMB::SMB1::BitField::Open2AccessMode do
|
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'raises an ArgumentError if given an invalid mode' do
|
76
|
-
expect{flags.set_access_mode('abcd')}.to raise_error(ArgumentError)
|
76
|
+
expect { flags.set_access_mode('abcd') }.to raise_error(ArgumentError)
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
80
|
-
|
81
79
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::BitField::SecurityFlags do
|
2
|
+
subject(:options) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :effective_only }
|
5
|
+
it { is_expected.to respond_to :context_tracking }
|
6
|
+
|
7
|
+
it 'is little endian' do
|
8
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#effective_only' do
|
12
|
+
it 'is a 1-bit flag' do
|
13
|
+
expect(options.effective_only).to be_a BinData::Bit1
|
14
|
+
end
|
15
|
+
|
16
|
+
it_behaves_like 'bit field with one flag set', :effective_only, 'C', 0x02
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#context_tracking' do
|
20
|
+
it 'is a 1-bit flag' do
|
21
|
+
expect(options.context_tracking).to be_a BinData::Bit1
|
22
|
+
end
|
23
|
+
|
24
|
+
it_behaves_like 'bit field with one flag set', :context_tracking, 'C', 0x01
|
25
|
+
end
|
26
|
+
end
|
@@ -9,13 +9,11 @@ RSpec.describe RubySMB::SMB1::BitField::SmbExtFileAttributes do
|
|
9
9
|
it { is_expected.to respond_to :read_only }
|
10
10
|
it { is_expected.to respond_to :compressed }
|
11
11
|
it { is_expected.to respond_to :temporary }
|
12
|
-
it { is_expected.to respond_to :
|
13
|
-
it { is_expected.to respond_to :
|
14
|
-
it { is_expected.to respond_to :
|
15
|
-
it { is_expected.to respond_to :
|
16
|
-
it { is_expected.to respond_to :
|
17
|
-
it { is_expected.to respond_to :backup_semantics }
|
18
|
-
it { is_expected.to respond_to :posix_semantics }
|
12
|
+
it { is_expected.to respond_to :encrypted }
|
13
|
+
it { is_expected.to respond_to :not_content_indexed }
|
14
|
+
it { is_expected.to respond_to :offline }
|
15
|
+
it { is_expected.to respond_to :reparse_point }
|
16
|
+
it { is_expected.to respond_to :sparse }
|
19
17
|
|
20
18
|
it 'is little endian' do
|
21
19
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
@@ -85,60 +83,43 @@ RSpec.describe RubySMB::SMB1::BitField::SmbExtFileAttributes do
|
|
85
83
|
it_behaves_like 'bit field with one flag set', :compressed, 'V', 0x00000800
|
86
84
|
end
|
87
85
|
|
88
|
-
describe '
|
86
|
+
describe 'encrypted' do
|
89
87
|
it 'should be a 1-bit field per the SMB spec' do
|
90
|
-
expect(attrs.
|
88
|
+
expect(attrs.encrypted).to be_a BinData::Bit1
|
91
89
|
end
|
92
90
|
|
93
|
-
it_behaves_like 'bit field with one flag set', :
|
91
|
+
it_behaves_like 'bit field with one flag set', :encrypted, 'V', 0x00004000
|
94
92
|
end
|
95
93
|
|
96
|
-
describe '
|
94
|
+
describe 'not_content_indexed' do
|
97
95
|
it 'should be a 1-bit field per the SMB spec' do
|
98
|
-
expect(attrs.
|
96
|
+
expect(attrs.not_content_indexed).to be_a BinData::Bit1
|
99
97
|
end
|
100
98
|
|
101
|
-
it_behaves_like 'bit field with one flag set', :
|
99
|
+
it_behaves_like 'bit field with one flag set', :not_content_indexed, 'V', 0x00002000
|
102
100
|
end
|
103
101
|
|
104
|
-
describe '
|
102
|
+
describe 'offline' do
|
105
103
|
it 'should be a 1-bit field per the SMB spec' do
|
106
|
-
expect(attrs.
|
104
|
+
expect(attrs.offline).to be_a BinData::Bit1
|
107
105
|
end
|
108
106
|
|
109
|
-
it_behaves_like 'bit field with one flag set', :
|
107
|
+
it_behaves_like 'bit field with one flag set', :offline, 'V', 0x00001000
|
110
108
|
end
|
111
109
|
|
112
|
-
describe '
|
110
|
+
describe 'reparse_point' do
|
113
111
|
it 'should be a 1-bit field per the SMB spec' do
|
114
|
-
expect(attrs.
|
112
|
+
expect(attrs.reparse_point).to be_a BinData::Bit1
|
115
113
|
end
|
116
114
|
|
117
|
-
it_behaves_like 'bit field with one flag set', :
|
115
|
+
it_behaves_like 'bit field with one flag set', :reparse_point, 'V', 0x00000400
|
118
116
|
end
|
119
117
|
|
120
|
-
describe '
|
118
|
+
describe 'sparse' do
|
121
119
|
it 'should be a 1-bit field per the SMB spec' do
|
122
|
-
expect(attrs.
|
120
|
+
expect(attrs.sparse).to be_a BinData::Bit1
|
123
121
|
end
|
124
122
|
|
125
|
-
it_behaves_like 'bit field with one flag set', :
|
123
|
+
it_behaves_like 'bit field with one flag set', :sparse, 'V', 0x00000200
|
126
124
|
end
|
127
|
-
|
128
|
-
describe 'no_buffering' do
|
129
|
-
it 'should be a 1-bit field per the SMB spec' do
|
130
|
-
expect(attrs.no_buffering).to be_a BinData::Bit1
|
131
|
-
end
|
132
|
-
|
133
|
-
it_behaves_like 'bit field with one flag set', :no_buffering, 'V', 0x20000000
|
134
|
-
end
|
135
|
-
|
136
|
-
describe 'write_through' do
|
137
|
-
it 'should be a 1-bit field per the SMB spec' do
|
138
|
-
expect(attrs.write_through).to be_a BinData::Bit1
|
139
|
-
end
|
140
|
-
|
141
|
-
it_behaves_like 'bit field with one flag set', :write_through, 'V', 0x80000000
|
142
|
-
end
|
143
|
-
|
144
125
|
end
|
@@ -0,0 +1,469 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::File do
|
2
|
+
|
3
|
+
let(:dispatcher) { RubySMB::Dispatcher::Socket.new(double('socket')) }
|
4
|
+
let(:client) { RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin') }
|
5
|
+
let(:connect_response) {
|
6
|
+
packet = RubySMB::SMB1::Packet::TreeConnectResponse.new
|
7
|
+
packet.smb_header.tid = 2051
|
8
|
+
packet.parameter_block.guest_access_rights.read("\xff\x01\x1f\x00")
|
9
|
+
packet.parameter_block.access_rights.read("\xff\x01\x1f\x01")
|
10
|
+
packet
|
11
|
+
}
|
12
|
+
let(:tree) { RubySMB::SMB1::Tree.new(client: client, share: '\\1.2.3.4\Share', response: connect_response) }
|
13
|
+
let(:nt_create_andx_response) {
|
14
|
+
response = RubySMB::SMB1::Packet::NtCreateAndxResponse.new
|
15
|
+
response.parameter_block.ext_file_attributes = { normal: 1 }
|
16
|
+
response.parameter_block.fid = 0x4000
|
17
|
+
response.parameter_block.last_access_time = DateTime.parse("2017-09-20T1:1:1")
|
18
|
+
response.parameter_block.last_change_time = DateTime.parse("2017-09-22T2:2:2")
|
19
|
+
response.parameter_block.last_write_time = DateTime.parse("2017-09-25T3:3:3")
|
20
|
+
response.parameter_block.end_of_file = 53
|
21
|
+
response.parameter_block.allocation_size = 4096
|
22
|
+
response
|
23
|
+
}
|
24
|
+
let(:filename) { 'specfile.txt' }
|
25
|
+
|
26
|
+
subject(:file) {
|
27
|
+
described_class.new(tree: tree, response: nt_create_andx_response, name: filename)
|
28
|
+
}
|
29
|
+
|
30
|
+
it { is_expected.to respond_to :tree }
|
31
|
+
it { is_expected.to respond_to :name }
|
32
|
+
it { is_expected.to respond_to :attributes }
|
33
|
+
it { is_expected.to respond_to :fid }
|
34
|
+
it { is_expected.to respond_to :last_access }
|
35
|
+
it { is_expected.to respond_to :last_change }
|
36
|
+
it { is_expected.to respond_to :last_write }
|
37
|
+
it { is_expected.to respond_to :size }
|
38
|
+
it { is_expected.to respond_to :size_on_disk }
|
39
|
+
|
40
|
+
it 'raises an exception when tree is no provided' do
|
41
|
+
expect { described_class.new(tree: nil, response: nt_create_andx_response, name: filename) }.to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises an exception when response is no provided' do
|
45
|
+
expect { described_class.new(tree: tree, response: nil, name: filename) }.to raise_error(ArgumentError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises an exception when name is no provided' do
|
49
|
+
expect { described_class.new(tree: tree, response: nt_create_andx_response, name: nil) }.to raise_error(ArgumentError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'inherits the tree that spawned it' do
|
53
|
+
expect(file.tree).to eq tree
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'sets the file name to the name passed as argument' do
|
57
|
+
expect(file.name).to eq filename
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'inherits the attributes from the response packet' do
|
61
|
+
expect(file.attributes).to eq nt_create_andx_response.parameter_block.ext_file_attributes
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'inherits the file ID from the response packet' do
|
65
|
+
expect(file.fid).to eq nt_create_andx_response.parameter_block.fid
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'inherits the last_access from the response packet' do
|
69
|
+
expect(file.last_access).to eq nt_create_andx_response.parameter_block.last_access_time.to_datetime
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'inherits the last_change from the response packet' do
|
73
|
+
expect(file.last_change).to eq nt_create_andx_response.parameter_block.last_change_time.to_datetime
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'inherits the last_write from the response packet' do
|
77
|
+
expect(file.last_write).to eq nt_create_andx_response.parameter_block.last_write_time.to_datetime
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'inherits the size from the response packet' do
|
81
|
+
expect(file.size).to eq nt_create_andx_response.parameter_block.end_of_file
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'inherits the size_on_disk from the response packet' do
|
85
|
+
expect(file.size_on_disk).to eq nt_create_andx_response.parameter_block.allocation_size
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#set_header_fields' do
|
89
|
+
let(:request) { RubySMB::SMB1::Packet::ReadAndxRequest.new }
|
90
|
+
it 'calls the set_header_field method from the Tree' do
|
91
|
+
expect(tree).to receive(:set_header_fields).with(request).and_call_original
|
92
|
+
file.set_header_fields(request)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'sets the packet file_id from the guid' do
|
96
|
+
expect(file.set_header_fields(request).parameter_block.fid).to eq file.fid
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#read_packet' do
|
101
|
+
it 'creates a new ReadAndxRequest packet' do
|
102
|
+
expect(RubySMB::SMB1::Packet::ReadAndxRequest).to receive(:new).and_call_original
|
103
|
+
file.read_packet
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'calls #set_header_fields to set ReadAndxRequest header fields' do
|
107
|
+
request = RubySMB::SMB1::Packet::ReadAndxRequest.new
|
108
|
+
allow(RubySMB::SMB1::Packet::ReadAndxRequest).to receive(:new).and_return(request)
|
109
|
+
expect(file).to receive(:set_header_fields).with(request).and_call_original
|
110
|
+
file.read_packet
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'sets the read_length of the packet' do
|
114
|
+
expect(file.read_packet(read_length: 55).parameter_block.max_count_of_bytes_to_return).to eq 55
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'sets the offset of the packet' do
|
118
|
+
expect(file.read_packet(offset: 55).parameter_block.offset).to eq 55
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#read' do
|
123
|
+
let(:read_data) { 'read data' }
|
124
|
+
let(:raw_response) { double('fake raw response data') }
|
125
|
+
let(:read_andx_response) {
|
126
|
+
res = RubySMB::SMB1::Packet::ReadAndxResponse.new
|
127
|
+
res.data_block.data = read_data
|
128
|
+
res
|
129
|
+
}
|
130
|
+
|
131
|
+
before :example do
|
132
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
133
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response).and_return(read_andx_response)
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when the number of bytes to read is not provided' do
|
137
|
+
it 'reads #size bytes by default' do
|
138
|
+
expect(file).to receive(:read_packet).with(read_length: file.size, offset: 0).once.and_call_original
|
139
|
+
expect(file.read).to eq(read_data)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when the number of bytes to read is less than or equal to max_buffer_size' do
|
144
|
+
it 'reads only one packet with the number of bytes provided as argument' do
|
145
|
+
client.max_buffer_size = read_data.size
|
146
|
+
expect(file).to receive(:read_packet).with(read_length: read_data.size, offset: 0).once.and_call_original
|
147
|
+
expect(file.read(bytes: read_data.size)).to eq(read_data)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when the number of bytes to read is greater than max_buffer_size' do
|
152
|
+
it 'reads multiple packets with at most max_buffer_size bytes per chunk' do
|
153
|
+
client.max_buffer_size = read_data.size - 1
|
154
|
+
read_io = StringIO.new(read_data)
|
155
|
+
expect(file).to receive(:read_packet).with(read_length: client.max_buffer_size, offset: 0).once.ordered.and_call_original
|
156
|
+
expect(file).to receive(:read_packet).with(read_length: (read_data.size - client.max_buffer_size), offset: client.max_buffer_size).once.ordered.and_call_original
|
157
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response) do
|
158
|
+
read_andx_response.data_block.data = read_io.read(client.max_buffer_size)
|
159
|
+
read_andx_response
|
160
|
+
end
|
161
|
+
expect(file.read(bytes: read_data.size)).to eq(read_data)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'when sending the request packet and gets a response back' do
|
166
|
+
context 'when the response is not a ReadAndxResponse packet' do
|
167
|
+
it 'raise an InvalidPacket exception' do
|
168
|
+
read_andx_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
169
|
+
expect { file.read }.to raise_error(RubySMB::Error::InvalidPacket)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'when the response status code is not STATUS_SUCCESS' do
|
174
|
+
it 'raise an UnexpectedStatusCode exception' do
|
175
|
+
read_andx_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
176
|
+
expect { file.read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the response is an EmptyPacket with the SMB_COM_READ_ANDX command and STATUS_SUCCESS status code' do
|
181
|
+
let(:empty_packet) do
|
182
|
+
empty_packet = RubySMB::SMB1::Packet::EmptyPacket.new
|
183
|
+
empty_packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
|
184
|
+
empty_packet
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'returns an empty string if it is the first request' do
|
188
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response).and_return(empty_packet)
|
189
|
+
expect(file.read).to eq('')
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'returns the current read data if it happens after the first request' do
|
193
|
+
partial_data = read_data[0..-2]
|
194
|
+
client.max_buffer_size = partial_data.size
|
195
|
+
first_request = true
|
196
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response).twice do
|
197
|
+
if first_request
|
198
|
+
read_andx_response.data_block.data = partial_data
|
199
|
+
first_request = false
|
200
|
+
read_andx_response
|
201
|
+
else
|
202
|
+
empty_packet
|
203
|
+
end
|
204
|
+
end
|
205
|
+
expect(file.read(bytes: read_data.size)).to eq(partial_data)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#write_packet' do
|
212
|
+
it 'creates a new WriteAndxRequest packet' do
|
213
|
+
expect(RubySMB::SMB1::Packet::WriteAndxRequest).to receive(:new).and_call_original
|
214
|
+
file.write_packet
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'calls #set_header_fields to set WriteAndxRequest headers' do
|
218
|
+
request = RubySMB::SMB1::Packet::WriteAndxRequest.new
|
219
|
+
allow(RubySMB::SMB1::Packet::WriteAndxRequest).to receive(:new).and_return(request)
|
220
|
+
expect(file).to receive(:set_header_fields).with(request).and_call_original
|
221
|
+
file.write_packet
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'sets the offset of the packet' do
|
225
|
+
expect(file.write_packet(offset: 55).parameter_block.offset).to eq 55
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'sets the write_mode to writethrough_mode' do
|
229
|
+
expect(file.write_packet.parameter_block.write_mode.writethrough_mode).to eq 1
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'sets the remaining number of bytes to data_length value' do
|
233
|
+
data = 'write data'
|
234
|
+
write_andx_request = file.write_packet(data: data)
|
235
|
+
expect(write_andx_request.parameter_block.remaining).to eq write_andx_request.parameter_block.data_length
|
236
|
+
expect(write_andx_request.parameter_block.remaining).to eq data.size
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'sets the data of the packet' do
|
240
|
+
data = 'write data'
|
241
|
+
expect(file.write_packet(data: data).data_block.data).to eq data
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe '#write' do
|
246
|
+
let(:write_data) { 'write data' }
|
247
|
+
let(:raw_response) { double('fake raw response data') }
|
248
|
+
let(:write_andx_response) do
|
249
|
+
response = RubySMB::SMB1::Packet::WriteAndxResponse.new
|
250
|
+
response.parameter_block.count_low = write_data.size
|
251
|
+
response
|
252
|
+
end
|
253
|
+
|
254
|
+
before :example do
|
255
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
256
|
+
allow(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response).and_return(write_andx_response)
|
257
|
+
end
|
258
|
+
|
259
|
+
describe 'offset' do
|
260
|
+
it 'writes from offset 0 by default' do
|
261
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: 0).and_call_original
|
262
|
+
file.write(data: write_data)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'writes from the offset passed as arguement' do
|
266
|
+
offset = 10
|
267
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: offset).and_call_original
|
268
|
+
file.write(data: write_data, offset: offset)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
context 'when the buffer size is less than or equal to max_buffer_size' do
|
273
|
+
it 'sends only one packet with the entire buffer' do
|
274
|
+
client.max_buffer_size = write_data.size
|
275
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: 0).once.and_call_original
|
276
|
+
expect(file.write(data: write_data)).to eq write_data.size
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context 'when the buffer size is greater than max_buffer_size' do
|
281
|
+
it 'sends multiple packets with at most max_buffer_size bytes per chunk' do
|
282
|
+
client.max_buffer_size = write_data.size - 1
|
283
|
+
first_data_chunk = write_data[0, client.max_buffer_size]
|
284
|
+
second_data_chunk = write_data[client.max_buffer_size..-1]
|
285
|
+
original_write_packet = file.method(:write_packet)
|
286
|
+
|
287
|
+
expect(file).to receive(:write_packet).with(data: first_data_chunk , offset: 0).once do
|
288
|
+
allow(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response) do
|
289
|
+
write_andx_response.parameter_block.count_low = first_data_chunk.size
|
290
|
+
write_andx_response
|
291
|
+
end
|
292
|
+
original_write_packet.call(data: first_data_chunk, offset: 0)
|
293
|
+
end
|
294
|
+
expect(file).to receive(:write_packet).with(data: second_data_chunk, offset: client.max_buffer_size).once do
|
295
|
+
allow(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response) do
|
296
|
+
write_andx_response.parameter_block.count_low = second_data_chunk.size
|
297
|
+
write_andx_response
|
298
|
+
end
|
299
|
+
original_write_packet.call(data: second_data_chunk, offset: client.max_buffer_size)
|
300
|
+
end
|
301
|
+
expect(file.write(data: write_data)).to eq write_data.size
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when sending the request packet and gets a response back' do
|
306
|
+
context 'when the response is not a WriteAndxResponse packet' do
|
307
|
+
it 'raise an InvalidPacket exception' do
|
308
|
+
write_andx_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
309
|
+
expect { file.write(data: write_data) }.to raise_error(RubySMB::Error::InvalidPacket)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
context 'when the response status code is not STATUS_SUCCESS' do
|
314
|
+
it 'raise an UnexpectedStatusCode exception' do
|
315
|
+
write_andx_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
316
|
+
expect { file.write(data: write_data) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe '#append' do
|
323
|
+
it 'calls #write with the expected data and the offset set to the end of the file (file size)' do
|
324
|
+
data = 'append data'
|
325
|
+
expect(file).to receive(:write).with(data: data, offset: file.size)
|
326
|
+
file.append(data: data)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe '#delete' do
|
331
|
+
let(:set_info_res) { RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.new }
|
332
|
+
|
333
|
+
before :example do
|
334
|
+
allow(client).to receive(:send_recv)
|
335
|
+
allow(RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse).to receive(:read).and_return(set_info_res)
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'calls #delete_packet' do
|
339
|
+
expect(file).to receive(:delete_packet)
|
340
|
+
file.delete
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'returns the response NTStatus code' do
|
344
|
+
status = WindowsError::NTStatus::STATUS_SUCCESS
|
345
|
+
set_info_res.smb_header.nt_status = status.value
|
346
|
+
expect(file.delete).to eq status
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
describe '#delete_packet' do
|
351
|
+
let(:request) do
|
352
|
+
request = RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest.new
|
353
|
+
passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_DISPOSITION_INFORMATION +
|
354
|
+
RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
|
355
|
+
request.data_block.trans2_parameters.information_level = passthrough_info_level
|
356
|
+
request
|
357
|
+
end
|
358
|
+
|
359
|
+
before :example do
|
360
|
+
allow(RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest).to receive(:new).and_return(request)
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'creates a new Trans2 SetFileInformationRequest packet' do
|
364
|
+
expect(RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest).to receive(:new).and_return(request)
|
365
|
+
file.delete_packet
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'calls Tree #set_header_fields to set SetFileInformationRequest headers' do
|
369
|
+
expect(tree).to receive(:set_header_fields).with(request).and_call_original
|
370
|
+
file.delete_packet
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'sets the Trans2 parameter #fid of the packet with the File FID' do
|
374
|
+
fid = 0x1000
|
375
|
+
file.fid = fid
|
376
|
+
expect(file.delete_packet.data_block.trans2_parameters.fid).to eq fid
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'sets the Trans2 parameter #information_level of the packet' do
|
380
|
+
request.data_block.trans2_parameters.information_level = 0
|
381
|
+
passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_DISPOSITION_INFORMATION +
|
382
|
+
RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
|
383
|
+
expect(file.delete_packet.data_block.trans2_parameters.information_level).to eq passthrough_info_level
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'sets the File Information #delete_pending field of the packet' do
|
387
|
+
expect(file.delete_packet.data_block.trans2_data.info_level_struct.delete_pending).to eq 1
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'sets the Trans2 ParameterBlock fields' do
|
391
|
+
parameter_block = file.delete_packet.parameter_block
|
392
|
+
expect(parameter_block.total_parameter_count).to eq request.parameter_block.parameter_count
|
393
|
+
expect(parameter_block.total_data_count).to eq request.parameter_block.data_count
|
394
|
+
expect(parameter_block.max_parameter_count).to eq request.parameter_block.parameter_count
|
395
|
+
expect(parameter_block.max_data_count).to eq 16_384
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe '#rename' do
|
400
|
+
let(:set_info_res) { RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.new }
|
401
|
+
let(:filename) { 'file.txt' }
|
402
|
+
|
403
|
+
before :example do
|
404
|
+
allow(client).to receive(:send_recv)
|
405
|
+
allow(RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse).to receive(:read).and_return(set_info_res)
|
406
|
+
end
|
407
|
+
|
408
|
+
it 'calls #rename_packet' do
|
409
|
+
expect(file).to receive(:rename_packet)
|
410
|
+
file.rename(filename)
|
411
|
+
end
|
412
|
+
|
413
|
+
it 'returns the response NTStatus code' do
|
414
|
+
status = WindowsError::NTStatus::STATUS_SUCCESS
|
415
|
+
set_info_res.smb_header.nt_status = status.value
|
416
|
+
expect(file.rename(filename)).to eq status
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe '#rename_packet' do
|
421
|
+
let(:request) do
|
422
|
+
request = RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest.new
|
423
|
+
passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_RENAME_INFORMATION +
|
424
|
+
RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
|
425
|
+
request.data_block.trans2_parameters.information_level = passthrough_info_level
|
426
|
+
request
|
427
|
+
end
|
428
|
+
|
429
|
+
before :example do
|
430
|
+
allow(RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest).to receive(:new).and_return(request)
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'creates a new Trans2 SetFileInformationRequest packet' do
|
434
|
+
expect(RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest).to receive(:new).and_return(request)
|
435
|
+
file.rename_packet(filename)
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'calls Tree #set_header_fields to set SetFileInformationRequest headers' do
|
439
|
+
expect(tree).to receive(:set_header_fields).with(request).and_call_original
|
440
|
+
file.rename_packet(filename)
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'sets the Trans2 parameter #fid of the packet with the File FID' do
|
444
|
+
fid = 0x1000
|
445
|
+
file.fid = fid
|
446
|
+
expect(file.rename_packet(filename).data_block.trans2_parameters.fid).to eq fid
|
447
|
+
end
|
448
|
+
|
449
|
+
it 'sets the Trans2 parameter #information_level of the packet' do
|
450
|
+
request.data_block.trans2_parameters.information_level = 0
|
451
|
+
passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_RENAME_INFORMATION +
|
452
|
+
RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
|
453
|
+
expect(file.rename_packet(filename).data_block.trans2_parameters.information_level).to eq passthrough_info_level
|
454
|
+
end
|
455
|
+
|
456
|
+
it 'sets the File Information #rename_pending field of the packet' do
|
457
|
+
expect(file.rename_packet(filename).data_block.trans2_data.info_level_struct.file_name).to eq filename.encode('utf-16le').force_encoding('ASCII-8BIT')
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'sets the Trans2 ParameterBlock fields' do
|
461
|
+
parameter_block = file.rename_packet(filename).parameter_block
|
462
|
+
expect(parameter_block.total_parameter_count).to eq request.parameter_block.parameter_count
|
463
|
+
expect(parameter_block.total_data_count).to eq request.parameter_block.data_count
|
464
|
+
expect(parameter_block.max_parameter_count).to eq request.parameter_block.parameter_count
|
465
|
+
expect(parameter_block.max_data_count).to eq 16_384
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|