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.
Files changed (298) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +247 -7
  5. data/examples/anonymous_auth.rb +6 -3
  6. data/examples/append_file.rb +40 -0
  7. data/examples/authenticate.rb +12 -7
  8. data/examples/delete_file.rb +40 -0
  9. data/examples/list_directory.rb +45 -0
  10. data/examples/negotiate.rb +0 -1
  11. data/examples/negotiate_with_netbios_service.rb +36 -0
  12. data/examples/net_share_enum_all.rb +30 -0
  13. data/examples/read_file.rb +39 -0
  14. data/examples/rename_file.rb +41 -0
  15. data/examples/tree_connect.rb +2 -4
  16. data/examples/write_file.rb +40 -0
  17. data/lib/ruby_smb.rb +5 -0
  18. data/lib/ruby_smb/client.rb +196 -43
  19. data/lib/ruby_smb/client/authentication.rb +89 -48
  20. data/lib/ruby_smb/client/echo.rb +1 -4
  21. data/lib/ruby_smb/client/negotiation.rb +46 -45
  22. data/lib/ruby_smb/client/signing.rb +9 -16
  23. data/lib/ruby_smb/client/tree_connect.rb +8 -13
  24. data/lib/ruby_smb/client/utils.rb +79 -0
  25. data/lib/ruby_smb/dcerpc.rb +30 -0
  26. data/lib/ruby_smb/dcerpc/bind.rb +60 -0
  27. data/lib/ruby_smb/dcerpc/handle.rb +60 -0
  28. data/lib/ruby_smb/dcerpc/ndr.rb +41 -0
  29. data/lib/ruby_smb/dcerpc/request.rb +43 -0
  30. data/lib/ruby_smb/dcerpc/response.rb +46 -0
  31. data/lib/ruby_smb/dcerpc/srvsvc.rb +17 -0
  32. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +93 -0
  33. data/lib/ruby_smb/dcerpc/uuid.rb +28 -0
  34. data/lib/ruby_smb/dispatcher.rb +7 -3
  35. data/lib/ruby_smb/dispatcher/base.rb +23 -14
  36. data/lib/ruby_smb/dispatcher/socket.rb +71 -51
  37. data/lib/ruby_smb/dispositions.rb +32 -0
  38. data/lib/ruby_smb/error.rb +24 -18
  39. data/lib/ruby_smb/field.rb +5 -2
  40. data/lib/ruby_smb/field/extended_attribute_flag.rb +1 -1
  41. data/lib/ruby_smb/field/file_time.rb +3 -1
  42. data/lib/ruby_smb/field/security_descriptor.rb +6 -6
  43. data/lib/ruby_smb/field/smb2_fileid.rb +11 -0
  44. data/lib/ruby_smb/field/smb_fea.rb +3 -3
  45. data/lib/ruby_smb/field/smb_fea_list.rb +3 -3
  46. data/lib/ruby_smb/field/smb_gea.rb +12 -0
  47. data/lib/ruby_smb/field/smb_gea_list.rb +13 -0
  48. data/lib/ruby_smb/field/string16.rb +14 -0
  49. data/lib/ruby_smb/field/stringz16.rb +3 -7
  50. data/lib/ruby_smb/field/utime.rb +11 -10
  51. data/lib/ruby_smb/fscc.rb +12 -0
  52. data/lib/ruby_smb/fscc/control_codes.rb +26 -0
  53. data/lib/ruby_smb/{field → fscc}/ea_info_array.rb +12 -14
  54. data/lib/ruby_smb/fscc/file_attributes.rb +29 -0
  55. data/lib/ruby_smb/{field → fscc}/file_full_ea_info.rb +5 -5
  56. data/lib/ruby_smb/fscc/file_information.rb +60 -0
  57. data/lib/ruby_smb/fscc/file_information/file_both_directory_information.rb +29 -0
  58. data/lib/ruby_smb/fscc/file_information/file_directory_information.rb +25 -0
  59. data/lib/ruby_smb/fscc/file_information/file_disposition_information.rb +15 -0
  60. data/lib/ruby_smb/fscc/file_information/file_full_directory_information.rb +26 -0
  61. data/lib/ruby_smb/fscc/file_information/file_id_both_directory_information.rb +31 -0
  62. data/lib/ruby_smb/fscc/file_information/file_id_full_directory_information.rb +28 -0
  63. data/lib/ruby_smb/fscc/file_information/file_names_information.rb +18 -0
  64. data/lib/ruby_smb/fscc/file_information/file_rename_information.rb +44 -0
  65. data/lib/ruby_smb/generic_packet.rb +40 -18
  66. data/lib/ruby_smb/gss.rb +49 -56
  67. data/lib/ruby_smb/impersonation_levels.rb +7 -2
  68. data/lib/ruby_smb/nbss.rb +16 -0
  69. data/lib/ruby_smb/nbss/negative_session_response.rb +30 -0
  70. data/lib/ruby_smb/nbss/session_header.rb +13 -0
  71. data/lib/ruby_smb/nbss/session_request.rb +13 -0
  72. data/lib/ruby_smb/smb1.rb +20 -17
  73. data/lib/ruby_smb/smb1/bit_field.rb +3 -0
  74. data/lib/ruby_smb/smb1/bit_field/create_options.rb +5 -5
  75. data/lib/ruby_smb/smb1/bit_field/file_status_flags.rb +18 -0
  76. data/lib/ruby_smb/smb1/bit_field/open2_access_mode.rb +11 -11
  77. data/lib/ruby_smb/smb1/bit_field/open2_open_mode.rb +1 -1
  78. data/lib/ruby_smb/smb1/bit_field/optional_support.rb +0 -1
  79. data/lib/ruby_smb/smb1/bit_field/security_flags.rb +15 -0
  80. data/lib/ruby_smb/smb1/bit_field/share_access.rb +2 -3
  81. data/lib/ruby_smb/smb1/bit_field/smb_ext_file_attributes.rb +21 -24
  82. data/lib/ruby_smb/smb1/bit_field/smb_file_attributes.rb +1 -1
  83. data/lib/ruby_smb/smb1/commands.rb +5 -0
  84. data/lib/ruby_smb/smb1/create_actions.rb +3 -5
  85. data/lib/ruby_smb/smb1/file.rb +289 -0
  86. data/lib/ruby_smb/smb1/oplock_levels.rb +2 -4
  87. data/lib/ruby_smb/smb1/packet.rb +10 -0
  88. data/lib/ruby_smb/smb1/packet/close_request.rb +31 -0
  89. data/lib/ruby_smb/smb1/packet/close_response.rb +28 -0
  90. data/lib/ruby_smb/smb1/packet/echo_request.rb +5 -7
  91. data/lib/ruby_smb/smb1/packet/echo_response.rb +5 -7
  92. data/lib/ruby_smb/smb1/packet/empty_packet.rb +1 -2
  93. data/lib/ruby_smb/smb1/packet/logoff_request.rb +1 -4
  94. data/lib/ruby_smb/smb1/packet/logoff_response.rb +1 -4
  95. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +22 -0
  96. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +22 -0
  97. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +62 -0
  98. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +66 -0
  99. data/lib/ruby_smb/smb1/packet/nt_trans.rb +1 -2
  100. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +19 -13
  101. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +8 -10
  102. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +11 -11
  103. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +10 -10
  104. data/lib/ruby_smb/smb1/packet/nt_trans/subcommands.rb +8 -1
  105. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +84 -0
  106. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +47 -0
  107. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -6
  108. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +1 -4
  109. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -6
  110. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -4
  111. data/lib/ruby_smb/smb1/packet/trans2.rb +8 -2
  112. data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +6 -7
  113. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +77 -0
  114. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +87 -0
  115. data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +32 -0
  116. data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_full_directory_info.rb +45 -0
  117. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +77 -0
  118. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +86 -0
  119. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +10 -10
  120. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +10 -12
  121. data/lib/ruby_smb/smb1/packet/trans2/request.rb +15 -17
  122. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +8 -10
  123. data/lib/ruby_smb/smb1/packet/trans2/response.rb +11 -13
  124. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +66 -0
  125. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +57 -0
  126. data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +5 -2
  127. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -6
  128. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +5 -7
  129. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  130. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -4
  131. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +68 -0
  132. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +35 -0
  133. data/lib/ruby_smb/smb1/resource_type.rb +18 -0
  134. data/lib/ruby_smb/smb1/tree.rb +188 -5
  135. data/lib/ruby_smb/smb2.rb +16 -11
  136. data/lib/ruby_smb/smb2/bit_field.rb +1 -0
  137. data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
  138. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +1 -2
  139. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +4 -6
  140. data/lib/ruby_smb/smb2/create_context.rb +29 -0
  141. data/lib/ruby_smb/smb2/file.rb +251 -0
  142. data/lib/ruby_smb/smb2/info_type.rb +21 -0
  143. data/lib/ruby_smb/smb2/packet.rb +16 -0
  144. data/lib/ruby_smb/smb2/packet/close_request.rb +22 -0
  145. data/lib/ruby_smb/smb2/packet/close_response.rb +29 -0
  146. data/lib/ruby_smb/smb2/packet/create_request.rb +54 -0
  147. data/lib/ruby_smb/smb2/packet/create_response.rb +35 -0
  148. data/lib/ruby_smb/smb2/packet/echo_request.rb +1 -3
  149. data/lib/ruby_smb/smb2/packet/echo_response.rb +1 -3
  150. data/lib/ruby_smb/smb2/packet/error_packet.rb +1 -3
  151. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +54 -0
  152. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +39 -0
  153. data/lib/ruby_smb/smb2/packet/logoff_request.rb +1 -4
  154. data/lib/ruby_smb/smb2/packet/logoff_response.rb +1 -4
  155. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +1 -1
  156. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
  157. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +35 -0
  158. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +45 -0
  159. data/lib/ruby_smb/smb2/packet/read_request.rb +30 -0
  160. data/lib/ruby_smb/smb2/packet/read_response.rb +26 -0
  161. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  162. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +4 -7
  163. data/lib/ruby_smb/smb2/packet/set_info_request.rb +58 -0
  164. data/lib/ruby_smb/smb2/packet/set_info_response.rb +20 -0
  165. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +3 -4
  166. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +5 -9
  167. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +1 -4
  168. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +1 -4
  169. data/lib/ruby_smb/smb2/packet/write_request.rb +29 -0
  170. data/lib/ruby_smb/smb2/packet/write_response.rb +26 -0
  171. data/lib/ruby_smb/smb2/tree.rb +163 -7
  172. data/lib/ruby_smb/version.rb +1 -1
  173. data/spec/lib/ruby_smb/client_spec.rb +459 -120
  174. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +14 -0
  175. data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +31 -0
  176. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +21 -0
  177. data/spec/lib/ruby_smb/dcerpc/response_spec.rb +15 -0
  178. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +13 -0
  179. data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +12 -0
  180. data/spec/lib/ruby_smb/dispatcher/base_spec.rb +26 -0
  181. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +118 -18
  182. data/spec/lib/ruby_smb/field/extended_attribute_flag_spec.rb +0 -3
  183. data/spec/lib/ruby_smb/field/file_time_spec.rb +4 -2
  184. data/spec/lib/ruby_smb/field/security_descriptor.rb +0 -1
  185. data/spec/lib/ruby_smb/field/smb2_fileid_spec.rb +10 -0
  186. data/spec/lib/ruby_smb/field/smb_fea_list_spec.rb +3 -5
  187. data/spec/lib/ruby_smb/field/smb_gea_list_spec.rb +37 -0
  188. data/spec/lib/ruby_smb/field/smb_gea_spec.rb +22 -0
  189. data/spec/lib/ruby_smb/field/stringz16_spec.rb +7 -9
  190. data/spec/lib/ruby_smb/field/utime_spec.rb +4 -2
  191. data/spec/lib/ruby_smb/{field → fscc}/ea_info_array_spec.rb +7 -9
  192. data/spec/lib/ruby_smb/{field → fscc}/file_full_ea_info_spec.rb +2 -3
  193. data/spec/lib/ruby_smb/fscc/file_information/file_both_directory_information_spec.rb +71 -0
  194. data/spec/lib/ruby_smb/fscc/file_information/file_directory_information_spec.rb +68 -0
  195. data/spec/lib/ruby_smb/fscc/file_information/file_disposition_information_spec.rb +26 -0
  196. data/spec/lib/ruby_smb/fscc/file_information/file_full_directory_information_spec.rb +69 -0
  197. data/spec/lib/ruby_smb/fscc/file_information/file_id_both_directory_information_spec.rb +72 -0
  198. data/spec/lib/ruby_smb/fscc/file_information/file_id_full_directory_information_spec.rb +70 -0
  199. data/spec/lib/ruby_smb/fscc/file_information/file_names_information_spec.rb +41 -0
  200. data/spec/lib/ruby_smb/fscc/file_information/file_rename_information_spec.rb +133 -0
  201. data/spec/lib/ruby_smb/fscc/fscc_file_attributes_spec.rb +143 -0
  202. data/spec/lib/ruby_smb/generic_packet_spec.rb +46 -21
  203. data/spec/lib/ruby_smb/nbss/negative_session_response_spec.rb +29 -0
  204. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +30 -0
  205. data/spec/lib/ruby_smb/nbss/session_request_spec.rb +30 -0
  206. data/spec/lib/ruby_smb/smb1/bit_field/create_options_spec.rb +9 -1
  207. data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +0 -2
  208. data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +0 -2
  209. data/spec/lib/ruby_smb/smb1/bit_field/file_status_flags_spec.rb +35 -0
  210. data/spec/lib/ruby_smb/smb1/bit_field/open2_access_mode_spec.rb +1 -3
  211. data/spec/lib/ruby_smb/smb1/bit_field/open2_flags_spec.rb +0 -2
  212. data/spec/lib/ruby_smb/smb1/bit_field/open2_open_mode_spec.rb +0 -1
  213. data/spec/lib/ruby_smb/smb1/bit_field/optional_support_spec.rb +0 -1
  214. data/spec/lib/ruby_smb/smb1/bit_field/security_flags_spec.rb +26 -0
  215. data/spec/lib/ruby_smb/smb1/bit_field/share_access_spec.rb +0 -3
  216. data/spec/lib/ruby_smb/smb1/bit_field/smb_ext_file_attributes_spec.rb +20 -39
  217. data/spec/lib/ruby_smb/smb1/bit_field/smb_file_attributes_spec.rb +0 -6
  218. data/spec/lib/ruby_smb/smb1/bit_field/smb_nmpipe_status_spec.rb +0 -2
  219. data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -2
  220. data/spec/lib/ruby_smb/smb1/bit_field/tree_connect_flags_spec.rb +0 -2
  221. data/spec/lib/ruby_smb/smb1/file_spec.rb +469 -0
  222. data/spec/lib/ruby_smb/smb1/packet/close_request_spec.rb +54 -0
  223. data/spec/lib/ruby_smb/smb1/packet/close_response_spec.rb +45 -0
  224. data/spec/lib/ruby_smb/smb1/packet/echo_request_spec.rb +1 -4
  225. data/spec/lib/ruby_smb/smb1/packet/echo_response_spec.rb +1 -4
  226. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +1 -3
  227. data/spec/lib/ruby_smb/smb1/packet/logoff_request_spec.rb +1 -4
  228. data/spec/lib/ruby_smb/smb1/packet/logoff_response_spec.rb +1 -4
  229. data/spec/lib/ruby_smb/smb1/packet/negotiate_request_spec.rb +1 -1
  230. data/spec/lib/ruby_smb/smb1/packet/negotiate_response_extended_spec.rb +37 -0
  231. data/spec/lib/ruby_smb/smb1/packet/negotiate_response_spec.rb +37 -0
  232. data/spec/lib/ruby_smb/smb1/packet/nt_create_andx_request_spec.rb +151 -0
  233. data/spec/lib/ruby_smb/smb1/packet/nt_create_andx_response_spec.rb +157 -0
  234. data/spec/lib/ruby_smb/smb1/packet/nt_trans/create_request_spec.rb +13 -6
  235. data/spec/lib/ruby_smb/smb1/packet/nt_trans/create_response_spec.rb +1 -7
  236. data/spec/lib/ruby_smb/smb1/packet/nt_trans/request_spec.rb +1 -6
  237. data/spec/lib/ruby_smb/smb1/packet/nt_trans/response_spec.rb +1 -5
  238. data/spec/lib/ruby_smb/smb1/packet/read_andx_request_spec.rb +149 -0
  239. data/spec/lib/ruby_smb/smb1/packet/read_andx_response_spec.rb +93 -0
  240. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +1 -5
  241. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +1 -5
  242. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +3 -8
  243. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +2 -4
  244. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +180 -0
  245. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +104 -0
  246. data/spec/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_full_directory_info_spec.rb +128 -0
  247. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +174 -0
  248. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +102 -0
  249. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_request_spec.rb +1 -6
  250. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +2 -7
  251. data/spec/lib/ruby_smb/smb1/packet/trans2/request_secondary_spec.rb +1 -5
  252. data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +1 -5
  253. data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +1 -4
  254. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +98 -0
  255. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +56 -0
  256. data/spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb +1 -5
  257. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +1 -6
  258. data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_request_spec.rb +1 -4
  259. data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_response_spec.rb +1 -4
  260. data/spec/lib/ruby_smb/smb1/packet/write_andx_request_spec.rb +148 -0
  261. data/spec/lib/ruby_smb/smb1/packet/write_andx_response_spec.rb +54 -0
  262. data/spec/lib/ruby_smb/smb1/tree_spec.rb +409 -7
  263. data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +0 -2
  264. data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +0 -2
  265. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +1 -1
  266. data/spec/lib/ruby_smb/smb2/bit_field/share_capabilities_spec.rb +0 -1
  267. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +0 -2
  268. data/spec/lib/ruby_smb/smb2/create_context_spec.rb +42 -0
  269. data/spec/lib/ruby_smb/smb2/file_spec.rb +233 -0
  270. data/spec/lib/ruby_smb/smb2/packet/close_request_spec.rb +40 -0
  271. data/spec/lib/ruby_smb/smb2/packet/close_response_spec.rb +40 -0
  272. data/spec/lib/ruby_smb/smb2/packet/create_request_spec.rb +101 -0
  273. data/spec/lib/ruby_smb/smb2/packet/create_response_spec.rb +64 -0
  274. data/spec/lib/ruby_smb/smb2/packet/echo_request_spec.rb +1 -3
  275. data/spec/lib/ruby_smb/smb2/packet/echo_response_spec.rb +1 -3
  276. data/spec/lib/ruby_smb/smb2/packet/ioctl_request_spec.rb +48 -0
  277. data/spec/lib/ruby_smb/smb2/packet/logoff_request_spec.rb +1 -3
  278. data/spec/lib/ruby_smb/smb2/packet/logoff_response_spec.rb +1 -3
  279. data/spec/lib/ruby_smb/smb2/packet/query_directory_request_spec.rb +80 -0
  280. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +64 -0
  281. data/spec/lib/ruby_smb/smb2/packet/read_request_spec.rb +43 -0
  282. data/spec/lib/ruby_smb/smb2/packet/read_response_spec.rb +50 -0
  283. data/spec/lib/ruby_smb/smb2/packet/session_setup_request_spec.rb +3 -4
  284. data/spec/lib/ruby_smb/smb2/packet/session_setup_response_spec.rb +2 -3
  285. data/spec/lib/ruby_smb/smb2/packet/set_info_request_spec.rb +205 -0
  286. data/spec/lib/ruby_smb/smb2/packet/set_info_response_spec.rb +32 -0
  287. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +3 -5
  288. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +1 -2
  289. data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_request_spec.rb +1 -3
  290. data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_response_spec.rb +1 -3
  291. data/spec/lib/ruby_smb/smb2/packet/write_request_spec.rb +51 -0
  292. data/spec/lib/ruby_smb/smb2/packet/write_response_spec.rb +38 -0
  293. data/spec/lib/ruby_smb/smb2/tree_spec.rb +191 -5
  294. data/spec/spec_helper.rb +1 -1
  295. metadata +195 -12
  296. metadata.gz.sig +0 -0
  297. data/lib/ruby_smb/smb1/dispositions.rb +0 -36
  298. data/spec/lib/ruby_smb/dispatcher/dispatcher_base_spec.rb +0 -22
@@ -0,0 +1,30 @@
1
+ module RubySMB
2
+ module Nbss
3
+
4
+
5
+ # Representation of the NetBIOS Negative Session Service Response packet as defined in
6
+ # [4.3.4 SESSION REQUEST PACKET](https://tools.ietf.org/html/rfc1002)
7
+ class NegativeSessionResponse < BinData::Record
8
+ endian :big
9
+
10
+ session_header :session_header
11
+ uint8 :error_code, label: 'Error Code'
12
+
13
+ def error_msg
14
+ case error_code
15
+ when 0x80
16
+ 'Not listening on called name'
17
+ when 0x81
18
+ 'Not listening for calling name'
19
+ when 0x82
20
+ 'Called name not present'
21
+ when 0x83
22
+ 'Called name present, but insufficient resources'
23
+ when 0x8F
24
+ 'Unspecified error'
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ module RubySMB
2
+ module Nbss
3
+ # Representation of the NetBIOS Session Service Header as defined in
4
+ # [4.3.1 GENERAL FORMAT OF SESSION PACKETS](https://tools.ietf.org/html/rfc1002)
5
+ class SessionHeader < BinData::Record
6
+ endian :big
7
+
8
+ uint8 :session_packet_type, label: 'Session Packet Type'
9
+ uint8 :flags, label: 'Flags', initial_value: 0
10
+ uint16 :packet_length, label: 'Packet Length'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module RubySMB
2
+ module Nbss
3
+ # Representation of the NetBIOS Session Service Request packet as defined in
4
+ # [4.3.2 SESSION REQUEST PACKET](https://tools.ietf.org/html/rfc1002)
5
+ class SessionRequest < BinData::Record
6
+ endian :big
7
+
8
+ session_header :session_header
9
+ string :called_name, label: 'Called Name'
10
+ string :calling_name, label: 'Calling Name'
11
+ end
12
+ end
13
+ end
data/lib/ruby_smb/smb1.rb CHANGED
@@ -1,19 +1,22 @@
1
- # This module adds the namespace for version 1 of the SMB Protocol
2
- # as defined in [MS-SMB](https://msdn.microsoft.com/en-us/library/cc246231.aspx)
3
- module RubySMB::SMB1
4
- # Protocol ID value. Translates to \xFFSMB
5
- SMB_PROTOCOL_ID = 0xFF534D42
1
+ module RubySMB
2
+ # This module adds the namespace for version 1 of the SMB Protocol
3
+ # as defined in [MS-SMB](https://msdn.microsoft.com/en-us/library/cc246231.aspx)
4
+ module SMB1
5
+ # Protocol ID value. Translates to \xFFSMB
6
+ SMB_PROTOCOL_ID = 0xFF534D42
6
7
 
7
- require 'ruby_smb/smb1/dispositions'
8
- require 'ruby_smb/smb1/create_actions'
9
- require 'ruby_smb/smb1/oplock_levels'
10
- require 'ruby_smb/smb1/commands'
11
- require 'ruby_smb/smb1/andx_block'
12
- require 'ruby_smb/smb1/bit_field'
13
- require 'ruby_smb/smb1/smb_header'
14
- require 'ruby_smb/smb1/parameter_block'
15
- require 'ruby_smb/smb1/data_block'
16
- require 'ruby_smb/smb1/dialect'
17
- require 'ruby_smb/smb1/packet'
18
- require 'ruby_smb/smb1/tree'
8
+ require 'ruby_smb/smb1/create_actions'
9
+ require 'ruby_smb/smb1/oplock_levels'
10
+ require 'ruby_smb/smb1/resource_type'
11
+ require 'ruby_smb/smb1/commands'
12
+ require 'ruby_smb/smb1/andx_block'
13
+ require 'ruby_smb/smb1/bit_field'
14
+ require 'ruby_smb/smb1/smb_header'
15
+ require 'ruby_smb/smb1/parameter_block'
16
+ require 'ruby_smb/smb1/data_block'
17
+ require 'ruby_smb/smb1/dialect'
18
+ require 'ruby_smb/smb1/packet'
19
+ require 'ruby_smb/smb1/tree'
20
+ require 'ruby_smb/smb1/file'
21
+ end
19
22
  end
@@ -1,5 +1,6 @@
1
1
  module RubySMB
2
2
  module SMB1
3
+ # Namespace for SMB1 Bit Mask style field definitions
3
4
  module BitField
4
5
  require 'ruby_smb/smb1/bit_field/header_flags'
5
6
  require 'ruby_smb/smb1/bit_field/header_flags2'
@@ -18,6 +19,8 @@ module RubySMB
18
19
  require 'ruby_smb/smb1/bit_field/smb_nmpipe_status'
19
20
  require 'ruby_smb/smb1/bit_field/share_access'
20
21
  require 'ruby_smb/smb1/bit_field/create_options'
22
+ require 'ruby_smb/smb1/bit_field/security_flags'
23
+ require 'ruby_smb/smb1/bit_field/file_status_flags'
21
24
  end
22
25
  end
23
26
  end
@@ -1,10 +1,10 @@
1
1
  module RubySMB
2
2
  module SMB1
3
3
  module BitField
4
-
5
4
  # Represents a CreateOptions BitField as used by both the NT_CREATE_ANDX
6
5
  # and the NT_TRANSACT_CREATE Requests. The definition for this field can be found at
7
- # [2.2.4.64.1 Request](https://msdn.microsoft.com/en-us/library/ee442175.aspx)
6
+ # [2.2.4.64.1 Request](https://msdn.microsoft.com/en-us/library/ee442175.aspx) and
7
+ # [2.2.4.9.1 Client Request Extensions](https://msdn.microsoft.com/en-us/library/cc246332.aspx)
8
8
  class CreateOptions < BinData::Record
9
9
  endian :little
10
10
  bit1 :create_tree_connection, label: 'Create Tree Connection'
@@ -27,12 +27,12 @@ module RubySMB
27
27
  # Byte Boundary
28
28
  bit1 :open_for_free_space_query, label: 'Open for Free Space Query'
29
29
  bit1 :open_no_recall, label: 'Open No Recall'
30
- bit1 :reserved2, label: 'Reserved Space'
30
+ bit1 :open_reparse_point, label: 'Open Reparse Point'
31
31
  bit1 :reserve_opfilter, label: 'Reserve OPFilter'
32
32
  bit4 :reserved, label: 'Reserved Space'
33
33
  # Byte Boundary
34
- bit8
34
+ bit8 :reserved2, label: 'Reserved Space'
35
35
  end
36
36
  end
37
37
  end
38
- end
38
+ end
@@ -0,0 +1,18 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # Represents a FileStatusFlags BitField as used by both the SMB_COM_NT_CREATE_ANDX
5
+ # and the NT_TRANSACT_CREATE Responses. The definition for this field can be found at
6
+ # [2.2.4.9.2 Server Response Extensions](https://msdn.microsoft.com/en-us/library/cc246334.aspx)
7
+ class FileStatusFlags < BinData::Record
8
+ endian :little
9
+ bit5 :reserved, label: 'Reserved'
10
+ bit1 :reparse_tag, label: 'No Reparse Tag'
11
+ bit1 :no_substreams, label: 'No Data Sream'
12
+ bit1 :no_eas, label: 'No Extended Attributes (EAs)'
13
+ # byte boundary
14
+ bit8 :reserved2, label: 'Reserved'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,7 +3,7 @@ module RubySMB
3
3
  module BitField
4
4
  # The AccessMode bit-field for an SMB1 Open2 Request as defined in
5
5
  # [2.2.6.1.1 Request](https://msdn.microsoft.com/en-us/library/ee441733.aspx)
6
- class Open2AccessMode< BinData::Record
6
+ class Open2AccessMode < BinData::Record
7
7
  endian :little
8
8
  bit1 :reserved2, label: 'Reserved Space'
9
9
  bit3 :sharing_mode, label: 'Sharing Mode'
@@ -22,18 +22,18 @@ module RubySMB
22
22
  # ReadWrite, and Execute respectively.
23
23
  #
24
24
  # @param mode [Symbol] the access mode to set
25
- def set_access_mode(mode=:r)
25
+ def set_access_mode(mode = :r)
26
26
  modes = [:r, :w, :rw, :x]
27
- raise ArgumentError, "Mode must be one of #{modes.to_s}" unless modes.include? mode
27
+ raise ArgumentError, "Mode must be one of #{modes}" unless modes.include? mode
28
28
  case mode
29
- when :r
30
- self.access_mode = 0
31
- when :w
32
- self.access_mode = 1
33
- when :rw
34
- self.access_mode = 2
35
- when :x
36
- self.access_mode = 3
29
+ when :r
30
+ self.access_mode = 0
31
+ when :w
32
+ self.access_mode = 1
33
+ when :rw
34
+ self.access_mode = 2
35
+ when :x
36
+ self.access_mode = 3
37
37
  end
38
38
  end
39
39
  end
@@ -3,7 +3,7 @@ module RubySMB
3
3
  module BitField
4
4
  # The OpenMode bit-field for an SMB1 Open2 Request as defined in
5
5
  # [2.2.6.1.1 Request](https://msdn.microsoft.com/en-us/library/ee441733.aspx)
6
- class Open2OpenMode< BinData::Record
6
+ class Open2OpenMode < BinData::Record
7
7
  endian :little
8
8
  bit3 :reserved2, label: 'Reserved Space'
9
9
  bit1 :create_file, label: 'Create File Options'
@@ -12,7 +12,6 @@ module RubySMB
12
12
  bit1 :dfs, label: 'DFS Share', initial_value: 0
13
13
  bit1 :search, label: 'Exclusive Search Bits', initial_value: 1
14
14
  bit8 :reserved2, label: 'Reserved Space', initial_value: 0
15
-
16
15
  end
17
16
  end
18
17
  end
@@ -0,0 +1,15 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # Represents a SecurityFlags BitField as used by both the SMB_COM_NT_CREATE_ANDX
5
+ # and the NT_TRANSACT_CREATE Requests. The definition for this field can be found at
6
+ # [2.2.4.64.1 Request](https://msdn.microsoft.com/en-us/library/ee442175.aspx)
7
+ class SecurityFlags < BinData::Record
8
+ endian :little
9
+ bit6 :reserved, label: 'Reserved Space'
10
+ bit1 :effective_only, label: 'Effective Only'
11
+ bit1 :context_tracking, label: 'Context Tracking'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,11 +1,10 @@
1
1
  module RubySMB
2
2
  module SMB1
3
3
  module BitField
4
-
5
4
  # Represents a ShareAccess Bit-Field as defined in
6
5
  # [2.2.4.64.1 Request](https://msdn.microsoft.com/en-us/library/ee442175.aspx)
7
6
  class ShareAccess < BinData::Record
8
- endian :little
7
+ endian :little
9
8
  bit5 :reserved, label: 'Reserved Space'
10
9
  bit1 :share_delete, label: 'Share Delete Access'
11
10
  bit1 :share_write, label: 'Share Write Access'
@@ -17,4 +16,4 @@ module RubySMB
17
16
  end
18
17
  end
19
18
  end
20
- end
19
+ end
@@ -2,33 +2,30 @@ module RubySMB
2
2
  module SMB1
3
3
  module BitField
4
4
  # The bit-field for SMB1 Extended File Attributes as defined in
5
- # [2.2.1.2.3 SMB_EXT_FILE_ATTR](https://msdn.microsoft.com/en-us/library/ee878573.aspx)
5
+ # [2.2.1.2.3 SMB_EXT_FILE_ATTR](https://msdn.microsoft.com/en-us/library/ee878573.aspx) and
6
+ # [2.2.1.2.1 Extended File Attribute (SMB_EXT_FILE_ATTR) Extensions](https://msdn.microsoft.com/en-us/library/cc246322.aspx)
6
7
  class SmbExtFileAttributes < BinData::Record
7
- endian :little
8
- bit1 :normal, label: 'Normal File'
9
- bit1 :reserved, label: 'Reserved Space'
10
- bit1 :archive, label: 'Archive'
11
- bit1 :directory, label: 'Directory'
12
- bit1 :reserved2, label: 'Reserved Space'
13
- bit1 :system, label: 'System File'
14
- bit1 :hidden, label: 'Hidden File'
15
- bit1 :read_only, label: 'Read Only'
8
+ endian :little
9
+ bit1 :normal, label: 'Normal File'
10
+ bit1 :reserved, label: 'Reserved Space'
11
+ bit1 :archive, label: 'Archive'
12
+ bit1 :directory, label: 'Directory'
13
+ bit1 :reserved2, label: 'Reserved Space'
14
+ bit1 :system, label: 'System File'
15
+ bit1 :hidden, label: 'Hidden File'
16
+ bit1 :read_only, label: 'Read Only'
16
17
  # Byte boundary
17
- bit4 :reserved3, label: 'Reserved Space'
18
- bit1 :compressed, label: 'Compressed File'
19
- bit2 :reserved4, label: 'Reserved Space'
20
- bit1 :temporary, label: 'Temporary File'
18
+ bit1 :reserved3, label: 'Reserved Space'
19
+ bit1 :encrypted, label: 'Encrypted'
20
+ bit1 :not_content_indexed, label: 'Not Content Indexed'
21
+ bit1 :offline, label: 'Offline'
22
+ bit1 :compressed, label: 'Compressed File'
23
+ bit1 :reparse_point, label: 'Reparse Point'
24
+ bit1 :sparse, label: 'Sparse File'
25
+ bit1 :temporary, label: 'Temporary File'
21
26
  # Byte Boundary
22
- bit8 :reserved5, label: 'Reserved Space'
23
- # Byte Boundary
24
- bit1 :write_through, label: 'Write through'
25
- bit1 :reserved6, label: 'Reserved Space'
26
- bit1 :no_buffering, label: 'Do not Buffer'
27
- bit1 :random_access, label: 'Random Access'
28
- bit1 :sequential_scan, label: 'Sequential Access'
29
- bit1 :delete_on_close, label: 'Delete on close'
30
- bit1 :backup_semantics, label: 'Backup Semantics'
31
- bit1 :posix_semantics, label: 'POSIX Semantics'
27
+ bit8 :reserved4, label: 'Reserved Space'
28
+ bit8 :reserved5, label: 'Reserved Space'
32
29
  end
33
30
  end
34
31
  end
@@ -4,7 +4,7 @@ module RubySMB
4
4
  # The Flags bit-field for SMB1 File Attributes as defined in
5
5
  # [2.2.1.2.4 SMB_FILE_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/ee441551.aspx)
6
6
  class SmbFileAttributes < BinData::Record
7
- endian :little
7
+ endian :little
8
8
  bit2 :reserved, label: 'Reserved Space'
9
9
  bit1 :archive, label: 'Archive'
10
10
  bit1 :directory, label: 'Directory'
@@ -1,7 +1,10 @@
1
1
  module RubySMB
2
2
  module SMB1
3
3
  module Commands
4
+ SMB_COM_CLOSE = 0x04
4
5
  SMB_COM_ECHO = 0x2B
6
+ SMB_COM_READ_ANDX = 0x2E
7
+ SMB_COM_WRITE_ANDX = 0x2F
5
8
  SMB_COM_TRANSACTION2 = 0x32
6
9
  SMB_COM_TRANSACTION2_SECONDARY = 0x33
7
10
  SMB_COM_TREE_DISCONNECT = 0x71
@@ -10,6 +13,8 @@ module RubySMB
10
13
  SMB_COM_LOGOFF = 0x74
11
14
  SMB_COM_TREE_CONNECT = 0x75
12
15
  SMB_COM_NT_TRANSACT = 0xA0
16
+ SMB_COM_NT_TRANSACT_SECONDARY = 0xA1
17
+ SMB_COM_NT_CREATE_ANDX = 0xA2
13
18
  SMB_COM_NO_ANDX_COMMAND = 0xFF
14
19
  end
15
20
  end
@@ -4,19 +4,17 @@ module RubySMB
4
4
  # SMB_COM_NT_CREATE_ANDX responses. The definitions for these values can be found at
5
5
  # [2.2.7.1.2 Response](https://msdn.microsoft.com/en-us/library/ee441961.aspx)
6
6
  module CreateActions
7
-
8
7
  # An existing file was deleted and a new file was created in its place.
9
- FILE_SUPERSEDED = 0x00000000
8
+ FILE_SUPERSEDED = 0x00000000
10
9
 
11
10
  # An existing file was opened.
12
- FILE_OPENED = 0x00000001
11
+ FILE_OPENED = 0x00000001
13
12
 
14
13
  # A new file was created.
15
14
  FILE_CREATED = 0x00000002
16
15
 
17
16
  # An existing file was overwritten.
18
17
  FILE_OVERWRITEN = 0x00000003
19
-
20
18
  end
21
19
  end
22
- end
20
+ end
@@ -0,0 +1,289 @@
1
+ module RubySMB
2
+ module SMB1
3
+ # Represents a file on the Remote server that we can perform
4
+ # various I/O operations on.
5
+ class File
6
+ # The {RubySMB::SMB1::Tree} that this file belong to
7
+ # @!attribute [rw] tree
8
+ # @return [RubySMB::SMB1::Tree]
9
+ attr_accessor :tree
10
+
11
+ # The name of the file
12
+ # @!attribute [rw] name
13
+ # @return [String]
14
+ attr_accessor :name
15
+
16
+ # The {SmbExtFileAttributes} for the file
17
+ # @!attribute [rw] attributes
18
+ # @return [RubySMB::SMB1::BitField::SmbExtFileAttributes]
19
+ attr_accessor :attributes
20
+
21
+ # The file ID
22
+ # @!attribute [rw] fid
23
+ # @return [Integer]
24
+ attr_accessor :fid
25
+
26
+ # The last access date/time for the file
27
+ # @!attribute [rw] last_access
28
+ # @return [DateTime]
29
+ attr_accessor :last_access
30
+
31
+ # The last change date/time for the file
32
+ # @!attribute [rw] last_change
33
+ # @return [DateTime]
34
+ attr_accessor :last_change
35
+
36
+ # The last write date/time for the file
37
+ # @!attribute [rw] last_write
38
+ # @return [DateTime]
39
+ attr_accessor :last_write
40
+
41
+ # The actual size, in bytes, of the file
42
+ # @!attribute [rw] size
43
+ # @return [Integer]
44
+ attr_accessor :size
45
+
46
+ # The size in bytes that the file occupies on disk
47
+ # @!attribute [rw] size_on_disk
48
+ # @return [Integer]
49
+ attr_accessor :size_on_disk
50
+
51
+ def initialize(tree:, response:, name:)
52
+ raise ArgumentError, 'No tree provided' if tree.nil?
53
+ raise ArgumentError, 'No response provided' if response.nil?
54
+ raise ArgumentError, 'No file name provided' if name.nil?
55
+
56
+ @tree = tree
57
+ @name = name
58
+
59
+ @attributes = response.parameter_block.ext_file_attributes
60
+ @fid = response.parameter_block.fid
61
+ @last_access = response.parameter_block.last_access_time.to_datetime
62
+ @last_change = response.parameter_block.last_change_time.to_datetime
63
+ @last_write = response.parameter_block.last_write_time.to_datetime
64
+ @size = response.parameter_block.end_of_file
65
+ @size_on_disk = response.parameter_block.allocation_size
66
+ end
67
+
68
+ # Appends the supplied data to the end of the file.
69
+ #
70
+ # @param data [String] the data to write to the file
71
+ # @return [WindowsError::ErrorCode] the NTStatus code returned from the operation
72
+ def append(data:)
73
+ write(data: data, offset: @size)
74
+ end
75
+
76
+ # Closes the handle to the remote file.
77
+ #
78
+ # @return [WindowsError::ErrorCode] the NTStatus code returned by the operation
79
+ # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_CLOSE
80
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
81
+ def close
82
+ close_request = set_header_fields(RubySMB::SMB1::Packet::CloseRequest.new)
83
+ raw_response = @tree.client.send_recv(close_request)
84
+ response = RubySMB::SMB1::Packet::CloseResponse.read(raw_response)
85
+ unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_CLOSE
86
+ raise RubySMB::Error::InvalidPacket, 'Not a CloseResponse packet'
87
+ end
88
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
89
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
90
+ end
91
+ response.status_code
92
+ end
93
+
94
+ # Read from the file, a specific number of bytes
95
+ # from a specific offset. If no parameters are given
96
+ # it will read the entire file.
97
+ #
98
+ # @param bytes [Integer] the number of bytes to read
99
+ # @param offset [Integer] the byte offset in the file to start reading from
100
+ # @return [String] the data read from the file
101
+ # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_READ_ANDX
102
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
103
+ def read(bytes: @size, offset: 0)
104
+ atomic_read_size = if bytes > @tree.client.max_buffer_size
105
+ @tree.client.max_buffer_size
106
+ else
107
+ bytes
108
+ end
109
+ remaining_bytes = bytes
110
+ data = ''
111
+
112
+ loop do
113
+ read_request = read_packet(read_length: atomic_read_size, offset: offset)
114
+ raw_response = @tree.client.send_recv(read_request)
115
+ response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
116
+ unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
117
+ raise RubySMB::Error::InvalidPacket, 'Not a ReadAndxResponse packet'
118
+ end
119
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
120
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
121
+ end
122
+
123
+ if response.is_a?(RubySMB::SMB1::Packet::ReadAndxResponse)
124
+ data << response.data_block.data.to_binary_s
125
+ else
126
+ # Returns the current data immediately if we got an empty packet with an
127
+ # SMB_COM_READ_ANDX command and a STATUS_SUCCESS (just in case)
128
+ return data
129
+ end
130
+
131
+ remaining_bytes -= atomic_read_size
132
+ break unless remaining_bytes > 0
133
+
134
+ offset += atomic_read_size
135
+ atomic_read_size = remaining_bytes if remaining_bytes < @tree.client.max_buffer_size
136
+ end
137
+
138
+ data
139
+ end
140
+
141
+ # Crafts the ReadRequest packet to be sent for read operations.
142
+ #
143
+ # @param bytes [Integer] the number of bytes to read
144
+ # @param offset [Integer] the byte offset in the file to start reading from
145
+ # @return [RubySMB::SMB1::Packet::ReadAndxRequest] the crafted ReadRequest packet
146
+ def read_packet(read_length: 0, offset: 0)
147
+ read_request = set_header_fields(RubySMB::SMB1::Packet::ReadAndxRequest.new)
148
+ read_request.parameter_block.max_count_of_bytes_to_return = read_length
149
+ read_request.parameter_block.offset = offset
150
+ read_request
151
+ end
152
+
153
+ def send_recv_read(read_length: 0, offset: 0)
154
+ read_request = read_packet(read_length: read_length, offset: offset)
155
+ raw_response = tree.client.send_recv(read_request)
156
+ response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
157
+ response.data_block.data.to_binary_s
158
+ end
159
+
160
+ # Delete a file on close
161
+ #
162
+ # @return [WindowsError::ErrorCode] the NTStatus Response code
163
+ def delete
164
+ raw_response = @tree.client.send_recv(delete_packet)
165
+ response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
166
+ response.status_code
167
+ end
168
+
169
+ # Crafts the SetFileInformationRequest packet to be sent for delete operations.
170
+ #
171
+ # @return [RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest] the set info packet
172
+ def delete_packet
173
+ delete_request = RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest.new
174
+ delete_request = @tree.set_header_fields(delete_request)
175
+ delete_request.data_block.trans2_parameters.fid = @fid
176
+ passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_DISPOSITION_INFORMATION +
177
+ RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
178
+ delete_request.data_block.trans2_parameters.information_level = passthrough_info_level
179
+ delete_request.data_block.trans2_data.info_level_struct.delete_pending = 1
180
+ set_trans2_params(delete_request)
181
+ end
182
+
183
+ # Write the supplied data to the file at the given offset.
184
+ #
185
+ # @param data [String] the data to write to the file
186
+ # @param offset [Integer] the offset in the file to start writing from
187
+ # @return [Integer] the count of bytes written
188
+ # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_WRITE_ANDX
189
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
190
+ def write(data:, offset: 0)
191
+ buffer = data.dup
192
+ bytes = data.length
193
+ total_bytes_written = 0
194
+
195
+ loop do
196
+ atomic_write_size = if bytes > @tree.client.max_buffer_size
197
+ @tree.client.max_buffer_size
198
+ else
199
+ bytes
200
+ end
201
+ write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset)
202
+ raw_response = @tree.client.send_recv(write_request)
203
+ response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
204
+ unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
205
+ raise RubySMB::Error::InvalidPacket, 'Not a WriteAndxResponse packet'
206
+ end
207
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
208
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
209
+ end
210
+ bytes_written = response.parameter_block.count_low + (response.parameter_block.count_high << 16)
211
+ total_bytes_written += bytes_written
212
+ offset += bytes_written
213
+ bytes -= bytes_written
214
+ break unless buffer.length > 0
215
+ end
216
+
217
+ total_bytes_written
218
+ end
219
+
220
+ # Creates the Request packet for the #write command
221
+ #
222
+ # @param data [String] the data to write to the file
223
+ # @param offset [Integer] the offset in the file to start writing from
224
+ # @return [RubySMB::SMB1::Packet::WriteAndxRequest] the request packet
225
+ def write_packet(data:'', offset: 0)
226
+ write_request = set_header_fields(RubySMB::SMB1::Packet::WriteAndxRequest.new)
227
+ write_request.parameter_block.offset = offset
228
+ write_request.parameter_block.write_mode.writethrough_mode = 1
229
+ write_request.data_block.data = data
230
+ write_request.parameter_block.remaining = write_request.parameter_block.data_length
231
+ write_request
232
+ end
233
+
234
+ def send_recv_write(data:'', offset: 0)
235
+ pkt = write_packet(data: data, offset: offset)
236
+ raw_response = @tree.client.send_recv(pkt)
237
+ response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
238
+ response.parameter_block.count_low
239
+ end
240
+
241
+ # Rename a file
242
+ #
243
+ # @param new_file_name [String] the new name
244
+ # @return [WindowsError::ErrorCode] the NTStatus Response code
245
+ def rename(new_file_name)
246
+ raw_response = tree.client.send_recv(rename_packet(new_file_name))
247
+ response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
248
+ response.status_code
249
+ end
250
+
251
+ # Crafts the SetFileInformationRequest packet to be sent for rename operations.
252
+ #
253
+ # @param new_file_name [String] the new name
254
+ # @return [RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest] the set info packet
255
+ def rename_packet(new_file_name)
256
+ rename_request = RubySMB::SMB1::Packet::Trans2::SetFileInformationRequest.new
257
+ rename_request = @tree.set_header_fields(rename_request)
258
+ rename_request.data_block.trans2_parameters.fid = @fid
259
+ passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_RENAME_INFORMATION +
260
+ RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
261
+ rename_request.data_block.trans2_parameters.information_level = passthrough_info_level
262
+ rename_request.data_block.trans2_data.info_level_struct.file_name = new_file_name.encode('utf-16le')
263
+ set_trans2_params(rename_request)
264
+ end
265
+
266
+ # Sets the header fields that we have to set on every packet
267
+ # we send for File operations.
268
+ #
269
+ # @param request [RubySMB::GenericPacket] the request packet to set fields on
270
+ # @return [RubySMB::GenericPacket] the modified request packet
271
+ def set_header_fields(request)
272
+ request = @tree.set_header_fields(request)
273
+ request.parameter_block.fid = @fid
274
+ request
275
+ end
276
+
277
+ # Sets ParameterBlock options for Trans2 requests
278
+ def set_trans2_params(request)
279
+ request.parameter_block.total_parameter_count = request.parameter_block.parameter_count
280
+ request.parameter_block.total_data_count = request.parameter_block.data_count
281
+ request.parameter_block.max_parameter_count = request.parameter_block.parameter_count
282
+ request.parameter_block.max_data_count = 16_384
283
+ request
284
+ end
285
+ private :set_trans2_params
286
+
287
+ end
288
+ end
289
+ end