ruby_smb 2.0.2 → 3.0.0

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 (285) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/verify.yml +46 -0
  4. data/README.md +0 -1
  5. data/examples/anonymous_auth.rb +3 -3
  6. data/examples/append_file.rb +10 -8
  7. data/examples/auth_capture.rb +71 -0
  8. data/examples/authenticate.rb +9 -5
  9. data/examples/delete_file.rb +8 -6
  10. data/examples/dump_secrets_from_sid.rb +207 -0
  11. data/examples/enum_domain_users.rb +75 -0
  12. data/examples/enum_registry_key.rb +5 -4
  13. data/examples/enum_registry_values.rb +5 -4
  14. data/examples/get_computer_info.rb +42 -0
  15. data/examples/list_directory.rb +8 -6
  16. data/examples/negotiate_with_netbios_service.rb +9 -5
  17. data/examples/net_share_enum_all.rb +6 -4
  18. data/examples/pipes.rb +11 -12
  19. data/examples/query_service_status.rb +102 -0
  20. data/examples/read_file.rb +8 -6
  21. data/examples/read_registry_key_value.rb +6 -5
  22. data/examples/rename_file.rb +9 -7
  23. data/examples/tree_connect.rb +7 -5
  24. data/examples/write_file.rb +9 -7
  25. data/lib/ruby_smb/client/authentication.rb +5 -10
  26. data/lib/ruby_smb/client/echo.rb +2 -4
  27. data/lib/ruby_smb/client/negotiation.rb +13 -16
  28. data/lib/ruby_smb/client/tree_connect.rb +2 -4
  29. data/lib/ruby_smb/client/utils.rb +16 -10
  30. data/lib/ruby_smb/client/winreg.rb +1 -1
  31. data/lib/ruby_smb/client.rb +102 -75
  32. data/lib/ruby_smb/compression/lznt1.rb +164 -0
  33. data/lib/ruby_smb/compression.rb +7 -0
  34. data/lib/ruby_smb/dcerpc/bind.rb +28 -20
  35. data/lib/ruby_smb/dcerpc/bind_ack.rb +29 -28
  36. data/lib/ruby_smb/dcerpc/client.rb +542 -0
  37. data/lib/ruby_smb/dcerpc/drsr/drs_bind_request.rb +24 -0
  38. data/lib/ruby_smb/dcerpc/drsr/drs_bind_response.rb +26 -0
  39. data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_request.rb +57 -0
  40. data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_response.rb +76 -0
  41. data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_request.rb +46 -0
  42. data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_response.rb +168 -0
  43. data/lib/ruby_smb/dcerpc/drsr/drs_extensions.rb +56 -0
  44. data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_request.rb +121 -0
  45. data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_response.rb +118 -0
  46. data/lib/ruby_smb/dcerpc/drsr/drs_unbind_request.rb +24 -0
  47. data/lib/ruby_smb/dcerpc/drsr/drs_unbind_response.rb +26 -0
  48. data/lib/ruby_smb/dcerpc/drsr.rb +909 -0
  49. data/lib/ruby_smb/dcerpc/epm/epm_ept_map_request.rb +26 -0
  50. data/lib/ruby_smb/dcerpc/epm/epm_ept_map_response.rb +25 -0
  51. data/lib/ruby_smb/dcerpc/epm/epm_twrt.rb +211 -0
  52. data/lib/ruby_smb/dcerpc/epm.rb +75 -0
  53. data/lib/ruby_smb/dcerpc/error.rb +20 -0
  54. data/lib/ruby_smb/dcerpc/ndr.rb +1204 -80
  55. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +27 -0
  56. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
  57. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
  58. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
  59. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +24 -0
  60. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
  61. data/lib/ruby_smb/dcerpc/netlogon.rb +102 -0
  62. data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +4 -3
  63. data/lib/ruby_smb/dcerpc/pdu_header.rb +7 -7
  64. data/lib/ruby_smb/dcerpc/ptypes.rb +1 -0
  65. data/lib/ruby_smb/dcerpc/request.rb +85 -19
  66. data/lib/ruby_smb/dcerpc/response.rb +45 -10
  67. data/lib/ruby_smb/dcerpc/rpc_auth3.rb +28 -0
  68. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  69. data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +118 -0
  70. data/lib/ruby_smb/dcerpc/samr/rpc_sid.rb +150 -0
  71. data/lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb +23 -0
  72. data/lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb +24 -0
  73. data/lib/ruby_smb/dcerpc/samr/samr_connect_request.rb +32 -0
  74. data/lib/ruby_smb/dcerpc/samr/samr_connect_response.rb +23 -0
  75. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request.rb +26 -0
  76. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +55 -0
  77. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_request.rb +48 -0
  78. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +38 -0
  79. data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb +23 -0
  80. data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb +48 -0
  81. data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb +24 -0
  82. data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb +25 -0
  83. data/lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb +27 -0
  84. data/lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb +24 -0
  85. data/lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb +26 -0
  86. data/lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb +24 -0
  87. data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request.rb +23 -0
  88. data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb +23 -0
  89. data/lib/ruby_smb/dcerpc/samr.rb +613 -0
  90. data/lib/ruby_smb/dcerpc/sec_trailer.rb +26 -0
  91. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +56 -79
  92. data/lib/ruby_smb/dcerpc/srvsvc.rb +27 -4
  93. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +36 -0
  94. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  95. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  96. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  97. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  98. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  99. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +25 -0
  100. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  101. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +23 -0
  102. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  103. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  104. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +45 -0
  105. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  106. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  107. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +26 -0
  108. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  109. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  110. data/lib/ruby_smb/dcerpc/svcctl.rb +477 -0
  111. data/lib/ruby_smb/dcerpc/uuid.rb +3 -0
  112. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +2 -2
  113. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +62 -0
  114. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  115. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +2 -19
  116. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +3 -20
  117. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +5 -14
  118. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +5 -14
  119. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +1 -9
  120. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +4 -3
  121. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +6 -7
  122. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +2 -2
  123. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  124. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +9 -18
  125. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +4 -13
  126. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +7 -15
  127. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +3 -1
  128. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +28 -0
  129. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  130. data/lib/ruby_smb/dcerpc/winreg.rb +99 -22
  131. data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb +26 -0
  132. data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb +88 -0
  133. data/lib/ruby_smb/dcerpc/wkssvc.rb +65 -0
  134. data/lib/ruby_smb/dcerpc.rb +45 -11
  135. data/lib/ruby_smb/dialect.rb +45 -0
  136. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  137. data/lib/ruby_smb/dispatcher/socket.rb +2 -2
  138. data/lib/ruby_smb/error.rb +21 -5
  139. data/lib/ruby_smb/field/file_time.rb +1 -1
  140. data/lib/ruby_smb/field/string16.rb +5 -1
  141. data/lib/ruby_smb/field/stringz16.rb +17 -1
  142. data/lib/ruby_smb/generic_packet.rb +11 -1
  143. data/lib/ruby_smb/gss/provider/authenticator.rb +42 -0
  144. data/lib/ruby_smb/gss/provider/ntlm.rb +303 -0
  145. data/lib/ruby_smb/gss/provider.rb +35 -0
  146. data/lib/ruby_smb/gss.rb +56 -63
  147. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  148. data/lib/ruby_smb/ntlm.rb +61 -0
  149. data/lib/ruby_smb/server/server_client/negotiation.rb +156 -0
  150. data/lib/ruby_smb/server/server_client/session_setup.rb +82 -0
  151. data/lib/ruby_smb/server/server_client.rb +162 -0
  152. data/lib/ruby_smb/server.rb +54 -0
  153. data/lib/ruby_smb/signing.rb +59 -0
  154. data/lib/ruby_smb/smb1/file.rb +10 -25
  155. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +11 -11
  156. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +1 -1
  157. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  158. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
  159. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
  160. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
  161. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
  162. data/lib/ruby_smb/smb1/pipe.rb +12 -6
  163. data/lib/ruby_smb/smb1/tree.rb +13 -9
  164. data/lib/ruby_smb/smb2/file.rb +33 -33
  165. data/lib/ruby_smb/smb2/negotiate_context.rb +18 -2
  166. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +4 -0
  167. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +9 -0
  168. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +0 -1
  169. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -2
  170. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +1 -1
  171. data/lib/ruby_smb/smb2/pipe.rb +13 -6
  172. data/lib/ruby_smb/smb2/tree.rb +21 -11
  173. data/lib/ruby_smb/smb2.rb +3 -1
  174. data/lib/ruby_smb/version.rb +1 -1
  175. data/lib/ruby_smb.rb +5 -3
  176. data/spec/lib/ruby_smb/client_spec.rb +199 -86
  177. data/spec/lib/ruby_smb/compression/lznt1_spec.rb +32 -0
  178. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +69 -41
  179. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +75 -21
  180. data/spec/lib/ruby_smb/dcerpc/client_spec.rb +714 -0
  181. data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +2169 -0
  182. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +3977 -239
  183. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  184. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  185. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  186. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  187. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  188. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  189. data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +18 -4
  190. data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +27 -1
  191. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +76 -11
  192. data/spec/lib/ruby_smb/dcerpc/response_spec.rb +99 -9
  193. data/spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb +75 -0
  194. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +162 -0
  195. data/spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb +340 -0
  196. data/spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb +116 -0
  197. data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb +40 -0
  198. data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb +48 -0
  199. data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb +56 -0
  200. data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_response_spec.rb +47 -0
  201. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request_spec.rb +63 -0
  202. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +265 -0
  203. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request_spec.rb +52 -0
  204. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response_spec.rb +36 -0
  205. data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_request_spec.rb +56 -0
  206. data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_response_spec.rb +48 -0
  207. data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request_spec.rb +48 -0
  208. data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb +42 -0
  209. data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +420 -0
  210. data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +92 -0
  211. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +149 -110
  212. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +21 -17
  213. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +168 -0
  214. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  215. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  216. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  217. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  218. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  219. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +68 -0
  220. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  221. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +53 -0
  222. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  223. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  224. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  225. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  226. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  227. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +76 -0
  228. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +47 -0
  229. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  230. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +508 -0
  231. data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +15 -23
  232. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +2 -2
  233. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +73 -0
  234. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  235. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +4 -56
  236. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +4 -56
  237. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +10 -34
  238. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +10 -34
  239. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +2 -26
  240. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +2 -2
  241. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +17 -20
  242. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +2 -2
  243. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  244. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +20 -44
  245. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +8 -32
  246. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +18 -42
  247. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +4 -0
  248. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +45 -0
  249. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  250. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +219 -62
  251. data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +43 -0
  252. data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +410 -0
  253. data/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +70 -0
  254. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  255. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  256. data/spec/lib/ruby_smb/field/string16_spec.rb +22 -0
  257. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  258. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  259. data/spec/lib/ruby_smb/gss/provider/ntlm/account_spec.rb +32 -0
  260. data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +101 -0
  261. data/spec/lib/ruby_smb/gss/provider/ntlm/os_version_spec.rb +32 -0
  262. data/spec/lib/ruby_smb/gss/provider/ntlm_spec.rb +113 -0
  263. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  264. data/spec/lib/ruby_smb/server/server_client_spec.rb +156 -0
  265. data/spec/lib/ruby_smb/server_spec.rb +32 -0
  266. data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
  267. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
  268. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
  269. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
  270. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
  271. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +20 -14
  272. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  273. data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
  274. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +2 -2
  275. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +20 -14
  276. data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
  277. data/spec/spec_helper.rb +1 -1
  278. data/spec/support/bin_helper.rb +9 -0
  279. data.tar.gz.sig +0 -0
  280. metadata +229 -23
  281. metadata.gz.sig +0 -0
  282. data/.travis.yml +0 -6
  283. data/lib/ruby_smb/client/signing.rb +0 -64
  284. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +0 -35
  285. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +0 -98
@@ -0,0 +1,101 @@
1
+ RSpec.describe RubySMB::Gss::Provider::NTLM::Authenticator do
2
+ let(:username) { 'RubySMB' }
3
+ let(:domain) { 'WORKGROUP' }
4
+ let(:password) { 'password' }
5
+ let(:provider) { RubySMB::Gss::Provider::NTLM.new.tap { |provider| provider.put_account(username, password, domain: domain) } }
6
+ let(:authenticator) { described_class.new(provider, nil) }
7
+ let(:type1_msg) do
8
+ Net::NTLM::Message::Type1.new.tap do |msg|
9
+ msg.domain = domain
10
+ end
11
+ end
12
+ let(:type3_msg) do
13
+ Net::NTLM::Message::Type2.new.response(user: username, password: '', domain: domain)
14
+ end
15
+
16
+ describe '#initialize' do
17
+ it 'defaults to a null session key' do
18
+ expect(authenticator.session_key).to be_nil
19
+ end
20
+
21
+ it 'defaults to a null server challenge' do
22
+ expect(authenticator.server_challenge).to be_nil
23
+ end
24
+ end
25
+
26
+ describe '#process' do
27
+ it 'should handle an empty GSS buffer' do
28
+ result = authenticator.process
29
+ expect(result).to be_a RubySMB::Gss::Provider::Result
30
+ expect(result.nt_status).to eq WindowsError::NTStatus::STATUS_SUCCESS
31
+ expect(result.buffer).to_not be_empty
32
+ expect(result.identity).to be_nil
33
+ end
34
+
35
+ it 'should handle an embedded NTLM type 1 message' do
36
+ expect(authenticator).to receive(:process_ntlm_type1).and_call_original
37
+ result = authenticator.process(RubySMB::Gss.gss_type1(type1_msg.serialize))
38
+ expect(result).to be_a RubySMB::Gss::Provider::Result
39
+ expect(result.nt_status).to eq WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED
40
+ expect(result.buffer).to_not be_empty
41
+ expect(result.identity).to be_nil
42
+ expect(authenticator.session_key).to be_nil
43
+ end
44
+
45
+ it 'should handle an embedded NTLM type 3 message' do
46
+ authenticator.server_challenge = Random.new.bytes(8)
47
+ expect(authenticator).to receive(:process_ntlm_type3).and_call_original
48
+ result = authenticator.process(RubySMB::Gss.gss_type3(type3_msg.serialize))
49
+ expect(result).to be_a RubySMB::Gss::Provider::Result
50
+ expect(result.nt_status).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
51
+ expect(result.buffer).to be_nil
52
+ expect(result.identity).to be_nil
53
+ expect(authenticator.session_key).to be_nil
54
+ end
55
+ end
56
+
57
+ describe '#process_ntlm_type1' do
58
+ it 'should process a NTLM type 1 message and return a type2 message' do
59
+ expect(authenticator.process_ntlm_type1(type1_msg)).to be_a Net::NTLM::Message::Type2
60
+ end
61
+ end
62
+
63
+ describe '#process_ntlm_type3' do
64
+ it 'should process a NTLM type 3 message and return an error code' do
65
+ expect(authenticator.process_ntlm_type3(type3_msg)).to be_a WindowsError::ErrorCode
66
+ expect(authenticator.process_ntlm_type3(type3_msg)).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
67
+ end
68
+ end
69
+
70
+ describe '#reset!' do
71
+ it 'should clear the server challenge' do
72
+ authenticator.instance_variable_set(:@server_challenge, Random.new.bytes(8))
73
+ authenticator.reset!
74
+ expect(authenticator.instance_variable_get(:@server_challenge)).to be_nil
75
+ end
76
+
77
+ it 'should clear the session key' do
78
+ authenticator.instance_variable_set(:@session_key, Random.new.bytes(16))
79
+ authenticator.reset!
80
+ expect(authenticator.instance_variable_get(:@session_key)).to be_nil
81
+ end
82
+ end
83
+
84
+ describe 'a full Net-NTLMv2 authentication exchange' do
85
+ let(:type2_msg) { authenticator.process_ntlm_type1(type1_msg)}
86
+
87
+ it 'should respond to a correct password with STATUS_SUCCESS' do
88
+ type3_msg = type2_msg.response({user: username, domain: domain, password: password}, ntlmv2: true)
89
+ type3_msg.user.force_encoding('UTF-16LE')
90
+ type3_msg.domain.force_encoding('UTF-16LE')
91
+ expect(authenticator.process_ntlm_type3(type3_msg)).to eq WindowsError::NTStatus::STATUS_SUCCESS
92
+ end
93
+
94
+ it 'should respond to an incorrect password with STATUS_LOGON_FAILURE' do
95
+ type3_msg = type2_msg.response({user: username, domain: domain, password: password + rand(0x41..0x5b).chr}, ntlmv2: true)
96
+ type3_msg.user.force_encoding('UTF-16LE')
97
+ type3_msg.domain.force_encoding('UTF-16LE')
98
+ expect(authenticator.process_ntlm_type3(type3_msg)).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.describe RubySMB::Gss::Provider::NTLM::OSVersion do
2
+ subject(:os_version) { RubySMB::Gss::Provider::NTLM::OSVersion.new }
3
+
4
+ it { is_expected.to respond_to :major }
5
+ it { is_expected.to respond_to :minor }
6
+ it { is_expected.to respond_to :build }
7
+ it { is_expected.to respond_to :ntlm_revision }
8
+
9
+ describe '#initialize' do
10
+ it 'defaults to an NTLM revision of 15' do
11
+ expect(os_version.ntlm_revision).to eq 15
12
+ end
13
+ end
14
+
15
+ describe '#read' do
16
+ it 'reads a packed version correctly' do
17
+ # Version 6.1 (Build 7601); NTLM Current Revision 15
18
+ os_version = RubySMB::Gss::Provider::NTLM::OSVersion.read("\x06\x01\xb1\x1d\x00\x00\x00\x0f")
19
+ expect(os_version.major).to eq 6
20
+ expect(os_version.minor).to eq 1
21
+ expect(os_version.build).to eq 7601
22
+ expect(os_version.ntlm_revision).to eq 15
23
+ end
24
+ end
25
+
26
+ describe '#to_s' do
27
+ it 'creates a string representation of the OS version' do
28
+ expect(os_version.to_s).to be_a String
29
+ expect(os_version.to_s).to match /Version \d+\.\d+ \(Build \d+\); NTLM Current Revision \d+/
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::Gss::Provider::NTLM do
4
+ let(:provider) { described_class.new }
5
+
6
+ it { is_expected.to respond_to :allow_anonymous }
7
+ it { is_expected.to respond_to :default_domain }
8
+
9
+ describe '#initialize' do
10
+ it 'defaults to false for allowing anonymous access' do
11
+ expect(provider.allow_anonymous).to be false
12
+ end
13
+
14
+ it 'defaults to a default domain of WORKGROUP' do
15
+ expect(provider.default_domain).to eq 'WORKGROUP'
16
+ end
17
+
18
+ it 'defaults to a random challenge generator' do
19
+ expect(provider.generate_server_challenge).to_not eq provider.generate_server_challenge
20
+ end
21
+ end
22
+
23
+ describe '#generate_server_challenge' do
24
+ it 'generates a valid 8-byte challenge' do
25
+ challenge = provider.generate_server_challenge
26
+ expect(challenge).to be_a String
27
+ expect(challenge.length).to eq 8
28
+ end
29
+
30
+ it 'should take a generator block' do
31
+ random_challenge = Random.new.bytes(8)
32
+ provider.generate_server_challenge do
33
+ random_challenge
34
+ end
35
+ expect(provider.generate_server_challenge).to eq random_challenge
36
+ end
37
+ end
38
+
39
+ describe '#get_account' do
40
+ let(:username) { 'RubySMB' }
41
+ let(:password) { 'password' }
42
+ let(:domain) { 'WORKGROUP' }
43
+
44
+ context 'when getting accounts' do
45
+ before(:each) do
46
+ provider.put_account(username, password)
47
+ end
48
+
49
+ it 'should return nil for an unknown account' do
50
+ account = provider.get_account('Spencer')
51
+ expect(account).to be_nil
52
+ end
53
+
54
+ it 'should work with a case sensitive name' do
55
+ account = provider.get_account(username)
56
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
57
+ expect(account.username).to eq username
58
+ end
59
+
60
+ it 'should work with a case insensitive name' do
61
+ account = provider.get_account(username.downcase)
62
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
63
+ expect(account.username).to eq username
64
+ end
65
+
66
+ it 'should work with a case sensitive domain' do
67
+ account = provider.get_account(username, domain: domain)
68
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
69
+ expect(account.domain).to eq domain
70
+ end
71
+
72
+ it 'should work with a case insensitive domain' do
73
+ account = provider.get_account(username, domain: domain.downcase)
74
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
75
+ expect(account.domain).to eq domain
76
+ end
77
+
78
+ it 'should work with the special . domain' do
79
+ account = provider.get_account(username, domain: '.')
80
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
81
+ expect(account.domain).to eq domain
82
+ end
83
+
84
+ # UTF-16LE is optionally used for encoding some Net-NTLM message fields, the #get_account method should handle it
85
+ # transparently
86
+ it 'should work with a UTF16-LE name' do
87
+ account = provider.get_account(username.encode('UTF-16LE'))
88
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
89
+ expect(account.username).to eq username
90
+ end
91
+
92
+ it 'should work with a UTF16-LE domain' do
93
+ account = provider.get_account(username, domain: domain.encode('UTF-16LE'))
94
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
95
+ expect(account.domain).to eq domain
96
+ end
97
+ end
98
+
99
+ context 'when putting accounts' do
100
+ it 'should accept new accounts with the default domain' do
101
+ provider.put_account(username, password)
102
+ end
103
+
104
+ after(:each) do
105
+ account = provider.get_account(username, domain: domain)
106
+ expect(account).to be_a RubySMB::Gss::Provider::NTLM::Account
107
+ expect(account.username).to eq username
108
+ expect(account.password).to eq password
109
+ expect(account.domain).to eq domain
110
+ end
111
+ end
112
+ end
113
+ end
@@ -2,8 +2,7 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
2
2
  subject(:session_header) { described_class.new }
3
3
 
4
4
  it { is_expected.to respond_to :session_packet_type }
5
- it { is_expected.to respond_to :flags }
6
- it { is_expected.to respond_to :packet_length }
5
+ it { is_expected.to respond_to :stream_protocol_length }
7
6
 
8
7
  it 'is big endian' do
9
8
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
@@ -15,15 +14,9 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
15
14
  end
16
15
  end
17
16
 
18
- describe '#flags' do
19
- it 'is a 7-bit Unsigned Integer' do
20
- expect(session_header.flags).to be_a BinData::Bit7
21
- end
22
- end
23
-
24
- describe '#packet_length' do
25
- it 'is a 17-bit Unsigned Integer' do
26
- expect(session_header.packet_length).to be_a BinData::Bit17
17
+ describe '#stream_protocol_length' do
18
+ it 'is a 24-bit Unsigned Integer' do
19
+ expect(session_header.stream_protocol_length).to be_a BinData::Uint24be
27
20
  end
28
21
  end
29
22
  end
@@ -0,0 +1,156 @@
1
+ RSpec.describe RubySMB::Server::ServerClient do
2
+ let(:server) { RubySMB::Server.new(server_sock: ::TCPServer.new(0)) }
3
+ let(:sock) { double('Socket', peeraddr: '192.168.1.5') }
4
+ let(:dispatcher) { RubySMB::Dispatcher::Socket.new(sock) }
5
+ subject(:server_client) { described_class.new(server, dispatcher) }
6
+
7
+ it { is_expected.to respond_to :dialect }
8
+ it { is_expected.to respond_to :identity }
9
+ it { is_expected.to respond_to :state }
10
+ it { is_expected.to respond_to :session_key }
11
+
12
+ describe '#disconnect!' do
13
+ it 'closes the socket' do
14
+ expect(dispatcher.tcp_socket).to receive(:close).with(no_args).and_return(nil)
15
+ server_client.disconnect!
16
+ end
17
+ end
18
+
19
+ describe '#initialize' do
20
+ it 'starts in the negotiate state' do
21
+ expect(server_client.state).to eq :negotiate
22
+ end
23
+
24
+ it 'starts without a dialect' do
25
+ expect(server_client.dialect).to be_nil
26
+ expect(server_client.metadialect).to be_nil
27
+ end
28
+
29
+ it 'starts without an identity' do
30
+ expect(server_client.identity).to be_nil
31
+ end
32
+
33
+ it 'starts without a session_key' do
34
+ expect(server_client.session_key).to be_nil
35
+ end
36
+
37
+ it 'creates a new authenticator instance' do
38
+ expect(server.gss_provider).to receive(:new_authenticator).and_call_original
39
+ described_class.new(server, dispatcher)
40
+ end
41
+ end
42
+
43
+ describe '#process_gss' do
44
+ before(:each) do
45
+ expect(server_client.instance_eval { @gss_authenticator }).to receive(:process).and_call_original
46
+ end
47
+
48
+ it 'should handle an empty GSS buffer' do
49
+ result = server_client.process_gss
50
+ expect(result).to be_a RubySMB::Gss::Provider::Result
51
+ expect(result.nt_status).to eq WindowsError::NTStatus::STATUS_SUCCESS
52
+ expect(result.buffer).to_not be_empty
53
+ expect(result.identity).to be_nil
54
+ end
55
+ end
56
+
57
+ describe '#recv_packet' do
58
+ it 'receives a new packet from the dispatcher' do
59
+ expect(dispatcher).to receive(:recv_packet).with(no_args)
60
+ server_client.recv_packet
61
+ end
62
+ end
63
+
64
+ describe '#run' do
65
+ let(:packet) { Random.new.bytes(16) }
66
+ before(:each) do
67
+ expect(server_client).to receive(:recv_packet).and_return(packet)
68
+ # this hook should ensure that the dispatcher loop returns after processing a single request
69
+ expect(dispatcher.tcp_socket).to receive(:closed?).and_return(true)
70
+ end
71
+
72
+ it 'calls #handle_negotiate when the state is negotiate' do
73
+ expect(server_client).to receive(:handle_negotiate).with(packet).and_return(nil)
74
+ server_client.instance_eval { @state = :negotiate }
75
+ server_client.run
76
+ end
77
+
78
+ it 'calls #handle_session_setup when the state is session_setup' do
79
+ expect(server_client).to receive(:handle_session_setup).with(packet).and_return(nil)
80
+ server_client.instance_eval { @state = :session_setup }
81
+ server_client.run
82
+ end
83
+
84
+ it 'calls #authenticated when the state is authenticated' do
85
+ expect(server_client).to receive(:handle_authenticated).with(packet).and_return(nil)
86
+ server_client.instance_eval { @state = :authenticated }
87
+ server_client.run
88
+ end
89
+ end
90
+
91
+ describe '#send_packet' do
92
+ let(:packet) { RubySMB::GenericPacket.new }
93
+
94
+ before(:each) do
95
+ expect(dispatcher).to receive(:send_packet).with(packet).and_return(nil)
96
+ end
97
+
98
+ it 'sends a packet to the dispatcher' do
99
+ server_client.send_packet(packet)
100
+ end
101
+
102
+ %w{ 0x0202 0x0210 0x0300 0x0302 0x0311 }.each do |dialect|
103
+ context "when the dialect is #{dialect}" do
104
+ before(:each) do
105
+ server_client.instance_eval { @dialect = dialect }
106
+ end
107
+
108
+ context 'and the state is authenticated' do
109
+ before(:each) do
110
+ server_client.instance_eval { @state = :authenticated }
111
+ end
112
+
113
+ context 'and the identity is anonymous' do
114
+ before(:each) do
115
+ server_client.instance_eval { @identity = RubySMB::Gss::Provider::IDENTITY_ANONYMOUS }
116
+ end
117
+
118
+ it 'does not sign packets' do
119
+ expect(server_client).to_not receive(:smb2_sign)
120
+ expect(server_client).to_not receive(:smb3_sign)
121
+ server_client.send_packet(packet)
122
+ end
123
+ end
124
+
125
+ context 'and the identity is not anonymous' do
126
+ before(:each) do
127
+ server_client.instance_eval { @identity = 'WORKGROUP\RubySMB'; @session_key = Random.new.bytes(16) }
128
+ end
129
+
130
+ it 'does sign packets' do
131
+ packet = RubySMB::GenericPacket.new
132
+ dialect_family = RubySMB::Dialect[dialect].family
133
+ if dialect_family == RubySMB::Dialect::FAMILY_SMB2
134
+ expect(server_client).to receive(:smb2_sign).with(packet).and_return(packet)
135
+ expect(server_client).to_not receive(:smb3_sign)
136
+ elsif dialect_family == RubySMB::Dialect::FAMILY_SMB3
137
+ expect(server_client).to receive(:smb3_sign).with(packet).and_return(packet)
138
+ expect(server_client).to_not receive(:smb2_sign)
139
+ end
140
+ server_client.send_packet(packet)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '#update_preauth_hash' do
149
+ it 'raises an EncryptionError exception if the preauth integrity hash algorithm is not known' do
150
+ expect { server_client.update_preauth_hash('Test') }.to raise_error(
151
+ RubySMB::Error::EncryptionError,
152
+ 'Cannot compute the Preauth Integrity Hash value: Preauth Integrity Hash Algorithm is nil'
153
+ )
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.describe RubySMB::Server do
2
+ before(:each) do
3
+ allow(::TCPServer).to receive(:new).and_return(::TCPServer.new(0))
4
+ end
5
+
6
+ it { is_expected.to respond_to :dialects }
7
+ it { is_expected.to respond_to :gss_provider }
8
+ it { is_expected.to respond_to :guid }
9
+
10
+ describe '#initialize' do
11
+ it 'should bind to TCP port 445 by default' do
12
+ expect(::TCPServer).to receive(:new).with(445).and_return(::TCPServer.new(0))
13
+ described_class.new
14
+ end
15
+
16
+ it 'should create a new NTLM GSS provider by default' do
17
+ expect(RubySMB::Gss::Provider::NTLM).to receive(:new).and_call_original
18
+ described_class.new
19
+ end
20
+
21
+ it 'should generate a random 16-byte GUID' do
22
+ server_guid = described_class.new.guid
23
+ expect(server_guid).to be_a String
24
+ expect(server_guid.length).to eq 16
25
+ expect(server_guid).to_not eq described_class.new.guid
26
+ end
27
+
28
+ it 'should support some dialects' do
29
+ expect(described_class.new.dialects).to_not be_empty
30
+ end
31
+ end
32
+ end
@@ -473,7 +473,7 @@ RSpec.describe RubySMB::SMB1::File do
473
473
  end
474
474
 
475
475
  it 'sets the File Information #rename_pending field of the packet' do
476
- expect(file.rename_packet(filename).data_block.trans2_data.info_level_struct.file_name).to eq filename.encode('utf-16le').force_encoding('ASCII-8BIT')
476
+ expect(file.rename_packet(filename).data_block.trans2_data.info_level_struct.file_name).to eq filename
477
477
  end
478
478
 
479
479
  it 'sets the Trans2 ParameterBlock fields' do
@@ -521,9 +521,7 @@ RSpec.describe RubySMB::SMB1::File do
521
521
 
522
522
  it 'raises an InvalidPacket exception if the response is not valid' do
523
523
  allow(response).to receive(:valid?).and_return(false)
524
- smb_header = double('SMB Header')
525
- allow(response).to receive(:smb_header).and_return(smb_header)
526
- allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
524
+ allow(response).to receive(:packet_smb_version)
527
525
  expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
528
526
  end
529
527
 
@@ -32,7 +32,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
32
32
  describe '#data_block' do
33
33
  subject(:data_block) { packet.data_block }
34
34
 
35
- it { is_expected.to respond_to :name }
36
35
  it { is_expected.to respond_to :trans2_parameters }
37
36
  it { is_expected.to respond_to :trans2_data }
38
37
 
@@ -32,7 +32,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
32
32
  describe '#data_block' do
33
33
  subject(:data_block) { packet.data_block }
34
34
 
35
- it { is_expected.to respond_to :name }
36
35
  it { is_expected.to respond_to :trans2_parameters }
37
36
  it { is_expected.to respond_to :trans2_data }
38
37
 
@@ -35,16 +35,11 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::Open2Response do
35
35
  end
36
36
 
37
37
  it { is_expected.to respond_to :trans2_parameters }
38
- it { is_expected.to respond_to :trans2_data }
39
38
 
40
39
  it 'should keep #trans2_parameters 4-byte aligned' do
41
40
  expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
42
41
  end
43
42
 
44
- it 'should keep #trans2_data 4-byte aligned' do
45
- expect(data_block.trans2_data.abs_offset % 4).to eq 0
46
- end
47
-
48
43
  describe '#trans2_parameters' do
49
44
  subject(:parameters) { data_block.trans2_parameters }
50
45
 
@@ -28,18 +28,12 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse do
28
28
  describe '#data_block' do
29
29
  subject(:data_block) { packet.data_block }
30
30
 
31
- it { is_expected.to respond_to :name }
32
31
  it { is_expected.to respond_to :trans2_parameters }
33
- it { is_expected.to respond_to :trans2_data }
34
32
 
35
33
  it 'should keep #trans2_parameters 4-byte aligned' do
36
34
  expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
37
35
  end
38
36
 
39
- it 'should keep #trans2_data 4-byte aligned' do
40
- expect(data_block.trans2_data.abs_offset % 4).to eq 0
41
- end
42
-
43
37
  describe '#trans2_parameters' do
44
38
  subject(:parameters) { data_block.trans2_parameters }
45
39
 
@@ -80,9 +80,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
80
80
 
81
81
  it 'raises an InvalidPacket exception if the response is not valid' do
82
82
  allow(response).to receive(:valid?).and_return(false)
83
- smb_header = double('SMB Header')
84
- allow(response).to receive(:smb_header).and_return(smb_header)
85
- allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
83
+ allow(response).to receive(:packet_smb_version)
86
84
  expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
87
85
  end
88
86
 
@@ -142,17 +140,26 @@ RSpec.describe RubySMB::SMB1::Pipe do
142
140
  expect(pipe.size_on_disk).to eq(nt_create_andx_response.parameter_block.allocation_size)
143
141
  end
144
142
 
145
- context 'with \'srvsvc\' filename' do
146
- it 'extends Srvsvc class' do
147
- pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'srvsvc')
148
- expect(pipe.respond_to?(:net_share_enum_all)).to be true
143
+ {
144
+ netlogon: RubySMB::Dcerpc::Netlogon,
145
+ srvsvc: RubySMB::Dcerpc::Srvsvc,
146
+ svcctl: RubySMB::Dcerpc::Svcctl,
147
+ winreg: RubySMB::Dcerpc::Winreg,
148
+ samr: RubySMB::Dcerpc::Samr,
149
+ wkssvc: RubySMB::Dcerpc::Wkssvc
150
+ }.each do |endpoint, klass|
151
+ context "with \'#{endpoint}\' filename" do
152
+ it "extends #{klass} class" do
153
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: endpoint.to_s)
154
+ expect(pipe).to be_a klass
155
+ end
149
156
  end
150
- end
151
157
 
152
- context 'with \'winreg\' filename' do
153
- it 'extends Winreg class' do
154
- pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
155
- expect(pipe.respond_to?(:has_registry_key?)).to be true
158
+ context "with \'\\#{endpoint}\' filename" do
159
+ it "extends #{klass} class" do
160
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: "\\#{endpoint.to_s}")
161
+ expect(pipe).to be_a klass
162
+ end
156
163
  end
157
164
  end
158
165
  end
@@ -238,8 +245,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
238
245
 
239
246
  context 'when the response is not a Trans packet' do
240
247
  it 'raises an InvalidPacket exception' do
241
- allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :protocol)
242
- allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
248
+ allow(trans_nmpipe_response).to receive(:packet_smb_version)
243
249
  allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
244
250
  expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
245
251
  end
@@ -492,4 +492,26 @@ RSpec.describe RubySMB::SMB1::Tree do
492
492
  end
493
493
  end
494
494
 
495
+ describe '#open_pipe' do
496
+ let(:opts) { { filename: 'test', write: true } }
497
+ before :example do
498
+ allow(tree).to receive(:open_file)
499
+ end
500
+
501
+ it 'calls #open_file with the provided options' do
502
+ opts[:filename] ='\\test'
503
+ expect(tree).to receive(:open_file).with(opts)
504
+ tree.open_pipe(**opts)
505
+ end
506
+
507
+ it 'prepends the filename with \\ if needed' do
508
+ expect(tree).to receive(:open_file).with(filename: '\\test', write: true)
509
+ tree.open_pipe(**opts)
510
+ end
511
+
512
+ it 'does not modify the original option hash' do
513
+ tree.open_pipe(**opts)
514
+ expect(opts).to eq( { filename: 'test', write: true } )
515
+ end
516
+ end
495
517
  end