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
@@ -1,121 +1,1245 @@
1
- module RubySMB
2
- module Dcerpc
3
- module Ndr
1
+ module RubySMB::Dcerpc::Ndr
4
2
 
5
- # NDR Syntax
6
- UUID = '8a885d04-1ceb-11c9-9fe8-08002b104860'
7
- VER_MAJOR = 2
8
- VER_MINOR = 0
3
+ require 'ruby_smb/field'
9
4
 
10
- # An NDR Top-level Full Pointers representation as defined in
11
- # [Transfer Syntax NDR - Top-level Full Pointers](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_11_01)
12
- # This class must be inherited and the subclass must have a #referent protperty
13
- class NdrTopLevelFullPointer < BinData::Primitive
14
- endian :little
5
+ # NDR Syntax
6
+ UUID = '8a885d04-1ceb-11c9-9fe8-08002b104860'
7
+ VER_MAJOR = 2
8
+ VER_MINOR = 0
15
9
 
16
- uint32 :referent_identifier, initial_value: 0x00020000
10
+ #####################################
11
+ # NDR Primitive Types #
12
+ #####################################
17
13
 
18
- def get
19
- is_a_null_pointer? ? 0 : self.referent
14
+ # Signed and unsigned integers use BinData primitives directly
15
+
16
+ # [Booleans](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_03)
17
+ class NdrBoolean < BinData::Uint32le
18
+ default_parameters byte_align: 4
19
+
20
+ def assign(val)
21
+ super(value_to_int(val))
22
+ end
23
+
24
+ def snapshot
25
+ return _value == 0 ? false : true
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def value_to_binary_string(val)
32
+ super(value_to_int(val))
33
+ end
34
+
35
+ def value_to_int(val)
36
+ val = val.snapshot if val.respond_to?(:snapshot)
37
+ case(val)
38
+ when FalseClass
39
+ return 0
40
+ when TrueClass
41
+ return 1
42
+ when Integer
43
+ # Any non-zero value is TRUE, let's assume the caller knows what he's doing
44
+ return val
45
+ else
46
+ raise ArgumentError.new(
47
+ "Type mismatch (#{val.class}). Expecting FalseClass, TrueClass or Integer"
48
+ )
49
+ end
50
+ end
51
+ end
52
+
53
+ # [Characters](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_04)
54
+ class NdrChar < BinData::String
55
+ default_parameter(length: 1, byte_align: 1)
56
+ end
57
+
58
+ class NdrWideChar < RubySMB::Field::String16
59
+ default_parameter(length: 2, byte_align: 2)
60
+ end
61
+
62
+ # An NDR Enum type as defined in
63
+ # [Transfer Syntax NDR - Enumerated Types](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_05_01)
64
+ class NdrEnum < BinData::Int16le
65
+ default_parameters byte_align: 2
66
+ end
67
+
68
+ # [Integers](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_05)
69
+ # This will define the four size Integers accepted by the NDR protocol:
70
+ # - NdrUint8
71
+ # - NdrUint16
72
+ # - NdrUint32
73
+ # - NdrUint64
74
+ {Uint8: 1, Uint16le: 2, Uint32le: 4, Uint64le: 8}.each do |klass, nb_bytes|
75
+ new_klass_name = "Ndr#{klass.to_s.chomp('le')}"
76
+ unless self.const_defined?(new_klass_name)
77
+ new_klass = Class.new(BinData.const_get(klass)) do
78
+ default_parameters byte_align: nb_bytes
79
+ end
80
+ self.const_set(new_klass_name, new_klass)
81
+ BinData::RegisteredClasses.register(new_klass_name, new_klass)
82
+ end
83
+ end
84
+
85
+ class NdrFileTime < RubySMB::Field::FileTime
86
+ # Note that the original Microsoft FILETIME structure is composed of two
87
+ # DWORDs, whereas RubySMB implementation uses an Uint64 field. For this
88
+ # reason, the alignement is set to the size of a DWORD (4 bytes) to match
89
+ # Microsoft structures.
90
+ default_parameters byte_align: 4
91
+ end
92
+
93
+
94
+
95
+ #####################################
96
+ # NDR Constructed Types #
97
+ #####################################
98
+
99
+ module ConstructedTypePlugin
100
+ def initialize_instance
101
+ @deferred_ptrs = []
102
+ super
103
+ end
104
+
105
+ def defer_ptr(ref)
106
+ @deferred_ptrs << ref
107
+ end
108
+
109
+ def has_deferred_ptrs?
110
+ !!@deferred_ptrs&.any?
111
+ end
112
+
113
+ def write_ptr(io)
114
+ @deferred_ptrs.each do |ptr_ref|
115
+ ptr_ref.do_write(io, is_deferred: true)
116
+ end
117
+ @deferred_ptrs.clear
118
+ end
119
+
120
+ def read_ptr(io)
121
+ @deferred_ptrs.each do |ptr_ref|
122
+ ptr_ref.do_read(io, is_deferred: true)
123
+ end
124
+ @deferred_ptrs.clear
125
+ end
126
+
127
+ def is_deferring(obj)
128
+ @deferred_ptrs.any? { |e| e.equal?(obj) }
129
+ end
130
+
131
+ def get_top_level_constructed_type
132
+ return self if is_a?(PointerPlugin)
133
+
134
+ res = nil
135
+ if parent&.is_a?(ConstructedTypePlugin)
136
+ res = parent.get_top_level_constructed_type
137
+ end
138
+ return res || self
139
+ end
140
+
141
+ def do_num_bytes_ptr(struct_offset)
142
+ sum = 0
143
+ @deferred_ptrs.each do |ptr_ref|
144
+ sum += ptr_ref.do_num_bytes(struct_offset + sum, is_deferred: true)
145
+ end
146
+ @deferred_ptrs.clear
147
+ sum
148
+ end
149
+ end
150
+
151
+
152
+ #
153
+ # Arrays
154
+ #
155
+
156
+ module ArrayClassPlugin
157
+ module ExtendArrayPlugin
158
+ def initialize_shared_instance
159
+ super
160
+ extend ArrayPlugin
161
+ end
162
+ end
163
+ module ExtendConfPlugin
164
+ def initialize_shared_instance
165
+ super
166
+ extend ConfPlugin
167
+ end
168
+ end
169
+ module ExtendVarPlugin
170
+ def initialize_shared_instance
171
+ super
172
+ extend VarPlugin
173
+ end
174
+ end
175
+ def self.extended(target)
176
+ target.default_parameters(
177
+ :read_until => lambda { index == (@obj.read_until_index - 1) },
178
+ # Set :byte_align to 4 bytes by default, which is the size of the `size
179
+ # information` field (:max_count or :offset/:actual_count). If the
180
+ # elements set with :type are greater, this parameter will be
181
+ # updated later in NdrArrayArgProcessor::sanitize_parameters!
182
+ :byte_align => 4
183
+ )
184
+ target.arg_processor :ndr_array
185
+ class_name = target.to_s.split('::').last
186
+ if class_name.include?('NdrVar') || class_name.include?('NdrConfVar')
187
+ target.include ExtendVarPlugin
188
+ end
189
+ if class_name.include?('NdrConf')
190
+ target.include ExtendConfPlugin
191
+ target.extend ConfClassPlugin
192
+ end
193
+ target.include ExtendArrayPlugin
194
+ end
195
+ end
196
+
197
+ module ArrayPlugin
198
+ include ConstructedTypePlugin
199
+
200
+ def align_element_size(offset)
201
+ align = eval_parameter(:type).instance_variable_get(:@obj_params)[:byte_align]
202
+ align ? (align - (offset % align)) % align : 0
203
+ end
204
+
205
+ def should_process_max_count?
206
+ # :max_count has already been processed if the parent structure is an
207
+ # NdrStruct, but this is not the case if we are dealing with a pointer
208
+ !parent.is_a?(NdrStruct) || self.is_a?(PointerPlugin)
209
+ end
210
+
211
+ def do_write(io)
212
+ if is_a?(ConfPlugin) && should_process_max_count?
213
+ io.writebytes([@max_count].pack('L<'))
214
+ end
215
+
216
+ if is_a?(VarPlugin)
217
+ io.writebytes([@offset].pack('L<'))
218
+ io.writebytes([@actual_count].pack('L<'))
219
+ end
220
+
221
+ unless empty?
222
+ io.writebytes("\x00" * align_element_size(io.offset))
223
+ super
224
+ end
225
+
226
+ if has_deferred_ptrs?
227
+ write_ptr(io)
228
+ end
229
+ end
230
+
231
+ def has_elements_to_read?
232
+ # When reading a binary stream, the only elements that indicate the array
233
+ # has elements to read are :actual_count, :max_count or :initial_length
234
+ # parameter, depending on the type of NDR Array:
235
+ # 1. When :actual_count is present (NdrVarArray and NdrConfVarArray), it
236
+ # indicates the actual number of elements passed
237
+ # 2. When only :max_count is present (NdrConfArray), we're assuming the
238
+ # maximum number of elements is the actual number of elements in this
239
+ # array
240
+ # 3. None of them are present, but :initial_length parameter has been
241
+ # set, meaning we are delaing with a fixed array without any embedded
242
+ # size information (NdrFixArray)
243
+ (@actual_count&.> 0) ||
244
+ @actual_count.nil? && (@max_count&.> 0) ||
245
+ @actual_count.nil? && @max_count.nil? && (eval_parameter(:initial_length)&.> 0)
246
+ end
247
+
248
+ def do_read(io)
249
+ if is_a?(ConfPlugin) && should_process_max_count?
250
+ set_max_count(io.readbytes(4).unpack('L<').first)
251
+ end
252
+
253
+ if is_a?(VarPlugin)
254
+ @offset = io.readbytes(4).unpack('L<').first
255
+ @actual_count = @read_until_index = io.readbytes(4).unpack('L<').first
256
+ end
257
+
258
+ if has_elements_to_read?
259
+ io.seekbytes(align_element_size(io.offset))
260
+ super
261
+ end
262
+
263
+ if has_deferred_ptrs?
264
+ read_ptr(io)
265
+ end
266
+ end
267
+
268
+ def do_num_bytes(struct_offset = 0)
269
+ sum = 0
270
+
271
+ if is_a?(ConfPlugin) && should_process_max_count?
272
+ sum += 4
273
+ end
274
+
275
+ if is_a?(VarPlugin)
276
+ sum += 8
277
+ end
278
+
279
+ unless empty?
280
+ sum += align_element_size(struct_offset + sum)
281
+ sum += super()
282
+ end
283
+
284
+ if has_deferred_ptrs?
285
+ sum += do_num_bytes_ptr(struct_offset + sum)
286
+ end
287
+ sum
288
+ end
289
+
290
+ def sum_num_bytes_below_index(index)
291
+ (0...index).inject(0) do |sum, i|
292
+ nbytes = 0
293
+ if elements[i].has_parameter?(:byte_align) && elements[i].respond_to?(:bytes_to_align)
294
+ nbytes = elements[i].bytes_to_align(elements[i], sum.ceil)
20
295
  end
296
+ nbytes += elements[i].do_num_bytes
21
297
 
22
- def set(v)
23
- if v.is_a?(Integer) && v == 0
24
- self.referent_identifier = 0
25
- else
26
- self.referent = v
27
- end
298
+ if nbytes.is_a?(Integer)
299
+ sum.ceil + nbytes
300
+ else
301
+ sum + nbytes
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ module ConfClassPlugin; end
308
+
309
+ module ConfPlugin
310
+ attr_accessor :read_until_index, :max_count
311
+
312
+ def initialize_instance
313
+ @read_until_index = 0
314
+ @max_count = 0
315
+ super
316
+ end
317
+
318
+ def insert(index, *objs)
319
+ obj = super
320
+ @max_count = length
321
+ obj
322
+ end
323
+
324
+ def slice_index(index)
325
+ obj = super
326
+ @max_count = length
327
+ obj
328
+ end
329
+
330
+ def []=(index, value)
331
+ obj = super
332
+ @max_count = length
333
+ obj
334
+ end
335
+
336
+ def set_max_count(val)
337
+ @max_count = @read_until_index = val
338
+ end
339
+ end
340
+
341
+ module VarPlugin
342
+ attr_accessor :read_until_index, :actual_count, :offset
343
+
344
+ def initialize_instance
345
+ @read_until_index = 0
346
+ @actual_count = 0
347
+ @offset = 0
348
+ super
349
+ end
350
+
351
+ def insert(index, *objs)
352
+ obj = super
353
+ @actual_count = length
354
+ obj
355
+ end
356
+
357
+ def slice_index(index)
358
+ obj = super
359
+ @actual_count = length
360
+ obj
361
+ end
362
+
363
+ def []=(index, value)
364
+ obj = super
365
+ @actual_count = length
366
+ obj
367
+ end
368
+ end
369
+
370
+ # This ArgProcessor needs to inherit from BinData::ArrayArgProcessor to make
371
+ # sure the ArrayArgProcessor `sanitize_parameters!` is called. This will
372
+ # perform proper Array-related sanity checks on the given parameters.
373
+ class ::BinData::NdrArrayArgProcessor < BinData::ArrayArgProcessor
374
+ def sanitize_parameters!(obj_class, params)
375
+ res = super
376
+
377
+ type_class = params[:type]
378
+ # Let the BinData::Array sanitization routine deal with "no type provided"
379
+ return res unless type_class
380
+
381
+ type_class, type_params = params[:type] if type_class.is_a?(Array)
382
+ if type_class.has_parameter?(:byte_align)
383
+ # According to NDR alignemnt rules for arrays: Array alignment is the
384
+ # largest alignment of the array element type and the size information
385
+ # type, if any.
386
+ # So, here, we pick the greatest value between the size of the `size
387
+ # information` field (:max_count or :offset/:actual_count), which is 4
388
+ # bytes for 32-bit NDR, and the element type size
389
+ byte_align = type_class.instance_variable_get(:@obj_params)[:byte_align]
390
+ if obj_class < NdrFixArray
391
+ # Fixed size arrays doesn't have size information
392
+ params[:byte_align] = byte_align
393
+ else
394
+ params[:byte_align] = [4, byte_align].max
395
+ end
396
+ return res
397
+ elsif type_params&.key?(:byte_align)
398
+ return res
399
+ end
400
+
401
+ raise ArgumentError.new(
402
+ "NDR Arrays must only include elements with the `:byte_align` "\
403
+ "parameter set. This makes sure the whole structure is correctly "\
404
+ "aligned. Use a predefined NDR element instead, or provide the "\
405
+ "`:byte_align` parameter in `:type` (Faulty element type: #{params[:type]})"
406
+ )
407
+ end
408
+ end
409
+
410
+ # [Uni-dimensional Fixed Arrays](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_01)
411
+ class NdrFixArray < BinData::Array
412
+ arg_processor :ndr_array
413
+
414
+ def initialize_shared_instance
415
+ super
416
+ extend ArrayPlugin
417
+ end
418
+
419
+ def insert(index, *objs)
420
+ fixed_size = get_parameter(:initial_length)
421
+ if (length + objs.size) != fixed_size
422
+ raise ArgumentError, "Can't add new elements to a NdrFixArray (set to #{fixed_size} elements)"
423
+ else
424
+ super
425
+ end
426
+ end
427
+
428
+ def append_new_element
429
+ fixed_size = get_parameter(:initial_length)
430
+ raise ArgumentError, "Can't add new elements to a NdrFixArray (set to #{fixed_size} elements)"
431
+ end
432
+ end
433
+
434
+ # Specific implementation for fixed array of bytes, which can be set from an array of unit8 or a string
435
+ class NdrFixedByteArray < NdrFixArray
436
+ default_parameters(type: :ndr_uint8, byte_align: 1)
437
+
438
+ def assign(val)
439
+ val = val.bytes if val.is_a?(String)
440
+ super(val.to_ary)
441
+ end
442
+ end
443
+
444
+ # [Uni-dimensional Conformant Arrays](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_02)
445
+ class NdrConfArray < BinData::Array
446
+ extend ArrayClassPlugin
447
+ end
448
+
449
+ # [Uni-dimensional Varying Arrays](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_03)
450
+ class NdrVarArray < BinData::Array
451
+ extend ArrayClassPlugin
452
+ end
453
+
454
+ # Uni-dimensional Conformant-varying Arrays
455
+ class NdrConfVarArray < BinData::Array
456
+ extend ArrayClassPlugin
457
+ end
458
+
459
+ # TODO: Multi-dimensional Arrays
460
+
461
+
462
+
463
+ #
464
+ # Strings
465
+ #
466
+
467
+ module StringClassPlugin
468
+ module ExtendVarStringPlugin
469
+ def initialize_shared_instance
470
+ super
471
+ extend VarStringPlugin
472
+ end
473
+ end
474
+ module ExtendConfStringPlugin
475
+ def initialize_shared_instance
476
+ super
477
+ extend ConfStringPlugin
478
+ end
479
+ end
480
+ def self.extended(target)
481
+ target.default_parameters byte_align: 4
482
+ char_size = 1
483
+ char_size = 2 if target < RubySMB::Field::String16 || target < RubySMB::Field::Stringz16
484
+ if target < BinData::Stringz
485
+ target.default_parameters(:max_length => lambda { @obj.actual_count * char_size })
486
+ else
487
+ target.default_parameters(:length => lambda { @obj.actual_count * char_size })
488
+ end
489
+ target.include ExtendVarStringPlugin
490
+ class_name = target.to_s.split('::').last
491
+ if class_name.include?('NdrConfVar')
492
+ target.include ExtendConfStringPlugin
493
+ target.extend ConfClassPlugin
494
+ end
495
+ end
496
+ end
497
+
498
+ module ConfStringPlugin
499
+ attr_accessor :max_count
500
+
501
+ def initialize_instance
502
+ @max_count = 0
503
+ if has_parameter?(:initial_value)
504
+ set_max_count(get_max_count(eval_parameter(:initial_value)))
505
+ end
506
+ super
507
+ end
508
+
509
+ def should_process_max_count?
510
+ # :max_count has already been processed if the parent structure is an
511
+ # NdrStruct, but this is not the case if we are dealing with a pointer
512
+ !parent.is_a?(NdrStruct) || self.is_a?(PointerPlugin)
513
+ end
514
+
515
+ def do_write(io)
516
+ if should_process_max_count?
517
+ io.writebytes([@max_count].pack('L<'))
518
+ end
519
+ super
520
+ end
521
+
522
+ def do_read(io)
523
+ if should_process_max_count?
524
+ set_max_count(io.readbytes(4).unpack('L<').first)
525
+ end
526
+ super
527
+ end
528
+
529
+ def assign(val)
530
+ if val.is_a?(ConfStringPlugin)
531
+ @max_count = val.max_count
532
+ else
533
+ set_max_count(get_max_count(val))
534
+ end
535
+ super
536
+ end
537
+
538
+ def do_num_bytes
539
+ sum = 0
540
+ if should_process_max_count?
541
+ # add max_count size
542
+ sum += 4
543
+ end
544
+ sum + super
545
+ end
546
+
547
+ def get_max_count(val)
548
+ if is_a?(BinData::Stringz)
549
+ max_count = val.to_s.strip.length
550
+ # Only count the terminating NULL byte if the string is not empty
551
+ max_count += 1 if max_count > 0
552
+ return max_count
553
+ else
554
+ return val.to_s.length
555
+ end
556
+ end
557
+
558
+ def set_max_count(val)
559
+ @max_count = val
560
+ end
561
+ end
562
+
563
+ module VarStringPlugin
564
+ attr_accessor :actual_count, :offset
565
+
566
+ def initialize_instance
567
+ @offset = 0
568
+ @actual_count = 0
569
+ if has_parameter?(:initial_value)
570
+ update_actual_count(eval_parameter(:initial_value))
571
+ end
572
+ super
573
+ end
574
+
575
+ def do_write(io)
576
+ io.writebytes([@offset].pack('L<'))
577
+ io.writebytes([@actual_count].pack('L<'))
578
+ super if @actual_count > 0
579
+ end
580
+
581
+ def do_read(io)
582
+ @offset = io.readbytes(4).unpack('L<').first
583
+ @actual_count = io.readbytes(4).unpack('L<').first
584
+ super if @actual_count > 0
585
+ end
586
+
587
+ def assign(val)
588
+ update_actual_count(val)
589
+ super
590
+ end
591
+
592
+ def do_num_bytes
593
+ @actual_count > 0 ? (8 + super) : 8
594
+ end
595
+
596
+ def update_actual_count(val)
597
+ if is_a?(BinData::Stringz)
598
+ @actual_count = val.to_s.strip.length
599
+ # Only count the terminating NULL byte if the string is not empty
600
+ @actual_count += 1 if @actual_count > 0
601
+ else
602
+ @actual_count = val.to_s.length
603
+ end
604
+ end
605
+ end
606
+
607
+ # [Varying Strings](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_01)
608
+ class NdrVarString < BinData::String
609
+ extend StringClassPlugin
610
+ end
611
+
612
+ class NdrVarStringz < BinData::Stringz
613
+ extend StringClassPlugin
614
+ end
615
+
616
+ class NdrVarWideString < RubySMB::Field::String16
617
+ extend StringClassPlugin
618
+ end
619
+
620
+ class NdrVarWideStringz < RubySMB::Field::Stringz16
621
+ extend StringClassPlugin
622
+ end
623
+
624
+ # [Conformant and Varying Strings](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_02)
625
+ class NdrConfVarString < BinData::String
626
+ extend StringClassPlugin
627
+ end
628
+
629
+ class NdrConfVarStringz < BinData::Stringz
630
+ extend StringClassPlugin
631
+ end
632
+
633
+ class NdrConfVarWideString < RubySMB::Field::String16
634
+ extend StringClassPlugin
635
+ end
636
+
637
+ class NdrConfVarWideStringz < RubySMB::Field::Stringz16
638
+ extend StringClassPlugin
639
+ end
640
+
641
+ # TODO:[Arrays of Strings](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_05)
642
+ # Microsoft DCERPC uses array of pointers for strings. I couldn't find any reference to array of strings.
643
+
644
+
645
+ #
646
+ # [Structures](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_06)
647
+ #
648
+
649
+ module StructPlugin
650
+ include ConstructedTypePlugin
651
+
652
+ def should_process_max_count?
653
+ # According to the NDR defintion for Structures Containing a Conformant
654
+ # Array:
655
+ #
656
+ # "In the NDR representation of a structure that contains a
657
+ # conformant array, the unsigned long integers that give maximum element
658
+ # counts for dimensions of the array are moved to the beginning of the
659
+ # structure, and the array elements appear in place at the end of the
660
+ # structure. If a structure that contains a conformant array itself a
661
+ # member of another structure, the maximum element counts are further
662
+ # moved to the beginning of the containing structure. This construction
663
+ # iterates through all enclosing structures."
664
+ #
665
+ # This only applies if the current object is the top level structure (no
666
+ # parent). Note that if it is a pointer to a structure and the current
667
+ # object is being deferred, :max_count still need to be processed since
668
+ # it had not been moved to the beginning of the parent structure.
669
+ klass = is_a?(PointerPlugin) ? self.class.superclass : self.class
670
+ parent_obj = nil
671
+ # TODO: possible issue: parent can be a BinData::Choice, and won't be
672
+ # detected as a ConstructedTypePlugin, even if the embeding structure is.
673
+ # Check this with a BinData::Choice that points to a structure embedding
674
+ # a conformant structure
675
+ if parent&.is_a?(ConstructedTypePlugin)
676
+ parent_obj = parent.get_top_level_constructed_type
677
+ end
678
+ klass.has_conformant_array && (parent_obj.nil? || parent_obj.is_deferring(self))
679
+ end
680
+
681
+ def do_write(io)
682
+ if should_process_max_count?
683
+ max_count = retrieve_max_count
684
+ io.writebytes([max_count].pack('L<')) if max_count
685
+
686
+ # Align the structure according to the alignment rules for the structure
687
+ if respond_to?(:referent_bytes_align)
688
+ io.writebytes("\x00" * referent_bytes_align(io.offset))
689
+ elsif has_parameter?(:byte_align)
690
+ io.writebytes("\x00" * bytes_to_align(self, io.offset))
28
691
  end
692
+ end
693
+
694
+ super
695
+
696
+ if has_deferred_ptrs?
697
+ write_ptr(io)
698
+ end
699
+ end
700
+
701
+ def do_read(io)
702
+ if should_process_max_count?
703
+ set_max_count(io.readbytes(4).unpack('L<').first)
29
704
 
30
- def is_a_null_pointer?
31
- self.referent_identifier == 0
705
+ # Align the structure according to the alignment rules for the structure
706
+ if respond_to?(:referent_bytes_align)
707
+ io.seekbytes(referent_bytes_align(io.offset))
708
+ elsif has_parameter?(:byte_align)
709
+ io.seekbytes(bytes_to_align(self, io.offset))
32
710
  end
33
711
  end
34
712
 
35
- # An NDR Conformant and Varying String representation as defined in
36
- # [Transfer Syntax NDR - Conformant and Varying Strings](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_02)
37
- # The string elements are Stringz16 (unicode)
38
- class NdrString < BinData::Primitive
39
- endian :little
713
+ super
40
714
 
41
- uint32 :max_count
42
- uint32 :offset, initial_value: 0
43
- uint32 :actual_count
44
- stringz16 :str, read_length: -> { actual_count }, onlyif: -> { actual_count > 0 }
715
+ if has_deferred_ptrs?
716
+ read_ptr(io)
717
+ end
718
+ end
719
+
720
+ def retrieve_max_count
721
+ obj = self[field_names.last]
722
+ return obj.length if obj.is_a?(ConfPlugin)
723
+ return obj.get_max_count(obj) if obj.is_a?(ConfStringPlugin)
724
+ if obj.is_a?(NdrStruct)
725
+ return obj.retrieve_max_count
726
+ end
727
+ end
728
+
729
+ def set_max_count(val)
730
+ obj = self[field_names.last]
731
+ obj.set_max_count(val)
732
+ end
733
+
734
+ def do_num_bytes
735
+ sum = 0
736
+
737
+ if should_process_max_count?
738
+ # count max_count (4 bytes)
739
+ max_count = retrieve_max_count
740
+ sum += 4 if max_count
45
741
 
46
- def get
47
- self.actual_count == 0 ? 0 : self.str
742
+ if respond_to?(:referent_bytes_align)
743
+ sum += referent_bytes_align(sum)
744
+ elsif has_parameter?(:byte_align)
745
+ sum += bytes_to_align(self, sum)
48
746
  end
747
+ end
49
748
 
50
- def set(v)
51
- if v.is_a?(Integer) && v == 0
52
- self.actual_count = 0
53
- else
54
- self.str = v
55
- self.max_count = self.actual_count = str.to_binary_s.size / 2
56
- end
749
+ sum += super
750
+
751
+ if has_deferred_ptrs?
752
+ sum += do_num_bytes_ptr(sum)
753
+ end
754
+
755
+ sum
756
+ end
757
+
758
+ def bytes_to_align(obj, rel_offset)
759
+ if obj.is_a?(PointerPlugin)
760
+ # Pointers are always 4-bytes aligned
761
+ return (4 - (rel_offset % 4)) % 4
762
+ end
763
+ if obj.is_a?(ConfPlugin)
764
+ # `max_count` should have been handled at the begining of the structure
765
+ # already. We need to fix `rel_offset` since it includes the
766
+ # `max_count` 4 bytes, plus the possible padding bytes needed to align
767
+ # the structure. This is required because BinData Struct is not
768
+ # aware of `max_count` and considere the first field to be the begining
769
+ # of the structure instead. We have to make sure the alignment is
770
+ # calculated from the begining of the structure.
771
+ align = eval_parameter(:byte_align)
772
+ pad_length = (align - (4 % align)) % align
773
+ rel_offset += (4 + pad_length)
774
+
775
+ # We need to handle another corner case, which is a Conformant array
776
+ # (not Varying). The size information (max_count) has been place in
777
+ # from of the structure and no other size information is present before
778
+ # the actual elements of the array. Therefore, the alignment must be
779
+ # done accroding to th rules of the elements. Since a NdrArray has its
780
+ # default :byte_align value set to 4 (:max_count size), we have to make
781
+ # sure the element size is used instead.
782
+ unless obj.is_a?(VarPlugin)
783
+ return obj.align_element_size(rel_offset)
57
784
  end
58
785
  end
786
+ is_a?(BinData::ByteAlignPlugin) ? super : 0
59
787
 
60
- # A pointer to a NdrString structure
61
- class NdrLpStr < NdrTopLevelFullPointer
62
- endian :little
788
+ end
789
+ end
790
+
791
+ class NdrStruct < BinData::Record
792
+ # Caller must specify :byte_align according to the type of the largest element in the structure.
793
+ # See https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_02
794
+ #
795
+ # "The alignment of a structure in the octet stream is the largest of the
796
+ # alignments of the fields it contains. These fields may also be
797
+ # constructed types. The same alignment rules apply recursively to nested
798
+ # constructed types."
799
+ mandatory_parameters(:byte_align)
63
800
 
64
- ndr_string :referent, onlyif: -> { !is_a_null_pointer? }
801
+ class << self; attr_reader :has_conformant_array end
65
802
 
66
- def to_s
67
- is_a_null_pointer? ? "\0" : self.referent
803
+ def self.validate_conformant_array(field)
804
+ if @has_conformant_array
805
+ raise ArgumentError.new(
806
+ "Invalid structure #{self}: Conformant array or embedded structure "\
807
+ "with Conformant array must be the last member of the structure"
808
+ )
809
+ end
810
+ obj_proto = field.last.prototype
811
+ obj_class = obj_proto.instance_variable_get(:@obj_class)
812
+ @has_conformant_array = true if obj_class < NdrStruct && obj_class.has_conformant_array
813
+ if obj_class.is_a?(ConfClassPlugin) && !obj_class.is_a?(PointerClassPlugin)
814
+ @has_conformant_array = true
815
+ end
816
+ end
817
+
818
+ def self.method_missing(symbol, *args, &block)
819
+ field = super
820
+ if field.is_a?(::Array) && field.last.is_a?(BinData::SanitizedField)
821
+ unless field.last.has_parameter?(:byte_align) || field.last.instantiate.bit_aligned?
822
+ raise ArgumentError.new(
823
+ "NDR Structures must only include elements with the `:byte_align` "\
824
+ "parameter set. This makes sure the whole structure is correctly "\
825
+ "aligned. Use a predefined NDR element instead, or provide the "\
826
+ "`:byte_align` parameter when defining the structure "\
827
+ "(Faulty element: #{field.last.name})"
828
+ )
68
829
  end
830
+ validate_conformant_array(field)
831
+ end
832
+ field
833
+ end
834
+
835
+ def initialize_shared_instance
836
+ super
837
+ extend StructPlugin
838
+ end
839
+ end
840
+
841
+ # TODO: Unions
842
+ # TODO: Pipes
843
+
844
+ #
845
+ # [Pointers](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_10)
846
+ #
847
+
848
+ module PointerClassPlugin
849
+ module ExtendPointerPlugin
850
+ def initialize_shared_instance
851
+ super
852
+ extend PointerPlugin
853
+ end
854
+ end
855
+ def self.extended(target)
856
+ target.default_parameters byte_align: 4
857
+ target.arg_processor :ndr_pointer
858
+ target.include ExtendPointerPlugin
859
+ end
860
+ end
861
+
862
+
863
+ module TopLevelPlugin
864
+ module TopLevelClassMethods
865
+ def pos
866
+ @@pos
867
+ end
868
+ def increment_pos
869
+ @@pos += 1
870
+ end
871
+ def reset_pos
872
+ @@pos = 0
873
+ end
874
+ end
875
+
876
+ def self.extended(target)
877
+ target.class.extend(TopLevelClassMethods)
878
+ target.class.reset_pos
879
+ end
880
+
881
+ def initialize_instance
882
+ super
883
+ @standalone_ptr = false
884
+ end
885
+
886
+ def do_write(io, is_deferred: false)
887
+ # If for whatever reasons, the #pos value has been modified, reset it to
888
+ # make sure the pointer ref_id will start from INITIAL_REF_ID
889
+ self.class.reset_pos if is_top_level_ptr || @standalone_ptr
890
+ if is_deferred
891
+ super(io, is_deferred: is_deferred)
892
+ else
893
+ super(io)
69
894
  end
895
+ # Since #pos has been incremented for each embedded pointer, let's reset
896
+ # it to go back to its initial state
897
+ self.class.reset_pos if is_top_level_ptr || @standalone_ptr
898
+ end
899
+
900
+ def to_binary_s
901
+ @standalone_ptr = true
902
+ res = super
903
+ @standalone_ptr = false
904
+ res
905
+ end
906
+
907
+ def set_top_level_ptr
908
+ @top_level_ptr = true
909
+ #update_ref_ids
910
+ end
911
+
912
+ def unset_top_level_ptr
913
+ @top_level_ptr = false
914
+ end
915
+
916
+ def is_top_level_ptr
917
+ !!@top_level_ptr
918
+ end
919
+
920
+ def num_bytes
921
+ @standalone_ptr = true
922
+ res = super
923
+ @standalone_ptr = false
924
+ res
925
+ end
926
+ end
927
+
928
+ # Windows SMB client uses 0x00020000 as an initial reference ID, but it is
929
+ # rejected by the server on the Windows Server 2003. On this version, only
930
+ # 0x00000001 seems to be accepted. So, we need to use this value to maintain
931
+ # compatibility.
932
+ INITIAL_REF_ID = 0x00000001
933
+
934
+ module PointerPlugin
935
+ attr_accessor :ref_id
70
936
 
71
- # An NDR Context Handle representation as defined in
72
- # [IDL Data Type Declarations - Basic Type Declarations](http://pubs.opengroup.org/onlinepubs/9629399/apdxn.htm#tagcjh_34_01)
73
- class NdrContextHandle < BinData::Primitive
74
- endian :little
75
- uint32 :context_handle_attributes
76
- uuid :context_handle_uuid
937
+ def initialize_instance
938
+ if @ref_id.nil?
939
+ if eval_parameter(:initial_value)
940
+ instantiate_referent
941
+ else
942
+ @ref_id = 0
943
+ end
944
+ end
945
+ extend_top_level_class
946
+ super
947
+ end
77
948
 
78
- def get
79
- {:context_handle_attributes => context_handle_attributes, :context_handle_uuid => context_handle_uuid}
949
+ def extend_top_level_class
950
+ current = self
951
+ loop do
952
+ current.extend(TopLevelPlugin) unless current.is_a?(TopLevelPlugin)
953
+ if current.parent.nil?
954
+ current.set_top_level_ptr unless current.is_top_level_ptr
955
+ break
956
+ else
957
+ current.unset_top_level_ptr if current.is_top_level_ptr
958
+ current = current.parent
80
959
  end
960
+ end
961
+ end
962
+
963
+ def snapshot
964
+ if is_alias?
965
+ fetch_alias_referent
966
+ elsif is_null_ptr? && !eval_parameter(:initial_value)
967
+ :null
968
+ else
969
+ super
970
+ end
971
+ end
972
+
973
+ def referent_bytes_align(offset)
974
+ align = self.class.superclass.default_parameters[:byte_align]
975
+ align = eval_parameter(:referent_byte_align) unless align
976
+ (align - (offset % align)) % align
977
+ end
81
978
 
82
- def set(handle)
83
- if handle.is_a?(Hash)
84
- self.context_handle_attributes = handle[:context_handle_attributes]
85
- self.context_handle_uuid = handle[:context_handle_uuid]
86
- elsif handle.is_a?(NdrContextHandle)
87
- read(handle.to_binary_s)
88
- else
89
- read(handle.to_s)
979
+ def write_ref_id(io)
980
+ if is_alias?
981
+ ref_field = fetch_alias_referent
982
+ if ref_field
983
+ if ref_field.class != self.class
984
+ raise ArgumentError, "Pointer points to a different referent type: #{ref_field.class} (set to #{obj.class})"
90
985
  end
986
+ @ref_id = ref_field.ref_id
987
+ end
988
+ elsif @ref_id != 0 || (is_null_ptr? && eval_parameter(:initial_value))
989
+ @ref_id = INITIAL_REF_ID + self.class.pos
990
+ self.class.increment_pos unless @standalone_ptr
991
+ end
992
+ io.writebytes([@ref_id].pack('L<'))
993
+ end
994
+
995
+ def do_write(io, is_deferred: false)
996
+ if is_deferred
997
+ if is_a?(NdrStruct) && self.class.superclass.has_conformant_array
998
+ # align :max_count since it will be placed in front of the structure.
999
+ # The structure itself will be properly aligned later.
1000
+ align = (4 - (io.offset % 4)) % 4
1001
+ io.writebytes("\x00" * align)
1002
+ else
1003
+ io.writebytes("\x00" * referent_bytes_align(io.offset))
1004
+ end
1005
+ else
1006
+ write_ref_id(io)
1007
+ parent_obj = nil
1008
+ if parent&.is_a?(ConstructedTypePlugin)
1009
+ parent_obj = parent.get_top_level_constructed_type
1010
+ end
1011
+ if parent_obj && @ref_id != 0 && !@standalone_ptr
1012
+ parent_obj.defer_ptr(self)
1013
+ return
91
1014
  end
92
1015
  end
1016
+ super(io) unless (is_null_ptr? && !eval_parameter(:initial_value)) || is_alias?
1017
+ end
93
1018
 
94
- # A pointer to a DWORD
95
- class NdrLpDword < NdrTopLevelFullPointer
96
- endian :little
1019
+ def do_read(io, is_deferred: false)
1020
+ if is_deferred
1021
+ if is_a?(NdrStruct) && self.class.superclass.has_conformant_array
1022
+ # align :max_count since it will be placed in front of the structure.
1023
+ # The structure itself will be properly aligned later.
1024
+ align = (4 - (io.offset % 4)) % 4
1025
+ io.seekbytes(align)
1026
+ else
1027
+ io.seekbytes(referent_bytes_align(io.offset))
1028
+ end
1029
+ else
1030
+ @ref_id = io.readbytes(4).unpack('L<').first
1031
+ parent_obj = nil
1032
+ if parent&.is_a?(ConstructedTypePlugin)
1033
+ parent_obj = parent.get_top_level_constructed_type
1034
+ end
1035
+ if parent_obj && @ref_id != 0
1036
+ parent_obj.defer_ptr(self)
1037
+ return
1038
+ end
1039
+ end
1040
+ super(io) unless is_null_ptr? || is_alias?
1041
+ end
97
1042
 
98
- uint32 :referent, onlyif: -> { !is_a_null_pointer? }
1043
+ def assign(val)
1044
+ if val == :null
1045
+ @ref_id = 0
1046
+ elsif is_alias?
1047
+ ref_field = fetch_alias_referent
1048
+ raise ArgumentError, "Referent of alias pointer does not exist: #{get_parameter(:ref_to)}" unless ref_field
1049
+ ref_field.assign(val)
1050
+ else
1051
+ instantiate_referent if is_null_ptr?
1052
+ super
99
1053
  end
1054
+ end
100
1055
 
101
- # An NDR Uni-dimensional Conformant-varying Arrays representation as defined in:
102
- # [Transfer Syntax NDR - NDR Constructed Types](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_04)
103
- class NdrLpByte < BinData::Record
104
- endian :little
1056
+ def is_alias?
1057
+ has_parameter?(:ref_to)
1058
+ end
105
1059
 
106
- uint32 :referent_identifier, initial_value: 0x00020000
107
- uint32 :max_count, initial_value: -> { actual_count }, onlyif: -> { referent_identifier != 0 }
108
- uint32 :offset, initial_value: 0, onlyif: -> { referent_identifier != 0 }
109
- uint32 :actual_count, initial_value: -> { bytes.size }, onlyif: -> { referent_identifier != 0 }
110
- array :bytes, :type => :uint8, initial_length: -> { actual_count }, onlyif: -> { referent_identifier != 0 }
1060
+ def fetch_alias_referent(current: parent, ref: get_parameter(:ref_to), name: nil)
1061
+ return if current.nil?
1062
+ if current.get_parameter(:ref_to) == ref
1063
+ raise ArgumentError.new(
1064
+ "Pointer alias refering to #{ref} cannot be found. This referent "\
1065
+ "should appears before the alias in the stream"
1066
+ )
1067
+ end
1068
+ return current if name == ref
1069
+ res = nil
1070
+ case current
1071
+ when ArrayPlugin
1072
+ current.each do |element|
1073
+ res = fetch_alias_referent(current: element, ref: ref, name: name)
1074
+ break if res
1075
+ end
1076
+ when BinData::Record, BinData::Struct
1077
+ current.each_pair do |name, field|
1078
+ res = fetch_alias_referent(current: field, ref: ref, name: name)
1079
+ break if res
1080
+ end
111
1081
  end
1082
+ return res
1083
+ end
112
1084
 
113
- # A pointer to a Windows FILETIME structure
114
- class NdrLpFileTime < NdrTopLevelFullPointer
115
- endian :little
1085
+ def do_num_bytes(struct_offset = 0, is_deferred: false)
1086
+ sum = 0
1087
+ if is_deferred
1088
+ if is_a?(NdrStruct) && self.class.superclass.has_conformant_array
1089
+ # align :max_count since it will be placed in front of the structure.
1090
+ # The structure itself will be properly aligned later.
1091
+ align = (4 - (struct_offset % 4)) % 4
1092
+ sum += align
1093
+ else
1094
+ sum += referent_bytes_align(struct_offset)
1095
+ end
1096
+ else
1097
+ # add ref_id size
1098
+ sum += 4
116
1099
 
117
- file_time :referent, onlyif: -> { !is_a_null_pointer? }
1100
+ parent_obj = nil
1101
+ if parent&.is_a?(ConstructedTypePlugin)
1102
+ parent_obj = parent.get_top_level_constructed_type
1103
+ end
1104
+ if parent_obj && @ref_id != 0 && !@standalone_ptr
1105
+ parent_obj.defer_ptr(self)
1106
+ # only return ref_id size, the actual referent size will be added later
1107
+ return sum
1108
+ end
1109
+ end
1110
+ unless (is_null_ptr? && !eval_parameter(:initial_value)) || is_alias?
1111
+ if is_a?(ArrayPlugin)
1112
+ sum += super(struct_offset + sum)
1113
+ else
1114
+ sum += super()
1115
+ end
118
1116
  end
1117
+
1118
+ sum
1119
+ end
1120
+
1121
+ def instantiate_referent
1122
+ @ref_id = INITIAL_REF_ID
1123
+ end
1124
+
1125
+ def is_null_ptr?
1126
+ @ref_id == 0
1127
+ end
1128
+
1129
+ def insert(index, *objs)
1130
+ obj = super
1131
+ # If we just pushed a new element and it was a null pointer (ref_id==0),
1132
+ # we will initialize the ref_id to make sure it is not considered a null
1133
+ # pointer anymore
1134
+ if is_null_ptr? && is_a?(BinData::Array) && !empty?
1135
+ instantiate_referent
1136
+ end
1137
+ obj
1138
+ end
1139
+ end
1140
+
1141
+ class ::BinData::NdrPointerArgProcessor < BinData::BaseArgProcessor
1142
+ def sanitize_parameters!(obj_class, params)
1143
+ obj_klass = obj_class
1144
+ obj_klass = obj_class.superclass if obj_class.superclass.arg_processor == self
1145
+ res = obj_class.superclass.arg_processor.sanitize_parameters!(obj_klass, params)
1146
+
1147
+ return res if obj_class.superclass.default_parameters[:byte_align]
1148
+ return res if params[:referent_byte_align]
1149
+
1150
+ raise ArgumentError.new(
1151
+ "NDR Pointers referent must have `:byte_align` parameter set. This "\
1152
+ "makes sure the whole structure is correctly aligned. Use a predefined "\
1153
+ "NDR element instead, or provide the `:referent_byte_align` parameter "\
1154
+ "when defining the structure (Faulty pointer class: #{obj_class})"
1155
+ )
1156
+ end
1157
+
1158
+ def extract_args(obj_class, obj_args)
1159
+ obj_class = obj_class.superclass if obj_class.superclass.arg_processor == self
1160
+ obj_class.superclass.arg_processor.extract_args(obj_class, obj_args)
1161
+ end
1162
+ end
1163
+
1164
+ # Pointers to NDR integers. This defined four pointers:
1165
+ # - NdrUint8Ptr
1166
+ # - NdrUint16Ptr
1167
+ # - NdrUint32Ptr
1168
+ # - NdrUint64Ptr
1169
+ {NdrUint8: 1, NdrUint16: 2, NdrUint32: 4, NdrUint64: 8}.each do |klass, align|
1170
+ new_klass_name = "#{klass.to_s}Ptr"
1171
+ unless self.const_defined?(new_klass_name)
1172
+ new_klass = Class.new(const_get(klass)) do
1173
+ extend PointerClassPlugin
1174
+ end
1175
+ self.const_set(new_klass_name, new_klass)
1176
+ BinData::RegisteredClasses.register(new_klass_name, new_klass)
119
1177
  end
120
1178
  end
1179
+
1180
+ # Pointers to other classes
1181
+ class NdrCharPtr < NdrChar
1182
+ extend PointerClassPlugin
1183
+ end
1184
+
1185
+ class NdrBooleanPtr < NdrBoolean
1186
+ extend PointerClassPlugin
1187
+ end
1188
+
1189
+ class NdrStringPtr < NdrConfVarString
1190
+ extend PointerClassPlugin
1191
+ end
1192
+
1193
+ class NdrStringzPtr < NdrConfVarStringz
1194
+ extend PointerClassPlugin
1195
+ end
1196
+
1197
+ class NdrWideStringPtr < NdrConfVarWideString
1198
+ extend PointerClassPlugin
1199
+ end
1200
+
1201
+ class NdrWideStringzPtr < NdrConfVarWideStringz
1202
+ extend PointerClassPlugin
1203
+ end
1204
+
1205
+ class NdrByteArrayPtr < NdrConfVarArray
1206
+ default_parameters type: :ndr_uint8
1207
+ extend PointerClassPlugin
1208
+ end
1209
+
1210
+ class NdrFileTimePtr < NdrFileTime
1211
+ extend PointerClassPlugin
1212
+ end
1213
+
1214
+ class UuidPtr < RubySMB::Dcerpc::Uuid
1215
+ default_parameter referent_byte_align: 4
1216
+ extend PointerClassPlugin
1217
+ end
1218
+
1219
+ # An NDR Context Handle representation as defined in
1220
+ # [IDL Data Type Declarations - Basic Type Declarations](http://pubs.opengroup.org/onlinepubs/9629399/apdxn.htm#tagcjh_34_01)
1221
+ class NdrContextHandle < BinData::Primitive
1222
+ default_parameters byte_align: 4
1223
+ endian :little
1224
+
1225
+ uint32 :context_handle_attributes
1226
+ uuid :context_handle_uuid
1227
+
1228
+ def get
1229
+ {:context_handle_attributes => context_handle_attributes, :context_handle_uuid => context_handle_uuid}
1230
+ end
1231
+
1232
+ def set(handle)
1233
+ if handle.is_a?(Hash)
1234
+ self.context_handle_attributes = handle[:context_handle_attributes]
1235
+ self.context_handle_uuid = handle[:context_handle_uuid]
1236
+ elsif handle.is_a?(NdrContextHandle)
1237
+ read(handle.to_binary_s)
1238
+ else
1239
+ read(handle.to_s)
1240
+ end
1241
+ end
1242
+ end
1243
+
121
1244
  end
1245
+