ruby_smb 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
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,20 @@
1
+ module RubySMB
2
+ module SMB2
3
+ module Packet
4
+ # An SMB2 Read Response Packet as defined in
5
+ # [2.2.40 SMB2 SET_INFO Response](https://msdn.microsoft.com/en-us/library/cc246562.aspx)
6
+ class SetInfoResponse < RubySMB::GenericPacket
7
+ endian :little
8
+
9
+ smb2_header :smb2_header
10
+ uint16 :structure_size, label: 'Structure Size', initial_value: 2
11
+
12
+ def initialize_instance
13
+ super
14
+ smb2_header.command = RubySMB::SMB2::Commands::SET_INFO
15
+ smb2_header.flags.reply = 1
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,7 +1,6 @@
1
1
  module RubySMB
2
2
  module SMB2
3
3
  module Packet
4
-
5
4
  # An SMB2 TreeConnectRequest Packet as defined in
6
5
  # [2.2.9 SMB2 TREE_CONNECT Request](https://msdn.microsoft.com/en-us/library/cc246567.aspx)
7
6
  class TreeConnectRequest < RubySMB::GenericPacket
@@ -10,7 +9,7 @@ module RubySMB
10
9
  uint16 :structure_size, label: 'Structure Size', initial_value: 9
11
10
  uint16 :flags, label: 'Flags', initial_value: 0x00
12
11
  uint16 :path_offset, label: 'Path Offset', initial_value: 0x48
13
- uint16 :path_length, label: 'Path Length', initial_value: lambda { self.path.length }
12
+ uint16 :path_length, label: 'Path Length', initial_value: -> { path.length }
14
13
  string :path, label: 'Path Buffer'
15
14
 
16
15
  def initialize_instance
@@ -19,9 +18,9 @@ module RubySMB
19
18
  end
20
19
 
21
20
  def encode_path(path)
22
- self.path = path.encode("utf-16le")
21
+ self.path = path.encode('utf-16le')
23
22
  end
24
23
  end
25
24
  end
26
25
  end
27
- end
26
+ end
@@ -1,11 +1,10 @@
1
1
  module RubySMB
2
2
  module SMB2
3
3
  module Packet
4
-
5
4
  # An SMB2 TreeConnectResponse Packet as defined in
6
5
  # [2.2.10 SMB2 TREE_CONNECT Response](https://msdn.microsoft.com/en-us/library/cc246499.aspx)
7
6
  class TreeConnectResponse < RubySMB::GenericPacket
8
- endian :little
7
+ endian :little
9
8
  smb2_header :smb2_header
10
9
  uint16 :structure_size, label: 'Structure Size', initial_value: 16
11
10
  uint8 :share_type, label: 'Share Type', initial_value: 0x01
@@ -28,9 +27,9 @@ module RubySMB
28
27
  # @return [RubySMB::SMB2::BitField::FileAccessMask] if anything else was connected to
29
28
  def access_rights
30
29
  if is_directory?
31
- self.maximal_access
30
+ maximal_access
32
31
  else
33
- mask = self.maximal_access.to_binary_s
32
+ mask = maximal_access.to_binary_s
34
33
  RubySMB::SMB2::BitField::FileAccessMask.read(mask)
35
34
  end
36
35
  end
@@ -39,12 +38,9 @@ module RubySMB
39
38
  #
40
39
  # @return [Boolean]
41
40
  def is_directory?
42
- self.share_type == 0x01
41
+ share_type == 0x01
43
42
  end
44
-
45
-
46
-
47
43
  end
48
44
  end
49
45
  end
50
- end
46
+ end
@@ -1,7 +1,6 @@
1
1
  module RubySMB
2
2
  module SMB2
3
3
  module Packet
4
-
5
4
  # An SMB2 TreeDisconnectRequest Packet as defined in
6
5
  # [2.2.11 SMB2 TREE_DISCONNECT Request](https://msdn.microsoft.com/en-us/library/cc246500.aspx)
7
6
  class TreeDisconnectRequest < RubySMB::GenericPacket
@@ -9,13 +8,11 @@ module RubySMB
9
8
  smb2_header :smb2_header
10
9
  uint16 :structure_size, label: 'Structure Size', initial_value: 4
11
10
 
12
-
13
11
  def initialize_instance
14
12
  super
15
13
  smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
16
14
  end
17
-
18
15
  end
19
16
  end
20
17
  end
21
- end
18
+ end
@@ -1,7 +1,6 @@
1
1
  module RubySMB
2
2
  module SMB2
3
3
  module Packet
4
-
5
4
  # An SMB2 TreeDisconnectResponse Packet as defined in
6
5
  # [2.2.12 SMB2 TREE_DISCONNECT Response](https://msdn.microsoft.com/en-us/library/cc246501.aspx)
7
6
  class TreeDisconnectResponse < RubySMB::GenericPacket
@@ -9,14 +8,12 @@ module RubySMB
9
8
  smb2_header :smb2_header
10
9
  uint16 :structure_size, label: 'Structure Size', initial_value: 4
11
10
 
12
-
13
11
  def initialize_instance
14
12
  super
15
13
  smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
16
14
  smb2_header.flags.reply = 1
17
15
  end
18
-
19
16
  end
20
17
  end
21
18
  end
22
- end
19
+ end
@@ -0,0 +1,29 @@
1
+ module RubySMB
2
+ module SMB2
3
+ module Packet
4
+ # An SMB2 Write Request Packet as defined in
5
+ # [2.2.21 SMB2 WRITE Request](https://msdn.microsoft.com/en-us/library/cc246532.aspx)
6
+ class WriteRequest < RubySMB::GenericPacket
7
+ endian :little
8
+
9
+ smb2_header :smb2_header
10
+ uint16 :structure_size, label: 'Structure Size', initial_value: 49
11
+ uint16 :data_offset, label: 'Data Offset' , initial_value: lambda { self.buffer.abs_offset }
12
+ uint32 :write_length, label: 'Write Length', initial_value: lambda { self.buffer.do_num_bytes }
13
+ uint64 :write_offset, label: 'File Write Offset'
14
+ smb2_fileid :file_id, label: 'File ID'
15
+ uint32 :channel, label: 'Channel'
16
+ uint32 :remaining_bytes, label: 'Remaining Bytes'
17
+ uint16 :channel_offset, label: 'Write Channel Info Offset'
18
+ uint16 :channel_length, label: 'Write Channel Info Length'
19
+ uint32 :flags, label: 'Flags'
20
+ string :buffer, label: 'Write Data Buffer'
21
+
22
+ def initialize_instance
23
+ super
24
+ smb2_header.command = RubySMB::SMB2::Commands::WRITE
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ module RubySMB
2
+ module SMB2
3
+ module Packet
4
+ # An SMB2 Write Response Packet as defined in
5
+ # [2.2.22 SMB2 WRITE Response](https://msdn.microsoft.com/en-us/library/cc246533.aspx)
6
+ class WriteResponse < RubySMB::GenericPacket
7
+ endian :little
8
+
9
+ smb2_header :smb2_header
10
+ uint16 :structure_size, label: 'Structure Size', initial_value: 17
11
+ uint16 :reserved, label: 'Reserved Space'
12
+ uint32 :write_count, label: 'Bytes Written'
13
+ uint32 :remaining_bytes, label: 'Remaining Bytes'
14
+ uint16 :channel_offset, label: 'Write Channel Info Offset'
15
+ uint16 :channel_length, label: 'Write Channel Info Length'
16
+
17
+
18
+ def initialize_instance
19
+ super
20
+ smb2_header.command = RubySMB::SMB2::Commands::WRITE
21
+ smb2_header.flags.reply = 1
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,10 +1,8 @@
1
1
  module RubySMB
2
2
  module SMB2
3
-
4
3
  # An SMB2 connected remote Tree, as returned by a
5
4
  # [RubySMB::SMB2::Packet::TreeConnectRequest]
6
5
  class Tree
7
-
8
6
  # The client this Tree is connected through
9
7
  # @!attribute [rw] client
10
8
  # @return [RubySMB::Client]
@@ -37,15 +35,173 @@ module RubySMB
37
35
  # @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
38
36
  def disconnect!
39
37
  request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
40
- request.smb2_header.tree_id = self.id
41
- request.smb2_header.credit_charge = 1
42
- request.smb2_header.credits = 256
43
- raw_response = self.client.send_recv(request)
38
+ request = set_header_fields(request)
39
+ raw_response = client.send_recv(request)
44
40
  response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
45
41
  response.status_code
46
42
  end
47
43
 
44
+ def open_file(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
45
+ impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
46
+
47
+ create_request = RubySMB::SMB2::Packet::CreateRequest.new
48
+ create_request = set_header_fields(create_request)
49
+
50
+ # If the user supplied file attributes, use those, otherwise set some
51
+ # sane defaults.
52
+ if attributes
53
+ create_request.file_attributes = attributes
54
+ else
55
+ create_request.file_attributes.directory = 0
56
+ create_request.file_attributes.normal = 1
57
+ end
58
+
59
+ # If the user supplied Create Options, use those, otherwise set some
60
+ # sane defaults.
61
+ if options
62
+ create_request.create_options = options
63
+ else
64
+ create_request.create_options.directory_file = 0
65
+ create_request.create_options.non_directory_file = 1
66
+ end
67
+
68
+ if read
69
+ create_request.share_access.read_access = 1
70
+ create_request.desired_access.read_data = 1
71
+ end
72
+
73
+ if write
74
+ create_request.share_access.write_access = 1
75
+ create_request.desired_access.write_data = 1
76
+ create_request.desired_access.append_data = 1
77
+ end
78
+
79
+ if delete
80
+ create_request.share_access.delete_access = 1
81
+ create_request.desired_access.delete_access = 1
82
+ end
83
+
84
+ create_request.requested_oplock = 0xff
85
+ create_request.impersonation_level = impersonation
86
+ create_request.create_disposition = disposition
87
+ create_request.name = filename
88
+
89
+ raw_response = client.send_recv(create_request)
90
+ response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
91
+
92
+ RubySMB::SMB2::File.new(name: filename, tree: self, response: response)
93
+ end
94
+
95
+ # List `directory` on the remote share.
96
+ #
97
+ # @example
98
+ # tree = client.tree_connect("\\\\192.168.99.134\\Share")
99
+ # tree.list(directory: "path\\to\\directory")
100
+ #
101
+ # @param directory [String] path to the directory to be listed
102
+ # @param pattern [String] search pattern
103
+ # @param type [Class] file information class
104
+ # @return [Array] array of directory structures
105
+ def list(directory: nil, pattern: '*', type: RubySMB::Fscc::FileInformation::FileIdFullDirectoryInformation)
106
+ create_response = open_directory(directory: directory)
107
+ file_id = create_response.file_id
108
+
109
+ directory_request = RubySMB::SMB2::Packet::QueryDirectoryRequest.new
110
+ directory_request.file_information_class = type::CLASS_LEVEL
111
+ directory_request.file_id = file_id
112
+ directory_request.name = pattern
113
+ directory_request.output_length = 65_535
114
+
115
+ directory_request = set_header_fields(directory_request)
116
+
117
+ files = []
118
+
119
+ loop do
120
+ response = client.send_recv(directory_request)
121
+ directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
48
122
 
123
+ status_code = directory_response.smb2_header.nt_status.to_nt_status
124
+
125
+ break if status_code == WindowsError::NTStatus::STATUS_NO_MORE_FILES
126
+
127
+ unless status_code == WindowsError::NTStatus::STATUS_SUCCESS
128
+
129
+ raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
130
+ end
131
+
132
+ files += directory_response.results(type)
133
+ # Reset the message id so the client can update appropriately.
134
+ directory_request.smb2_header.message_id = 0
135
+ end
136
+
137
+ files
138
+ end
139
+
140
+ # 'Opens' a directory file on the remote end, using a CreateRequest. This
141
+ # can be used to open an existing directory, or create a new one, depending
142
+ # on the disposition set.
143
+ #
144
+ # @param directory [String] the name of the directory file
145
+ # @param disposition [Integer] the create disposition to use, should be one of {RubySMB::Dispositions}
146
+ # @param impersonation [Integer] the impersonation level to use, should be one of {RubySMB::ImpersonationLevels}
147
+ # @param read [Boolean] whether to request read access
148
+ # @param write [Boolean] whether to request write access
149
+ # @param delete [Boolean] whether to request delete access
150
+ # @return [RubySMB::SMB2::Packet::CreateResponse] the response packet returned from the server
151
+ def open_directory(directory: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
152
+ impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE,
153
+ read: true, write: false, delete: false)
154
+
155
+ create_request = open_directory_packet(directory: directory, disposition: disposition,
156
+ impersonation: impersonation, read: read, write: write, delete: delete)
157
+ raw_response = client.send_recv(create_request)
158
+ RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
159
+ end
160
+
161
+ # Creates the Packet for the #open_directory method.
162
+ #
163
+ # @param directory [String] the name of the directory file
164
+ # @param disposition [Integer] the create disposition to use, should be one of {RubySMB::Dispositions}
165
+ # @param impersonation [Integer] the impersonation level to use, should be one of {RubySMB::ImpersonationLevels}
166
+ # @param read [Boolean] whether to request read access
167
+ # @param write [Boolean] whether to request write access
168
+ # @param delete [Boolean] whether to request delete access
169
+ # @return [RubySMB::SMB2::Packet::CreateRequest] the request packet to send to the server
170
+ def open_directory_packet(directory: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
171
+ impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE,
172
+ read: true, write: false, delete: false)
173
+ create_request = RubySMB::SMB2::Packet::CreateRequest.new
174
+ create_request = set_header_fields(create_request)
175
+
176
+ create_request.impersonation_level = impersonation
177
+ create_request.create_options.directory_file = 1
178
+ create_request.file_attributes.directory = 1
179
+ create_request.desired_access.list = 1
180
+ create_request.share_access.read_access = 1 if read
181
+ create_request.share_access.write_access = 1 if write
182
+ create_request.share_access.delete_access = 1 if delete
183
+ create_request.create_disposition = disposition
184
+
185
+ if directory.nil? || directory.empty?
186
+ create_request.name = "\x00"
187
+ create_request.name_length = 0
188
+ else
189
+ create_request.name = directory
190
+ end
191
+ create_request
192
+ end
193
+
194
+ # Sets a few preset header fields that will always be set the same
195
+ # way for Tree operations. This is, the TreeID, Credits, and Credit Charge.
196
+ #
197
+ # @param [RubySMB::SMB2::Packet] the request packet to modify
198
+ # @return [RubySMB::SMB2::Packet] the modified packet.
199
+ def set_header_fields(request)
200
+ request.smb2_header.tree_id = id
201
+ request.smb2_header.credit_charge = 1
202
+ request.smb2_header.credits = 256
203
+ request
204
+ end
49
205
  end
50
206
  end
51
- end
207
+ end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '0.0.18'
2
+ VERSION = '0.0.19'.freeze
3
3
  end
@@ -1,19 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe RubySMB::Client do
4
-
5
- let(:sock) { double("Socket", peeraddr: '192.168.1.5' ) }
4
+ let(:sock) { double('Socket', peeraddr: '192.168.1.5') }
6
5
  let(:dispatcher) { RubySMB::Dispatcher::Socket.new(sock) }
7
6
  let(:username) { 'msfadmin' }
8
- let(:password) { 'msfadmin' }
7
+ let(:password) { 'msfpasswd' }
9
8
  subject(:client) { described_class.new(dispatcher, username: username, password: password) }
10
- let(:smb1_client) { described_class.new(dispatcher, smb2:false, username: username, password: password) }
11
- let(:smb2_client) { described_class.new(dispatcher, smb1:false, username: username, password: password) }
9
+ let(:smb1_client) { described_class.new(dispatcher, smb2: false, username: username, password: password) }
10
+ let(:smb2_client) { described_class.new(dispatcher, smb1: false, username: username, password: password) }
12
11
  let(:empty_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
13
12
 
14
13
  describe '#initialize' do
15
14
  it 'should raise an ArgumentError without a valid dispatcher' do
16
- expect{ described_class.new(nil) }.to raise_error(ArgumentError)
15
+ expect { described_class.new(nil) }.to raise_error(ArgumentError)
17
16
  end
18
17
 
19
18
  it 'defaults to true for SMB1 support' do
@@ -25,8 +24,7 @@ RSpec.describe RubySMB::Client do
25
24
  end
26
25
 
27
26
  it 'accepts an argument to disable smb1 support' do
28
- smb_client = described_class.new(dispatcher, smb1:false, username: username, password: password)
29
- expect(smb_client.smb1).to be false
27
+ expect(smb2_client.smb1).to be false
30
28
  end
31
29
 
32
30
  it 'accepts an argument to disable smb2 support' do
@@ -34,10 +32,10 @@ RSpec.describe RubySMB::Client do
34
32
  end
35
33
 
36
34
  it 'raises an exception if both SMB1 and SMB2 are disabled' do
37
- expect{described_class.new(dispatcher, smb1:false, smb2:false, username: username, password: password)}.to raise_error(ArgumentError, 'You must enable at least one Protocol')
35
+ expect { described_class.new(dispatcher, smb1: false, smb2: false, username: username, password: password) }.to raise_error(ArgumentError, 'You must enable at least one Protocol')
38
36
  end
39
37
 
40
- it 'sets the username attribute' do
38
+ it 'sets the username attribute' do
41
39
  expect(client.username).to eq username
42
40
  end
43
41
 
@@ -45,9 +43,36 @@ RSpec.describe RubySMB::Client do
45
43
  expect(client.password).to eq password
46
44
  end
47
45
 
48
- it 'crates an NTLM client' do
46
+ it 'creates an NTLM client' do
49
47
  expect(client.ntlm_client).to be_a Net::NTLM::Client
50
48
  end
49
+
50
+ it 'passes the expected arguments when creating the NTLM client' do
51
+ domain = 'SPEC_DOMAIN'
52
+ local_workstation = 'SPEC_WORKSTATION'
53
+
54
+ allow(Net::NTLM::Client).to receive(:new) do |username, passwd, opt|
55
+ expect(username).to eq(username)
56
+ expect(password).to eq(password)
57
+ expect(opt[:workstation]).to eq(local_workstation)
58
+ expect(opt[:domain]).to eq(domain)
59
+ flags = Net::NTLM::Client::DEFAULT_FLAGS |
60
+ Net::NTLM::FLAGS[:TARGET_INFO] | 0x02000000
61
+ expect(opt[:flags]).to eq(flags)
62
+ end
63
+
64
+ described_class.new(
65
+ dispatcher,
66
+ username: username,
67
+ password: password,
68
+ domain: domain,
69
+ local_workstation: local_workstation
70
+ )
71
+ end
72
+
73
+ it 'sets the max_buffer_size to MAX_BUFFER_SIZE' do
74
+ expect(client.max_buffer_size).to eq RubySMB::Client::MAX_BUFFER_SIZE
75
+ end
51
76
  end
52
77
 
53
78
  describe '#send_recv' do
@@ -56,7 +81,7 @@ RSpec.describe RubySMB::Client do
56
81
 
57
82
  before(:each) do
58
83
  expect(dispatcher).to receive(:send_packet).and_return(nil)
59
- expect(dispatcher).to receive(:recv_packet).and_return("A")
84
+ expect(dispatcher).to receive(:recv_packet).and_return('A')
60
85
  end
61
86
 
62
87
  it 'checks the packet version' do
@@ -64,7 +89,7 @@ RSpec.describe RubySMB::Client do
64
89
  client.send_recv(smb1_request)
65
90
  end
66
91
 
67
- it 'calls #smb1_sign if it is an SMB1 packet' do
92
+ it 'calls #smb1_sign if it is an SMB1 packet' do
68
93
  expect(client).to receive(:smb1_sign).with(smb1_request).and_call_original
69
94
  client.send_recv(smb1_request)
70
95
  end
@@ -73,7 +98,6 @@ RSpec.describe RubySMB::Client do
73
98
  expect(client).to receive(:smb2_sign).with(smb2_request).and_call_original
74
99
  client.send_recv(smb2_request)
75
100
  end
76
-
77
101
  end
78
102
 
79
103
  describe '#login' do
@@ -83,39 +107,39 @@ RSpec.describe RubySMB::Client do
83
107
  end
84
108
 
85
109
  it 'defaults username to what was in the initializer' do
86
- expect{ client.login }.to_not change(client, :username)
110
+ expect { client.login }.to_not change(client, :username)
87
111
  end
88
112
 
89
113
  it 'overrides username if it is passed as a parameter' do
90
- expect{ client.login(username:'test') }.to change(client, :username).to('test')
114
+ expect { client.login(username: 'test') }.to change(client, :username).to('test')
91
115
  end
92
116
 
93
117
  it 'defaults password to what was in the initializer' do
94
- expect{ client.login }.to_not change(client, :password)
118
+ expect { client.login }.to_not change(client, :password)
95
119
  end
96
120
 
97
121
  it 'overrides password if it is passed as a parameter' do
98
- expect{ client.login(password:'test') }.to change(client, :password).to('test')
122
+ expect { client.login(password: 'test') }.to change(client, :password).to('test')
99
123
  end
100
124
 
101
125
  it 'defaults domain to what was in the initializer' do
102
- expect{ client.login }.to_not change(client, :domain)
126
+ expect { client.login }.to_not change(client, :domain)
103
127
  end
104
128
 
105
129
  it 'overrides domain if it is passed as a parameter' do
106
- expect{ client.login(domain:'test') }.to change(client, :domain).to('test')
130
+ expect { client.login(domain: 'test') }.to change(client, :domain).to('test')
107
131
  end
108
132
 
109
133
  it 'defaults local_workstation to what was in the initializer' do
110
- expect{ client.login }.to_not change(client, :local_workstation)
134
+ expect { client.login }.to_not change(client, :local_workstation)
111
135
  end
112
136
 
113
137
  it 'overrides local_workstation if it is passed as a parameter' do
114
- expect{ client.login(local_workstation:'test') }.to change(client, :local_workstation).to('test')
138
+ expect { client.login(local_workstation: 'test') }.to change(client, :local_workstation).to('test')
115
139
  end
116
140
 
117
141
  it 'initialises a new NTLM Client' do
118
- expect{ client.login }.to change(client, :ntlm_client)
142
+ expect { client.login }.to change(client, :ntlm_client)
119
143
  end
120
144
 
121
145
  it 'calls negotiate after the setup' do
@@ -127,37 +151,129 @@ RSpec.describe RubySMB::Client do
127
151
  expect(client).to receive(:authenticate)
128
152
  client.login
129
153
  end
154
+ end
155
+
156
+ context 'NetBIOS Session Service' do
157
+ describe '#session_request' do
158
+ let(:called_name) { '*SMBSERVER ' }
159
+ let(:calling_name) { " \x00" }
160
+ let(:session_header) { RubySMB::Nbss::SessionHeader.new }
161
+ let(:session_request) { RubySMB::Nbss::SessionRequest.new }
162
+
163
+ before :example do
164
+ allow(RubySMB::Nbss::SessionRequest).to receive(:new).and_return(session_request)
165
+ allow(dispatcher).to receive(:send_packet)
166
+ allow(dispatcher).to receive(:recv_packet).and_return(session_header.to_binary_s)
167
+ end
168
+
169
+ it 'requests a session for *SMBSERVER by default' do
170
+ expect(client).to receive(:nb_name_encode).with(called_name).once
171
+ expect(client).to receive(:nb_name_encode).with(calling_name).once
172
+ client.session_request
173
+ end
174
+
175
+ it 'requests a session for the provided name and the expected calling name' do
176
+ name = 'NBNAME'
177
+ called_name = "#{name} "
178
+
179
+ expect(client).to receive(:nb_name_encode).with(called_name).once
180
+ expect(client).to receive(:nb_name_encode).with(calling_name).once
181
+ client.session_request(name)
182
+ end
183
+
184
+ it 'makes NetBIOS name uppercase' do
185
+ name = 'nbNamE'
186
+ called_name = "#{name.upcase} "
187
+
188
+ expect(client).to receive(:nb_name_encode).with(called_name).once
189
+ expect(client).to receive(:nb_name_encode).with(calling_name).once
190
+ client.session_request(name)
191
+ end
192
+
193
+ it 'creates a SessionRequest packet' do
194
+ expect(RubySMB::Nbss::SessionRequest).to receive(:new).and_return(session_request)
195
+ client.session_request
196
+ end
197
+
198
+ it 'sets the expected fields of the SessionRequest packet' do
199
+ encoded_called_name = "\x20#{client.nb_name_encode(called_name)}\x00"
200
+ encoded_calling_name = "\x20#{client.nb_name_encode(calling_name)}\x00"
201
+ allow(dispatcher).to receive(:send_packet) do |packet, _opts|
202
+ expect(packet).to be_a(RubySMB::Nbss::SessionRequest)
203
+ expect(packet.session_header.session_packet_type).to eq RubySMB::Nbss::SESSION_REQUEST
204
+ expect(packet.called_name).to eq encoded_called_name
205
+ expect(packet.calling_name).to eq encoded_calling_name
206
+ expect(packet.session_header.packet_length).to eq (encoded_called_name.size + encoded_calling_name.size)
207
+ end
208
+ client.session_request
209
+ end
210
+
211
+ it 'sends the SessionRequest packet without adding additional NetBIOS Session Header' do
212
+ expect(dispatcher).to receive(:send_packet).with(session_request, nbss_header: false)
213
+ client.session_request
214
+ end
215
+
216
+ it 'reads the full response packet, including the NetBIOS Session Header' do
217
+ expect(dispatcher).to receive(:recv_packet).with(full_response: true).and_return(session_header.to_binary_s)
218
+ client.session_request
219
+ end
220
+
221
+ it 'parses the response with SessionHeader packet structure' do
222
+ expect(RubySMB::Nbss::SessionHeader).to receive(:read).with(session_header.to_binary_s).and_return(session_header)
223
+ client.session_request
224
+ end
225
+
226
+ it 'returns true when it is a POSITIVE_SESSION_RESPONSE' do
227
+ session_header.session_packet_type = RubySMB::Nbss::POSITIVE_SESSION_RESPONSE
228
+ expect(client.session_request).to be true
229
+ end
230
+
231
+ it 'raises an exception when it is a NEGATIVE_SESSION_RESPONSE' do
232
+ negative_session_response = RubySMB::Nbss::NegativeSessionResponse.new
233
+ negative_session_response.session_header.session_packet_type = RubySMB::Nbss::NEGATIVE_SESSION_RESPONSE
234
+ negative_session_response.error_code = 0x80
235
+ allow(dispatcher).to receive(:recv_packet).and_return(negative_session_response.to_binary_s)
236
+ expect { client.session_request }.to raise_error(RubySMB::Error::NetBiosSessionService)
237
+ end
238
+ end
130
239
 
240
+ describe '#nb_name_encode' do
241
+ it 'encodes as expected' do
242
+ input = 'TESTNB '
243
+ output = 'FEEFFDFEEOECCACACACACACACACACACA'
244
+ expect(client.nb_name_encode(input)).to eq output
245
+ end
246
+ end
131
247
  end
132
248
 
133
249
  context 'Protocol Negotiation' do
134
- let(:random_junk) { "fgrgrwgawrtw4t4tg4gahgn" }
250
+ let(:random_junk) { 'fgrgrwgawrtw4t4tg4gahgn' }
135
251
  let(:smb1_capabilities) {
136
- {:level_2_oplocks=>1,
137
- :nt_status=>1,
138
- :rpc_remote_apis=>1,
139
- :nt_smbs=>1,
140
- :large_files=>1,
141
- :unicode=>1,
142
- :mpx_mode=>0,
143
- :raw_mode=>0,
144
- :large_writex=>1,
145
- :large_readx=>1,
146
- :info_level_passthru=>1,
147
- :dfs=>0,
148
- :reserved1=>0,
149
- :bulk_transfer=>0,
150
- :nt_find=>1,
151
- :lock_and_read=>1,
152
- :unix=>0,
153
- :reserved2=>0,
154
- :lwio=>1,
155
- :extended_security=>1,
156
- :reserved3=>0,
157
- :dynamic_reauth=>0,
158
- :reserved4=>0,
159
- :compressed_data=>0,
160
- :reserved5=>0}
252
+ { level_2_oplocks: 1,
253
+ nt_status: 1,
254
+ rpc_remote_apis: 1,
255
+ nt_smbs: 1,
256
+ large_files: 1,
257
+ unicode: 1,
258
+ mpx_mode: 0,
259
+ raw_mode: 0,
260
+ large_writex: 1,
261
+ large_readx: 1,
262
+ info_level_passthru: 1,
263
+ dfs: 0,
264
+ reserved1: 0,
265
+ bulk_transfer: 0,
266
+ nt_find: 1,
267
+ lock_and_read: 1,
268
+ unix: 0,
269
+ reserved2: 0,
270
+ lwio: 1,
271
+ extended_security: 1,
272
+ reserved3: 0,
273
+ dynamic_reauth: 0,
274
+ reserved4: 0,
275
+ compressed_data: 0,
276
+ reserved5: 0 }
161
277
  }
162
278
  let(:smb1_extended_response) {
163
279
  packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.new
@@ -176,19 +292,19 @@ RSpec.describe RubySMB::Client do
176
292
  end
177
293
 
178
294
  it 'sets the default SMB1 Dialect' do
179
- expect(client.smb1_negotiate_request.dialects).to include({:buffer_format=>2, :dialect_string=> RubySMB::Client::SMB1_DIALECT_SMB1_DEFAULT})
295
+ expect(client.smb1_negotiate_request.dialects).to include(buffer_format: 2, dialect_string: RubySMB::Client::SMB1_DIALECT_SMB1_DEFAULT)
180
296
  end
181
297
 
182
298
  it 'sets the SMB2.02 dialect if SMB2 support is enabled' do
183
- expect(client.smb1_negotiate_request.dialects).to include({:buffer_format=>2, :dialect_string=> RubySMB::Client::SMB1_DIALECT_SMB2_DEFAULT})
299
+ expect(client.smb1_negotiate_request.dialects).to include(buffer_format: 2, dialect_string: RubySMB::Client::SMB1_DIALECT_SMB2_DEFAULT)
184
300
  end
185
301
 
186
302
  it 'excludes the SMB2.02 Dialect if SMB2 support is disabled' do
187
- expect(smb1_client.smb1_negotiate_request.dialects).to_not include({:buffer_format=>2, :dialect_string=> RubySMB::Client::SMB1_DIALECT_SMB2_DEFAULT})
303
+ expect(smb1_client.smb1_negotiate_request.dialects).to_not include(buffer_format: 2, dialect_string: RubySMB::Client::SMB1_DIALECT_SMB2_DEFAULT)
188
304
  end
189
305
 
190
306
  it 'excludes the default SMB1 Dialect if SMB1 support is disabled' do
191
- expect(smb2_client.smb1_negotiate_request.dialects).to_not include({:buffer_format=>2, :dialect_string=> RubySMB::Client::SMB1_DIALECT_SMB1_DEFAULT})
307
+ expect(smb2_client.smb1_negotiate_request.dialects).to_not include(buffer_format: 2, dialect_string: RubySMB::Client::SMB1_DIALECT_SMB1_DEFAULT)
192
308
  end
193
309
  end
194
310
 
@@ -209,26 +325,18 @@ RSpec.describe RubySMB::Client do
209
325
  describe '#negotiate_request' do
210
326
  it 'calls #smb1_negotiate_request if SMB1 is enabled' do
211
327
  expect(smb1_client).to receive(:smb1_negotiate_request)
212
- expect(smb1_client).to receive(:send_recv)
213
328
  smb1_client.negotiate_request
214
329
  end
215
330
 
216
331
  it 'calls #smb1_negotiate_request if both protocols are enabled' do
217
332
  expect(client).to receive(:smb1_negotiate_request)
218
- expect(client).to receive(:send_recv)
219
333
  client.negotiate_request
220
334
  end
221
335
 
222
336
  it 'calls #smb2_negotiate_request if SMB2 is enabled' do
223
337
  expect(smb2_client).to receive(:smb2_negotiate_request)
224
- expect(smb2_client).to receive(:send_recv)
225
338
  smb2_client.negotiate_request
226
339
  end
227
-
228
- it 'returns the raw response string from the server' do
229
- expect(client).to receive(:send_recv).and_return('A')
230
- expect(client.negotiate_request).to eq "A"
231
- end
232
340
  end
233
341
 
234
342
  describe '#negotiate_response' do
@@ -238,39 +346,39 @@ RSpec.describe RubySMB::Client do
238
346
  end
239
347
 
240
348
  it 'raises an exception if the Response is invalid' do
241
- expect{ smb1_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
349
+ expect { smb1_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
242
350
  end
243
351
 
244
352
  it 'considers the response invalid if it is not an actual Negotiate Response' do
245
353
  bogus_response = smb1_extended_response
246
354
  bogus_response.smb_header.command = 0xff
247
- expect{ smb1_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
355
+ expect { smb1_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
248
356
  end
249
357
 
250
358
  it 'considers the response invalid if Extended Security is not enabled' do
251
359
  bogus_response = smb1_extended_response
252
360
  bogus_response.parameter_block.capabilities.extended_security = 0
253
- expect{ smb1_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
361
+ expect { smb1_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
254
362
  end
255
363
  end
256
364
 
257
365
  context 'with only SMB2' do
258
366
  it 'returns a properly formed packet' do
259
- expect( smb2_client.negotiate_response(smb2_response.to_binary_s) ).to eq smb2_response
367
+ expect(smb2_client.negotiate_response(smb2_response.to_binary_s)).to eq smb2_response
260
368
  end
261
369
 
262
370
  it 'raises an exception if the Response is invalid' do
263
- expect{ smb2_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
371
+ expect { smb2_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
264
372
  end
265
373
  end
266
374
 
267
375
  context 'with SMB1 and SMB2 enabled' do
268
376
  it 'returns an SMB1 NegotiateResponse if it looks like SMB1' do
269
- expect( client.negotiate_response(smb1_extended_response_raw) ).to eq smb1_extended_response
377
+ expect(client.negotiate_response(smb1_extended_response_raw)).to eq smb1_extended_response
270
378
  end
271
379
 
272
380
  it 'returns an SMB2 NegotiateResponse if it looks like SMB2' do
273
- expect( client.negotiate_response(smb2_response.to_binary_s) ).to eq smb2_response
381
+ expect(client.negotiate_response(smb2_response.to_binary_s)).to eq smb2_response
274
382
  end
275
383
  end
276
384
  end
@@ -279,7 +387,7 @@ RSpec.describe RubySMB::Client do
279
387
  context 'when SMB1 was Negotiated' do
280
388
  it 'turns off SMB2 support' do
281
389
  client.parse_negotiate_response(smb1_extended_response)
282
- expect( client.smb2 ).to be false
390
+ expect(client.smb2).to be false
283
391
  end
284
392
 
285
393
  it 'sets whether or not signing is required' do
@@ -287,12 +395,27 @@ RSpec.describe RubySMB::Client do
287
395
  client.parse_negotiate_response(smb1_extended_response)
288
396
  expect(client.signing_required).to be true
289
397
  end
398
+
399
+ it 'sets #dialect to the negotiated dialect' do
400
+ smb1_extended_response.dialects = [
401
+ RubySMB::SMB1::Dialect.new(dialect_string: 'A'),
402
+ RubySMB::SMB1::Dialect.new(dialect_string: 'B'),
403
+ RubySMB::SMB1::Dialect.new(dialect_string: 'C'),
404
+ ]
405
+ smb1_extended_response.parameter_block.dialect_index = 1
406
+ client.parse_negotiate_response(smb1_extended_response)
407
+ expect(client.dialect).to eq 'B'
408
+ end
409
+
410
+ it 'returns the string \'SMB1\'' do
411
+ expect(client.parse_negotiate_response(smb1_extended_response)).to eq ('SMB1')
412
+ end
290
413
  end
291
414
 
292
415
  context 'when SMB2 was negotiated' do
293
416
  it 'turns off SMB1 support' do
294
417
  client.parse_negotiate_response(smb2_response)
295
- expect( client.smb1 ).to be false
418
+ expect(client.smb1).to be false
296
419
  end
297
420
 
298
421
  it 'sets whether or not signing is required' do
@@ -300,25 +423,50 @@ RSpec.describe RubySMB::Client do
300
423
  client.parse_negotiate_response(smb2_response)
301
424
  expect(client.signing_required).to be true
302
425
  end
426
+
427
+ it 'sets #dialect to the negotiated dialect' do
428
+ smb2_response.dialect_revision = 2
429
+ client.parse_negotiate_response(smb2_response)
430
+ expect(client.dialect).to eq '0x0002'
431
+ end
432
+
433
+ it 'returns the string \'SMB2\'' do
434
+ expect(client.parse_negotiate_response(smb2_response)).to eq ('SMB2')
435
+ end
303
436
  end
304
437
  end
305
438
 
306
439
  describe '#negotiate' do
307
440
  it 'calls the backing methods' do
308
441
  expect(client).to receive(:negotiate_request)
442
+ expect(client).to receive(:send_recv)
309
443
  expect(client).to receive(:negotiate_response)
310
444
  expect(client).to receive(:parse_negotiate_response)
311
445
  client.negotiate
312
446
  end
447
+
448
+ it 'sets the response-packet #dialects array with the dialects sent in the request' do
449
+ request_packet = client.smb1_negotiate_request
450
+ allow(client).to receive(:negotiate_request).and_return(request_packet)
451
+ allow(client).to receive(:send_recv)
452
+ allow(client).to receive(:negotiate_response).and_return(smb1_extended_response)
453
+ expect(smb1_extended_response).to receive(:dialects=).with(request_packet.dialects)
454
+ client.negotiate
455
+ end
456
+
457
+ it 'raise the expected exception if an error occurs' do
458
+ allow(client).to receive(:send_recv).and_raise(RubySMB::Error::InvalidPacket)
459
+ expect { client.negotiate }.to raise_error(RubySMB::Error::NegotiationFailure)
460
+ end
313
461
  end
314
462
  end
315
463
 
316
464
  context 'Authentication' do
317
465
  let(:type2_string) {
318
- "TlRMTVNTUAACAAAAHgAeADgAAAA1goriwmZ8HEHtFHAAAAAAAAAAAJgAmABW\nAAAABgGxHQAAAA" +
319
- "9XAEkATgAtAFMATgBKAEQARwAwAFUAQQA5ADAARgACAB4A\nVwBJAE4ALQBTAE4ASgBEAEcAMABV" +
320
- "AEEAOQAwAEYAAQAeAFcASQBOAC0AUwBO\nAEoARABHADAAVQBBADkAMABGAAQAHgBXAEkATgAtAF" +
321
- "MATgBKAEQARwAwAFUA\nQQA5ADAARgADAB4AVwBJAE4ALQBTAE4ASgBEAEcAMABVAEEAOQAwAEYABw" +
466
+ "TlRMTVNTUAACAAAAHgAeADgAAAA1goriwmZ8HEHtFHAAAAAAAAAAAJgAmABW\nAAAABgGxHQAAAA" \
467
+ "9XAEkATgAtAFMATgBKAEQARwAwAFUAQQA5ADAARgACAB4A\nVwBJAE4ALQBTAE4ASgBEAEcAMABV" \
468
+ "AEEAOQAwAEYAAQAeAFcASQBOAC0AUwBO\nAEoARABHADAAVQBBADkAMABGAAQAHgBXAEkATgAtAF" \
469
+ "MATgBKAEQARwAwAFUA\nQQA5ADAARgADAB4AVwBJAE4ALQBTAE4ASgBEAEcAMABVAEEAOQAwAEYABw" \
322
470
  "AI\nADxThZ4nnNIBAAAAAA==\n"
323
471
  }
324
472
 
@@ -342,28 +490,89 @@ RSpec.describe RubySMB::Client do
342
490
  end
343
491
 
344
492
  context 'for SMB1' do
345
- let(:ntlm_client) { smb1_client.ntlm_client }
346
- let(:type1_message) { ntlm_client.init_context }
493
+ let(:ntlm_client) { smb1_client.ntlm_client }
494
+ let(:type1_message) { ntlm_client.init_context }
347
495
  let(:negotiate_packet) { RubySMB::SMB1::Packet::SessionSetupRequest.new }
496
+ let(:response_packet) { RubySMB::SMB1::Packet::SessionSetupResponse.new }
497
+ let(:final_response_packet) { RubySMB::SMB1::Packet::SessionSetupResponse.new }
348
498
  let(:type3_message) { ntlm_client.init_context(type2_string) }
349
499
  let(:user_id) { 2041 }
350
500
 
501
+ describe '#smb1_authenticate' do
502
+ before :example do
503
+ allow(smb1_client).to receive(:smb1_ntlmssp_negotiate)
504
+ allow(smb1_client).to receive(:smb1_ntlmssp_challenge_packet).and_return(response_packet)
505
+ allow(smb1_client).to receive(:smb1_type2_message).and_return(type2_string)
506
+ allow(smb1_client).to receive(:smb1_ntlmssp_authenticate)
507
+ allow(smb1_client).to receive(:smb1_ntlmssp_final_packet).and_return(final_response_packet)
508
+ end
509
+
510
+ it 'calls the backing methods' do
511
+ response_packet.smb_header.uid = user_id
512
+ expect(smb1_client).to receive(:smb1_ntlmssp_negotiate).and_return(negotiate_packet)
513
+ expect(smb1_client).to receive(:smb1_ntlmssp_challenge_packet).with(negotiate_packet).and_return(response_packet)
514
+ expect(smb1_client).to receive(:smb1_type2_message).with(response_packet).and_return(type2_string)
515
+ expect(smb1_client).to receive(:store_target_info).with(String)
516
+ expect(smb1_client).to receive(:extract_os_version).with(String)
517
+ expect(smb1_client).to receive(:smb1_ntlmssp_authenticate).with(Net::NTLM::Message::Type3, user_id)
518
+ expect(smb1_client).to receive(:smb1_ntlmssp_final_packet).and_return(final_response_packet)
519
+ smb1_client.smb1_authenticate
520
+ end
521
+
522
+ it 'stores the OS information from the challenge packet' do
523
+ native_os = 'Windows 7 Professional 7601 Service Pack 1'
524
+ native_lm = 'Windows 7 Professional 6.1'
525
+ response_packet.data_block.native_os = native_os
526
+ response_packet.data_block.native_lan_man = native_lm
527
+ smb1_client.smb1_authenticate
528
+
529
+ expect(smb1_client.peer_native_os).to eq native_os
530
+ expect(smb1_client.peer_native_lm).to eq native_lm
531
+ end
532
+
533
+ it 'stores the session key from the NTLM client' do
534
+ smb1_client.smb1_authenticate
535
+ expect(smb1_client.session_key).to eq ntlm_client.session_key
536
+ end
537
+
538
+ it 'stores the OS version number from the challenge message' do
539
+ smb1_client.smb1_authenticate
540
+ expect(smb1_client.os_version).to eq '6.1.7601'
541
+ end
542
+
543
+ it 'stores the user ID if the status code is \'STATUS_SUCCESS\'' do
544
+ response_packet.smb_header.uid = user_id
545
+ final_response_packet.smb_header.nt_status = WindowsError::NTStatus::STATUS_SUCCESS.value
546
+ smb1_client.smb1_authenticate
547
+ expect(smb1_client.user_id).to eq user_id
548
+ end
549
+
550
+ it 'does not store the user ID if the status code is not \'STATUS_SUCCESS\'' do
551
+ response_packet.smb_header.uid = user_id
552
+ final_response_packet.smb_header.nt_status = WindowsError::NTStatus::STATUS_PENDING.value
553
+ smb1_client.smb1_authenticate
554
+ expect(smb1_client.user_id).to eq nil
555
+ end
556
+ end
351
557
 
352
558
  describe '#smb1_ntlmssp_auth_packet' do
353
559
  it 'creates a new SessionSetupRequest packet' do
354
560
  expect(RubySMB::SMB1::Packet::SessionSetupRequest).to receive(:new).and_return(negotiate_packet)
355
- smb1_client.smb1_ntlmssp_auth_packet(type2_string, user_id)
561
+ smb1_client.smb1_ntlmssp_auth_packet(type3_message, user_id)
356
562
  end
357
563
 
358
- it 'builds the security blob with an NTLM Type 3 Message' do
564
+ it 'sets the security blob with an NTLM Type 3 Message' do
359
565
  expect(RubySMB::SMB1::Packet::SessionSetupRequest).to receive(:new).and_return(negotiate_packet)
360
- expect(ntlm_client).to receive(:init_context).with(type2_string).and_return(type3_message)
361
566
  expect(negotiate_packet).to receive(:set_type3_blob).with(type3_message.serialize)
362
- smb1_client.smb1_ntlmssp_auth_packet(type2_string, user_id)
567
+ smb1_client.smb1_ntlmssp_auth_packet(type3_message, user_id)
363
568
  end
364
569
 
365
570
  it 'enables extended security on the packet' do
366
- expect(smb1_client.smb1_ntlmssp_auth_packet(type2_string, user_id).smb_header.flags2.extended_security).to eq 1
571
+ expect(smb1_client.smb1_ntlmssp_auth_packet(type3_message, user_id).smb_header.flags2.extended_security).to eq 1
572
+ end
573
+
574
+ it 'sets the max_buffer_size to the client\'s max_buffer_size' do
575
+ expect(smb1_client.smb1_ntlmssp_auth_packet(type3_message, user_id).parameter_block.max_buffer_size).to eq smb1_client.max_buffer_size
367
576
  end
368
577
  end
369
578
 
@@ -383,6 +592,10 @@ RSpec.describe RubySMB::Client do
383
592
  it 'enables extended security on the packet' do
384
593
  expect(smb1_client.smb1_ntlmssp_negotiate_packet.smb_header.flags2.extended_security).to eq 1
385
594
  end
595
+
596
+ it 'sets the max_buffer_size to the client\'s max_buffer_size' do
597
+ expect(smb1_client.smb1_ntlmssp_negotiate_packet.parameter_block.max_buffer_size).to eq smb1_client.max_buffer_size
598
+ end
386
599
  end
387
600
 
388
601
  describe '#smb1_ntlmssp_authenticate' do
@@ -390,7 +603,7 @@ RSpec.describe RubySMB::Client do
390
603
  expect(smb1_client).to receive(:smb1_ntlmssp_auth_packet).and_return(negotiate_packet)
391
604
  expect(dispatcher).to receive(:send_packet).with(negotiate_packet)
392
605
  expect(dispatcher).to receive(:recv_packet)
393
- smb1_client.smb1_ntlmssp_authenticate(type2_string, user_id)
606
+ smb1_client.smb1_ntlmssp_authenticate(type3_message, user_id)
394
607
  end
395
608
  end
396
609
 
@@ -421,11 +634,11 @@ RSpec.describe RubySMB::Client do
421
634
 
422
635
  it 'raises an UnexpectedStatusCode if the status code is not correct' do
423
636
  response.smb_header.nt_status = 0xc0000015
424
- expect{ smb1_client.smb1_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error( RubySMB::Error::UnexpectedStatusCode)
637
+ expect { smb1_client.smb1_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
425
638
  end
426
639
 
427
640
  it 'raises an InvalidPacket if the Command field is wrong' do
428
- expect{ smb1_client.smb1_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
641
+ expect { smb1_client.smb1_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
429
642
  end
430
643
  end
431
644
 
@@ -446,12 +659,12 @@ RSpec.describe RubySMB::Client do
446
659
  end
447
660
 
448
661
  it 'raises an InvalidPacket if the Command field is wrong' do
449
- expect{ smb1_client.smb1_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
662
+ expect { smb1_client.smb1_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
450
663
  end
451
664
  end
452
665
 
453
666
  describe '#smb1_type2_message' do
454
- let(:fake_type2) { "NTLMSSP FOO" }
667
+ let(:fake_type2) { 'NTLMSSP FOO' }
455
668
  let(:response_packet) {
456
669
  packet = RubySMB::SMB1::Packet::SessionSetupResponse.new
457
670
  packet.set_type2_blob(fake_type2)
@@ -466,10 +679,50 @@ RSpec.describe RubySMB::Client do
466
679
  let(:anonymous_request) { RubySMB::SMB1::Packet::SessionSetupLegacyRequest.new }
467
680
  let(:anonymous_response) { RubySMB::SMB1::Packet::SessionSetupLegacyResponse.new }
468
681
 
682
+ describe '#smb1_anonymous_auth' do
683
+ it 'calls the backing methods' do
684
+ expect(client).to receive(:smb1_anonymous_auth_request).and_return(anonymous_request)
685
+ expect(client).to receive(:send_recv).with(anonymous_request)
686
+ expect(client).to receive(:smb1_anonymous_auth_response).and_return(anonymous_response)
687
+ client.smb1_anonymous_auth
688
+ end
689
+
690
+ it 'returns the status code' do
691
+ allow(client).to receive(:send_recv)
692
+ allow(client).to receive(:smb1_anonymous_auth_response).and_return(anonymous_response)
693
+ anonymous_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_PENDING.value
694
+ expect(client.smb1_anonymous_auth).to eq WindowsError::NTStatus::STATUS_PENDING
695
+ end
696
+
697
+ it 'sets the expected Client\'s attribute from the response when the status code is STATUS_SUCCESS' do
698
+ native_os = 'Windows 7 Professional 7601 Service Pack 1'
699
+ native_lm = 'Windows 7 Professional 6.1'
700
+ primary_domain = 'SPEC_DOMAIN'
701
+ anonymous_response.smb_header.uid = user_id
702
+ anonymous_response.data_block.native_os = native_os
703
+ anonymous_response.data_block.native_lan_man = native_lm
704
+ anonymous_response.data_block.primary_domain = primary_domain
705
+ anonymous_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_SUCCESS.value
706
+
707
+ allow(client).to receive(:send_recv)
708
+ allow(client).to receive(:smb1_anonymous_auth_response).and_return(anonymous_response)
709
+
710
+ client.smb1_anonymous_auth
711
+ expect(client.user_id).to eq user_id
712
+ expect(client.peer_native_os).to eq native_os
713
+ expect(client.peer_native_lm).to eq native_lm
714
+ expect(client.primary_domain).to eq primary_domain
715
+ end
716
+ end
717
+
469
718
  describe '#smb1_anonymous_auth_request' do
470
719
  it 'creates a SessionSetupLegacyRequest packet with a null byte for the oem password' do
471
720
  expect(smb1_client.smb1_anonymous_auth_request.data_block.oem_password).to eq "\x00"
472
721
  end
722
+
723
+ it 'creates a SessionSetupLegacyRequest packet with the max_buffer_size set to the client\'s max_buffer_size' do
724
+ expect(smb1_client.smb1_anonymous_auth_request.parameter_block.max_buffer_size).to eq smb1_client.max_buffer_size
725
+ end
473
726
  end
474
727
 
475
728
  describe '#smb1_anonymous_auth_response' do
@@ -484,20 +737,59 @@ RSpec.describe RubySMB::Client do
484
737
 
485
738
  it 'raises an InvalidPacket error if the command is wrong' do
486
739
  anonymous_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
487
- expect{ smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
740
+ expect { smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
488
741
  end
489
742
  end
490
-
491
743
  end
492
744
  end
493
745
 
494
746
  context 'for SMB2' do
495
747
  let(:ntlm_client) { smb2_client.ntlm_client }
496
- let(:type1_message) { ntlm_client.init_context }
748
+ let(:type1_message) { ntlm_client.init_context }
497
749
  let(:negotiate_packet) { RubySMB::SMB2::Packet::SessionSetupRequest.new }
750
+ let(:response_packet) { RubySMB::SMB2::Packet::SessionSetupResponse.new }
751
+ let(:final_response_packet) { RubySMB::SMB2::Packet::SessionSetupResponse.new }
498
752
  let(:type3_message) { ntlm_client.init_context(type2_string) }
499
753
  let(:session_id) { 0x0000040000000005 }
500
754
 
755
+ describe '#smb2_authenticate' do
756
+ before :example do
757
+ allow(smb2_client).to receive(:smb2_ntlmssp_negotiate)
758
+ allow(smb2_client).to receive(:smb2_ntlmssp_challenge_packet).and_return(response_packet)
759
+ allow(smb2_client).to receive(:smb2_type2_message).and_return(type2_string)
760
+ allow(smb2_client).to receive(:smb2_ntlmssp_authenticate)
761
+ allow(smb2_client).to receive(:smb2_ntlmssp_final_packet).and_return(final_response_packet)
762
+ end
763
+
764
+ it 'calls the backing methods' do
765
+ response_packet.smb2_header.session_id = session_id
766
+ expect(smb2_client).to receive(:smb2_ntlmssp_negotiate).and_return(negotiate_packet)
767
+ expect(smb2_client).to receive(:smb2_ntlmssp_challenge_packet).with(negotiate_packet).and_return(response_packet)
768
+ expect(smb2_client).to receive(:smb2_type2_message).with(response_packet).and_return(type2_string)
769
+ expect(smb2_client).to receive(:store_target_info).with(String)
770
+ expect(smb2_client).to receive(:extract_os_version).with(String)
771
+ expect(smb2_client).to receive(:smb2_ntlmssp_authenticate).with(Net::NTLM::Message::Type3, session_id)
772
+ expect(smb2_client).to receive(:smb2_ntlmssp_final_packet).and_return(final_response_packet)
773
+ smb2_client.smb2_authenticate
774
+ end
775
+
776
+ it 'stores the session ID from the challenge message' do
777
+ response_packet.smb2_header.session_id = session_id
778
+ smb2_client.smb2_authenticate
779
+ expect(smb2_client.session_id).to eq session_id
780
+ end
781
+
782
+ it 'stores the session key from the NTLM client' do
783
+ smb2_client.smb2_authenticate
784
+ expect(smb2_client.session_key).to eq ntlm_client.session_key
785
+ end
786
+
787
+ it 'stores the OS version number from the challenge message' do
788
+ smb2_client.smb2_authenticate
789
+ expect(smb2_client.os_version).to eq '6.1.7601'
790
+ end
791
+ end
792
+
501
793
  describe '#smb2_ntlmssp_negotiate_packet' do
502
794
  it 'creates a new SessionSetupRequest packet' do
503
795
  expect(RubySMB::SMB2::Packet::SessionSetupRequest).to receive(:new).and_return(negotiate_packet)
@@ -516,7 +808,7 @@ RSpec.describe RubySMB::Client do
516
808
  end
517
809
 
518
810
  it 'increments client#smb2_message_id' do
519
- expect{ smb2_client.smb2_ntlmssp_negotiate_packet }.to change(smb2_client, :smb2_message_id).to(2)
811
+ expect { smb2_client.smb2_ntlmssp_negotiate_packet }.to change(smb2_client, :smb2_message_id).to(2)
520
812
  end
521
813
  end
522
814
 
@@ -547,16 +839,16 @@ RSpec.describe RubySMB::Client do
547
839
 
548
840
  it 'raises an UnexpectedStatusCode if the status code is not correct' do
549
841
  response.smb2_header.nt_status = 0xc0000015
550
- expect{ smb2_client.smb2_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error( RubySMB::Error::UnexpectedStatusCode)
842
+ expect { smb2_client.smb2_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
551
843
  end
552
844
 
553
845
  it 'raises an InvalidPacket if the Command field is wrong' do
554
- expect{ smb2_client.smb2_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
846
+ expect { smb2_client.smb2_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
555
847
  end
556
848
  end
557
849
 
558
850
  describe '#smb2_type2_message' do
559
- let(:fake_type2) { "NTLMSSP FOO" }
851
+ let(:fake_type2) { 'NTLMSSP FOO' }
560
852
  let(:response_packet) {
561
853
  packet = RubySMB::SMB2::Packet::SessionSetupResponse.new
562
854
  packet.set_type2_blob(fake_type2)
@@ -567,23 +859,21 @@ RSpec.describe RubySMB::Client do
567
859
  end
568
860
  end
569
861
 
570
- describe '#smb1_ntlmssp_auth_packet' do
862
+ describe '#smb2_ntlmssp_auth_packet' do
571
863
  it 'creates a new SessionSetupRequest packet' do
572
864
  expect(RubySMB::SMB2::Packet::SessionSetupRequest).to receive(:new).and_return(negotiate_packet)
573
- smb2_client.smb2_ntlmssp_auth_packet(type2_string, session_id)
865
+ smb2_client.smb2_ntlmssp_auth_packet(type3_message, session_id)
574
866
  end
575
867
 
576
- it 'builds the security blob with an NTLM Type 3 Message' do
868
+ it 'sets the security blob with an NTLM Type 3 Message' do
577
869
  expect(RubySMB::SMB2::Packet::SessionSetupRequest).to receive(:new).and_return(negotiate_packet)
578
- expect(ntlm_client).to receive(:init_context).with(type2_string).and_return(type3_message)
579
870
  expect(negotiate_packet).to receive(:set_type3_blob).with(type3_message.serialize)
580
- smb2_client.smb2_ntlmssp_auth_packet(type2_string, session_id)
871
+ smb2_client.smb2_ntlmssp_auth_packet(type3_message, session_id)
581
872
  end
582
873
 
583
874
  it 'sets the session ID on the request packet' do
584
- expect(smb2_client.smb2_ntlmssp_auth_packet(type2_string, session_id).smb2_header.session_id).to eq session_id
875
+ expect(smb2_client.smb2_ntlmssp_auth_packet(type3_message, session_id).smb2_header.session_id).to eq session_id
585
876
  end
586
-
587
877
  end
588
878
 
589
879
  describe '#smb2_ntlmssp_authenticate' do
@@ -591,7 +881,7 @@ RSpec.describe RubySMB::Client do
591
881
  expect(smb2_client).to receive(:smb2_ntlmssp_auth_packet).and_return(negotiate_packet)
592
882
  expect(dispatcher).to receive(:send_packet).with(negotiate_packet)
593
883
  expect(dispatcher).to receive(:recv_packet)
594
- smb2_client.smb2_ntlmssp_authenticate(type2_string, session_id)
884
+ smb2_client.smb2_ntlmssp_authenticate(type3_message, session_id)
595
885
  end
596
886
  end
597
887
 
@@ -612,10 +902,50 @@ RSpec.describe RubySMB::Client do
612
902
  end
613
903
 
614
904
  it 'raises an InvalidPacket if the Command field is wrong' do
615
- expect{ smb2_client.smb2_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
905
+ expect { smb2_client.smb2_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
616
906
  end
617
907
  end
618
908
  end
909
+
910
+ describe '#store_target_info' do
911
+ let(:target_info_str) { "\x02\x00\x14\x00T\x00E\x00S\x00T\x00D\x00O\x00M"\
912
+ "\x00A\x00I\x00N\x00\x01\x00\x10\x00T\x00E\x00S\x00T\x00N\x00A\x00M"\
913
+ "\x00E\x00\x04\x00 \x00t\x00e\x00s\x00t\x00d\x00o\x00m\x00a\x00i\x00"\
914
+ "n\x00.\x00l\x00o\x00c\x00a\x00l\x00\x03\x002\x00t\x00e\x00s\x00t\x00"\
915
+ "n\x00a\x00m\x00e\x00.\x00t\x00e\x00s\x00t\x00d\x00o\x00m\x00a\x00i"\
916
+ "\x00n\x00.\x00l\x00o\x00c\x00a\x00l\x00\x05\x00 \x00t\x00e\x00s\x00t"\
917
+ "\x00f\x00o\x00r\x00e\x00s\x00t\x00.\x00l\x00o\x00c\x00a\x00l\x00\a"\
918
+ "\x00\b\x00Q7w\x01Fh\xD3\x01\x00\x00\x00\x00" }
919
+
920
+ it 'creates a Net::NTLM::TargetInfo object from the target_info string' do
921
+ expect(Net::NTLM::TargetInfo).to receive(:new).with(target_info_str).and_call_original
922
+ client.store_target_info(target_info_str)
923
+ end
924
+
925
+ it 'sets the expected Client\'s attribute' do
926
+ client.store_target_info(target_info_str)
927
+ expect(client.default_name).to eq 'TESTNAME'
928
+ expect(client.default_domain).to eq 'TESTDOMAIN'
929
+ expect(client.dns_host_name).to eq 'testname.testdomain.local'
930
+ expect(client.dns_domain_name).to eq 'testdomain.local'
931
+ expect(client.dns_tree_name).to eq 'testforest.local'
932
+ end
933
+
934
+ it 'stores the strings with UTF-8 encoding' do
935
+ client.store_target_info(target_info_str)
936
+ expect(client.default_name.encoding.name).to eq 'UTF-8'
937
+ expect(client.default_domain.encoding.name).to eq 'UTF-8'
938
+ expect(client.dns_host_name.encoding.name).to eq 'UTF-8'
939
+ expect(client.dns_domain_name.encoding.name).to eq 'UTF-8'
940
+ expect(client.dns_tree_name.encoding.name).to eq 'UTF-8'
941
+ end
942
+ end
943
+
944
+ describe '#extract_os_version' do
945
+ it 'returns the expected version number' do
946
+ expect(client.extract_os_version("\x06\x00q\x17\x00\x00\x00\x0F")).to eq '6.0.6001'
947
+ end
948
+ end
619
949
  end
620
950
 
621
951
  context 'Signing' do
@@ -626,13 +956,13 @@ RSpec.describe RubySMB::Client do
626
956
  packet.smb2_header.signature = "\x00" * 16
627
957
  packet
628
958
  }
629
- let(:fake_hmac) { "\x31\x07\x78\x3e\x35\xd7\x0e\x89\x08\x43\x8a\x18\xcd\x78\x52\x39".force_encoding("ASCII-8BIT") }
959
+ let(:fake_hmac) { "\x31\x07\x78\x3e\x35\xd7\x0e\x89\x08\x43\x8a\x18\xcd\x78\x52\x39".force_encoding('ASCII-8BIT') }
630
960
 
631
961
  context 'if signing is required and we have a session key' do
632
962
  it 'generates the HMAC based on the packet and the NTLM session key and signs the packet with it' do
633
963
  smb2_client.session_key = 'foo'
634
964
  smb2_client.signing_required = true
635
- expect(OpenSSL::HMAC).to receive(:digest).with(instance_of(OpenSSL::Digest::SHA256),smb2_client.session_key,request1.to_binary_s).and_return(fake_hmac)
965
+ expect(OpenSSL::HMAC).to receive(:digest).with(instance_of(OpenSSL::Digest::SHA256), smb2_client.session_key, request1.to_binary_s).and_return(fake_hmac)
636
966
  expect(smb2_client.smb2_sign(request1).smb2_header.signature).to eq fake_hmac
637
967
  end
638
968
  end
@@ -652,12 +982,11 @@ RSpec.describe RubySMB::Client do
652
982
  expect(smb2_client.smb2_sign(request1)).to eq request1
653
983
  end
654
984
  end
655
-
656
985
  end
657
986
 
658
987
  describe '#smb1_sign' do
659
988
  let(:request1) { RubySMB::SMB1::Packet::SessionSetupRequest.new }
660
- let(:fake_sig) { "\x9f\x62\xcf\x08\xd9\xc2\x83\x21".force_encoding("ASCII-8BIT") }
989
+ let(:fake_sig) { "\x9f\x62\xcf\x08\xd9\xc2\x83\x21".force_encoding('ASCII-8BIT') }
661
990
 
662
991
  context 'if signing is required and we have a session key' do
663
992
  it 'generates the signature based on the packet, the sequence counter and the NTLM session key and signs the packet with it' do
@@ -685,7 +1014,7 @@ RSpec.describe RubySMB::Client do
685
1014
  smb1_client.signing_required = true
686
1015
  expect(smb1_client.smb1_sign(request1)).to eq request1
687
1016
  end
688
- end
1017
+ end
689
1018
  end
690
1019
  end
691
1020
 
@@ -699,7 +1028,7 @@ RSpec.describe RubySMB::Client do
699
1028
 
700
1029
  it 'increments the client message id' do
701
1030
  client.smb2_message_id = 1
702
- expect{ client.increment_smb_message_id(request_packet) }.to change{ client.smb2_message_id}.by(1)
1031
+ expect { client.increment_smb_message_id(request_packet) }.to change { client.smb2_message_id }.by(1)
703
1032
  end
704
1033
  end
705
1034
 
@@ -735,23 +1064,23 @@ RSpec.describe RubySMB::Client do
735
1064
  describe '#smb1_tree_from_response' do
736
1065
  it 'raises an InvalidPacket exception if the command is not TREE_CONNECT' do
737
1066
  response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
738
- expect{ smb1_client.smb1_tree_from_response(path,response) }.to raise_error(RubySMB::Error::InvalidPacket)
1067
+ expect { smb1_client.smb1_tree_from_response(path, response) }.to raise_error(RubySMB::Error::InvalidPacket)
739
1068
  end
740
1069
 
741
1070
  it 'raises an UnexpectedStatusCode exception if we do not get STATUS_SUCCESS' do
742
1071
  response.smb_header.nt_status = 0xc0000015
743
- expect{ smb1_client.smb1_tree_from_response(path,response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
1072
+ expect { smb1_client.smb1_tree_from_response(path, response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
744
1073
  end
745
1074
 
746
1075
  it 'creates a new Tree from itself, the share path, and the response packet' do
747
- expect(RubySMB::SMB1::Tree).to receive(:new).with(client:smb1_client, share:path, response:response)
748
- smb1_client.smb1_tree_from_response(path,response)
1076
+ expect(RubySMB::SMB1::Tree).to receive(:new).with(client: smb1_client, share: path, response: response)
1077
+ smb1_client.smb1_tree_from_response(path, response)
749
1078
  end
750
1079
  end
751
1080
  end
752
1081
 
753
1082
  context 'with SMB2' do
754
- let(:request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
1083
+ let(:request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
755
1084
  let(:response) {
756
1085
  packet = RubySMB::SMB2::Packet::TreeConnectResponse.new
757
1086
  packet.smb2_header.tree_id = tree_id
@@ -779,20 +1108,28 @@ RSpec.describe RubySMB::Client do
779
1108
  describe '#smb2_tree_from_response' do
780
1109
  it 'raises an InvalidPacket exception if the command is not TREE_CONNECT' do
781
1110
  response.smb2_header.command = RubySMB::SMB2::Commands::NEGOTIATE
782
- expect{ smb2_client.smb2_tree_from_response(path,response) }.to raise_error(RubySMB::Error::InvalidPacket)
1111
+ expect { smb2_client.smb2_tree_from_response(path, response) }.to raise_error(RubySMB::Error::InvalidPacket)
783
1112
  end
784
1113
 
785
1114
  it 'raises an UnexpectedStatusCode exception if we do not get STATUS_SUCCESS' do
786
1115
  response.smb2_header.nt_status = 0xc0000015
787
- expect{ smb2_client.smb2_tree_from_response(path,response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
1116
+ expect { smb2_client.smb2_tree_from_response(path, response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
788
1117
  end
789
1118
 
790
1119
  it 'creates a new Tree from itself, the share path, and the response packet' do
791
- expect(RubySMB::SMB2::Tree).to receive(:new).with(client:smb2_client, share:path, response:response)
792
- smb2_client.smb2_tree_from_response(path,response)
1120
+ expect(RubySMB::SMB2::Tree).to receive(:new).with(client: smb2_client, share: path, response: response)
1121
+ smb2_client.smb2_tree_from_response(path, response)
793
1122
  end
794
1123
  end
795
1124
 
1125
+ describe '#net_share_enum_all' do
1126
+ let(:shares){{}}
1127
+
1128
+ it 'it calls the smb2 method' do
1129
+ expect(smb2_client).to receive(:smb2_net_share_enum_all).with(sock.peeraddr).and_return(shares)
1130
+ smb2_client.net_share_enum_all(sock.peeraddr)
1131
+ end
1132
+ end
796
1133
  end
797
1134
  end
798
1135
 
@@ -819,9 +1156,9 @@ RSpec.describe RubySMB::Client do
819
1156
 
820
1157
  it 'sets the data on the request packet' do
821
1158
  modified_request = echo_request
822
- modified_request.data_block.data = "DEADBEEF"
1159
+ modified_request.data_block.data = 'DEADBEEF'
823
1160
  expect(smb1_client).to receive(:send_recv).with(modified_request).and_return(echo_response.to_binary_s)
824
- smb1_client.smb1_echo(data: "DEADBEEF")
1161
+ smb1_client.smb1_echo(data: 'DEADBEEF')
825
1162
  end
826
1163
 
827
1164
  it 'returns the NT status code' do
@@ -841,4 +1178,6 @@ RSpec.describe RubySMB::Client do
841
1178
  end
842
1179
  end
843
1180
  end
844
- end
1181
+
1182
+ end
1183
+