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
@@ -7,7 +7,6 @@
7
7
  require 'bundler/setup'
8
8
  require 'ruby_smb'
9
9
 
10
-
11
10
  def run_negotiation(address, smb1, smb2)
12
11
  # Create our socket and add it to the dispatcher
13
12
  sock = TCPSocket.new address, 445
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This script is for testing the NetBIOS Session Service Request on port 139/tcp.
4
+ # Example usage: ruby negotiate.rb 192.168.172.138 NBNAME
5
+ # This will connect to 192.168.172.138 (139/TCP) and request a NetBIOS session with NBNAME as the called name.
6
+ # If successful, a SMB negotiation is performed using this NetBIOS session.
7
+ # The default *SMBSERVER name is used if the NetBIOS name is not provided.
8
+
9
+ require 'bundler/setup'
10
+ require 'ruby_smb'
11
+
12
+ def run_negotiation(address, smb1, smb2, netbios_name)
13
+ sock = TCPSocket.new address, 139
14
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
15
+
16
+ client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, username: 'msfadmin', password: 'msfadmin')
17
+ begin
18
+ client.session_request(netbios_name)
19
+ rescue RubySMB::Error::NetBiosSessionService => e
20
+ puts "NetBIOS Session refused with #{netbios_name}: #{e.message}"
21
+ return
22
+ end
23
+ puts "NetBIOS Session granted with #{netbios_name}, negotiating..."
24
+ smb_version = client.negotiate
25
+ puts "#{smb_version} successfully negotiated."
26
+ end
27
+
28
+ address = ARGV[0]
29
+ netbios_name = ARGV[1] || '*SMBSERVER'
30
+
31
+ # Negotiate with both SMB1 and SMB2 enabled on the client
32
+ run_negotiation(ARGV[0], true, true, netbios_name)
33
+ # Negotiate with only SMB1 enabled
34
+ run_negotiation(ARGV[0], true, false, netbios_name)
35
+ # Negotiate with only SMB2 enabled
36
+ run_negotiation(ARGV[0], false, true, netbios_name)
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This example script is used for testing NetShareEnumAll functionality
4
+ # It will attempt to connect to a host and enumerate shares.
5
+ # Example usage: ruby net_share_enum_all.rb 192.168.172.138 msfadmin msfadmin
6
+ # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentials
7
+
8
+ require 'bundler/setup'
9
+ require 'ruby_smb'
10
+
11
+ address = ARGV[0]
12
+ username = ARGV[1]
13
+ password = ARGV[2]
14
+ path = "\\\\#{address}\\IPC$"
15
+
16
+ sock = TCPSocket.new address, 445
17
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
18
+
19
+ client = RubySMB::Client.new(dispatcher, smb1: false, smb2: true, username: username, password: password)
20
+ protocol = client.negotiate
21
+ status = client.authenticate
22
+
23
+ puts "#{protocol} : #{status}"
24
+
25
+ begin
26
+ shares = client.net_share_enum_all(address)
27
+ puts shares
28
+ rescue => e
29
+ puts "failed to enum shares: #{e.message}, #{e.backtrace_locations}"
30
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This example script is used for testing the reading of a file.
4
+ # It will attempt to connect to a specific share and then read a specified file.
5
+ # Example usage: ruby read_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt
6
+ # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
+ # and read the file short.txt
8
+
9
+ require 'bundler/setup'
10
+ require 'ruby_smb'
11
+
12
+ address = ARGV[0]
13
+ username = ARGV[1]
14
+ password = ARGV[2]
15
+ share = ARGV[3]
16
+ file = ARGV[4]
17
+ path = "\\\\#{address}\\#{share}"
18
+
19
+ sock = TCPSocket.new address, 445
20
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
21
+
22
+ client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
23
+ protocol = client.negotiate
24
+ status = client.authenticate
25
+
26
+ puts "#{protocol} : #{status}"
27
+
28
+ begin
29
+ tree = client.tree_connect(path)
30
+ puts "Connected to #{path} successfully!"
31
+ rescue StandardError => e
32
+ puts "Failed to connect to #{path}: #{e.message}"
33
+ end
34
+
35
+ file = tree.open_file(filename: file)
36
+
37
+ data = file.read
38
+ puts data
39
+ file.close
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This example script is used for testing the deleting of a file.
4
+ # It will attempt to connect to a specific share and then rename a specified file.
5
+ # Example usage: ruby rename_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt shortrenamed.txt
6
+ # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
+ # and rename the file short.txt
8
+
9
+ require 'bundler/setup'
10
+ require 'ruby_smb'
11
+
12
+ address = ARGV[0]
13
+ username = ARGV[1]
14
+ password = ARGV[2]
15
+ share = ARGV[3]
16
+ file = ARGV[4]
17
+ new_name = ARGV[5]
18
+ path = "\\\\#{address}\\#{share}"
19
+
20
+ sock = TCPSocket.new address, 445
21
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
22
+
23
+ client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
24
+
25
+ protocol = client.negotiate
26
+ status = client.authenticate
27
+
28
+ puts "#{protocol} : #{status}"
29
+
30
+ begin
31
+ tree = client.tree_connect(path)
32
+ puts "Connected to #{path} successfully!"
33
+ rescue StandardError => e
34
+ puts "Failed to connect to #{path}: #{e.message}"
35
+ end
36
+
37
+ file = tree.open_file(filename: file, write: true, delete: true)
38
+
39
+ data = file.rename(new_name)
40
+ puts data
41
+ file.close
@@ -19,7 +19,7 @@ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
19
19
 
20
20
  client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
21
21
  protocol = client.negotiate
22
- status = client.authenticate
22
+ status = client.authenticate
23
23
 
24
24
  puts "#{protocol} : #{status}"
25
25
 
@@ -27,8 +27,6 @@ begin
27
27
  tree = client.tree_connect(path)
28
28
  puts "Connected to #{path} successfully!"
29
29
  tree.disconnect!
30
- rescue Exception => e
30
+ rescue StandardError => e
31
31
  puts "Failed to connect to #{path}: #{e.message}"
32
32
  end
33
-
34
-
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This example script is used for testing the writing to a file.
4
+ # It will attempt to connect to a specific share and then write to a specified file.
5
+ # Example usage: ruby write_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE test.txt "data to write"
6
+ # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
+ # and write "data to write" the file test.txt
8
+
9
+ require 'bundler/setup'
10
+ require 'ruby_smb'
11
+
12
+ address = ARGV[0]
13
+ username = ARGV[1]
14
+ password = ARGV[2]
15
+ share = ARGV[3]
16
+ file = ARGV[4]
17
+ data = ARGV[5]
18
+ path = "\\\\#{address}\\#{share}"
19
+
20
+ sock = TCPSocket.new address, 445
21
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
22
+
23
+ client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
24
+ protocol = client.negotiate
25
+ status = client.authenticate
26
+
27
+ puts "#{protocol} : #{status}"
28
+
29
+ begin
30
+ tree = client.tree_connect(path)
31
+ puts "Connected to #{path} successfully!"
32
+ rescue StandardError => e
33
+ puts "Failed to connect to #{path}: #{e.message}"
34
+ end
35
+
36
+ file = tree.open_file(filename: file, write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF)
37
+
38
+ result = file.write(data: data)
39
+ puts result.to_s
40
+ file.close
data/lib/ruby_smb.rb CHANGED
@@ -8,8 +8,13 @@ require 'windows_error/nt_status'
8
8
  # [[MS-SMB] Server Mesage Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
9
9
  # [[MS-SMB2] Server Mesage Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
10
10
  module RubySMB
11
+ require 'ruby_smb/dispositions'
12
+ require 'ruby_smb/impersonation_levels'
11
13
  require 'ruby_smb/gss'
12
14
  require 'ruby_smb/field'
15
+ require 'ruby_smb/nbss'
16
+ require 'ruby_smb/fscc'
17
+ require 'ruby_smb/dcerpc'
13
18
  require 'ruby_smb/generic_packet'
14
19
  require 'ruby_smb/dispatcher'
15
20
  require 'ruby_smb/error'
@@ -1,5 +1,4 @@
1
1
  module RubySMB
2
-
3
2
  # Represents an SMB client capable of talking to SMB1 or SMB2 servers and handling
4
3
  # all end-user client functionality.
5
4
  class Client
@@ -8,20 +7,23 @@ module RubySMB
8
7
  require 'ruby_smb/client/signing'
9
8
  require 'ruby_smb/client/tree_connect'
10
9
  require 'ruby_smb/client/echo'
10
+ require 'ruby_smb/client/utils'
11
11
 
12
12
  include RubySMB::Client::Negotiation
13
13
  include RubySMB::Client::Authentication
14
14
  include RubySMB::Client::Signing
15
15
  include RubySMB::Client::TreeConnect
16
16
  include RubySMB::Client::Echo
17
+ include RubySMB::Client::Utils
17
18
 
18
19
  # The Default SMB1 Dialect string used in an SMB1 Negotiate Request
19
- SMB1_DIALECT_SMB1_DEFAULT = "NT LM 0.12"
20
+ SMB1_DIALECT_SMB1_DEFAULT = 'NT LM 0.12'.freeze
20
21
  # The Default SMB2 Dialect string used in an SMB1 Negotiate Request
21
- SMB1_DIALECT_SMB2_DEFAULT = "SMB 2.002"
22
+ SMB1_DIALECT_SMB2_DEFAULT = 'SMB 2.002'.freeze
22
23
  # Dialect value for SMB2 Default (Version 2.02)
23
24
  SMB2_DIALECT_DEFAULT = 0x0202
24
-
25
+ # The default maximum size of a SMB message that the Client accepts (in bytes)
26
+ MAX_BUFFER_SIZE = 4356
25
27
 
26
28
  # The dispatcher responsible for sending packets
27
29
  # @!attribute [rw] dispatcher
@@ -54,6 +56,54 @@ module RubySMB
54
56
  # @return [String]
55
57
  attr_accessor :peer_native_os
56
58
 
59
+ # The Native LAN Manager of the Peer/Server.
60
+ # Currently only available with SMB1.
61
+ # @!attribute [rw] peer_native_lm
62
+ # @return [String]
63
+ attr_accessor :peer_native_lm
64
+
65
+ # The Primary Domain of the Peer/Server.
66
+ # Currently only available with SMB1 and only when authentiation
67
+ # without NTLMSSP is used.
68
+ # @!attribute [rw] primary_domain
69
+ # @return [String]
70
+ attr_accessor :primary_domain
71
+
72
+ # The Netbios Name of the Peer/Server.
73
+ # @!attribute [rw] default_name
74
+ # @return [String]
75
+ attr_accessor :default_name
76
+
77
+ # The Netbios Domain of the Peer/Server.
78
+ # @!attribute [rw] default_domain
79
+ # @return [String]
80
+ attr_accessor :default_domain
81
+
82
+ # The Fully Qualified Domain Name (FQDN) of the computer.
83
+ # @!attribute [rw] dns_host_name
84
+ # @return [String]
85
+ attr_accessor :dns_host_name
86
+
87
+ # The Fully Qualified Domain Name (FQDN) of the domain.
88
+ # @!attribute [rw] dns_domain_name
89
+ # @return [String]
90
+ attr_accessor :dns_domain_name
91
+
92
+ # The Fully Qualified Domain Name (FQDN) of the forest.
93
+ # @!attribute [rw] dns_tree_name
94
+ # @return [String]
95
+ attr_accessor :dns_tree_name
96
+
97
+ # The OS version number (<major>.<minor>.<build>) of the Peer/Server.
98
+ # @!attribute [rw] os_version
99
+ # @return [String]
100
+ attr_accessor :os_version
101
+
102
+ # The negotiated dialect.
103
+ # @!attribute [rw] dialect
104
+ # @return [Integer]
105
+ attr_accessor :dialect
106
+
57
107
  # The Sequence Counter used for SMB1 Signing.
58
108
  # It tracks the number of packets both sent and received
59
109
  # since the NTLM session was initialized with the Challenge.
@@ -96,32 +146,48 @@ module RubySMB
96
146
  # @return [String]
97
147
  attr_accessor :user_id
98
148
 
149
+ # The maximum size of a SMB message that the Client accepts (in bytes)
150
+ # Its default value is equal to {MAX_BUFFER_SIZE}.
151
+ # @!attribute [rw] max_buffer_size
152
+ # @return [Integer]
153
+ attr_accessor :max_buffer_size
154
+
99
155
  # @param dispatcher [RubySMB::Dispacther::Socket] the packet dispatcher to use
100
156
  # @param smb1 [Boolean] whether or not to enable SMB1 support
101
157
  # @param smb2 [Boolean] whether or not to enable SMB2 support
102
- def initialize(dispatcher, smb1: true, smb2: true, username:,password:, domain:'.', local_workstation:'WORKSTATION')
103
- raise ArgumentError, 'No Dispatcher provided' unless dispatcher.kind_of? RubySMB::Dispatcher::Base
158
+ def initialize(dispatcher, smb1: true, smb2: true, username:, password:, domain: '.', local_workstation: 'WORKSTATION')
159
+ raise ArgumentError, 'No Dispatcher provided' unless dispatcher.is_a? RubySMB::Dispatcher::Base
104
160
  if smb1 == false && smb2 == false
105
161
  raise ArgumentError, 'You must enable at least one Protocol'
106
162
  end
107
163
  @dispatcher = dispatcher
108
164
  @domain = domain
109
165
  @local_workstation = local_workstation
110
- @password = password.encode("utf-8") || ''.encode("utf-8")
166
+ @password = password.encode('utf-8') || ''.encode('utf-8')
111
167
  @sequence_counter = 0
112
168
  @session_id = 0x00
113
169
  @session_key = ''
114
170
  @signing_required = false
115
171
  @smb1 = smb1
116
172
  @smb2 = smb2
117
- @username = username.encode("utf-8") || ''.encode("utf-8")
173
+ @username = username.encode('utf-8') || ''.encode('utf-8')
174
+ @max_buffer_size = MAX_BUFFER_SIZE
175
+
176
+ negotiate_version_flag = 0x02000000
177
+ flags = Net::NTLM::Client::DEFAULT_FLAGS |
178
+ Net::NTLM::FLAGS[:TARGET_INFO] |
179
+ negotiate_version_flag
118
180
 
119
181
  @ntlm_client = Net::NTLM::Client.new(
120
182
  @username,
121
183
  @password,
122
184
  workstation: @local_workstation,
123
- domain: @domain
185
+ domain: @domain,
186
+ flags: flags
124
187
  )
188
+
189
+ @tree_connects = []
190
+ @open_files = {}
125
191
 
126
192
  @smb2_message_id = 0
127
193
  end
@@ -145,12 +211,12 @@ module RubySMB
145
211
  # @param echo [Integer] the number of times the server should echo (ignored in SMB2)
146
212
  # @param data [String] the data the server should echo back (ignored in SMB2)
147
213
  # @return [WindowsError::ErrorCode] the NTStatus of the last response received
148
- def echo(count: 1, data: '' )
149
- if smb2
150
- response = smb2_echo
151
- else
152
- response = smb1_echo(count:count, data:data)
153
- end
214
+ def echo(count: 1, data: '')
215
+ response = if smb2
216
+ smb2_echo
217
+ else
218
+ smb1_echo(count: count, data: data)
219
+ end
154
220
  response.status_code
155
221
  end
156
222
 
@@ -161,8 +227,8 @@ module RubySMB
161
227
  # @param packet [RubySMB::GenericPacket] the packet to set the message id for
162
228
  # @return [RubySMB::GenericPacket] the modified packet
163
229
  def increment_smb_message_id(packet)
164
- if packet.smb2_header.message_id == 0 && self.smb2_message_id != 0
165
- packet.smb2_header.message_id = self.smb2_message_id
230
+ if packet.smb2_header.message_id.zero? && smb2_message_id != 0
231
+ packet.smb2_header.message_id = smb2_message_id
166
232
  self.smb2_message_id += 1
167
233
  end
168
234
  packet
@@ -170,20 +236,32 @@ module RubySMB
170
236
 
171
237
  # Performs protocol negotiation and session setup. It defaults to using
172
238
  # the credentials supplied during initialization, but can take a new set of credentials if needed.
173
- def login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation )
239
+ def login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation)
240
+ negotiate
241
+ session_setup(username, password, domain, true,
242
+ local_workstation: local_workstation)
243
+ end
244
+
245
+ def session_setup(user, pass, domain, do_recv=true,
246
+ local_workstation: self.local_workstation)
174
247
  @domain = domain
175
248
  @local_workstation = local_workstation
176
- @password = password.encode("utf-8") || ''.encode("utf-8")
177
- @username = username.encode("utf-8") || ''.encode("utf-8")
178
-
249
+ @password = pass.encode('utf-8') || ''.encode('utf-8')
250
+ @username = user.encode('utf-8') || ''.encode('utf-8')
251
+
252
+ negotiate_version_flag = 0x02000000
253
+ flags = Net::NTLM::Client::DEFAULT_FLAGS |
254
+ Net::NTLM::FLAGS[:TARGET_INFO] |
255
+ negotiate_version_flag
256
+
179
257
  @ntlm_client = Net::NTLM::Client.new(
180
- @username,
181
- @password,
182
- workstation: @local_workstation,
183
- domain: @domain
258
+ @username,
259
+ @password,
260
+ workstation: @local_workstation,
261
+ domain: @domain,
262
+ flags: flags
184
263
  )
185
264
 
186
- negotiate
187
265
  authenticate
188
266
  end
189
267
 
@@ -211,26 +289,22 @@ module RubySMB
211
289
  # @return [String] the raw response data received
212
290
  def send_recv(packet)
213
291
  case packet.packet_smb_version
214
- when 'SMB1'
215
- if self.user_id
216
- packet.smb_header.uid = self.user_id
217
- end
218
- packet = smb1_sign(packet)
219
- when 'SMB2'
220
- packet = increment_smb_message_id(packet)
221
- packet.smb2_header.session_id = self.session_id
222
- unless packet.is_a?(RubySMB::SMB2::Packet::SessionSetupRequest)
223
- packet = smb2_sign(packet)
224
- end
225
- else
226
- packet = packet
292
+ when 'SMB1'
293
+ packet.smb_header.uid = user_id if user_id
294
+ packet = smb1_sign(packet)
295
+ when 'SMB2'
296
+ packet = increment_smb_message_id(packet)
297
+ packet.smb2_header.session_id = session_id
298
+ unless packet.is_a?(RubySMB::SMB2::Packet::SessionSetupRequest)
299
+ packet = smb2_sign(packet)
300
+ end
301
+ else
302
+ packet = packet
227
303
  end
228
304
  dispatcher.send_packet(packet)
229
305
  raw_response = dispatcher.recv_packet
230
306
 
231
- if self.signing_required && !self.session_key.empty?
232
- self.sequence_counter += 1
233
- end
307
+ self.sequence_counter += 1 if signing_required && !session_key.empty?
234
308
  raw_response
235
309
  end
236
310
 
@@ -240,11 +314,55 @@ module RubySMB
240
314
  # @return [RubySMB::SMB1::Tree] if talking over SMB1
241
315
  # @return [RubySMB::SMB2::Tree] if talking over SMB2
242
316
  def tree_connect(share)
243
- if smb2
317
+ connected_tree = if smb2
244
318
  smb2_tree_connect(share)
245
319
  else
246
320
  smb1_tree_connect(share)
247
321
  end
322
+ @tree_connects << connected_tree
323
+ connected_tree
324
+ end
325
+
326
+ # Returns array of shares
327
+ #
328
+ # @return [Array] of shares
329
+ # @param [String] host
330
+ def net_share_enum_all(host)
331
+ if smb2
332
+ smb2_net_share_enum_all(host)
333
+ else
334
+ smb1_net_share_enum_all(host)
335
+ end
336
+ end
337
+
338
+ #
339
+ # SMB2 Methods
340
+ #
341
+
342
+ # Sends a request to connect to a remote host and returns the Array
343
+ # of shares
344
+ #
345
+ # @return [Array] List of shares
346
+ # @param [String] host
347
+ def smb2_net_share_enum_all(host)
348
+
349
+ tree = tree_connect("\\\\#{host}\\IPC$")
350
+
351
+ named_pipe = tree.open_file(filename: "srvsvc",
352
+ write: true,
353
+ read: true,
354
+ disposition: RubySMB::Dispositions::FILE_OPEN_IF)
355
+
356
+ handle = Dcerpc::Handle.new(named_pipe)
357
+
358
+ handle.bind(endpoint: Dcerpc::Srvsvc)
359
+ handle.request(
360
+ opnum: Dcerpc::Srvsvc::NetShareEnumAll::Opnum,
361
+ stub: Dcerpc::Srvsvc::NetShareEnumAll,
362
+ options:{host: host}
363
+ )
364
+ shares = Dcerpc::Srvsvc::NetShareEnumAll.parse_response(handle.response)
365
+ shares.map{|s|{name: s[0], type: s[1], comment: s[2]}}
248
366
  end
249
367
 
250
368
  # Resets all of the session state on the client, setting it
@@ -260,6 +378,41 @@ module RubySMB
260
378
  self.smb2_message_id = 0
261
379
  end
262
380
 
381
+ # Requests a NetBIOS Session Service using the provided name.
382
+ #
383
+ # @param name [String] the NetBIOS name to request
384
+ # @return [TrueClass] if session request is granted
385
+ # @raise [RubySMB::Error::NetBiosSessionService] if session request is refused
386
+ def session_request(name = '*SMBSERVER')
387
+ encoded_called_name = nb_name_encode("#{name.upcase.ljust(15)}\x20")
388
+ encoded_calling_name = nb_name_encode("#{''.ljust(15)}\x00")
389
+
390
+ session_request = RubySMB::Nbss::SessionRequest.new
391
+ session_request.session_header.session_packet_type = RubySMB::Nbss::SESSION_REQUEST
392
+ session_request.called_name = "\x20#{encoded_called_name}\x00"
393
+ session_request.calling_name = "\x20#{encoded_calling_name}\x00"
394
+ session_request.session_header.packet_length = session_request.do_num_bytes - session_request.session_header.do_num_bytes
395
+
396
+ dispatcher.send_packet(session_request, nbss_header: false)
397
+ raw_response = dispatcher.recv_packet(full_response: true)
398
+ session_header = RubySMB::Nbss::SessionHeader.read(raw_response)
399
+ if session_header.session_packet_type == RubySMB::Nbss::NEGATIVE_SESSION_RESPONSE
400
+ negative_session_response = RubySMB::Nbss::NegativeSessionResponse.read(raw_response)
401
+ raise RubySMB::Error::NetBiosSessionService, "Session Request failed: #{negative_session_response.error_msg}"
402
+ end
263
403
 
404
+ return true
405
+ end
406
+
407
+ def nb_name_encode(name)
408
+ encoded_name = ''
409
+ name.each_byte do |char|
410
+ first_half = (char >> 4) + 'A'.ord
411
+ second_half = (char & 0xF) + 'A'.ord
412
+ encoded_name << first_half.chr
413
+ encoded_name << second_half.chr
414
+ end
415
+ encoded_name
416
+ end
264
417
  end
265
418
  end